Compare commits
616 Commits
wip/jimmac
...
gbsneto/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6345a5c8b | ||
|
|
628b34e96f | ||
|
|
5743b52ec8 | ||
|
|
55b57421dc | ||
|
|
320df13b65 | ||
|
|
e4920b2f80 | ||
|
|
c9fbae3408 | ||
|
|
a3c6217875 | ||
|
|
db7726c5bf | ||
|
|
0b91dee5a9 | ||
|
|
3838220961 | ||
|
|
9bb12f6f87 | ||
|
|
4dea1f801a | ||
|
|
91a5133116 | ||
|
|
c4c5c4fd5c | ||
|
|
f67b409fc1 | ||
|
|
22fe4e92c7 | ||
|
|
91eb84fa4e | ||
|
|
4e1492c926 | ||
|
|
ed97f61750 | ||
|
|
b5676a2a5c | ||
|
|
7059dcced3 | ||
|
|
c7e0c7eb79 | ||
|
|
ff775213a5 | ||
|
|
7f9c709c85 | ||
|
|
74d7d3e259 | ||
|
|
0353a5bf2c | ||
|
|
ab6a629955 | ||
|
|
6cad251187 | ||
|
|
d7c569c692 | ||
|
|
0615370930 | ||
|
|
7a92a9ba21 | ||
|
|
0199857c5b | ||
|
|
59e3a1a816 | ||
|
|
6533690fff | ||
|
|
d0d1845bb6 | ||
|
|
20f4fc7c87 | ||
|
|
b4128967a1 | ||
|
|
38ad1d7c13 | ||
|
|
f78136182f | ||
|
|
11d46cf5b3 | ||
|
|
7326e7a9fa | ||
|
|
a65164e540 | ||
|
|
279024afc2 | ||
|
|
ef8000d2e6 | ||
|
|
986600ab31 | ||
|
|
3d39b32a0b | ||
|
|
6205d5eb27 | ||
|
|
a722b4c51d | ||
|
|
31fe517007 | ||
|
|
31d915a38a | ||
|
|
e00878ab75 | ||
|
|
3b5675b79a | ||
|
|
ee97512bcc | ||
|
|
085531b43d | ||
|
|
9e8b97d474 | ||
|
|
a3a7953704 | ||
|
|
92c0171aeb | ||
|
|
6a6d66486d | ||
|
|
1cc766d636 | ||
|
|
60cad01880 | ||
|
|
63c9a6efd0 | ||
|
|
1d1b42756f | ||
|
|
a95601afdb | ||
|
|
2dbdf792db | ||
|
|
e23ce37e62 | ||
|
|
a05cb76e0d | ||
|
|
60cab56f86 | ||
|
|
70a5c3875c | ||
|
|
0fdbde9101 | ||
|
|
2156577333 | ||
|
|
f3e09b2b2f | ||
|
|
6180f59c13 | ||
|
|
506b75fc7f | ||
|
|
a0d0a17d68 | ||
|
|
92e5713e29 | ||
|
|
856c32db91 | ||
|
|
7b45ffa511 | ||
|
|
b6754d7db7 | ||
|
|
2a9977a5b3 | ||
|
|
dab60d5580 | ||
|
|
8e3aac8ed7 | ||
|
|
147cb53140 | ||
|
|
54f369404a | ||
|
|
af1aabff75 | ||
|
|
d6ba6dc554 | ||
|
|
42188b7698 | ||
|
|
48adb2ef4b | ||
|
|
f8e648b7e3 | ||
|
|
daa5452af2 | ||
|
|
259874d731 | ||
|
|
23344701de | ||
|
|
00e95de114 | ||
|
|
942758bb30 | ||
|
|
e0947b01bd | ||
|
|
cf00231aa8 | ||
|
|
5c3f4f5f8b | ||
|
|
5f10047b58 | ||
|
|
3094f86334 | ||
|
|
8ffea9d5c5 | ||
|
|
4f3c8b8d69 | ||
|
|
edf6bd6909 | ||
|
|
3e58af10ca | ||
|
|
9e55d262f9 | ||
|
|
252e694979 | ||
|
|
efed695eca | ||
|
|
b446667df6 | ||
|
|
133a1e7bef | ||
|
|
5b3935fa43 | ||
|
|
471165ca9b | ||
|
|
111f87a1b2 | ||
|
|
93525539c2 | ||
|
|
a77377efe7 | ||
|
|
81ab2865f7 | ||
|
|
e585f7d97b | ||
|
|
1a32e3e74a | ||
|
|
8d6820c4df | ||
|
|
2546445884 | ||
|
|
e44b7df078 | ||
|
|
3a9eaa39ea | ||
|
|
af87bd8c87 | ||
|
|
4bfb4a0e3d | ||
|
|
d1a6601e60 | ||
|
|
817aec5466 | ||
|
|
314a89a837 | ||
|
|
57ed68541a | ||
|
|
413c677fcf | ||
|
|
3d86e6e791 | ||
|
|
3fbd61cbf0 | ||
|
|
43b4f2c7d5 | ||
|
|
7eb4088f45 | ||
|
|
f00201fa6c | ||
|
|
1aca2ba6bb | ||
|
|
e9131465dd | ||
|
|
0ee7f02f8e | ||
|
|
451f4e3636 | ||
|
|
2fc4987c73 | ||
|
|
4525ad346d | ||
|
|
e4b8a4b432 | ||
|
|
62e594af6d | ||
|
|
ce92270626 | ||
|
|
bdcf3037ca | ||
|
|
9698ff491a | ||
|
|
2a9e065cfb | ||
|
|
4c93ef39fa | ||
|
|
22107c183b | ||
|
|
c06eb5d0a7 | ||
|
|
e76877c4b8 | ||
|
|
2a32fb2e72 | ||
|
|
de86920e0e | ||
|
|
8754736fda | ||
|
|
d2ead59d74 | ||
|
|
2f4fcc59a1 | ||
|
|
ba6dbb228d | ||
|
|
60e386048b | ||
|
|
c2904fa14d | ||
|
|
dfdb139d9c | ||
|
|
ce63d21dcc | ||
|
|
1da9937453 | ||
|
|
9f11fbad16 | ||
|
|
f54e7804c5 | ||
|
|
7db5f8b28e | ||
|
|
743ce23fbc | ||
|
|
a3267be192 | ||
|
|
4ad2523877 | ||
|
|
4bfee3a8ca | ||
|
|
fc964f975a | ||
|
|
52f85c9465 | ||
|
|
691610f23c | ||
|
|
b6a2b2b8a5 | ||
|
|
1ad8a2fcf6 | ||
|
|
7ce08845f1 | ||
|
|
d469250130 | ||
|
|
7fd5c47e06 | ||
|
|
8704b1004e | ||
|
|
65a9fb8c01 | ||
|
|
25a7a8006a | ||
|
|
6fe1d3248a | ||
|
|
13f97532bf | ||
|
|
1acee3d702 | ||
|
|
1d17404471 | ||
|
|
48b860b69f | ||
|
|
a030c54661 | ||
|
|
dcf7bae6c7 | ||
|
|
d0ace108e5 | ||
|
|
32d5744014 | ||
|
|
d16094774b | ||
|
|
ac664ba321 | ||
|
|
0888a9bffd | ||
|
|
5e82d72424 | ||
|
|
2513835e89 | ||
|
|
98b70ef00f | ||
|
|
ae11381b88 | ||
|
|
e9596f2775 | ||
|
|
8adbc8010a | ||
|
|
76fb559964 | ||
|
|
1bc1b4d9d8 | ||
|
|
dfc0ef56f6 | ||
|
|
1e68e78d8e | ||
|
|
17fa5a2db4 | ||
|
|
004a5e1042 | ||
|
|
4915a9e8e4 | ||
|
|
8a7e44ccf0 | ||
|
|
a497afe695 | ||
|
|
15c252c11d | ||
|
|
27da3ed1fe | ||
|
|
8656102182 | ||
|
|
24d3744cb9 | ||
|
|
031913b9df | ||
|
|
e53443daf9 | ||
|
|
06317f4f6a | ||
|
|
c69e195441 | ||
|
|
a53b48de4c | ||
|
|
eca98aee42 | ||
|
|
ea5aaa8ab2 | ||
|
|
72566eda43 | ||
|
|
7a4f9a5ff3 | ||
|
|
ba23fd9989 | ||
|
|
c101196f5b | ||
|
|
1687a5451e | ||
|
|
ea4d5f89eb | ||
|
|
9e388ebcfd | ||
|
|
8d9cae45f9 | ||
|
|
406d0900a7 | ||
|
|
cf611d2be8 | ||
|
|
7875fc831b | ||
|
|
44bca36385 | ||
|
|
e2c3198627 | ||
|
|
8b549f3d5b | ||
|
|
a0e3c342a6 | ||
|
|
a80331dbcf | ||
|
|
0068dab001 | ||
|
|
7d42990462 | ||
|
|
e6dec7a9dd | ||
|
|
8adfc5b106 | ||
|
|
8be95b5785 | ||
|
|
9194de8460 | ||
|
|
6dccbc5a90 | ||
|
|
efba1e83c7 | ||
|
|
d1442765a6 | ||
|
|
72e5caf6e1 | ||
|
|
3768b6b701 | ||
|
|
e5cde4700f | ||
|
|
a207f67f73 | ||
|
|
b73aace476 | ||
|
|
346d37ecbb | ||
|
|
7bb29817f7 | ||
|
|
92b92a2e0a | ||
|
|
8e79f9f2dc | ||
|
|
05b345cc92 | ||
|
|
89f9925208 | ||
|
|
fcc1d7beff | ||
|
|
f226398c7c | ||
|
|
890ac9ff38 | ||
|
|
6a027cd566 | ||
|
|
1dc971d760 | ||
|
|
dcf0bf0bb1 | ||
|
|
cf156b469c | ||
|
|
da6c154ceb | ||
|
|
957fa910b3 | ||
|
|
8ac5be95d3 | ||
|
|
c27bd62106 | ||
|
|
480e8b8842 | ||
|
|
c6580421b3 | ||
|
|
c2f5331187 | ||
|
|
5d0c403f1d | ||
|
|
20fc4b4490 | ||
|
|
ea3f906f38 | ||
|
|
2c4df6abcf | ||
|
|
67a0b3b98e | ||
|
|
c366e9f3ca | ||
|
|
812a8552e5 | ||
|
|
069d7d6cac | ||
|
|
785a8b78b1 | ||
|
|
2d927639fe | ||
|
|
d5cad10181 | ||
|
|
441a56b916 | ||
|
|
c2a6a6c939 | ||
|
|
15d1aee21a | ||
|
|
f1bc2d56f4 | ||
|
|
6f62965305 | ||
|
|
a6aa0ac74a | ||
|
|
32ed4ee12e | ||
|
|
33a48aecb7 | ||
|
|
3b63062a30 | ||
|
|
b680952197 | ||
|
|
a4ec460f96 | ||
|
|
5bd295842b | ||
|
|
db9a7ea7a9 | ||
|
|
490a62e781 | ||
|
|
d4b8912c0e | ||
|
|
532acf4c4a | ||
|
|
7141c5be6d | ||
|
|
2df7757905 | ||
|
|
9d5c743a98 | ||
|
|
653e6c85bb | ||
|
|
d9fa389079 | ||
|
|
a429fdbd08 | ||
|
|
f9357457bf | ||
|
|
369e400e32 | ||
|
|
07ad4d8911 | ||
|
|
803a096b7e | ||
|
|
1b40abe37a | ||
|
|
0de5209cf1 | ||
|
|
07fad38a50 | ||
|
|
ac4b88f25d | ||
|
|
23a7aa5740 | ||
|
|
0b1e29e5e3 | ||
|
|
c8c93b2a70 | ||
|
|
d8c7cac536 | ||
|
|
5cb02c1cb5 | ||
|
|
10c1df61cd | ||
|
|
387e5ef0f1 | ||
|
|
f8f40f247f | ||
|
|
16cb918e0d | ||
|
|
638b315e40 | ||
|
|
a20b8dc1ad | ||
|
|
4370aee81e | ||
|
|
779e37fbd9 | ||
|
|
6f4c5022eb | ||
|
|
b499ca47a3 | ||
|
|
dc38e48202 | ||
|
|
7efdb97641 | ||
|
|
14fd7c7532 | ||
|
|
21e14bd46f | ||
|
|
f0e1dc5715 | ||
|
|
6b7af407e1 | ||
|
|
d67c64af83 | ||
|
|
5d2e5fe85a | ||
|
|
308da6ae53 | ||
|
|
76eceec1f5 | ||
|
|
209d332a30 | ||
|
|
35dbc3fcc9 | ||
|
|
ada01507a4 | ||
|
|
826ac95726 | ||
|
|
9b7f228f8e | ||
|
|
5d8ea4f9a3 | ||
|
|
4c89eac9a4 | ||
|
|
f76f30fd6a | ||
|
|
488d98289c | ||
|
|
ff3d32dd18 | ||
|
|
be6ce3c5b4 | ||
|
|
21966afbc6 | ||
|
|
68e3f74ffd | ||
|
|
87f5aa7a13 | ||
|
|
1dadbd0cbb | ||
|
|
481490fdc7 | ||
|
|
3114a24d1f | ||
|
|
73850fee02 | ||
|
|
c0047cd11d | ||
|
|
dd9a452594 | ||
|
|
e45c917811 | ||
|
|
fd19906c64 | ||
|
|
54a2773046 | ||
|
|
ec8b7bc7b2 | ||
|
|
ea71172d44 | ||
|
|
5dfa620f86 | ||
|
|
09d5f0779d | ||
|
|
d1880dc987 | ||
|
|
928b49705f | ||
|
|
f50cac3005 | ||
|
|
ec6e1315a5 | ||
|
|
ad55cb6d5d | ||
|
|
0ce0376725 | ||
|
|
015ca2c507 | ||
|
|
21e752e5e4 | ||
|
|
1e20a1249a | ||
|
|
b67c300484 | ||
|
|
8ac2086ed1 | ||
|
|
72defaa97e | ||
|
|
9097c5e9c0 | ||
|
|
79b54f65b4 | ||
|
|
52c2417685 | ||
|
|
9073debe60 | ||
|
|
8b368d010f | ||
|
|
8b97a06961 | ||
|
|
fffe7bdf9c | ||
|
|
ef18f621ac | ||
|
|
dfa41f6926 | ||
|
|
3d3dca4aa2 | ||
|
|
928595fe21 | ||
|
|
fc958f4215 | ||
|
|
0846238f69 | ||
|
|
007b6ca2e8 | ||
|
|
0b4a4487a0 | ||
|
|
99b4e047dd | ||
|
|
ae2af34453 | ||
|
|
fdf24ceecc | ||
|
|
870dd84a50 | ||
|
|
5d6db923b7 | ||
|
|
8eb88d17fe | ||
|
|
abe012b9fc | ||
|
|
749f52fc8b | ||
|
|
1e6cb43815 | ||
|
|
213d10bf4e | ||
|
|
1abfbb82c5 | ||
|
|
bf36d99a33 | ||
|
|
3ee525833e | ||
|
|
bf497ed643 | ||
|
|
9b8c0f7519 | ||
|
|
12ec5d1cbe | ||
|
|
0f178c3b3d | ||
|
|
9aa06e3001 | ||
|
|
00ec8ca989 | ||
|
|
9c6f558c9e | ||
|
|
1c172955ee | ||
|
|
1d44bf7ce6 | ||
|
|
036e41621d | ||
|
|
3003e9091d | ||
|
|
8d9da10710 | ||
|
|
4d23c12028 | ||
|
|
476816732f | ||
|
|
31968ea53c | ||
|
|
7e00d22bfa | ||
|
|
50055004f5 | ||
|
|
abe2f07779 | ||
|
|
277f0d77f3 | ||
|
|
01d2ad760a | ||
|
|
25f118bf2c | ||
|
|
12b8fb15b1 | ||
|
|
5295866eff | ||
|
|
02b47f4640 | ||
|
|
108ac7cf20 | ||
|
|
933c037c6e | ||
|
|
8f3554ff3e | ||
|
|
668128f8c9 | ||
|
|
28ab1f4af4 | ||
|
|
d360114226 | ||
|
|
5fc456d9d9 | ||
|
|
007d305736 | ||
|
|
ae7ec648b2 | ||
|
|
99a2fad311 | ||
|
|
82d466598c | ||
|
|
3a748fe737 | ||
|
|
89ce53e3ff | ||
|
|
2f29081667 | ||
|
|
cb0d28770f | ||
|
|
86c3909908 | ||
|
|
b970ee7293 | ||
|
|
5545e84430 | ||
|
|
85d9f39417 | ||
|
|
a81450df17 | ||
|
|
a7c94b2cd2 | ||
|
|
9d65c8b2ec | ||
|
|
1b7ff76092 | ||
|
|
17e32bf16d | ||
|
|
74905f3edc | ||
|
|
8e1b13ca96 | ||
|
|
c0e90807e0 | ||
|
|
3db1058c2c | ||
|
|
a57c4c580e | ||
|
|
33bbbdc322 | ||
|
|
5826336a77 | ||
|
|
3b5d13a0b2 | ||
|
|
ed37ba1d9b | ||
|
|
8ea6fd1925 | ||
|
|
93a461f3f7 | ||
|
|
fda7c9b06e | ||
|
|
1e13f32cea | ||
|
|
e357559582 | ||
|
|
71759a0769 | ||
|
|
11b116cb9d | ||
|
|
2f97a1a55d | ||
|
|
79cf3a6dd0 | ||
|
|
0257de1b7e | ||
|
|
466dc8da8f | ||
|
|
2c61badc02 | ||
|
|
3f8d3a7ee2 | ||
|
|
a455860978 | ||
|
|
0ecf135a4b | ||
|
|
cebb6d40df | ||
|
|
0ee13672ee | ||
|
|
49260a85ad | ||
|
|
da9f37e629 | ||
|
|
164f3fa3fd | ||
|
|
8e75d81a44 | ||
|
|
1d60c4d9d4 | ||
|
|
eaa32090b9 | ||
|
|
32ddb6f739 | ||
|
|
2653402c5c | ||
|
|
2743f18af4 | ||
|
|
dd1fdf88ff | ||
|
|
2a041e9d8d | ||
|
|
1117f4760c | ||
|
|
7dda7abf5e | ||
|
|
7ca3cca306 | ||
|
|
d471e3a23b | ||
|
|
ce1bee727a | ||
|
|
43cb3754d9 | ||
|
|
1d6ddf060b | ||
|
|
9928125e7d | ||
|
|
1c63893c4b | ||
|
|
a7ec7583aa | ||
|
|
4a3476266f | ||
|
|
32e0b895a4 | ||
|
|
58806359ee | ||
|
|
4589da957b | ||
|
|
6a4c55b852 | ||
|
|
ea17740719 | ||
|
|
d82810240f | ||
|
|
2768b73015 | ||
|
|
f9a7718dda | ||
|
|
d9d9778a98 | ||
|
|
bd5162105e | ||
|
|
208c5e9562 | ||
|
|
305e63750e | ||
|
|
ab0f74aa15 | ||
|
|
43443d08ae | ||
|
|
b82b553b9e | ||
|
|
08464eadff | ||
|
|
49e56776e8 | ||
|
|
043667dde5 | ||
|
|
f583a7c6d8 | ||
|
|
2d908e80fc | ||
|
|
8f0e9abe47 | ||
|
|
1a27ff6130 | ||
|
|
3f2cffc2e6 | ||
|
|
a78527050a | ||
|
|
a823a213ba | ||
|
|
2c8d380e67 | ||
|
|
3996309f8a | ||
|
|
bd18313d12 | ||
|
|
2ff7a78b56 | ||
|
|
c765082f72 | ||
|
|
7d2c5c1ac9 | ||
|
|
404bc34089 | ||
|
|
16ca7a21a7 | ||
|
|
1b31fd5afe | ||
|
|
e0457b6dc4 | ||
|
|
42b77e7ba5 | ||
|
|
f6bed08993 | ||
|
|
5f77cdb0b9 | ||
|
|
109b8e8f38 | ||
|
|
4c0bd88a2c | ||
|
|
3731be9947 | ||
|
|
6cc19ee6f0 | ||
|
|
1570f838f3 | ||
|
|
74feb110b5 | ||
|
|
6ba03ac2a6 | ||
|
|
55c717c2dc | ||
|
|
355b5eebec | ||
|
|
51938c398a | ||
|
|
dbb71f0dfc | ||
|
|
1cac7b2218 | ||
|
|
ff9bb5399b | ||
|
|
68e45eb051 | ||
|
|
d0da96ad29 | ||
|
|
55b036170b | ||
|
|
5473637736 | ||
|
|
bb6d9734e4 | ||
|
|
53be76c9e2 | ||
|
|
be40de5a9b | ||
|
|
7359e431d3 | ||
|
|
8a5de327bb | ||
|
|
1778adae0d | ||
|
|
0d035a4e53 | ||
|
|
46874eed05 | ||
|
|
e95f3febd6 | ||
|
|
0bdd1b6fc4 | ||
|
|
8a22092632 | ||
|
|
915415d919 | ||
|
|
14d7897a93 | ||
|
|
1398aa6562 | ||
|
|
8fcd6c7153 | ||
|
|
6ed5bc2f6c | ||
|
|
5ec4c2e43e | ||
|
|
6f8dd065a4 | ||
|
|
02db21fc55 | ||
|
|
8c28f9a77d | ||
|
|
95b80eec01 | ||
|
|
02c76695e5 | ||
|
|
d5a1a888d9 | ||
|
|
6c33aff6d1 | ||
|
|
61f86cbc54 | ||
|
|
4c5206954a | ||
|
|
8fda3116f0 | ||
|
|
7ac35c644e | ||
|
|
29b04fcbf2 | ||
|
|
55235c2552 | ||
|
|
f250643385 | ||
|
|
d008c6c5c5 | ||
|
|
e2e02c9a2f | ||
|
|
e56d7f5021 | ||
|
|
e7d44bb349 | ||
|
|
321730fcb9 | ||
|
|
fe83cd91bb | ||
|
|
0b08ee54bb | ||
|
|
f6b4b96737 | ||
|
|
b87455c089 | ||
|
|
2c1a81f448 | ||
|
|
b3736f45e6 | ||
|
|
3c382c4bbe | ||
|
|
5f3bad9c94 | ||
|
|
6970f43e66 | ||
|
|
9476aa598a | ||
|
|
69725e5d41 | ||
|
|
42dabef8c7 | ||
|
|
e10a768ddb | ||
|
|
a8f0787c91 | ||
|
|
074129682b | ||
|
|
c67460a1e3 | ||
|
|
eab320dab5 | ||
|
|
04c7cb6fbe | ||
|
|
d4582491f5 | ||
|
|
0641b1e279 | ||
|
|
ae0450b68e | ||
|
|
cb0a5de83b | ||
|
|
2f5086efaf | ||
|
|
68e580e394 | ||
|
|
b143869d5d | ||
|
|
6a477be874 | ||
|
|
03bb8cdcbd | ||
|
|
8864816b94 | ||
|
|
751cd2f1c1 | ||
|
|
6f6b6fb9d6 | ||
|
|
44e1a6ce06 |
6
.eslintrc.json
Normal file
6
.eslintrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": [
|
||||
"./lint/eslintrc-gjs.json",
|
||||
"./lint/eslintrc-shell.json"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
stages:
|
||||
- review
|
||||
- source_check
|
||||
- build
|
||||
- test
|
||||
|
||||
@@ -26,19 +25,27 @@ check_commit_log:
|
||||
|
||||
js_check:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
|
||||
stage: source_check
|
||||
stage: review
|
||||
script:
|
||||
- find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
|
||||
- (! grep -q . $JS_LOG)
|
||||
<<: *only_default
|
||||
only:
|
||||
changes:
|
||||
- js/**/*
|
||||
artifacts:
|
||||
paths:
|
||||
- ${JS_LOG}
|
||||
when: on_failure
|
||||
|
||||
eslint:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
|
||||
stage: review
|
||||
script:
|
||||
- ./.gitlab-ci/run-eslint.sh
|
||||
<<: *only_default
|
||||
artifacts:
|
||||
paths:
|
||||
- reports
|
||||
when: always
|
||||
|
||||
build:
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v2
|
||||
stage: build
|
||||
@@ -47,7 +54,7 @@ build:
|
||||
- meson mutter mutter/build --prefix=/usr -Dtests=false
|
||||
- ninja -C mutter/build install
|
||||
script:
|
||||
- meson . build -Dbuiltype=debugoptimized
|
||||
- meson . build -Dbuiltype=debugoptimized -Dman=false --werror
|
||||
- ninja -C build
|
||||
- ninja -C build install
|
||||
<<: *only_default
|
||||
@@ -60,6 +67,8 @@ build:
|
||||
test:
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v2
|
||||
stage: test
|
||||
variables:
|
||||
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
|
||||
before_script:
|
||||
- ninja -C mutter/build install
|
||||
script:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM registry.fedoraproject.org/fedora:latest
|
||||
|
||||
RUN dnf -y update && dnf -y upgrade && \
|
||||
dnf install -y 'dnf-command(copr)' && \
|
||||
dnf install -y 'dnf-command(copr)' git && \
|
||||
|
||||
# For syntax checks with `find . -name '*.js' -exec js60 -c -s '{}' ';'`
|
||||
dnf install -y findutils mozjs60-devel && \
|
||||
|
||||
105
.gitlab-ci/run-eslint.sh
Executable file
105
.gitlab-ci/run-eslint.sh
Executable file
@@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
OUTPUT_REGULAR=reports/lint-regular-report.txt
|
||||
OUTPUT_LEGACY=reports/lint-legacy-report.txt
|
||||
OUTPUT_FINAL=reports/lint-common-report.txt
|
||||
|
||||
OUTPUT_MR=reports/lint-mr-report.txt
|
||||
|
||||
LINE_CHANGES=changed-lines.txt
|
||||
|
||||
is_empty() {
|
||||
(! grep -q . $1)
|
||||
}
|
||||
|
||||
run_eslint() {
|
||||
ARGS_LEGACY='--config lint/eslintrc-legacy.json'
|
||||
|
||||
local extra_args=ARGS_$1
|
||||
local output=OUTPUT_$1
|
||||
eslint -f unix ${!extra_args} -o ${!output} js
|
||||
}
|
||||
|
||||
list_commit_range_additions() {
|
||||
# Turn raw context-less git-diff into a list of
|
||||
# filename:lineno pairs of new (+) lines
|
||||
git diff -U0 "$@" -- js |
|
||||
awk '
|
||||
BEGIN { file=""; }
|
||||
/^+++ b/ { file=substr($0,7); }
|
||||
/^@@ / {
|
||||
len = split($3,a,",")
|
||||
start=a[1]
|
||||
count=(len > 1) ? a[2] : 1
|
||||
|
||||
for (line=start; line<start+count; line++)
|
||||
printf "%s/%s:%d:\n",ENVIRON["PWD"],file,line;
|
||||
}'
|
||||
}
|
||||
|
||||
copy_matched_lines() {
|
||||
local source=$1
|
||||
local matches=$2
|
||||
local target=$3
|
||||
|
||||
echo -n > $target
|
||||
for l in $(<$matches); do
|
||||
grep $l $source >> $target
|
||||
done
|
||||
}
|
||||
|
||||
create_common() {
|
||||
# comm requires sorted input;
|
||||
# we also strip the error message to make the following a "common" error:
|
||||
# regular:
|
||||
# file.js:42:23 Indentation of 55, expected 42
|
||||
# legacy:
|
||||
# file.js:42:23 Indentation of 55, extected 24
|
||||
prepare() {
|
||||
sed 's: .*::' $1 | sort
|
||||
}
|
||||
|
||||
comm -12 <(prepare $OUTPUT_REGULAR) <(prepare $OUTPUT_LEGACY) >$OUTPUT_FINAL.tmp
|
||||
|
||||
# Now add back the stripped error messages
|
||||
copy_matched_lines $OUTPUT_REGULAR $OUTPUT_FINAL.tmp $OUTPUT_FINAL
|
||||
rm $OUTPUT_FINAL.tmp
|
||||
}
|
||||
|
||||
# Disable MR handling for now. We aren't ready to enforce
|
||||
# non-legacy style just yet ...
|
||||
unset CI_MERGE_REQUEST_TARGET_BRANCH_NAME
|
||||
|
||||
if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
|
||||
git fetch $CI_MERGE_REQUEST_PROJECT_URL.git $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
|
||||
branch_point=$(git merge-base HEAD FETCH_HEAD)
|
||||
commit_range=$branch_point...$CI_COMMIT_SHA
|
||||
|
||||
list_commit_range_additions $commit_range > $LINE_CHANGES
|
||||
|
||||
# Don't bother with running lint when no JS changed
|
||||
if is_empty $LINE_CHANGES; then
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
echo Generating lint report using regular configuration
|
||||
run_eslint REGULAR
|
||||
echo Generating lint report using legacy configuration
|
||||
run_eslint LEGACY
|
||||
echo Done.
|
||||
create_common
|
||||
|
||||
if ! is_empty $OUTPUT_FINAL; then
|
||||
cat $OUTPUT_FINAL
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Just show the report and succeed when not testing a MR
|
||||
if [ -z "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
copy_matched_lines $OUTPUT_REGULAR $LINE_CHANGES $OUTPUT_MR
|
||||
cat $OUTPUT_MR
|
||||
is_empty $OUTPUT_MR
|
||||
91
HACKING.md
91
HACKING.md
@@ -84,7 +84,6 @@ don't use.
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Util = imports.misc.util;
|
||||
```
|
||||
The alphabetical ordering should be done independently of the location of the
|
||||
@@ -187,15 +186,27 @@ and "double quotes" for strings that the user may see. This allows us to
|
||||
quickly find untranslated or mistranslated strings by grepping through the
|
||||
sources for double quotes without a gettext call around them.
|
||||
|
||||
## `actor` and `_delegate`
|
||||
## `actor` (deprecated) and `_delegate`
|
||||
|
||||
gjs allows us to set so-called "expando properties" on introspected objects,
|
||||
allowing us to treat them like any other. Because the Shell was built before
|
||||
you could inherit from GTypes natively in JS, we usually have a wrapper class
|
||||
that has a property called `actor`. We call this wrapper class the "delegate".
|
||||
you could inherit from GTypes natively in JS, in some cases we have a wrapper
|
||||
class that has a property called `actor` (now deprecated). We call this
|
||||
wrapper class the "delegate".
|
||||
|
||||
We sometimes use expando properties to set a property called `_delegate` on
|
||||
the actor itself:
|
||||
```javascript
|
||||
var MyActor = GObject.registerClass(
|
||||
class MyActor extends Clutter.Actor {
|
||||
_init(params) {
|
||||
super._init(params);
|
||||
this._delegate = this;
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Or using the deprecated `actor`:
|
||||
```javascript
|
||||
var MyClass = class {
|
||||
constructor() {
|
||||
@@ -216,6 +227,7 @@ delegate object from an associated actor. For instance, the drag and drop
|
||||
system calls the `handleDragOver` function on the delegate of a "drop target"
|
||||
when the user drags an item over it. If you do not set the `_delegate`
|
||||
property, your actor will not be able to be dropped onto.
|
||||
In case the class is an actor itself, the `_delegate` can be just set to `this`.
|
||||
|
||||
## Functional style
|
||||
|
||||
@@ -277,34 +289,49 @@ If your usage of an object is like a hash table (and thus conceptually the keys
|
||||
can have special chars in them), don't use quotes, but use brackets: `{ bar: 42
|
||||
}`, `foo['bar']`.
|
||||
|
||||
## Getters, setters, and Tweener
|
||||
## Animations
|
||||
|
||||
Most objects that are animated are actors, and most properties used in animations
|
||||
are animatable, which means they can use implicit animations:
|
||||
|
||||
Getters and setters should be used when you are dealing with an API that is
|
||||
designed around setting properties, like Tweener. If you want to animate an
|
||||
arbitrary property, create a getter and setter, and use Tweener to animate the
|
||||
property.
|
||||
```javascript
|
||||
var ANIMATION_TIME = 2000;
|
||||
|
||||
var MyClass = class {
|
||||
constructor() {
|
||||
this.actor = new St.BoxLayout();
|
||||
this._position = 0;
|
||||
}
|
||||
|
||||
get position() {
|
||||
return this._position;
|
||||
}
|
||||
|
||||
set position(value) {
|
||||
this._position = value;
|
||||
this.actor.set_position(value, value);
|
||||
}
|
||||
};
|
||||
|
||||
let myThing = new MyClass();
|
||||
Tweener.addTween(myThing,
|
||||
{ position: 100,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
moveActor(actor, x, y) {
|
||||
actor.ease({
|
||||
x,
|
||||
y,
|
||||
duration: 500, // ms
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The above is a convenience wrapper around the actual Clutter API, and should generally
|
||||
be preferred over the more verbose:
|
||||
|
||||
```javascript
|
||||
moveActor(actor, x, y) {
|
||||
actor.save_easing_state();
|
||||
|
||||
actor.set_easing_duration(500);
|
||||
actor.set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD);
|
||||
actor.set({
|
||||
x,
|
||||
y
|
||||
});
|
||||
|
||||
actor.restore_easing_state();
|
||||
}
|
||||
```
|
||||
|
||||
There is a similar convenience API around Clutter.PropertyTransition to animate
|
||||
actor (or actor meta) properties that cannot use implicit animations:
|
||||
|
||||
```javascript
|
||||
desaturateActor(actor, desaturate) {
|
||||
let factor = desaturate ? 1.0 : 0.0;
|
||||
actor.ease_property('@effects.desaturate.factor', factor, {
|
||||
duration: 500, // ms
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
178
NEWS
178
NEWS
@@ -1,3 +1,181 @@
|
||||
3.35.1
|
||||
======
|
||||
* Misc. bug fixes and cleanups [Marco; Matthias; !758, #701212]
|
||||
|
||||
Contributors:
|
||||
Marco Trevisan (Treviño)
|
||||
|
||||
3.34.1
|
||||
======
|
||||
* Fix "Frequent" view icons disappearing on hover [Jonas D.; #1502]
|
||||
* Allow editing app folder names [Georges, Marco; !675, !720]
|
||||
* Skip property transitions while hidden [Florian; !708]
|
||||
* Make menu animations more consistent [Florian, GB_2; #1595, !717]
|
||||
* Improve performance when enabling/disabling all extensions [Jonas D.; !96]
|
||||
* Fix extra icons appearing in "Frequent" view animation [Georges; !696]
|
||||
* Fix fading out desktop icons [Harshula; #1616]
|
||||
* Fix box-shadow glitch with prerendered resources [Daniel; #1186]
|
||||
* Fix accidentally skipped animations [Florian; #1572]
|
||||
* Fix screenshots and window animations when scaled [Robert; !728]
|
||||
* Don't leak NOTIFY_SOCKET environment variable to applications [Benjamin; !741]
|
||||
* Fix lock-up on X11 when ibus is already running on startup [Marco; #1712]
|
||||
* Fix screen dimming on idle [Marco; #1683]
|
||||
* Do not notify systemd before initialization is complete [Iain; !750]
|
||||
* Support SAE secrets in network agent [Lubomir; !751]
|
||||
* Fix various regressions with dynamic workspaces [Florian; #1497]
|
||||
* Fixed crashes [Florian, Marco; #1678, !746]
|
||||
* Misc. bug fixes and cleanups [Marco, Jonas D., Florian, Iain, Georges,
|
||||
Jonas Å., Martin, Takao, Carlos; !700, !705, !709, !711, !707, #1538, !710,
|
||||
!713, !699, !715, !718, !716, !719, !721, #1243, !725, !731, #1614, !683,
|
||||
!732, !121, !735, !736, !740, #573, #1641, #1571]
|
||||
|
||||
Contributors:
|
||||
Marco Trevisan (Treviño), Benjamin Berg, Jonas Dreßler, Takao Fujiwara, GB_2,
|
||||
Carlos Garnacho, Harshula Jayasuriya, Iain Lane, Robert Mader,
|
||||
Daniel García Moreno, Florian Müllner, Georges Basile Stavracas Neto,
|
||||
Lubomir Rintel, Martin Zurowietz, Jonas Ådahl
|
||||
|
||||
Translators:
|
||||
Rafael Fontenelle [pt_BR], Fran Dieguez [gl], Balázs Úr [hu],
|
||||
Milo Casagrande [it], Daniel Șerbănescu [ro], Kukuh Syafaat [id],
|
||||
Jiri Grönroos [fi], Daniel Mustieles [es], Piotr Drąg [pl],
|
||||
Anders Jonsson [sv], Marek Černocký [cs], Jordi Mas [ca],
|
||||
Aurimas Černius [lt], Christian Kirbach [de], Emin Tufan Çetin [tr],
|
||||
Enrico Nicoletto [pt_BR], Danial Behzadi [fa], Марко Костић [sr],
|
||||
Alexandre Franke [fr], Charles Monzat [fr], Kjartan Maraas [nb],
|
||||
Ryuta Fujii [ja], Nathan Follens [nl], Dušan Kazik [sk], Fabio Tomat [fur],
|
||||
Matej Urbančič [sl], Ask Hjorth Larsen [da], Alan Mortensen [da]
|
||||
|
||||
3.34.0
|
||||
======
|
||||
* Handle startup/shutdown of misc X11 services [Carlos; !680]
|
||||
* Fix sound volume mute/unmute [Iain; #1557]
|
||||
* Correctly terminate pasted text [Carlos; #1570]
|
||||
|
||||
Contributors:
|
||||
Carlos Garnacho, Iain Lane
|
||||
|
||||
Translators:
|
||||
Tom Tryfonidis [el], Milo Casagrande [it], Ryuta Fujii [ja],
|
||||
Efstathios Iosifidis [el], Carmen Bianca BAKKER [eo], Sabri Ünal [tr],
|
||||
Dušan Kazik [sk], Balázs Meskó [hu], Claude Paroz [fr]
|
||||
|
||||
3.33.92
|
||||
=======
|
||||
* Animate pointer a11y pie timer [Jonas D.; !688]
|
||||
* Fix restarting shell in systemd user session [Benjamin; !690]
|
||||
* Misc. bug fixes and cleanups [Florian, Jonas D., Jonas Å., Will;
|
||||
!691, !689, !692, #1552, !698]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Benjamin Berg, Piotr Drąg, Jonas Dreßler, Florian Müllner,
|
||||
Will Thompson
|
||||
|
||||
Translators:
|
||||
Daniel Șerbănescu [ro], Danial Behzadi [fa], Daniel Mustieles [es],
|
||||
Jiri Grönroos [fi], Asier Sarasua Garmendia [eu], Piotr Drąg [pl],
|
||||
Rūdolfs Mazurs [lv], Anders Jonsson [sv], Fran Dieguez [gl], Jordi Mas [ca],
|
||||
Matej Urbančič [sl], Zander Brown [en_GB], Ryuta Fujii [ja], Tim Sabsch [de],
|
||||
Fabio Tomat [fur], Pawan Chitrakar [ne], A S Alam [pa], Changwoo Ryu [ko],
|
||||
Aurimas Černius [lt], Daniel Rusek [cs], Marek Černocký [cs],
|
||||
Kukuh Syafaat [id], Goran Vidović [hr], Rafael Fontenelle [pt_BR]
|
||||
|
||||
3.33.91
|
||||
=======
|
||||
* Fix regression when adjusting brightness [Florian; #1500]
|
||||
* Fix pointer a11y timeout animation [Jonas D.; #1533]
|
||||
* Add new extensions CLI tool [Florian; #1234]
|
||||
* Only track top-level windows [Carlos; #556]
|
||||
* Misc. bug fixes and cleanups [Jonas D., Jonas Å., Piotr, Florian;
|
||||
!678, !682, !686]
|
||||
|
||||
Contributors:
|
||||
Jonas Ådahl, Jonas Dreßler, Carlos Garnacho, Florian Müllner
|
||||
|
||||
Translators:
|
||||
Asier Sarasua Garmendia [eu], Sveinn í Felli [is], Anders Jonsson [sv],
|
||||
Jordi Mas [ca], Kukuh Syafaat [id], Florentina Mușat [ro], Jiri Grönroos [fi],
|
||||
Aurimas Černius [lt], Daniel Mustieles [es], Piotr Drąg [pl],
|
||||
Danial Behzadi [fa]
|
||||
|
||||
3.33.90
|
||||
=======
|
||||
* Implement DND app picker folder management [Georges; !643, !645, !664, !671]
|
||||
* Make Clocks/Weather integration work with sandboxed apps [Florian; #1158]
|
||||
* Support startup via systemd user instance [Benjamin; !507]
|
||||
* Replace Tweener with Clutter animations [Florian; !663, !22, !666, !668, !669]
|
||||
* Minimize travel distance in overview animation [Sergey; !267]
|
||||
* Rescan icon theme when installed apps changed [Georges; !661]
|
||||
* Consistently animate new window actions [Jonas; !662, !673]
|
||||
* Misc. bug fixes and cleanups [Florian, Daniel, Ray, Bastien, Jonas, Niels,
|
||||
Marco, Georges; !635, !636, !637, #1462, !628, !640, !641, !627, !644, !647,
|
||||
!385, #1474, !651, #1144, !646, !653, !652, !655, #1482, !656, $654, !665,
|
||||
!667, !670, #1357, !672, !657, #1507, !674, !677]
|
||||
|
||||
Contributors:
|
||||
Benjamin Berg, Sergey Bugaev, Jonas Dreßler, Niels De Graef, Florian Müllner,
|
||||
Georges Basile Stavracas Neto, Bastien Nocera, Ray Strode,
|
||||
Marco Trevisan (Treviño), verdre, Daniel van Vugt
|
||||
|
||||
Translators:
|
||||
Asier Sarasua Garmendia [eu], Rafael Fontenelle [pt_BR],
|
||||
Kristjan SCHMIDT [eo], Jor Teron [mjw], Daniel Mustieles [es],
|
||||
Kukuh Syafaat [id], Jordi Mas [ca], Fabio Tomat [fur], Daniel Șerbănescu [ro],
|
||||
Anders Jonsson [sv]
|
||||
|
||||
3.33.4
|
||||
======
|
||||
* Fix unintentional interference between gestures [Jonas; !598]
|
||||
* Fix unintentional loop while polkit dialog is active [Ray; !602]
|
||||
* Fix alt-tab icon size on HiDPI [Jonas; !587]
|
||||
* Style fixes and improvements [Frederik, Jakub; !610, #1446, #1449]
|
||||
* Fix style updates for non-background CSS properties [Florian; #1212]
|
||||
* Fix cursor visibility in screen recordings [Illya; #1208]
|
||||
* Add option for disabling the hot corner [Florian; #688320]
|
||||
* Use more fine-grained levels in battery indicator [Florian; !561, #1442]
|
||||
* Fix the calculation of the maximum number of app search results [Jonas; !110]
|
||||
* Handle horizontal workspace layout with gestures/animations [Florian; !575]
|
||||
* Improve handling of session mode extensions [Florian, Didier; #789852]
|
||||
* Misc. bug fixes and cleanups [Jonas, Florian, Sonny, Carlos, Mario, Benjamin,
|
||||
Marco, Ting-Wei; !599, !600, !591, !606, !152, !607, !604, !495, !608, !611,
|
||||
!614, !612, !615, !618, #369, !620, #774, !621, !616, #1065, !609, !626,
|
||||
!491, !631, !632, !633, #1457]
|
||||
|
||||
Contributors:
|
||||
Benjamin Berg, Jonas Dreßler, Frederik Feichtmeier, Carlos Garnacho,
|
||||
Illya Klymov, Ting-Wei Lan, Florian Müllner, Sonny Piers, Mario Sanchez Prada,
|
||||
Didier Roche, Jakub Steiner, Ray Strode, Jor Teron, Marco Trevisan (Treviño)
|
||||
|
||||
Translators:
|
||||
Jordi Mas [ca], Jor Teron [mjw]
|
||||
|
||||
3.33.3
|
||||
======
|
||||
* Prepare for optional X11 [Carlos; !378]
|
||||
* Fix opening window menu [Marco; !557]
|
||||
* Reload search providers when installed applications change [Cosimo; !562]
|
||||
* Implement locate-pointer accessibility feature [Olivier; #981]
|
||||
* Allow to disable window menus via session mode [Cosimo; !569]
|
||||
* Implement mouse accessibility [Olivier; !474]
|
||||
* Call GDM's RegisterSession() after startup [Iain; !570]
|
||||
* Fix extended keys popups being hidden by on-screen keyboard [Marco; !583]
|
||||
* Fix top bar being hidden by lock screen [Jonas; !571]
|
||||
* Update theme to better match GTK's Adwaita [Frederik; #841]
|
||||
* Set up GJS profiler when GJS_TRACE_FD is set [Christian; !573]
|
||||
* Misc. bug fixes and cleanups [Jonas, Cosimo, Robert, Florian, Marco, Simon,
|
||||
Laurent, Niels, Will; !551, !555, !464, #1333, !565, !572, !568, !558, #1205,
|
||||
#1336, !579, !576, #1392, !582, !586, #1406, #1351]
|
||||
|
||||
Contributors:
|
||||
Laurent Bigonville, Cosimo Cecchi, Piotr Drąg, Jonas Dreßler,
|
||||
Frederik Feichtmeier, Olivier Fourdan, Carlos Garnacho, Niels De Graef,
|
||||
Christian Hergert, Iain Lane, Robert Mader, Florian Müllner, Simon Schampijer,
|
||||
Jakub Steiner, Will Thompson, Marco Trevisan (Treviño)
|
||||
|
||||
Translators:
|
||||
Kukuh Syafaat [id], Balázs Meskó [hu], Daniel Mustieles [es],
|
||||
Fabio Tomat [fur], Nathan Follens [nl], Goran Vidović [hr], Jordi Mas [ca]
|
||||
|
||||
3.33.2
|
||||
======
|
||||
* Fix keeping actors visible in scrollviews [Marco; #1061]
|
||||
|
||||
15
data/dbus-interfaces/org.gnome.Shell.ClocksIntegration.xml
Normal file
15
data/dbus-interfaces/org.gnome.Shell.ClocksIntegration.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<node>
|
||||
|
||||
<!--
|
||||
org.gnome.Shell.ClocksIntegration:
|
||||
@short_description: Clocks integration interface
|
||||
|
||||
The interface used for exporting location settings to GNOME Shell's
|
||||
world clocks integration.
|
||||
-->
|
||||
<interface name="org.gnome.Shell.ClocksIntegration">
|
||||
|
||||
<property name="Locations" type="av" access="read"/>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
@@ -173,6 +173,30 @@
|
||||
<arg type="s" direction="in" name="uuid"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
EnableExtension:
|
||||
@uuid: The UUID of the extension
|
||||
@success: Whether the operation was successful
|
||||
|
||||
Enable an extension.
|
||||
-->
|
||||
<method name="EnableExtension"> \
|
||||
<arg type="s" direction="in" name="uuid"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
</method> \
|
||||
|
||||
<!--
|
||||
DisableExtension:
|
||||
@uuid: The UUID of the extension
|
||||
@success: Whether the operation was successful
|
||||
|
||||
Disable an extension.
|
||||
-->
|
||||
<method name="DisableExtension"> \
|
||||
<arg type="s" direction="in" name="uuid"/> \
|
||||
<arg type="b" direction="out" name="success"/> \
|
||||
</method> \
|
||||
|
||||
<!--
|
||||
LaunchExtensionPrefs:
|
||||
@uuid: The UUID of the extension
|
||||
@@ -189,6 +213,15 @@
|
||||
-->
|
||||
<method name="CheckForUpdates"/>
|
||||
|
||||
<signal name="ExtensionStateChanged">
|
||||
<arg type="s" name="uuid"/>
|
||||
<arg type="a{sv}" name="state"/>
|
||||
</signal>
|
||||
|
||||
<!--
|
||||
ExtensionStatusChanged:
|
||||
Deprecated for ExtensionStateChanged
|
||||
-->
|
||||
<signal name="ExtensionStatusChanged">
|
||||
<arg type="s" name="uuid"/>
|
||||
<arg type="i" name="state"/>
|
||||
|
||||
16
data/dbus-interfaces/org.gnome.Shell.WeatherIntegration.xml
Normal file
16
data/dbus-interfaces/org.gnome.Shell.WeatherIntegration.xml
Normal file
@@ -0,0 +1,16 @@
|
||||
<node>
|
||||
|
||||
<!--
|
||||
org.gnome.Shell.WeatherIntegration:
|
||||
@short_description: Weather integration interface
|
||||
|
||||
The interface used for exporting location settings to GNOME Shell's
|
||||
weather integration.
|
||||
-->
|
||||
<interface name="org.gnome.Shell.WeatherIntegration">
|
||||
|
||||
<property name="AutomaticLocation" type="b" access="read"/>
|
||||
<property name="Locations" type="av" access="read"/>
|
||||
|
||||
</interface>
|
||||
</node>
|
||||
@@ -9,7 +9,7 @@
|
||||
<method name="ShowOSD">
|
||||
<arg type="a{sv}" direction="in" name="params"/>
|
||||
</method>
|
||||
<method name="ShowMonitorLabels2">
|
||||
<method name="ShowMonitorLabels">
|
||||
<arg type="a{sv}" direction="in" name="params"/>
|
||||
</method>
|
||||
<method name="HideMonitorLabels"/>
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
<file preprocess="xml-stripblanks">org.gnome.SettingsDaemon.Wacom.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.AudioDeviceSelection.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.CalendarServer.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.ClocksIntegration.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.Extensions.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.Introspect.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.HotplugSniffer.xml</file>
|
||||
@@ -48,6 +49,7 @@
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.Screencast.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.Screenshot.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.Wacom.PadOsd.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.WeatherIntegration.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gnome.Shell.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.Gtk.MountOperationHandler.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.gtk.Notifications.xml</file>
|
||||
|
||||
14
data/gnome-shell-disable-extensions.service
Normal file
14
data/gnome-shell-disable-extensions.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Disable GNOME Shell extensions after failure
|
||||
DefaultDependencies=no
|
||||
|
||||
# Only disable extensions for a short period of time after login.
|
||||
# This means we err on the side of failing the first login after a broken
|
||||
# extension was installed.
|
||||
Requisite=gnome-session-stable.timer
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# Disable extensions
|
||||
ExecStart=gsettings set org.gnome.shell disable-user-extensions true
|
||||
Restart=no
|
||||
@@ -25,9 +25,11 @@
|
||||
<file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
|
||||
<file alias="icons/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file>
|
||||
<file>process-working.svg</file>
|
||||
<file>toggle-off-intl.svg</file>
|
||||
<file>toggle-off.svg</file>
|
||||
<file>toggle-off-dark.svg</file>
|
||||
<file>toggle-off-hc.svg</file>
|
||||
<file>toggle-on-intl.svg</file>
|
||||
<file>toggle-on.svg</file>
|
||||
<file>toggle-on-dark.svg</file>
|
||||
<file>toggle-on-hc.svg</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
||||
27
data/gnome-shell-wayland.service.in
Normal file
27
data/gnome-shell-wayland.service.in
Normal file
@@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=GNOME Shell on Wayland
|
||||
# On wayland, force a session shutdown
|
||||
OnFailure=gnome-shell-disable-extensions.service gnome-session-shutdown.target
|
||||
OnFailureJobMode=replace-irreversibly
|
||||
CollectMode=inactive-or-failed
|
||||
RefuseManualStart=on
|
||||
RefuseManualStop=on
|
||||
|
||||
After=gnome-session-manager.target
|
||||
|
||||
Requisite=gnome-session-initialized.target
|
||||
PartOf=gnome-session-initialized.target
|
||||
Before=gnome-session-initialized.target
|
||||
|
||||
# The units already conflict because they use the same BusName
|
||||
#Conflicts=gnome-shell-x11.service
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=@bindir@/gnome-shell
|
||||
# Exit code 1 means we are probably *not* dealing with an extension failure
|
||||
SuccessExitStatus=1
|
||||
# On wayland we cannot restart
|
||||
Restart=no
|
||||
# Kill any stubborn child processes after this long
|
||||
TimeoutStopSec=5
|
||||
@@ -1,5 +1,10 @@
|
||||
[Unit]
|
||||
Description=GNOME Shell (wayland sync point)
|
||||
After=gnome-shell.service
|
||||
BindsTo=gnome-shell.service
|
||||
Conflicts=gnome-shell-x11.target
|
||||
Description=GNOME Shell on Wayland
|
||||
DefaultDependencies=no
|
||||
|
||||
Requisite=gnome-session-initialized.target
|
||||
PartOf=gnome-session-initialized.target
|
||||
Before=gnome-session-initialized.target
|
||||
|
||||
Requires=gnome-shell-wayland.service
|
||||
After=gnome-shell-wayland.service
|
||||
|
||||
33
data/gnome-shell-x11.service.in
Normal file
33
data/gnome-shell-x11.service.in
Normal file
@@ -0,0 +1,33 @@
|
||||
[Unit]
|
||||
Description=GNOME Shell on X11
|
||||
# On X11, try to show the GNOME Session Failed screen
|
||||
OnFailure=gnome-shell-disable-extensions.service gnome-session-failed.target
|
||||
OnFailureJobMode=replace
|
||||
CollectMode=inactive-or-failed
|
||||
RefuseManualStart=on
|
||||
RefuseManualStop=on
|
||||
|
||||
After=gnome-session-manager.target
|
||||
|
||||
Requisite=gnome-session-initialized.target
|
||||
PartOf=gnome-session-initialized.target
|
||||
Before=gnome-session-initialized.target
|
||||
|
||||
# The units already conflict because they use the same BusName
|
||||
#Conflicts=gnome-shell-wayland.service
|
||||
|
||||
# Limit startup frequency more than the default
|
||||
StartLimitIntervalSec=15s
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Type=notify
|
||||
ExecStart=@bindir@/gnome-shell
|
||||
# Exit code 1 means we are probably *not* dealing with an extension failure
|
||||
SuccessExitStatus=1
|
||||
# On X11 we want to restart on-success (Alt+F2 + r) and on-failure.
|
||||
Restart=always
|
||||
# Do not wait before restarting the shell
|
||||
RestartSec=0ms
|
||||
# Kill any stubborn child processes after this long
|
||||
TimeoutStopSec=5
|
||||
@@ -1,5 +1,10 @@
|
||||
[Unit]
|
||||
Description=GNOME Shell (x11 sync point)
|
||||
After=gnome-shell.service
|
||||
BindsTo=gnome-shell.service
|
||||
Conflicts=gnome-shell-wayland.target
|
||||
Description=GNOME Shell on X11
|
||||
DefaultDependencies=no
|
||||
|
||||
Requisite=gnome-session-initialized.target
|
||||
PartOf=gnome-session-initialized.target
|
||||
Before=gnome-session-initialized.target
|
||||
|
||||
Requires=gnome-shell-x11.service
|
||||
After=gnome-shell-x11.service
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
[Unit]
|
||||
Description=GNOME Shell
|
||||
Wants=gnome-session.service
|
||||
After=graphical-session-pre.target gnome-session-bus.target
|
||||
PartOf=graphical-session.target
|
||||
|
||||
[Service]
|
||||
Type=dbus
|
||||
ExecStart=@bindir@/gnome-shell
|
||||
Restart=on-failure
|
||||
BusName=org.gnome.Shell
|
||||
@@ -14,6 +14,8 @@ desktopconf = configuration_data()
|
||||
# file when built in a non-system prefix
|
||||
desktopconf.set('bindir', bindir)
|
||||
desktopconf.set('VERSION', meson.project_version())
|
||||
desktopconf.set('systemd_hidden', have_systemd ? 'true' : 'false')
|
||||
|
||||
foreach desktop_file : desktop_files
|
||||
i18n.merge_file('desktop',
|
||||
input: configure_file(
|
||||
@@ -22,7 +24,7 @@ foreach desktop_file : desktop_files
|
||||
configuration: desktopconf
|
||||
),
|
||||
output: desktop_file,
|
||||
po_dir: '../po',
|
||||
po_dir: po_dir,
|
||||
install: true,
|
||||
install_dir: desktopdir,
|
||||
type: 'desktop'
|
||||
@@ -98,15 +100,23 @@ if have_systemd
|
||||
unitconf = configuration_data()
|
||||
unitconf.set('bindir', bindir)
|
||||
|
||||
unit = configure_file(
|
||||
input: 'gnome-shell.service.in',
|
||||
output: 'gnome-shell.service',
|
||||
configure_file(
|
||||
input: 'gnome-shell-x11.service.in',
|
||||
output: 'gnome-shell-x11.service',
|
||||
configuration: unitconf,
|
||||
install_dir: systemduserunitdir
|
||||
)
|
||||
|
||||
units = files('gnome-shell-wayland.target',
|
||||
'gnome-shell-x11.target')
|
||||
configure_file(
|
||||
input: 'gnome-shell-wayland.service.in',
|
||||
output: 'gnome-shell-wayland.service',
|
||||
configuration: unitconf,
|
||||
install_dir: systemduserunitdir
|
||||
)
|
||||
|
||||
units = files('gnome-shell-x11.target',
|
||||
'gnome-shell-wayland.target',
|
||||
'gnome-shell-disable-extensions.service')
|
||||
|
||||
install_data(units, install_dir: systemduserunitdir)
|
||||
endif
|
||||
|
||||
@@ -14,3 +14,4 @@ X-GNOME-Autostart-Phase=DisplayServer
|
||||
X-GNOME-Provides=panel;windowmanager;
|
||||
X-GNOME-Autostart-Notify=true
|
||||
X-GNOME-AutoRestart=false
|
||||
X-GNOME-HiddenUnderSystemd=@systemd_hidden@
|
||||
|
||||
@@ -21,6 +21,17 @@
|
||||
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
|
||||
</description>
|
||||
</key>
|
||||
<key name="disabled-extensions" type="as">
|
||||
<default>[]</default>
|
||||
<summary>UUIDs of extensions to force disabling</summary>
|
||||
<description>
|
||||
GNOME Shell extensions have a UUID property; this key lists extensions
|
||||
which should be disabled, even if loaded as part of the current mode.
|
||||
You can also manipulate this list with the EnableExtension and
|
||||
DisableExtension D-Bus methods on org.gnome.Shell.
|
||||
This key takes precedence over the “enabled-extensions” setting.
|
||||
</description>
|
||||
</key>
|
||||
<key name="disable-user-extensions" type="b">
|
||||
<default>false</default>
|
||||
<summary>Disable user extensions</summary>
|
||||
@@ -99,7 +110,6 @@
|
||||
</description>
|
||||
</key>
|
||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/"
|
||||
@@ -140,11 +150,6 @@
|
||||
Keybinding to focus the active notification.
|
||||
</description>
|
||||
</key>
|
||||
<key name="pause-resume-tweens" type="as">
|
||||
<default>[]</default>
|
||||
<summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
<key name="switch-to-application-1" type="as">
|
||||
<default>["<Super>1"]</default>
|
||||
<summary>Switch to application 1</summary>
|
||||
@@ -183,17 +188,6 @@
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="keyboard-type" type="s">
|
||||
<default>'touch'</default>
|
||||
<summary>Which keyboard to use</summary>
|
||||
<description>
|
||||
The type of keyboard to use.
|
||||
</description>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.app-switcher"
|
||||
path="/org/gnome/shell/app-switcher/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
@@ -234,6 +228,36 @@
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.world-clocks" path="/org/gnome/shell/world-clocks/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="locations" type="av">
|
||||
<summary>Locations</summary>
|
||||
<description>
|
||||
The locations to show in world clocks
|
||||
</description>
|
||||
<default>[]</default>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.weather" path="/org/gnome/shell/weather/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="automatic-location" type="b">
|
||||
<summary>Automatic location</summary>
|
||||
<description>
|
||||
Whether to fetch the current location or not
|
||||
</description>
|
||||
<default>false</default>
|
||||
</key>
|
||||
|
||||
<key name="locations" type="av">
|
||||
<summary>Location</summary>
|
||||
<description>
|
||||
The location for which to show a forecast
|
||||
</description>
|
||||
<default>[]</default>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<!-- unused, change 00_org.gnome.shell.gschema.override instead -->
|
||||
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
$variant: 'light';
|
||||
|
||||
@import "gnome-shell-sass/_high-contrast-colors"; //use gtk colors
|
||||
@import "gnome-shell-sass/_drawing";
|
||||
@import "gnome-shell-sass/_common";
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
|
||||
|
||||
$base_color: if($variant == 'light', #ffffff, lighten(desaturate(#241f31, 20%), 2%));
|
||||
$bg_color: if($variant == 'light', #f6f5f4, desaturate(#3d3846, 10%));
|
||||
$bg_color: if($variant == 'light', #f6f5f4, darken(desaturate(#3d3846, 100%), 4%));
|
||||
$fg_color: if($variant == 'light', #2e3436, #eeeeec);
|
||||
|
||||
$selected_fg_color: #ffffff;
|
||||
$selected_bg_color: if($variant == 'light', #3584e4, darken(#3584e4, 20%));
|
||||
$selected_bg_color: if($variant == 'light', #3584e4, darken(#3584e4, 10%));
|
||||
$selected_borders_color: if($variant== 'light', darken($selected_bg_color, 15%), darken($selected_bg_color, 30%));
|
||||
$borders_color: if($variant == 'light', darken($bg_color, 18%), darken($bg_color, 10%));
|
||||
$borders_edge: if($variant == 'light', transparentize(white, 0.2), transparentize($fg_color, 0.93));
|
||||
@@ -21,11 +21,15 @@ $success_color: if($variant == 'light', #33d17a, darken(#33d17a, 10%));
|
||||
$destructive_color: if($variant == 'light', #e01b24, darken(#e01b24, 10%));
|
||||
|
||||
$osd_fg_color: #eeeeec;
|
||||
$osd_bg_color: #2e3436;
|
||||
$osd_text_color: white;
|
||||
$osd_bg_color: transparentize(darken(desaturate(#3d3846, 100%), 12%),0.04);
|
||||
$osd_insensitive_bg_color: transparentize(mix($osd_fg_color, opacify($osd_bg_color, 1), 10%), 0.5);
|
||||
$osd_insensitive_fg_color: mix($osd_fg_color, opacify($osd_bg_color, 1), 50%);
|
||||
$osd_borders_color: transparentize(black, 0.3);
|
||||
$osd_outer_borders_color: transparentize(white, 0.9);
|
||||
$osd_outer_borders_color: transparentize(white, 0.84);
|
||||
|
||||
$tooltip_borders_color: $osd_outer_borders_color;
|
||||
$shadow_color: transparentize(black, 0.9);
|
||||
|
||||
//insensitive state derived colors
|
||||
$insensitive_fg_color: mix($fg_color, $bg_color, 50%);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -37,16 +37,13 @@
|
||||
// possible $t values:
|
||||
// normal, focus, insensitive
|
||||
//
|
||||
$_inner_shadows: inset 0 2px 4px transparentize(black, 0.6);
|
||||
|
||||
@if $t==normal {
|
||||
background-color: $base_color;
|
||||
border-color: $borders_color;
|
||||
@include _shadows($_inner_shadows);
|
||||
|
||||
}
|
||||
@if $t==focus {
|
||||
@include _shadows($_inner_shadows);
|
||||
border-color: if($fc==$selected_bg_color,
|
||||
$selected_borders_color,
|
||||
darken($fc,35%));
|
||||
@@ -111,7 +108,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
@mixin button($t, $c:$osd_bg_color, $tc:$fg_color, $edge: $borders_edge) {
|
||||
@mixin button($t, $c:$bg_color, $tc:$fg_color, $edge: $borders_edge) {
|
||||
//
|
||||
// Button drawing function
|
||||
//
|
||||
@@ -130,46 +127,39 @@
|
||||
$_hilight_color: _button_hilight_color($c);
|
||||
$_button_edge: if($edge == none, none, _widget_edge($edge));
|
||||
$_blank_edge: if($edge == none, none, _widget_edge(transparentize($edge,1)));
|
||||
|
||||
$_button_shadow: 0 1px 2px transparentize($shadow_color, 0.03);
|
||||
|
||||
@if $t==normal {
|
||||
//
|
||||
// normal button
|
||||
//
|
||||
$_bg: if($c!=$osd_bg_color, transparentize($c, 0.5),
|
||||
$osd_bg_color);
|
||||
|
||||
color: $osd_fg_color;
|
||||
background-color: $_bg;
|
||||
border-color: $osd_borders_color;
|
||||
box-shadow: inset 0 1px lighten($osd_bg_color,10%);
|
||||
color: $tc;
|
||||
background-color: $c;
|
||||
border-color: $borders_color;
|
||||
box-shadow: $_button_shadow;
|
||||
text-shadow: 0 1px black;
|
||||
icon-shadow: 0 1px black;
|
||||
}
|
||||
@if $t==focus {
|
||||
//
|
||||
// focused button
|
||||
//
|
||||
$_bg: if($c!=$osd_bg_color, transparentize($c, 0.3),
|
||||
lighten($osd_bg_color,3%));
|
||||
|
||||
color: $osd_fg_color;
|
||||
//
|
||||
color: $tc;
|
||||
text-shadow: 0 1px black;
|
||||
icon-shadow: 0 1px black;
|
||||
box-shadow: inset 0px 0px 0px 1px $selected_bg_color;
|
||||
box-shadow: inset 0px 0px 0px 2px $selected_bg_color;
|
||||
//border-color: $selected_bg_color;
|
||||
}
|
||||
|
||||
@else if $t==hover {
|
||||
//
|
||||
// active osd button
|
||||
//
|
||||
$_bg: if($c!=$osd_bg_color, transparentize($c, 0.3),
|
||||
lighten($osd_bg_color,3%));
|
||||
|
||||
color: white;
|
||||
border-color: $osd_borders_color;
|
||||
background-color: $_bg;
|
||||
box-shadow: inset 0 1px lighten($osd_bg_color,20%);
|
||||
color: $tc;
|
||||
border-color: $borders_color;
|
||||
background-color: $c;
|
||||
box-shadow: $_button_shadow;
|
||||
text-shadow: 0 1px black;
|
||||
icon-shadow: 0 1px black;
|
||||
|
||||
@@ -178,27 +168,18 @@
|
||||
//
|
||||
// active osd button
|
||||
//
|
||||
$_bg: if($c!=$bg_color, $c, $osd_borders_color);
|
||||
|
||||
color: white;
|
||||
border-color: $osd_borders_color;
|
||||
background-color: $selected_bg_color;
|
||||
// This should be none, but it's creating some issues with borders, so to
|
||||
// workaround it for now, use inset wich goes through a different code path.
|
||||
// see https://bugzilla.gnome.org/show_bug.cgi?id=752934
|
||||
box-shadow: inset 0 0 black;
|
||||
color: $tc;
|
||||
border-color: $borders_color;
|
||||
background-color: $c;
|
||||
text-shadow: none;
|
||||
icon-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
@else if $t==insensitive {
|
||||
//
|
||||
// insensitive osd button
|
||||
//
|
||||
$_bg: transparentize(mix($insensitive_fg_color,$osd_bg_color,20%),0.3);
|
||||
|
||||
color: $insensitive_fg_color;
|
||||
border-color: $osd_borders_color;
|
||||
background-color: $_bg;
|
||||
border-color: $insensitive_borders_color;
|
||||
background-color: $insensitive_bg_color;
|
||||
box-shadow: none;
|
||||
text-shadow: none;
|
||||
icon-shadow: none;
|
||||
|
||||
@@ -26,6 +26,7 @@ $osd_borders_color: transparentize(black, 0.3);
|
||||
$osd_outer_borders_color: transparentize(white, 0.9);
|
||||
|
||||
$tooltip_borders_color: $osd_outer_borders_color;
|
||||
$shadow_color: transparentize(black, 0.9);
|
||||
|
||||
//insensitive state derived colors
|
||||
$insensitive_fg_color: mix($fg_color, $bg_color, 50%);
|
||||
|
||||
1
data/theme/toggle-off-dark.svg
Normal file
1
data/theme/toggle-off-dark.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="46" height="22"><defs><linearGradient id="a"><stop offset="0" stop-color="#39393a"/><stop offset="1" stop-color="#302f30"/></linearGradient><linearGradient xlink:href="#a" id="b" x1="53" y1="294.429" x2="53" y2="309.804" gradientUnits="userSpaceOnUse" gradientTransform="translate(-42.76)"/></defs><g transform="translate(0 -291.18)" stroke-width="1.085"><rect style="marker:none" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#323233" stroke="#272728"/><rect ry="10.455" rx="10.455" y="291.715" x=".543" height="20.911" width="21.143" style="marker:none" fill="url(#b)" stroke="#151515"/></g></svg>
|
||||
|
After Width: | Height: | Size: 725 B |
@@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="46"
|
||||
height="22"
|
||||
viewBox="0 0 46 22"
|
||||
version="1.1"
|
||||
id="svg2751"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||
sodipodi:docname="toggle-off-intl.svg">
|
||||
<defs
|
||||
id="defs2745">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3329">
|
||||
<stop
|
||||
style="stop-color:#39393a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3325" />
|
||||
<stop
|
||||
style="stop-color:#302f30;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3327" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3329"
|
||||
id="linearGradient3331"
|
||||
x1="53"
|
||||
y1="294.42917"
|
||||
x2="53"
|
||||
y2="309.80417"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-42.760724)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#535353"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="-19.436775"
|
||||
inkscape:cy="-13.499723"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
showborder="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3298" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2748">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-291.17916)">
|
||||
<rect
|
||||
style="opacity:1;vector-effect:none;fill:#323233;fill-opacity:1;stroke:#272728;stroke-width:1.08532763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect3296"
|
||||
width="44.446434"
|
||||
height="20.910645"
|
||||
x="0.625"
|
||||
y="291.71494"
|
||||
rx="10.455324"
|
||||
ry="10.073335" />
|
||||
<rect
|
||||
ry="10.455322"
|
||||
rx="10.455322"
|
||||
y="291.71494"
|
||||
x="0.5428465"
|
||||
height="20.910645"
|
||||
width="21.142862"
|
||||
id="rect3300"
|
||||
style="opacity:1;vector-effect:none;fill:url(#linearGradient3331);fill-opacity:1;stroke:#151515;stroke-width:1.08532763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
1
data/theme/toggle-off.svg
Normal file
1
data/theme/toggle-off.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="22"><g transform="translate(0 -291.18)"><rect style="marker:none;font-variant-east_asian:normal" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#e1dedb" stroke="#cdc7c2" stroke-linecap="round" stroke-linejoin="round"/><rect ry="10.455" rx="10.455" y="291.715" x=".543" height="20.911" width="21.143" style="marker:none;font-variant-east_asian:normal" fill="#f8f7f7" stroke="#aa9f98" stroke-linecap="round" stroke-linejoin="round"/><g transform="matrix(.97148 0 0 1 1658.914 -2552.91)" stroke-width="1.015" stroke-linecap="round" stroke-linejoin="round"><rect ry="13.17" rx="13.556" y="1234.681" x="-1242.732" height="26" width="49.409" style="marker:none" fill="#e1dedb" stroke="#cdc7c2"/><rect style="marker:none" width="26.763" height="26" x="-1242.732" y="1234.769" rx="13.511" ry="13.126" fill="#f8f7f7" stroke="#aa9f98"/></g><g transform="matrix(.97148 0 0 1 1658.914 -2512.91)" stroke-width="1.015" stroke="#2b73cc"><rect style="marker:none" width="49.409" height="26" x="-1242.732" y="1234.681" rx="13.556" ry="13.17" fill="#3081e3"/><rect ry="13.126" rx="13.511" y="1234.769" x="-1220.086" height="26" width="26.763" style="marker:none" fill="#f8f7f7" stroke-linecap="round" stroke-linejoin="round"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
1
data/theme/toggle-on-dark.svg
Normal file
1
data/theme/toggle-on-dark.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="46" height="22"><defs><linearGradient id="a"><stop offset="0" stop-color="#39393a"/><stop offset="1" stop-color="#302f30"/></linearGradient><linearGradient xlink:href="#a" id="b" x1="53" y1="294.429" x2="53" y2="309.804" gradientUnits="userSpaceOnUse" gradientTransform="translate(-19)"/></defs><g transform="translate(0 -291.18)" stroke="#030e1b" stroke-width="1.085"><rect style="marker:none" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#15539e"/><rect ry="10.455" rx="10.455" y="291.715" x="24.304" height="20.911" width="21.143" style="marker:none" fill="url(#b)"/></g></svg>
|
||||
|
After Width: | Height: | Size: 707 B |
@@ -1,103 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="46"
|
||||
height="22"
|
||||
viewBox="0 0 46 22"
|
||||
version="1.1"
|
||||
id="svg2751"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
||||
sodipodi:docname="toggle-on-intl.svg">
|
||||
<defs
|
||||
id="defs2745">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient3329">
|
||||
<stop
|
||||
style="stop-color:#39393a;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3325" />
|
||||
<stop
|
||||
style="stop-color:#302f30;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop3327" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3329"
|
||||
id="linearGradient3331"
|
||||
x1="53"
|
||||
y1="294.42917"
|
||||
x2="53"
|
||||
y2="309.80417"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(-19)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#535353"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="13.588971"
|
||||
inkscape:cy="14.124546"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:pagecheckerboard="true"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
showborder="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3298" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata2748">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-291.17916)">
|
||||
<rect
|
||||
style="opacity:1;vector-effect:none;fill:#15539e;fill-opacity:1;stroke:#030e1b;stroke-width:1.08532763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="rect3296"
|
||||
width="44.446434"
|
||||
height="20.910645"
|
||||
x="0.625"
|
||||
y="291.71494"
|
||||
rx="10.455324"
|
||||
ry="10.073335" />
|
||||
<rect
|
||||
ry="10.455322"
|
||||
rx="10.455322"
|
||||
y="291.71494"
|
||||
x="24.30357"
|
||||
height="20.910645"
|
||||
width="21.142862"
|
||||
id="rect3300"
|
||||
style="opacity:1;vector-effect:none;fill:url(#linearGradient3331);fill-opacity:1;stroke:#030e1b;stroke-width:1.08532763;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.3 KiB |
1
data/theme/toggle-on.svg
Normal file
1
data/theme/toggle-on.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="22"><g transform="translate(0 -291.18)" stroke="#2b73cc"><rect style="marker:none;font-variant-east_asian:normal" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#3081e3"/><rect ry="10.455" rx="10.455" y="291.715" x="24.304" height="20.911" width="21.143" style="marker:none;font-variant-east_asian:normal" fill="#f8f7f7" stroke-linecap="round" stroke-linejoin="round"/></g></svg>
|
||||
|
After Width: | Height: | Size: 473 B |
@@ -28,7 +28,7 @@ foreach iface : ifaces
|
||||
output: 'doc-gen-' + iface[1],
|
||||
command: [
|
||||
'gdbus-codegen',
|
||||
'--interface-prefix=@0@.'.format(iface),
|
||||
'--interface-prefix=@0@.'.format(iface[0]),
|
||||
'--generate-docbook', 'doc-gen',
|
||||
'--output-directory', '@OUTDIR@',
|
||||
'@INPUT@'
|
||||
|
||||
@@ -31,34 +31,34 @@ its dependencies to build from tarballs.</description>
|
||||
<programming-language>JavaScript</programming-language>
|
||||
<programming-language>C</programming-language>
|
||||
|
||||
<maintainer>
|
||||
<author>
|
||||
<foaf:Person>
|
||||
<foaf:name>William Jon McCann</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:jmccann@redhat.com" />
|
||||
<gnome:userid>mccann</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
</author>
|
||||
<author>
|
||||
<foaf:Person>
|
||||
<foaf:name>Owen Taylor</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:otaylor@redhat.com" />
|
||||
<gnome:userid>otaylor</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
</author>
|
||||
<author>
|
||||
<foaf:Person>
|
||||
<foaf:name>Colin Walters</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:walters@verbum.org" />
|
||||
<gnome:userid>walters</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
</author>
|
||||
<author>
|
||||
<foaf:Person>
|
||||
<foaf:name>Marina Zhurakhinskaya</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:marinaz@redhat.com" />
|
||||
<gnome:userid>marinaz</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
</author>
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Florian Müllner</foaf:name>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/* exported main */
|
||||
imports.gi.versions.Gdk = '3.0';
|
||||
imports.gi.versions.Gtk = '3.0';
|
||||
|
||||
const Gettext = imports.gettext;
|
||||
const { Gdk, GLib, Gio, GObject, Gtk, Pango } = imports.gi;
|
||||
const Format = imports.format;
|
||||
@@ -8,6 +12,8 @@ const Config = imports.misc.config;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
const { ExtensionState } = ExtensionUtils;
|
||||
|
||||
const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
|
||||
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
|
||||
|
||||
@@ -17,74 +23,54 @@ function stripPrefix(string, prefix) {
|
||||
return string;
|
||||
}
|
||||
|
||||
var Application = class {
|
||||
constructor() {
|
||||
var Application = GObject.registerClass({
|
||||
GTypeName: 'ExtensionPrefs_Application'
|
||||
}, class Application extends Gtk.Application {
|
||||
_init() {
|
||||
GLib.set_prgname('gnome-shell-extension-prefs');
|
||||
this.application = new Gtk.Application({
|
||||
super._init({
|
||||
application_id: 'org.gnome.shell.ExtensionPrefs',
|
||||
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE
|
||||
});
|
||||
|
||||
this.application.connect('activate', this._onActivate.bind(this));
|
||||
this.application.connect('command-line', this._onCommandLine.bind(this));
|
||||
this.application.connect('startup', this._onStartup.bind(this));
|
||||
|
||||
this._extensionPrefsModules = {};
|
||||
|
||||
this._startupUuid = null;
|
||||
this._loaded = false;
|
||||
this._skipMainWindow = false;
|
||||
this._shellProxy = null;
|
||||
}
|
||||
|
||||
_extensionAvailable(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
get shellProxy() {
|
||||
return this._shellProxy;
|
||||
}
|
||||
|
||||
if (!extension)
|
||||
_showPrefs(uuid) {
|
||||
let row = this._extensionSelector.get_children().find(c => {
|
||||
return c.uuid === uuid && c.hasPrefs;
|
||||
});
|
||||
|
||||
if (!row)
|
||||
return false;
|
||||
|
||||
if (!extension.dir.get_child('prefs.js').query_exists(null))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_getExtensionPrefsModule(extension) {
|
||||
let uuid = extension.metadata.uuid;
|
||||
|
||||
if (this._extensionPrefsModules.hasOwnProperty(uuid))
|
||||
return this._extensionPrefsModules[uuid];
|
||||
|
||||
ExtensionUtils.installImporter(extension);
|
||||
|
||||
let prefsModule = extension.imports.prefs;
|
||||
prefsModule.init(extension.metadata);
|
||||
|
||||
this._extensionPrefsModules[uuid] = prefsModule;
|
||||
return prefsModule;
|
||||
}
|
||||
|
||||
_selectExtension(uuid) {
|
||||
if (!this._extensionAvailable(uuid))
|
||||
return;
|
||||
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
let widget;
|
||||
|
||||
try {
|
||||
let prefsModule = this._getExtensionPrefsModule(extension);
|
||||
widget = prefsModule.buildPrefsWidget();
|
||||
widget = row.prefsModule.buildPrefsWidget();
|
||||
} catch (e) {
|
||||
widget = this._buildErrorUI(extension, e);
|
||||
widget = this._buildErrorUI(row, e);
|
||||
}
|
||||
|
||||
let dialog = new Gtk.Window({ modal: !this._skipMainWindow,
|
||||
type_hint: Gdk.WindowTypeHint.DIALOG });
|
||||
dialog.set_titlebar(new Gtk.HeaderBar({ show_close_button: true,
|
||||
title: extension.metadata.name,
|
||||
visible: true }));
|
||||
let dialog = new Gtk.Window({
|
||||
modal: !this._skipMainWindow,
|
||||
type_hint: Gdk.WindowTypeHint.DIALOG
|
||||
});
|
||||
dialog.set_titlebar(new Gtk.HeaderBar({
|
||||
show_close_button: true,
|
||||
title: row.name,
|
||||
visible: true
|
||||
}));
|
||||
|
||||
if (this._skipMainWindow) {
|
||||
this.application.add_window(dialog);
|
||||
this.add_window(dialog);
|
||||
if (this._window)
|
||||
this._window.destroy();
|
||||
this._window = dialog;
|
||||
@@ -96,9 +82,11 @@ var Application = class {
|
||||
dialog.set_default_size(600, 400);
|
||||
dialog.add(widget);
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_buildErrorUI(extension, exc) {
|
||||
_buildErrorUI(row, exc) {
|
||||
let scroll = new Gtk.ScrolledWindow({
|
||||
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||
propagate_natural_height: true
|
||||
@@ -168,13 +156,20 @@ var Application = class {
|
||||
|
||||
copyButton.connect('clicked', w => {
|
||||
let clipboard = Gtk.Clipboard.get_default(w.get_display());
|
||||
let backticks = '```';
|
||||
clipboard.set_text(
|
||||
// markdown for pasting in gitlab issues
|
||||
`The settings of extension ${extension.uuid} had an error:\n${
|
||||
backticks}\n${exc}\n${backticks}\n\nStack trace:\n${
|
||||
backticks}\n${exc.stack}${backticks}\n`, -1
|
||||
);
|
||||
// markdown for pasting in gitlab issues
|
||||
let lines = [
|
||||
`The settings of extension ${row.uuid} had an error:`,
|
||||
'```',
|
||||
`${exc}`,
|
||||
'```',
|
||||
'',
|
||||
'Stack trace:',
|
||||
'```',
|
||||
exc.stack.replace(/\n$/, ''), // stack without trailing newline
|
||||
'```',
|
||||
''
|
||||
];
|
||||
clipboard.set_text(lines.join('\n'), -1);
|
||||
});
|
||||
|
||||
let spacing = new Gtk.SeparatorToolItem({ draw: false });
|
||||
@@ -185,13 +180,13 @@ var Application = class {
|
||||
label: _("Homepage"),
|
||||
tooltip_text: _("Visit extension homepage"),
|
||||
no_show_all: true,
|
||||
visible: extension.metadata.url != null
|
||||
visible: row.url != null
|
||||
});
|
||||
toolbar.add(urlButton);
|
||||
|
||||
urlButton.connect('clicked', w => {
|
||||
let context = w.get_display().get_app_launch_context();
|
||||
Gio.AppInfo.launch_default_for_uri(extension.metadata.url, context);
|
||||
Gio.AppInfo.launch_default_for_uri(row.url, context);
|
||||
});
|
||||
|
||||
let expandedBox = new Gtk.Box({
|
||||
@@ -206,8 +201,8 @@ var Application = class {
|
||||
return scroll;
|
||||
}
|
||||
|
||||
_buildUI(app) {
|
||||
this._window = new Gtk.ApplicationWindow({ application: app,
|
||||
_buildUI() {
|
||||
this._window = new Gtk.ApplicationWindow({ application: this,
|
||||
window_position: Gtk.WindowPosition.CENTER });
|
||||
|
||||
this._window.set_default_size(800, 500);
|
||||
@@ -241,18 +236,14 @@ var Application = class {
|
||||
this._mainStack.add_named(new EmptyPlaceholder(), 'placeholder');
|
||||
|
||||
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
|
||||
this._shellProxy.connectSignal('ExtensionStatusChanged', (proxy, senderName, [uuid, state, error]) => {
|
||||
if (ExtensionUtils.extensions[uuid] !== undefined)
|
||||
this._scanExtensions();
|
||||
});
|
||||
this._shellProxy.connectSignal('ExtensionStateChanged',
|
||||
this._onExtensionStateChanged.bind(this));
|
||||
|
||||
this._window.show_all();
|
||||
}
|
||||
|
||||
_sortList(row1, row2) {
|
||||
let name1 = ExtensionUtils.extensions[row1.uuid].metadata.name;
|
||||
let name2 = ExtensionUtils.extensions[row2.uuid].metadata.name;
|
||||
return name1.localeCompare(name2);
|
||||
return row1.name.localeCompare(row2.name);
|
||||
}
|
||||
|
||||
_updateHeader(row, before) {
|
||||
@@ -263,19 +254,56 @@ var Application = class {
|
||||
row.set_header(sep);
|
||||
}
|
||||
|
||||
_scanExtensions() {
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', this._extensionFound.bind(this));
|
||||
finder.scanExtensions();
|
||||
this._extensionsLoaded();
|
||||
_findExtensionRow(uuid) {
|
||||
return this._extensionSelector.get_children().find(c => c.uuid === uuid);
|
||||
}
|
||||
|
||||
_extensionFound(finder, extension) {
|
||||
let row = new ExtensionRow(extension.uuid);
|
||||
_onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
|
||||
let row = this._findExtensionRow(uuid);
|
||||
if (row) {
|
||||
let { state } = ExtensionUtils.deserializeExtension(newState);
|
||||
if (state == ExtensionState.UNINSTALLED)
|
||||
row.destroy();
|
||||
return; // we only deal with new and deleted extensions here
|
||||
}
|
||||
|
||||
this._shellProxy.GetExtensionInfoRemote(uuid, ([serialized]) => {
|
||||
let extension = ExtensionUtils.deserializeExtension(serialized);
|
||||
if (!extension)
|
||||
return;
|
||||
// check the extension wasn't added in between
|
||||
if (this._findExtensionRow(uuid) != null)
|
||||
return;
|
||||
this._addExtensionRow(extension);
|
||||
});
|
||||
}
|
||||
|
||||
_scanExtensions() {
|
||||
this._shellProxy.ListExtensionsRemote(([extensionsMap], e) => {
|
||||
if (e) {
|
||||
if (e instanceof Gio.DBusError) {
|
||||
log(`Failed to connect to shell proxy: ${e}`);
|
||||
this._mainStack.add_named(new NoShellPlaceholder(), 'noshell');
|
||||
this._mainStack.visible_child_name = 'noshell';
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (let uuid in extensionsMap) {
|
||||
let extension = ExtensionUtils.deserializeExtension(extensionsMap[uuid]);
|
||||
this._addExtensionRow(extension);
|
||||
}
|
||||
this._extensionsLoaded();
|
||||
});
|
||||
}
|
||||
|
||||
_addExtensionRow(extension) {
|
||||
let row = new ExtensionRow(extension);
|
||||
|
||||
row.prefsButton.visible = this._extensionAvailable(row.uuid);
|
||||
row.prefsButton.connect('clicked', () => {
|
||||
this._selectExtension(row.uuid);
|
||||
this._showPrefs(row.uuid);
|
||||
});
|
||||
|
||||
row.show_all();
|
||||
@@ -288,24 +316,26 @@ var Application = class {
|
||||
else
|
||||
this._mainStack.visible_child_name = 'placeholder';
|
||||
|
||||
if (this._startupUuid && this._extensionAvailable(this._startupUuid))
|
||||
this._selectExtension(this._startupUuid);
|
||||
if (this._startupUuid)
|
||||
this._showPrefs(this._startupUuid);
|
||||
this._startupUuid = null;
|
||||
this._skipMainWindow = false;
|
||||
this._loaded = true;
|
||||
}
|
||||
|
||||
_onActivate() {
|
||||
vfunc_activate() {
|
||||
this._window.present();
|
||||
}
|
||||
|
||||
_onStartup(app) {
|
||||
this._buildUI(app);
|
||||
vfunc_startup() {
|
||||
super.vfunc_startup();
|
||||
|
||||
this._buildUI();
|
||||
this._scanExtensions();
|
||||
}
|
||||
|
||||
_onCommandLine(app, commandLine) {
|
||||
app.activate();
|
||||
vfunc_command_line(commandLine) {
|
||||
this.activate();
|
||||
let args = commandLine.get_arguments();
|
||||
|
||||
if (args.length) {
|
||||
@@ -316,16 +346,14 @@ var Application = class {
|
||||
// Strip off "extension:///" prefix which fakes a URI, if it exists
|
||||
uuid = stripPrefix(uuid, "extension:///");
|
||||
|
||||
if (this._extensionAvailable(uuid))
|
||||
this._selectExtension(uuid);
|
||||
else if (!this._loaded)
|
||||
if (!this._loaded)
|
||||
this._startupUuid = uuid;
|
||||
else
|
||||
else if (!this._showPrefs(uuid))
|
||||
this._skipMainWindow = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var Expander = GObject.registerClass({
|
||||
Properties: {
|
||||
@@ -492,6 +520,35 @@ class EmptyPlaceholder extends Gtk.Box {
|
||||
}
|
||||
});
|
||||
|
||||
var NoShellPlaceholder = GObject.registerClass(
|
||||
class NoShellPlaceholder extends Gtk.Box {
|
||||
_init() {
|
||||
super._init({
|
||||
orientation: Gtk.Orientation.VERTICAL,
|
||||
spacing: 12,
|
||||
margin: 100,
|
||||
margin_bottom: 60
|
||||
});
|
||||
|
||||
let label = new Gtk.Label({
|
||||
label: '<span size="x-large">%s</span>'.format(
|
||||
_("Something’s gone wrong")),
|
||||
use_markup: true
|
||||
});
|
||||
label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
|
||||
this.add(label);
|
||||
|
||||
label = new Gtk.Label({
|
||||
label: _("We’re very sorry, but it was not possible to get the list of installed extensions. Make sure you are logged into GNOME and try again."),
|
||||
justify: Gtk.Justification.CENTER,
|
||||
wrap: true
|
||||
});
|
||||
this.add(label);
|
||||
|
||||
this.show_all();
|
||||
}
|
||||
});
|
||||
|
||||
var DescriptionLabel = GObject.registerClass(
|
||||
class DescriptionLabel extends Gtk.Label {
|
||||
vfunc_get_preferred_height_for_width(width) {
|
||||
@@ -504,30 +561,59 @@ class DescriptionLabel extends Gtk.Label {
|
||||
|
||||
var ExtensionRow = GObject.registerClass(
|
||||
class ExtensionRow extends Gtk.ListBoxRow {
|
||||
_init(uuid) {
|
||||
_init(extension) {
|
||||
super._init();
|
||||
|
||||
this.uuid = uuid;
|
||||
this._app = Gio.Application.get_default();
|
||||
this._extension = extension;
|
||||
this._prefsModule = null;
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
|
||||
this._settings.connect('changed::enabled-extensions', () => {
|
||||
this._switch.state = this._isEnabled();
|
||||
});
|
||||
this._settings.connect('changed::disable-extension-version-validation',
|
||||
() => {
|
||||
this._switch.sensitive = this._canEnable();
|
||||
});
|
||||
this._settings.connect('changed::disable-user-extensions',
|
||||
() => {
|
||||
this._switch.sensitive = this._canEnable();
|
||||
});
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
|
||||
this._buildUI();
|
||||
|
||||
this._extensionStateChangedId = this._app.shellProxy.connectSignal(
|
||||
'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
|
||||
if (this.uuid !== uuid)
|
||||
return;
|
||||
|
||||
this._extension = ExtensionUtils.deserializeExtension(newState);
|
||||
let state = (this._extension.state == ExtensionState.ENABLED);
|
||||
|
||||
GObject.signal_handler_block(this._switch, this._notifyActiveId);
|
||||
this._switch.state = state;
|
||||
GObject.signal_handler_unblock(this._switch, this._notifyActiveId);
|
||||
|
||||
this._switch.sensitive = this._canToggle();
|
||||
});
|
||||
}
|
||||
|
||||
get uuid() {
|
||||
return this._extension.uuid;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this._extension.metadata.name;
|
||||
}
|
||||
|
||||
get hasPrefs() {
|
||||
return this._extension.hasPrefs;
|
||||
}
|
||||
|
||||
get url() {
|
||||
return this._extension.metadata.url;
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
if (!this._app.shellProxy)
|
||||
return;
|
||||
|
||||
if (this._extensionStateChangedId)
|
||||
this._app.shellProxy.disconnectSignal(this._extensionStateChangedId);
|
||||
this._extensionStateChangedId = 0;
|
||||
}
|
||||
|
||||
_buildUI() {
|
||||
let extension = ExtensionUtils.extensions[this.uuid];
|
||||
|
||||
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
|
||||
hexpand: true, margin_end: 24, spacing: 24,
|
||||
margin: 12 });
|
||||
@@ -537,19 +623,20 @@ class ExtensionRow extends Gtk.ListBoxRow {
|
||||
spacing: 6, hexpand: true });
|
||||
hbox.add(vbox);
|
||||
|
||||
let name = GLib.markup_escape_text(extension.metadata.name, -1);
|
||||
let name = GLib.markup_escape_text(this.name, -1);
|
||||
let label = new Gtk.Label({ label: '<b>' + name + '</b>',
|
||||
use_markup: true,
|
||||
halign: Gtk.Align.START });
|
||||
vbox.add(label);
|
||||
|
||||
let desc = extension.metadata.description.split('\n')[0];
|
||||
let desc = this._extension.metadata.description.split('\n')[0];
|
||||
label = new DescriptionLabel({ label: desc, wrap: true, lines: 2,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
xalign: 0, yalign: 0 });
|
||||
vbox.add(label);
|
||||
|
||||
let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
|
||||
visible: this.hasPrefs,
|
||||
no_show_all: true });
|
||||
button.set_image(new Gtk.Image({ icon_name: 'emblem-system-symbolic',
|
||||
icon_size: Gtk.IconSize.BUTTON,
|
||||
@@ -559,51 +646,37 @@ class ExtensionRow extends Gtk.ListBoxRow {
|
||||
|
||||
this.prefsButton = button;
|
||||
|
||||
this._switch = new Gtk.Switch({ valign: Gtk.Align.CENTER,
|
||||
sensitive: this._canEnable(),
|
||||
state: this._isEnabled() });
|
||||
this._switch.connect('notify::active', () => {
|
||||
this._switch = new Gtk.Switch({
|
||||
valign: Gtk.Align.CENTER,
|
||||
sensitive: this._canToggle(),
|
||||
state: this._extension.state === ExtensionState.ENABLED
|
||||
});
|
||||
this._notifyActiveId = this._switch.connect('notify::active', () => {
|
||||
if (this._switch.active)
|
||||
this._enable();
|
||||
this._app.shellProxy.EnableExtensionRemote(this.uuid);
|
||||
else
|
||||
this._disable();
|
||||
this._app.shellProxy.DisableExtensionRemote(this.uuid);
|
||||
});
|
||||
this._switch.connect('state-set', () => true);
|
||||
hbox.add(this._switch);
|
||||
}
|
||||
|
||||
_canEnable() {
|
||||
let extension = ExtensionUtils.extensions[this.uuid];
|
||||
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
|
||||
|
||||
return !this._settings.get_boolean('disable-user-extensions') &&
|
||||
!(checkVersion && ExtensionUtils.isOutOfDate(extension));
|
||||
_canToggle() {
|
||||
return this._extension.canChange;
|
||||
}
|
||||
|
||||
_isEnabled() {
|
||||
let extensions = this._settings.get_strv('enabled-extensions');
|
||||
return extensions.indexOf(this.uuid) != -1;
|
||||
}
|
||||
get prefsModule() {
|
||||
if (!this._prefsModule) {
|
||||
ExtensionUtils.installImporter(this._extension);
|
||||
|
||||
_enable() {
|
||||
let extensions = this._settings.get_strv('enabled-extensions');
|
||||
if (extensions.indexOf(this.uuid) != -1)
|
||||
return;
|
||||
// give extension prefs access to their own extension object
|
||||
ExtensionUtils.getCurrentExtension = () => this._extension;
|
||||
|
||||
extensions.push(this.uuid);
|
||||
this._settings.set_strv('enabled-extensions', extensions);
|
||||
}
|
||||
this._prefsModule = this._extension.imports.prefs;
|
||||
this._prefsModule.init(this._extension.metadata);
|
||||
}
|
||||
|
||||
_disable() {
|
||||
let extensions = this._settings.get_strv('enabled-extensions');
|
||||
let pos = extensions.indexOf(this.uuid);
|
||||
if (pos == -1)
|
||||
return;
|
||||
do {
|
||||
extensions.splice(pos, 1);
|
||||
pos = extensions.indexOf(this.uuid);
|
||||
} while (pos != -1);
|
||||
this._settings.set_strv('enabled-extensions', extensions);
|
||||
return this._prefsModule;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -611,12 +684,12 @@ function initEnvironment() {
|
||||
// Monkey-patch in a "global" object that fakes some Shell utilities
|
||||
// that ExtensionUtils depends on.
|
||||
window.global = {
|
||||
log() {
|
||||
print([].join.call(arguments, ', '));
|
||||
log(...args) {
|
||||
print(args.join(', '));
|
||||
},
|
||||
|
||||
logError(s) {
|
||||
log('ERROR: ' + s);
|
||||
log(`ERROR: ${s}`);
|
||||
},
|
||||
|
||||
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell'])
|
||||
@@ -631,6 +704,5 @@ function main(argv) {
|
||||
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
|
||||
Gettext.textdomain(Config.GETTEXT_PACKAGE);
|
||||
|
||||
let app = new Application();
|
||||
app.application.run(argv);
|
||||
new Application().run(argv);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported AuthPrompt */
|
||||
|
||||
const { Clutter, Pango, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
const { Clutter, GObject, Pango, Shell, St } = imports.gi;
|
||||
|
||||
const Animation = imports.ui.animation;
|
||||
const Batch = imports.gdm.batch;
|
||||
const GdmUtil = imports.gdm.util;
|
||||
const Params = imports.misc.params;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const UserWidget = imports.ui.userWidget;
|
||||
|
||||
var DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
|
||||
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
|
||||
var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3;
|
||||
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000;
|
||||
var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300;
|
||||
|
||||
var MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5;
|
||||
var MESSAGE_FADE_OUT_ANIMATION_TIME = 500;
|
||||
|
||||
var AuthPromptMode = {
|
||||
UNLOCK_ONLY: 0,
|
||||
@@ -34,8 +33,21 @@ var BeginRequestType = {
|
||||
DONT_PROVIDE_USERNAME: 1
|
||||
};
|
||||
|
||||
var AuthPrompt = class {
|
||||
constructor(gdmClient, mode) {
|
||||
var AuthPrompt = GObject.registerClass({
|
||||
Signals: {
|
||||
'cancelled': {},
|
||||
'failed': {},
|
||||
'next': {},
|
||||
'prompted': {},
|
||||
'reset': { param_types: [GObject.TYPE_UINT] },
|
||||
}
|
||||
}, class AuthPrompt extends St.BoxLayout {
|
||||
_init(gdmClient, mode) {
|
||||
super._init({
|
||||
style_class: 'login-dialog-prompt-layout',
|
||||
vertical: true
|
||||
});
|
||||
|
||||
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
|
||||
|
||||
this._gdmClient = gdmClient;
|
||||
@@ -59,47 +71,42 @@ var AuthPrompt = class {
|
||||
this.smartcardDetected = this._userVerifier.smartcardDetected;
|
||||
|
||||
this.connect('next', () => {
|
||||
this.updateSensitivity(false);
|
||||
this.startSpinning();
|
||||
if (this._queryingService) {
|
||||
this._userVerifier.answerQuery(this._queryingService, this._entry.text);
|
||||
} else {
|
||||
this._preemptiveAnswer = this._entry.text;
|
||||
}
|
||||
});
|
||||
this.updateSensitivity(false);
|
||||
this.startSpinning();
|
||||
if (this._queryingService) {
|
||||
this._userVerifier.answerQuery(this._queryingService, this._entry.text);
|
||||
} else {
|
||||
this._preemptiveAnswer = this._entry.text;
|
||||
}
|
||||
});
|
||||
|
||||
this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
||||
vertical: true });
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
this.actor.connect('key-press-event', (actor, event) => {
|
||||
if (event.get_key_symbol() == Clutter.KEY_Escape)
|
||||
this.cancel();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
});
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
|
||||
this._userWell = new St.Bin({ x_fill: true,
|
||||
x_align: St.Align.START });
|
||||
this.actor.add(this._userWell,
|
||||
{ x_align: St.Align.START,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
this._userWell = new St.Bin({ x_fill: true, x_align: St.Align.START });
|
||||
this.add(this._userWell, {
|
||||
x_align: St.Align.START,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true
|
||||
});
|
||||
this._label = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
||||
|
||||
this.actor.add(this._label,
|
||||
{ expand: true,
|
||||
x_fill: false,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START });
|
||||
this.add(this._label, {
|
||||
expand: true,
|
||||
x_fill: false,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START
|
||||
});
|
||||
this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
||||
can_focus: true });
|
||||
ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
|
||||
|
||||
this.actor.add(this._entry,
|
||||
{ expand: true,
|
||||
x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START });
|
||||
this.add(this._entry, {
|
||||
expand: true,
|
||||
x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START
|
||||
});
|
||||
|
||||
this._entry.grab_key_focus();
|
||||
|
||||
@@ -107,14 +114,15 @@ var AuthPrompt = class {
|
||||
styleClass: 'login-dialog-message' });
|
||||
this._message.clutter_text.line_wrap = true;
|
||||
this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
|
||||
this.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
|
||||
|
||||
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
|
||||
vertical: false });
|
||||
this.actor.add(this._buttonBox,
|
||||
{ expand: true,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.END });
|
||||
this.add(this._buttonBox, {
|
||||
expand: true,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.END
|
||||
});
|
||||
|
||||
this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
this._defaultButtonWellActor = null;
|
||||
@@ -122,9 +130,9 @@ var AuthPrompt = class {
|
||||
this._initButtons();
|
||||
|
||||
this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
|
||||
this._spinner.actor.opacity = 0;
|
||||
this._spinner.actor.show();
|
||||
this._defaultButtonWell.add_child(this._spinner.actor);
|
||||
this._spinner.opacity = 0;
|
||||
this._spinner.show();
|
||||
this._defaultButtonWell.add_child(this._spinner);
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
@@ -132,13 +140,19 @@ var AuthPrompt = class {
|
||||
this._userVerifier = null;
|
||||
}
|
||||
|
||||
vfunc_key_press_event(keyPressEvent) {
|
||||
if (keyPressEvent.keyval == Clutter.KEY_Escape)
|
||||
this.cancel();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
_initButtons() {
|
||||
this.cancelButton = new St.Button({ style_class: 'modal-dialog-button button',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
label: _("Cancel") });
|
||||
this.cancelButton.connect('clicked', () => { this.cancel(); });
|
||||
this.cancelButton.connect('clicked', () => this.cancel());
|
||||
this._buttonBox.add(this.cancelButton,
|
||||
{ expand: false,
|
||||
x_fill: false,
|
||||
@@ -157,7 +171,7 @@ var AuthPrompt = class {
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
label: _("Next") });
|
||||
this.nextButton.connect('clicked', () => { this.emit('next'); });
|
||||
this.nextButton.connect('clicked', () => this.emit('next'));
|
||||
this.nextButton.add_style_pseudo_class('default');
|
||||
this._buttonBox.add(this.nextButton,
|
||||
{ expand: false,
|
||||
@@ -267,16 +281,16 @@ var AuthPrompt = class {
|
||||
let oldActor = this._defaultButtonWellActor;
|
||||
|
||||
if (oldActor)
|
||||
Tweener.removeTweens(oldActor);
|
||||
oldActor.remove_all_transitions();
|
||||
|
||||
let wasSpinner;
|
||||
if (oldActor == this._spinner.actor)
|
||||
if (oldActor == this._spinner)
|
||||
wasSpinner = true;
|
||||
else
|
||||
wasSpinner = false;
|
||||
|
||||
let isSpinner;
|
||||
if (actor == this._spinner.actor)
|
||||
if (actor == this._spinner)
|
||||
isSpinner = true;
|
||||
else
|
||||
isSpinner = false;
|
||||
@@ -290,19 +304,18 @@ var AuthPrompt = class {
|
||||
this._spinner.stop();
|
||||
}
|
||||
} else {
|
||||
Tweener.addTween(oldActor,
|
||||
{ opacity: 0,
|
||||
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
|
||||
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
|
||||
transition: 'linear',
|
||||
onCompleteScope: this,
|
||||
onComplete() {
|
||||
if (wasSpinner) {
|
||||
if (this._spinner)
|
||||
this._spinner.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
oldActor.ease({
|
||||
opacity: 0,
|
||||
duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
|
||||
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
onComplete: () => {
|
||||
if (wasSpinner) {
|
||||
if (this._spinner)
|
||||
this._spinner.stop();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,18 +326,19 @@ var AuthPrompt = class {
|
||||
if (!animate)
|
||||
actor.opacity = 255;
|
||||
else
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 255,
|
||||
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
|
||||
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
|
||||
transition: 'linear' });
|
||||
actor.ease({
|
||||
opacity: 255,
|
||||
duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
|
||||
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
|
||||
mode: Clutter.AnimationMode.LINEAR
|
||||
});
|
||||
}
|
||||
|
||||
this._defaultButtonWellActor = actor;
|
||||
}
|
||||
|
||||
startSpinning() {
|
||||
this.setActorInDefaultButtonWell(this._spinner.actor, true);
|
||||
this.setActorInDefaultButtonWell(this._spinner, true);
|
||||
}
|
||||
|
||||
stopSpinning() {
|
||||
@@ -366,12 +380,12 @@ var AuthPrompt = class {
|
||||
_fadeOutMessage() {
|
||||
if (this._message.opacity == 0)
|
||||
return;
|
||||
Tweener.removeTweens(this._message);
|
||||
Tweener.addTween(this._message,
|
||||
{ opacity: 0,
|
||||
time: MESSAGE_FADE_OUT_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
this._message.remove_all_transitions();
|
||||
this._message.ease({
|
||||
opacity: 0,
|
||||
duration: MESSAGE_FADE_OUT_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
}
|
||||
|
||||
setMessage(message, type) {
|
||||
@@ -386,7 +400,7 @@ var AuthPrompt = class {
|
||||
this._message.remove_style_class_name('login-dialog-message-hint');
|
||||
|
||||
if (message) {
|
||||
Tweener.removeTweens(this._message);
|
||||
this._message.remove_all_transitions();
|
||||
this._message.text = message;
|
||||
this._message.opacity = 255;
|
||||
} else {
|
||||
@@ -405,9 +419,9 @@ var AuthPrompt = class {
|
||||
this._entry.clutter_text.editable = sensitive;
|
||||
}
|
||||
|
||||
hide() {
|
||||
vfunc_hide() {
|
||||
this.setActorInDefaultButtonWell(null, true);
|
||||
this.actor.hide();
|
||||
super.vfunc_hide();
|
||||
this._message.opacity = 0;
|
||||
|
||||
this.setUser(null);
|
||||
@@ -423,7 +437,7 @@ var AuthPrompt = class {
|
||||
|
||||
if (user) {
|
||||
let userWidget = new UserWidget.UserWidget(user);
|
||||
this._userWell.set_child(userWidget.actor);
|
||||
this._userWell.set_child(userWidget);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -508,5 +522,4 @@ var AuthPrompt = class {
|
||||
this.reset();
|
||||
this.emit('cancelled');
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(AuthPrompt.prototype);
|
||||
});
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
* In order for transformation animations to look good, they need to be
|
||||
* incremental and have some order to them (e.g., fade out hidden items,
|
||||
* then shrink to close the void left over). Chaining animations in this way can
|
||||
* be error-prone and wordy using just Tweener callbacks.
|
||||
* be error-prone and wordy using just ease() callbacks.
|
||||
*
|
||||
* The classes in this file help with this:
|
||||
*
|
||||
@@ -44,6 +44,7 @@
|
||||
* replaced by something else.
|
||||
*/
|
||||
|
||||
const { GObject } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
var Task = class {
|
||||
@@ -176,36 +177,35 @@ Signals.addSignalMethods(Batch.prototype);
|
||||
|
||||
var ConcurrentBatch = class extends Batch {
|
||||
process() {
|
||||
let hold = this.runTask();
|
||||
let hold = this.runTask();
|
||||
|
||||
if (hold) {
|
||||
this.hold.acquireUntilAfter(hold);
|
||||
}
|
||||
if (hold) {
|
||||
this.hold.acquireUntilAfter(hold);
|
||||
}
|
||||
|
||||
// Regardless of the state of the just run task,
|
||||
// fire off the next one, so all the tasks can run
|
||||
// concurrently.
|
||||
this.nextTask();
|
||||
// Regardless of the state of the just run task,
|
||||
// fire off the next one, so all the tasks can run
|
||||
// concurrently.
|
||||
this.nextTask();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ConcurrentBatch.prototype);
|
||||
|
||||
var ConsecutiveBatch = class extends Batch {
|
||||
process() {
|
||||
let hold = this.runTask();
|
||||
let hold = this.runTask();
|
||||
|
||||
if (hold && hold.isAcquired()) {
|
||||
// This task is inhibiting the batch. Wait on it
|
||||
// before processing the next one.
|
||||
let signalId = hold.connect('release', () => {
|
||||
hold.disconnect(signalId);
|
||||
this.nextTask();
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
// This task finished, process the next one
|
||||
this.nextTask();
|
||||
}
|
||||
if (hold && hold.isAcquired()) {
|
||||
// This task is inhibiting the batch. Wait on it
|
||||
// before processing the next one.
|
||||
let signalId = hold.connect('release', () => {
|
||||
hold.disconnect(signalId);
|
||||
this.nextTask();
|
||||
});
|
||||
} else {
|
||||
// This task finished, process the next one
|
||||
this.nextTask();
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ConsecutiveBatch.prototype);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported FprintManager */
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
|
||||
@@ -23,8 +24,8 @@ function FprintManager() {
|
||||
|
||||
try {
|
||||
self.init(null);
|
||||
} catch(e) {
|
||||
log('Failed to connect to Fprint service: ' + e.message);
|
||||
} catch (e) {
|
||||
log(`Failed to connect to Fprint service: ${e.message}`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported LoginDialog */
|
||||
/*
|
||||
* Copyright 2011 Red Hat, Inc
|
||||
*
|
||||
@@ -18,7 +19,6 @@
|
||||
|
||||
const { AccountsService, Atk, Clutter, Gdm, Gio,
|
||||
GLib, GObject, Meta, Pango, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const AuthPrompt = imports.gdm.authPrompt;
|
||||
const Batch = imports.gdm.batch;
|
||||
@@ -30,81 +30,88 @@ const LoginManager = imports.misc.loginManager;
|
||||
const Main = imports.ui.main;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Realmd = imports.gdm.realmd;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const UserWidget = imports.ui.userWidget;
|
||||
|
||||
const _FADE_ANIMATION_TIME = 0.25;
|
||||
const _SCROLL_ANIMATION_TIME = 0.5;
|
||||
const _FADE_ANIMATION_TIME = 250;
|
||||
const _SCROLL_ANIMATION_TIME = 500;
|
||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
||||
const _LOGO_ICON_HEIGHT = 48;
|
||||
const _MAX_BOTTOM_MENU_ITEMS = 5;
|
||||
|
||||
var UserListItem = class {
|
||||
constructor(user) {
|
||||
var UserListItem = GObject.registerClass({
|
||||
GTypeName: 'LoginDialog_UserListItem',
|
||||
Signals: { 'activate': {} }
|
||||
}, class UserListItem extends St.Button {
|
||||
_init(user) {
|
||||
let layout = new St.BoxLayout({ vertical: true });
|
||||
super._init({
|
||||
style_class: 'login-dialog-user-list-item',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
can_focus: true,
|
||||
child: layout,
|
||||
reactive: true,
|
||||
x_align: St.Align.START,
|
||||
x_fill: true
|
||||
});
|
||||
|
||||
this.user = user;
|
||||
this._userChangedId = this.user.connect('changed',
|
||||
this._onUserChanged.bind(this));
|
||||
this._onUserChanged.bind(this));
|
||||
|
||||
let layout = new St.BoxLayout({ vertical: true });
|
||||
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
can_focus: true,
|
||||
child: layout,
|
||||
reactive: true,
|
||||
x_align: St.Align.START,
|
||||
x_fill: true });
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
|
||||
this.actor.connect('key-focus-in', () => {
|
||||
this._setSelected(true);
|
||||
});
|
||||
this.actor.connect('key-focus-out', () => {
|
||||
this._setSelected(false);
|
||||
});
|
||||
this.actor.connect('notify::hover', () => {
|
||||
this._setSelected(this.actor.hover);
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
this.connect('notify::hover', () => {
|
||||
this._setSelected(this.hover);
|
||||
});
|
||||
|
||||
this._userWidget = new UserWidget.UserWidget(this.user);
|
||||
layout.add(this._userWidget.actor);
|
||||
layout.add(this._userWidget);
|
||||
|
||||
this._userWidget.actor.bind_property('label-actor', this.actor, 'label-actor',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this._userWidget.bind_property('label-actor', this, 'label-actor',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
|
||||
scale_x: 0,
|
||||
visible: false });
|
||||
layout.add(this._timedLoginIndicator);
|
||||
|
||||
this.actor.connect('clicked', this._onClicked.bind(this));
|
||||
this._onUserChanged();
|
||||
}
|
||||
|
||||
vfunc_key_focus_in() {
|
||||
super.vfunc_key_focus_in();
|
||||
this._setSelected(true);
|
||||
}
|
||||
|
||||
vfunc_key_focus_out() {
|
||||
super.vfunc_key_focus_out();
|
||||
this._setSelected(false);
|
||||
}
|
||||
|
||||
_onUserChanged() {
|
||||
this._updateLoggedIn();
|
||||
}
|
||||
|
||||
_updateLoggedIn() {
|
||||
if (this.user.is_logged_in())
|
||||
this.actor.add_style_pseudo_class('logged-in');
|
||||
this.add_style_pseudo_class('logged-in');
|
||||
else
|
||||
this.actor.remove_style_pseudo_class('logged-in');
|
||||
this.remove_style_pseudo_class('logged-in');
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
this.user.disconnect(this._userChangedId);
|
||||
}
|
||||
|
||||
_onClicked() {
|
||||
vfunc_clicked() {
|
||||
this.emit('activate');
|
||||
}
|
||||
|
||||
_setSelected(selected) {
|
||||
if (selected) {
|
||||
this.actor.add_style_pseudo_class('selected');
|
||||
this.actor.grab_key_focus();
|
||||
this.add_style_pseudo_class('selected');
|
||||
this.grab_key_focus();
|
||||
} else {
|
||||
this.actor.remove_style_pseudo_class('selected');
|
||||
this.remove_style_pseudo_class('selected');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,23 +152,30 @@ var UserListItem = class {
|
||||
this._timedLoginIndicator.visible = false;
|
||||
this._timedLoginIndicator.scale_x = 0.;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(UserListItem.prototype);
|
||||
});
|
||||
|
||||
var UserList = class {
|
||||
constructor() {
|
||||
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
|
||||
this.actor.set_policy(St.PolicyType.NEVER,
|
||||
St.PolicyType.AUTOMATIC);
|
||||
var UserList = GObject.registerClass({
|
||||
GTypeName: 'LoginDialog_UserList',
|
||||
Signals: {
|
||||
'activate': { param_types: [UserListItem.$gtype] },
|
||||
'item-added': { param_types: [UserListItem.$gtype] },
|
||||
}
|
||||
}, class UserList extends St.ScrollView {
|
||||
_init() {
|
||||
super._init({ style_class: 'login-dialog-user-list-view' });
|
||||
this.set_policy(St.PolicyType.NEVER,
|
||||
St.PolicyType.AUTOMATIC);
|
||||
|
||||
this._box = new St.BoxLayout({ vertical: true,
|
||||
style_class: 'login-dialog-user-list',
|
||||
pseudo_class: 'expanded' });
|
||||
|
||||
this.actor.add_actor(this._box);
|
||||
this.add_actor(this._box);
|
||||
this._items = {};
|
||||
}
|
||||
|
||||
this.actor.connect('key-focus-in', this._moveFocusToItems.bind(this));
|
||||
vfunc_key_focus_in() {
|
||||
this._moveFocusToItems();
|
||||
}
|
||||
|
||||
_moveFocusToItems() {
|
||||
@@ -170,10 +184,10 @@ var UserList = class {
|
||||
if (!hasItems)
|
||||
return;
|
||||
|
||||
if (global.stage.get_key_focus() != this.actor)
|
||||
if (global.stage.get_key_focus() != this)
|
||||
return;
|
||||
|
||||
let focusSet = this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
|
||||
let focusSet = this.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
|
||||
if (!focusSet) {
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
this._moveFocusToItems();
|
||||
@@ -187,8 +201,6 @@ var UserList = class {
|
||||
}
|
||||
|
||||
updateStyle(isExpanded) {
|
||||
let tasks = [];
|
||||
|
||||
if (isExpanded)
|
||||
this._box.add_style_pseudo_class('expanded');
|
||||
else
|
||||
@@ -196,27 +208,26 @@ var UserList = class {
|
||||
|
||||
for (let userName in this._items) {
|
||||
let item = this._items[userName];
|
||||
item.actor.sync_hover();
|
||||
item.sync_hover();
|
||||
}
|
||||
}
|
||||
|
||||
scrollToItem(item) {
|
||||
let box = item.actor.get_allocation_box();
|
||||
let box = item.get_allocation_box();
|
||||
|
||||
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
|
||||
let adjustment = this.get_vscroll_bar().get_adjustment();
|
||||
|
||||
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
||||
Tweener.removeTweens(adjustment);
|
||||
Tweener.addTween (adjustment,
|
||||
{ value: value,
|
||||
time: _SCROLL_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
adjustment.ease(value, {
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
duration: _SCROLL_ANIMATION_TIME
|
||||
});
|
||||
}
|
||||
|
||||
jumpToItem(item) {
|
||||
let box = item.actor.get_allocation_box();
|
||||
let box = item.get_allocation_box();
|
||||
|
||||
let adjustment = this.actor.get_vscroll_bar().get_adjustment();
|
||||
let adjustment = this.get_vscroll_bar().get_adjustment();
|
||||
|
||||
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
|
||||
|
||||
@@ -244,7 +255,7 @@ var UserList = class {
|
||||
return;
|
||||
|
||||
if (user.locked)
|
||||
return;
|
||||
return;
|
||||
|
||||
let userName = user.get_user_name();
|
||||
|
||||
@@ -254,14 +265,14 @@ var UserList = class {
|
||||
this.removeUser(user);
|
||||
|
||||
let item = new UserListItem(user);
|
||||
this._box.add(item.actor, { x_fill: true });
|
||||
this._box.add(item, { x_fill: true });
|
||||
|
||||
this._items[userName] = item;
|
||||
|
||||
item.connect('activate', this._onItemActivated.bind(this));
|
||||
|
||||
// Try to keep the focused item front-and-center
|
||||
item.actor.connect('key-focus-in', () => { this.scrollToItem(item); });
|
||||
item.connect('key-focus-in', () => this.scrollToItem(item));
|
||||
|
||||
this._moveFocusToItems();
|
||||
|
||||
@@ -282,33 +293,38 @@ var UserList = class {
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
item.actor.destroy();
|
||||
item.destroy();
|
||||
delete this._items[userName];
|
||||
}
|
||||
|
||||
numItems() {
|
||||
return Object.keys(this._items).length;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(UserList.prototype);
|
||||
});
|
||||
|
||||
var SessionMenuButton = class {
|
||||
constructor() {
|
||||
var SessionMenuButton = GObject.registerClass({
|
||||
GTypeName: 'LoginDialog_SessionMenuButton',
|
||||
Signals: { 'session-activated': { param_types: [GObject.TYPE_STRING] } }
|
||||
}, class SessionMenuButton extends St.Bin {
|
||||
_init() {
|
||||
let gearIcon = new St.Icon({ icon_name: 'emblem-system-symbolic' });
|
||||
this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
|
||||
reactive: true,
|
||||
track_hover: true,
|
||||
can_focus: true,
|
||||
accessible_name: _("Choose Session"),
|
||||
accessible_role: Atk.Role.MENU,
|
||||
child: gearIcon });
|
||||
let button = new St.Button({
|
||||
style_class: 'login-dialog-session-list-button',
|
||||
reactive: true,
|
||||
track_hover: true,
|
||||
can_focus: true,
|
||||
accessible_name: _("Choose Session"),
|
||||
accessible_role: Atk.Role.MENU,
|
||||
child: gearIcon
|
||||
});
|
||||
|
||||
this.actor = new St.Bin({ child: this._button });
|
||||
super._init({ child: button });
|
||||
this._button = button;
|
||||
|
||||
let side = St.Side.TOP;
|
||||
let align = 0;
|
||||
if (Gdm.get_session_ids().length > _MAX_BOTTOM_MENU_ITEMS) {
|
||||
if (this.actor.text_direction == Clutter.TextDirection.RTL)
|
||||
if (this.text_direction == Clutter.TextDirection.RTL)
|
||||
side = St.Side.RIGHT;
|
||||
else
|
||||
side = St.Side.LEFT;
|
||||
@@ -319,17 +335,17 @@ var SessionMenuButton = class {
|
||||
this._menu.actor.hide();
|
||||
|
||||
this._menu.connect('open-state-changed', (menu, isOpen) => {
|
||||
if (isOpen)
|
||||
this._button.add_style_pseudo_class('active');
|
||||
else
|
||||
this._button.remove_style_pseudo_class('active');
|
||||
if (isOpen)
|
||||
this._button.add_style_pseudo_class('active');
|
||||
else
|
||||
this._button.remove_style_pseudo_class('active');
|
||||
});
|
||||
|
||||
this._manager = new PopupMenu.PopupMenuManager(this._button,
|
||||
{ actionMode: Shell.ActionMode.NONE });
|
||||
this._manager.addMenu(this._menu);
|
||||
|
||||
this._button.connect('clicked', () => { this._menu.toggle(); });
|
||||
this._button.connect('clicked', () => this._menu.toggle());
|
||||
|
||||
this._items = {};
|
||||
this._activeSessionId = null;
|
||||
@@ -353,11 +369,11 @@ var SessionMenuButton = class {
|
||||
}
|
||||
|
||||
setActiveSession(sessionId) {
|
||||
if (sessionId == this._activeSessionId)
|
||||
return;
|
||||
if (sessionId == this._activeSessionId)
|
||||
return;
|
||||
|
||||
this._activeSessionId = sessionId;
|
||||
this._updateOrnament();
|
||||
this._activeSessionId = sessionId;
|
||||
this._updateOrnament();
|
||||
}
|
||||
|
||||
close() {
|
||||
@@ -374,7 +390,7 @@ var SessionMenuButton = class {
|
||||
}
|
||||
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
|
||||
let [sessionName, sessionDescription_] = Gdm.get_session_name_and_description(ids[i]);
|
||||
|
||||
let id = ids[i];
|
||||
let item = new PopupMenu.PopupMenuItem(sessionName);
|
||||
@@ -387,15 +403,13 @@ var SessionMenuButton = class {
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(SessionMenuButton.prototype);
|
||||
});
|
||||
|
||||
var LoginDialog = GObject.registerClass({
|
||||
Signals: { 'failed': {} },
|
||||
}, class LoginDialog extends St.Widget {
|
||||
_init(parentActor) {
|
||||
super._init({ style_class: 'login-dialog',
|
||||
visible: false });
|
||||
super._init({ style_class: 'login-dialog', visible: false });
|
||||
|
||||
this.get_accessible().set_role(Atk.Role.WINDOW);
|
||||
|
||||
@@ -403,18 +417,18 @@ var LoginDialog = GObject.registerClass({
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
parentActor.add_child(this);
|
||||
|
||||
this._userManager = AccountsService.UserManager.get_default()
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
this._gdmClient = new Gdm.Client();
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||
|
||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
||||
this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_KEY}`,
|
||||
this._updateBanner.bind(this));
|
||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
||||
this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_TEXT_KEY}`,
|
||||
this._updateBanner.bind(this));
|
||||
this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
|
||||
this._settings.connect(`changed::${GdmUtil.DISABLE_USER_LIST_KEY}`,
|
||||
this._updateDisableUserList.bind(this));
|
||||
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
||||
this._settings.connect(`changed::${GdmUtil.LOGO_KEY}`,
|
||||
this._updateLogo.bind(this));
|
||||
|
||||
this._textureCache = St.TextureCache.get_default();
|
||||
@@ -429,7 +443,7 @@ var LoginDialog = GObject.registerClass({
|
||||
this.add_child(this._userSelectionBox);
|
||||
|
||||
this._userList = new UserList();
|
||||
this._userSelectionBox.add(this._userList.actor,
|
||||
this._userSelectionBox.add(this._userList,
|
||||
{ expand: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
@@ -438,7 +452,7 @@ var LoginDialog = GObject.registerClass({
|
||||
this._authPrompt.connect('prompted', this._onPrompted.bind(this));
|
||||
this._authPrompt.connect('reset', this._onReset.bind(this));
|
||||
this._authPrompt.hide();
|
||||
this.add_child(this._authPrompt.actor);
|
||||
this.add_child(this._authPrompt);
|
||||
|
||||
// translators: this message is shown below the user list on the
|
||||
// login screen. It can be activated to reveal an entry for
|
||||
@@ -497,9 +511,9 @@ var LoginDialog = GObject.registerClass({
|
||||
(list, sessionId) => {
|
||||
this._greeter.call_select_session_sync (sessionId, null);
|
||||
});
|
||||
this._sessionMenuButton.actor.opacity = 0;
|
||||
this._sessionMenuButton.actor.show();
|
||||
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
|
||||
this._sessionMenuButton.opacity = 0;
|
||||
this._sessionMenuButton.show();
|
||||
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton);
|
||||
|
||||
this._disableUserList = undefined;
|
||||
this._userListLoaded = false;
|
||||
@@ -520,7 +534,7 @@ var LoginDialog = GObject.registerClass({
|
||||
_getBannerAllocation(dialogBox) {
|
||||
let actorBox = new Clutter.ActorBox();
|
||||
|
||||
let [minWidth, minHeight, natWidth, natHeight] = this._bannerView.get_preferred_size();
|
||||
let [, , natWidth, natHeight] = this._bannerView.get_preferred_size();
|
||||
let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
|
||||
|
||||
actorBox.x1 = Math.floor(centerX - natWidth / 2);
|
||||
@@ -534,7 +548,7 @@ var LoginDialog = GObject.registerClass({
|
||||
_getLogoBinAllocation(dialogBox) {
|
||||
let actorBox = new Clutter.ActorBox();
|
||||
|
||||
let [minWidth, minHeight, natWidth, natHeight] = this._logoBin.get_preferred_size();
|
||||
let [, , natWidth, natHeight] = this._logoBin.get_preferred_size();
|
||||
let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
|
||||
|
||||
actorBox.x1 = Math.floor(centerX - natWidth / 2);
|
||||
@@ -548,7 +562,7 @@ var LoginDialog = GObject.registerClass({
|
||||
_getCenterActorAllocation(dialogBox, actor) {
|
||||
let actorBox = new Clutter.ActorBox();
|
||||
|
||||
let [minWidth, minHeight, natWidth, natHeight] = actor.get_preferred_size();
|
||||
let [, , natWidth, natHeight] = actor.get_preferred_size();
|
||||
let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
|
||||
let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2;
|
||||
|
||||
@@ -575,19 +589,15 @@ var LoginDialog = GObject.registerClass({
|
||||
// First find out what space the children require
|
||||
let bannerAllocation = null;
|
||||
let bannerHeight = 0;
|
||||
let bannerWidth = 0;
|
||||
if (this._bannerView.visible) {
|
||||
bannerAllocation = this._getBannerAllocation(dialogBox, this._bannerView);
|
||||
bannerHeight = bannerAllocation.y2 - bannerAllocation.y1;
|
||||
bannerWidth = bannerAllocation.x2 - bannerAllocation.x1;
|
||||
}
|
||||
|
||||
let authPromptAllocation = null;
|
||||
let authPromptHeight = 0;
|
||||
let authPromptWidth = 0;
|
||||
if (this._authPrompt.actor.visible) {
|
||||
authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor);
|
||||
authPromptHeight = authPromptAllocation.y2 - authPromptAllocation.y1;
|
||||
if (this._authPrompt.visible) {
|
||||
authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt);
|
||||
authPromptWidth = authPromptAllocation.x2 - authPromptAllocation.x1;
|
||||
}
|
||||
|
||||
@@ -619,64 +629,64 @@ var LoginDialog = GObject.registerClass({
|
||||
let leftOverYSpace = bannerSpace - bannerHeight;
|
||||
|
||||
if (leftOverYSpace > 0) {
|
||||
// First figure out how much left over space is up top
|
||||
let leftOverTopSpace = leftOverYSpace / 2;
|
||||
// First figure out how much left over space is up top
|
||||
let leftOverTopSpace = leftOverYSpace / 2;
|
||||
|
||||
// Then, shift the banner into the middle of that extra space
|
||||
let yShift = Math.floor(leftOverTopSpace / 2);
|
||||
// Then, shift the banner into the middle of that extra space
|
||||
let yShift = Math.floor(leftOverTopSpace / 2);
|
||||
|
||||
bannerAllocation.y1 += yShift;
|
||||
bannerAllocation.y2 += yShift;
|
||||
bannerAllocation.y1 += yShift;
|
||||
bannerAllocation.y2 += yShift;
|
||||
} else {
|
||||
// Then figure out how much space there would be if we switched to a
|
||||
// wide layout with banner on one side and authprompt on the other.
|
||||
let leftOverXSpace = dialogWidth - authPromptWidth;
|
||||
// Then figure out how much space there would be if we switched to a
|
||||
// wide layout with banner on one side and authprompt on the other.
|
||||
let leftOverXSpace = dialogWidth - authPromptWidth;
|
||||
|
||||
// In a wide view, half of the available space goes to the banner,
|
||||
// and the other half goes to the margins.
|
||||
let wideBannerWidth = leftOverXSpace / 2;
|
||||
let wideSpacing = leftOverXSpace - wideBannerWidth;
|
||||
// In a wide view, half of the available space goes to the banner,
|
||||
// and the other half goes to the margins.
|
||||
let wideBannerWidth = leftOverXSpace / 2;
|
||||
let wideSpacing = leftOverXSpace - wideBannerWidth;
|
||||
|
||||
// If we do go with a wide layout, we need there to be at least enough
|
||||
// space for the banner and the auth prompt to be the same width,
|
||||
// so it doesn't look unbalanced.
|
||||
if (authPromptWidth > 0 && wideBannerWidth > authPromptWidth) {
|
||||
let centerX = dialogBox.x1 + dialogWidth / 2;
|
||||
let centerY = dialogBox.y1 + dialogHeight / 2;
|
||||
// If we do go with a wide layout, we need there to be at least enough
|
||||
// space for the banner and the auth prompt to be the same width,
|
||||
// so it doesn't look unbalanced.
|
||||
if (authPromptWidth > 0 && wideBannerWidth > authPromptWidth) {
|
||||
let centerX = dialogBox.x1 + dialogWidth / 2;
|
||||
let centerY = dialogBox.y1 + dialogHeight / 2;
|
||||
|
||||
// A small portion of the spacing goes down the center of the
|
||||
// screen to help delimit the two columns of the wide view
|
||||
let centerGap = wideSpacing / 8;
|
||||
// A small portion of the spacing goes down the center of the
|
||||
// screen to help delimit the two columns of the wide view
|
||||
let centerGap = wideSpacing / 8;
|
||||
|
||||
// place the banner along the left edge of the center margin
|
||||
bannerAllocation.x2 = Math.floor(centerX - centerGap / 2);
|
||||
bannerAllocation.x1 = Math.floor(bannerAllocation.x2 - wideBannerWidth);
|
||||
// place the banner along the left edge of the center margin
|
||||
bannerAllocation.x2 = Math.floor(centerX - centerGap / 2);
|
||||
bannerAllocation.x1 = Math.floor(bannerAllocation.x2 - wideBannerWidth);
|
||||
|
||||
// figure out how tall it would like to be and try to accommodate
|
||||
// but don't let it get too close to the logo
|
||||
let [wideMinHeight, wideBannerHeight] = this._bannerView.get_preferred_height(wideBannerWidth);
|
||||
// figure out how tall it would like to be and try to accommodate
|
||||
// but don't let it get too close to the logo
|
||||
let [, wideBannerHeight] = this._bannerView.get_preferred_height(wideBannerWidth);
|
||||
|
||||
let maxWideHeight = dialogHeight - 3 * logoHeight;
|
||||
wideBannerHeight = Math.min(maxWideHeight, wideBannerHeight);
|
||||
bannerAllocation.y1 = Math.floor(centerY - wideBannerHeight / 2);
|
||||
bannerAllocation.y2 = bannerAllocation.y1 + wideBannerHeight;
|
||||
let maxWideHeight = dialogHeight - 3 * logoHeight;
|
||||
wideBannerHeight = Math.min(maxWideHeight, wideBannerHeight);
|
||||
bannerAllocation.y1 = Math.floor(centerY - wideBannerHeight / 2);
|
||||
bannerAllocation.y2 = bannerAllocation.y1 + wideBannerHeight;
|
||||
|
||||
// place the auth prompt along the right edge of the center margin
|
||||
authPromptAllocation.x1 = Math.floor(centerX + centerGap / 2);
|
||||
authPromptAllocation.x2 = authPromptAllocation.x1 + authPromptWidth;
|
||||
} else {
|
||||
// If we aren't going to do a wide view, then we need to limit
|
||||
// the height of the banner so it will present scrollbars
|
||||
// place the auth prompt along the right edge of the center margin
|
||||
authPromptAllocation.x1 = Math.floor(centerX + centerGap / 2);
|
||||
authPromptAllocation.x2 = authPromptAllocation.x1 + authPromptWidth;
|
||||
} else {
|
||||
// If we aren't going to do a wide view, then we need to limit
|
||||
// the height of the banner so it will present scrollbars
|
||||
|
||||
// First figure out how much space there is without the banner
|
||||
leftOverYSpace += bannerHeight;
|
||||
// First figure out how much space there is without the banner
|
||||
leftOverYSpace += bannerHeight;
|
||||
|
||||
// Then figure out how much of that space is up top
|
||||
let availableTopSpace = Math.floor(leftOverYSpace / 2);
|
||||
// Then figure out how much of that space is up top
|
||||
let availableTopSpace = Math.floor(leftOverYSpace / 2);
|
||||
|
||||
// Then give all of that space to the banner
|
||||
bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace;
|
||||
}
|
||||
// Then give all of that space to the banner
|
||||
bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace;
|
||||
}
|
||||
}
|
||||
} else if (userSelectionAllocation) {
|
||||
// Grow the user list to fill the space
|
||||
@@ -697,7 +707,7 @@ var LoginDialog = GObject.registerClass({
|
||||
}
|
||||
|
||||
if (authPromptAllocation)
|
||||
this._authPrompt.actor.allocate(authPromptAllocation, flags);
|
||||
this._authPrompt.allocate(authPromptAllocation, flags);
|
||||
|
||||
if (userSelectionAllocation)
|
||||
this._userSelectionBox.allocate(userSelectionAllocation, flags);
|
||||
@@ -764,14 +774,15 @@ var LoginDialog = GObject.registerClass({
|
||||
|
||||
_fadeInBannerView() {
|
||||
this._bannerView.show();
|
||||
Tweener.addTween(this._bannerView,
|
||||
{ opacity: 255,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
this._bannerView.ease({
|
||||
opacity: 255,
|
||||
duration: _FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
}
|
||||
|
||||
_hideBannerView() {
|
||||
Tweener.removeTweens(this._bannerView);
|
||||
this._bannerView.remove_all_transitions();
|
||||
this._bannerView.opacity = 0;
|
||||
this._bannerView.hide();
|
||||
}
|
||||
@@ -800,7 +811,7 @@ var LoginDialog = GObject.registerClass({
|
||||
_onPrompted() {
|
||||
if (this._shouldShowSessionMenuButton()) {
|
||||
this._sessionMenuButton.updateSensitivity(true);
|
||||
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
|
||||
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton);
|
||||
} else {
|
||||
this._sessionMenuButton.updateSensitivity(false);
|
||||
}
|
||||
@@ -851,23 +862,24 @@ var LoginDialog = GObject.registerClass({
|
||||
_shouldShowSessionMenuButton() {
|
||||
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING &&
|
||||
this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_FAILED)
|
||||
return false;
|
||||
return false;
|
||||
|
||||
if (this._user && this._user.is_loaded && this._user.is_logged_in())
|
||||
return false;
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
_showPrompt() {
|
||||
if (this._authPrompt.actor.visible)
|
||||
if (this._authPrompt.visible)
|
||||
return;
|
||||
this._authPrompt.actor.opacity = 0;
|
||||
this._authPrompt.actor.show();
|
||||
Tweener.addTween(this._authPrompt.actor,
|
||||
{ opacity: 255,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
this._authPrompt.opacity = 0;
|
||||
this._authPrompt.show();
|
||||
this._authPrompt.ease({
|
||||
opacity: 255,
|
||||
duration: _FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
this._fadeInBannerView();
|
||||
}
|
||||
|
||||
@@ -911,28 +923,31 @@ var LoginDialog = GObject.registerClass({
|
||||
this._showPrompt();
|
||||
}
|
||||
|
||||
_bindOpacity() {
|
||||
this._bindings = Main.layoutManager.uiGroup.get_children()
|
||||
.filter(c => c != Main.layoutManager.screenShieldGroup)
|
||||
.map(c => this.bind_property('opacity', c, 'opacity', 0));
|
||||
}
|
||||
|
||||
_unbindOpacity() {
|
||||
this._bindings.forEach(b => b.unbind());
|
||||
}
|
||||
|
||||
_loginScreenSessionActivated() {
|
||||
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
return;
|
||||
|
||||
Tweener.addTween(this,
|
||||
{ opacity: 255,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onUpdate() {
|
||||
let children = Main.layoutManager.uiGroup.get_children();
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i] != Main.layoutManager.screenShieldGroup)
|
||||
children[i].opacity = this.opacity;
|
||||
}
|
||||
},
|
||||
onUpdateScope: this,
|
||||
onComplete() {
|
||||
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
this._authPrompt.reset();
|
||||
},
|
||||
onCompleteScope: this });
|
||||
this._bindOpacity();
|
||||
this.ease({
|
||||
opacity: 255,
|
||||
duration: _FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
|
||||
this._authPrompt.reset();
|
||||
this._unbindOpacity();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_gotGreeterSessionProxy(proxy) {
|
||||
@@ -945,34 +960,27 @@ var LoginDialog = GObject.registerClass({
|
||||
}
|
||||
|
||||
_startSession(serviceName) {
|
||||
Tweener.addTween(this,
|
||||
{ opacity: 0,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onUpdate() {
|
||||
let children = Main.layoutManager.uiGroup.get_children();
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i] != Main.layoutManager.screenShieldGroup)
|
||||
children[i].opacity = this.opacity;
|
||||
}
|
||||
},
|
||||
onUpdateScope: this,
|
||||
onComplete() {
|
||||
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
||||
},
|
||||
onCompleteScope: this });
|
||||
this._bindOpacity();
|
||||
this.ease({
|
||||
opacity: 0,
|
||||
duration: _FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
||||
this._unbindOpacity();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_onSessionOpened(client, serviceName) {
|
||||
this._authPrompt.finish(() => { this._startSession(serviceName); });
|
||||
this._authPrompt.finish(() => this._startSession(serviceName));
|
||||
}
|
||||
|
||||
_waitForItemForUser(userName) {
|
||||
let item = this._userList.getItemFromUserName(userName);
|
||||
|
||||
if (item)
|
||||
return null;
|
||||
return null;
|
||||
|
||||
let hold = new Batch.Hold();
|
||||
let signalId = this._userList.connect('item-added',
|
||||
@@ -983,7 +991,7 @@ var LoginDialog = GObject.registerClass({
|
||||
hold.release();
|
||||
});
|
||||
|
||||
hold.connect('release', () => { this._userList.disconnect(signalId); });
|
||||
hold.connect('release', () => this._userList.disconnect(signalId));
|
||||
|
||||
return hold;
|
||||
}
|
||||
@@ -1047,18 +1055,19 @@ var LoginDialog = GObject.registerClass({
|
||||
return this._blockTimedLoginUntilIdle();
|
||||
} else {
|
||||
animationTime = delay;
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
() => {
|
||||
// If idle timeout is done, make sure the timed login indicator is shown
|
||||
if (delay > _TIMED_LOGIN_IDLE_THRESHOLD &&
|
||||
this._authPrompt.actor.visible)
|
||||
this._authPrompt.visible)
|
||||
this._authPrompt.cancel();
|
||||
|
||||
if (delay > _TIMED_LOGIN_IDLE_THRESHOLD || firstRun) {
|
||||
this._userList.scrollToItem(loginItem);
|
||||
loginItem.actor.grab_key_focus();
|
||||
loginItem.grab_key_focus();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1082,12 +1091,12 @@ var LoginDialog = GObject.registerClass({
|
||||
|
||||
// Restart timed login on user interaction
|
||||
global.stage.connect('captured-event', (actor, event) => {
|
||||
if (event.type() == Clutter.EventType.KEY_PRESS ||
|
||||
if (event.type() == Clutter.EventType.KEY_PRESS ||
|
||||
event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
this._startTimedLogin(userName, seconds);
|
||||
}
|
||||
this._startTimedLogin(userName, seconds);
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1119,7 +1128,7 @@ var LoginDialog = GObject.registerClass({
|
||||
this._sessionMenuButton.close();
|
||||
this._setUserListExpanded(true);
|
||||
this._notListedButton.show();
|
||||
this._userList.actor.grab_key_focus();
|
||||
this._userList.grab_key_focus();
|
||||
}
|
||||
|
||||
_beginVerificationForItem(item) {
|
||||
@@ -1227,16 +1236,17 @@ var LoginDialog = GObject.registerClass({
|
||||
_("Login Window"),
|
||||
'dialog-password-symbolic',
|
||||
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
|
||||
this._userList.actor.grab_key_focus();
|
||||
this._userList.grab_key_focus();
|
||||
this.show();
|
||||
this.opacity = 0;
|
||||
|
||||
Main.pushModal(this, { actionMode: Shell.ActionMode.LOGIN_SCREEN });
|
||||
|
||||
Tweener.addTween(this,
|
||||
{ opacity: 255,
|
||||
time: 1,
|
||||
transition: 'easeInQuad' });
|
||||
this.ease({
|
||||
opacity: 255,
|
||||
duration: 1000,
|
||||
mode: Clutter.AnimationMode.EASE_IN_QUAD
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1250,7 +1260,7 @@ var LoginDialog = GObject.registerClass({
|
||||
this._authPrompt.cancel();
|
||||
}
|
||||
|
||||
addCharacter(unichar) {
|
||||
addCharacter(_unichar) {
|
||||
// Don't allow type ahead at the login screen
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported getOVirtCredentialsManager */
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Signals = imports.signals;
|
||||
|
||||
@@ -15,12 +15,13 @@ const RealmIface = loadInterfaceXML("org.freedesktop.realmd.Realm");
|
||||
const Realm = Gio.DBusProxy.makeProxyWrapper(RealmIface);
|
||||
|
||||
var Manager = class {
|
||||
constructor(parentActor) {
|
||||
constructor() {
|
||||
this._aggregateProvider = Provider(Gio.DBus.system,
|
||||
'org.freedesktop.realmd',
|
||||
'/org/freedesktop/realmd',
|
||||
this._reloadRealms.bind(this))
|
||||
this._reloadRealms.bind(this));
|
||||
this._realms = {};
|
||||
this._loginFormat = null;
|
||||
|
||||
this._signalId = this._aggregateProvider.connect('g-properties-changed',
|
||||
(proxy, properties) => {
|
||||
@@ -36,10 +37,10 @@ var Manager = class {
|
||||
return;
|
||||
|
||||
for (let i = 0; i < realmPaths.length; i++) {
|
||||
let realm = Realm(Gio.DBus.system,
|
||||
'org.freedesktop.realmd',
|
||||
realmPaths[i],
|
||||
this._onRealmLoaded.bind(this));
|
||||
Realm(Gio.DBus.system,
|
||||
'org.freedesktop.realmd',
|
||||
realmPaths[i],
|
||||
this._onRealmLoaded.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +87,7 @@ var Manager = class {
|
||||
}
|
||||
|
||||
get loginFormat() {
|
||||
if (this._loginFormat !== undefined)
|
||||
if (this._loginFormat)
|
||||
return this._loginFormat;
|
||||
|
||||
this._updateLoginFormat();
|
||||
@@ -98,10 +99,10 @@ var Manager = class {
|
||||
Service(Gio.DBus.system,
|
||||
'org.freedesktop.realmd',
|
||||
'/org/freedesktop/realmd',
|
||||
service => { service.ReleaseRemote(); });
|
||||
service => service.ReleaseRemote());
|
||||
this._aggregateProvider.disconnect(this._signalId);
|
||||
this._realms = { };
|
||||
this._updateLoginFormat();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Manager.prototype)
|
||||
Signals.addSignalMethods(Manager.prototype);
|
||||
|
||||
126
js/gdm/util.js
126
js/gdm/util.js
@@ -1,4 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
|
||||
DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */
|
||||
|
||||
const { Clutter, Gio, GLib } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
@@ -9,14 +11,13 @@ const OVirt = imports.gdm.oVirt;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const SmartcardManager = imports.misc.smartcardManager;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
var PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
||||
var OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
|
||||
var FADE_ANIMATION_TIME = 0.16;
|
||||
var CLONE_FADE_ANIMATION_TIME = 0.25;
|
||||
var FADE_ANIMATION_TIME = 160;
|
||||
var CLONE_FADE_ANIMATION_TIME = 250;
|
||||
|
||||
var LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
||||
var PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
|
||||
@@ -30,7 +31,7 @@ var LOGO_KEY = 'logo';
|
||||
var DISABLE_USER_LIST_KEY = 'disable-user-list';
|
||||
|
||||
// Give user 48ms to read each character of a PAM message
|
||||
var USER_READ_TIME = 48
|
||||
var USER_READ_TIME = 48;
|
||||
|
||||
var MessageType = {
|
||||
NONE: 0,
|
||||
@@ -45,20 +46,20 @@ function fadeInActor(actor) {
|
||||
|
||||
let hold = new Batch.Hold();
|
||||
actor.show();
|
||||
let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
|
||||
let [, naturalHeight] = actor.get_preferred_height(-1);
|
||||
|
||||
actor.opacity = 0;
|
||||
actor.set_height(0);
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 255,
|
||||
height: naturalHeight,
|
||||
time: FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete() {
|
||||
this.set_height(-1);
|
||||
hold.release();
|
||||
},
|
||||
});
|
||||
actor.ease({
|
||||
opacity: 255,
|
||||
height: naturalHeight,
|
||||
duration: FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
this.set_height(-1);
|
||||
hold.release();
|
||||
}
|
||||
});
|
||||
|
||||
return hold;
|
||||
}
|
||||
@@ -71,17 +72,17 @@ function fadeOutActor(actor) {
|
||||
}
|
||||
|
||||
let hold = new Batch.Hold();
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 0,
|
||||
height: 0,
|
||||
time: FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete() {
|
||||
this.hide();
|
||||
this.set_height(-1);
|
||||
hold.release();
|
||||
},
|
||||
});
|
||||
actor.ease({
|
||||
opacity: 0,
|
||||
height: 0,
|
||||
duration: FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
this.hide();
|
||||
this.set_height(-1);
|
||||
hold.release();
|
||||
}
|
||||
});
|
||||
return hold;
|
||||
}
|
||||
|
||||
@@ -101,15 +102,15 @@ function cloneAndFadeOutActor(actor) {
|
||||
clone.set_position(x, y);
|
||||
|
||||
let hold = new Batch.Hold();
|
||||
Tweener.addTween(clone,
|
||||
{ opacity: 0,
|
||||
time: CLONE_FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete() {
|
||||
clone.destroy();
|
||||
hold.release();
|
||||
}
|
||||
});
|
||||
clone.ease({
|
||||
opacity: 0,
|
||||
duration: CLONE_FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
clone.destroy();
|
||||
hold.release();
|
||||
}
|
||||
});
|
||||
return hold;
|
||||
}
|
||||
|
||||
@@ -303,7 +304,7 @@ var ShellUserVerifier = class {
|
||||
});
|
||||
}
|
||||
|
||||
_oVirtUserAuthenticated(token) {
|
||||
_oVirtUserAuthenticated(_token) {
|
||||
this._preemptingService = OVIRT_SERVICE_NAME;
|
||||
this.emit('ovirt-user-authenticated');
|
||||
}
|
||||
@@ -342,7 +343,7 @@ var ShellUserVerifier = class {
|
||||
try {
|
||||
this._clearUserVerifier();
|
||||
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
if (e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
|
||||
@@ -369,7 +370,7 @@ var ShellUserVerifier = class {
|
||||
try {
|
||||
this._clearUserVerifier();
|
||||
this._userVerifier = client.get_user_verifier_finish(result);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
this._reportInitError('Failed to obtain user verifier', e);
|
||||
@@ -423,36 +424,31 @@ var ShellUserVerifier = class {
|
||||
_startService(serviceName) {
|
||||
this._hold.acquire();
|
||||
if (this._userName) {
|
||||
this._userVerifier.call_begin_verification_for_user(serviceName,
|
||||
this._userName,
|
||||
this._cancellable,
|
||||
(obj, result) => {
|
||||
try {
|
||||
obj.call_begin_verification_for_user_finish(result);
|
||||
} catch(e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
this._reportInitError('Failed to start verification for user', e);
|
||||
return;
|
||||
}
|
||||
this._userVerifier.call_begin_verification_for_user(serviceName, this._userName, this._cancellable, (obj, result) => {
|
||||
try {
|
||||
obj.call_begin_verification_for_user_finish(result);
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
this._reportInitError('Failed to start verification for user', e);
|
||||
return;
|
||||
}
|
||||
|
||||
this._hold.release();
|
||||
});
|
||||
this._hold.release();
|
||||
});
|
||||
} else {
|
||||
this._userVerifier.call_begin_verification(serviceName,
|
||||
this._cancellable,
|
||||
(obj, result) => {
|
||||
try {
|
||||
obj.call_begin_verification_finish(result);
|
||||
} catch(e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
this._reportInitError('Failed to start verification', e);
|
||||
return;
|
||||
}
|
||||
this._userVerifier.call_begin_verification(serviceName, this._cancellable, (obj, result) => {
|
||||
try {
|
||||
obj.call_begin_verification_finish(result);
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
this._reportInitError('Failed to start verification', e);
|
||||
return;
|
||||
}
|
||||
|
||||
this._hold.release();
|
||||
});
|
||||
this._hold.release();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,37 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported ExtensionState, ExtensionType, getCurrentExtension,
|
||||
getSettings, initTranslations, isOutOfDate, installImporter,
|
||||
serializeExtension, deserializeExtension */
|
||||
|
||||
// Common utils for the extension system and the extension
|
||||
// preferences tool
|
||||
|
||||
const Gettext = imports.gettext;
|
||||
const Signals = imports.signals;
|
||||
const { Gio, GLib } = imports.gi;
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gettext = imports.gettext;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
|
||||
var ExtensionType = {
|
||||
SYSTEM: 1,
|
||||
PER_USER: 2
|
||||
};
|
||||
|
||||
// Maps uuid -> metadata object
|
||||
var extensions = {};
|
||||
var ExtensionState = {
|
||||
ENABLED: 1,
|
||||
DISABLED: 2,
|
||||
ERROR: 3,
|
||||
OUT_OF_DATE: 4,
|
||||
DOWNLOADING: 5,
|
||||
INITIALIZED: 6,
|
||||
|
||||
// Used as an error state for operations on unknown extensions,
|
||||
// should never be in a real extensionMeta object.
|
||||
UNINSTALLED: 99
|
||||
};
|
||||
|
||||
const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs', 'canChange'];
|
||||
|
||||
/**
|
||||
* getCurrentExtension:
|
||||
@@ -31,7 +45,7 @@ function getCurrentExtension() {
|
||||
// Search for an occurrence of an extension stack frame
|
||||
// Start at 1 because 0 is the stack frame of this function
|
||||
for (let i = 1; i < stack.length; i++) {
|
||||
if (stack[i].indexOf('/gnome-shell/extensions/') > -1) {
|
||||
if (stack[i].includes('/gnome-shell/extensions/')) {
|
||||
extensionStackLine = stack[i];
|
||||
break;
|
||||
}
|
||||
@@ -49,13 +63,17 @@ function getCurrentExtension() {
|
||||
if (!match)
|
||||
return null;
|
||||
|
||||
// local import, as the module is used from outside the gnome-shell process
|
||||
// as well (not this function though)
|
||||
let extensionManager = imports.ui.main.extensionManager;
|
||||
|
||||
let path = match[1];
|
||||
let file = Gio.File.new_for_path(path);
|
||||
|
||||
// Walk up the directory tree, looking for an extension with
|
||||
// the same UUID as a directory name.
|
||||
while (file != null) {
|
||||
let extension = extensions[file.get_basename()];
|
||||
let extension = extensionManager.lookup(file.get_basename());
|
||||
if (extension !== undefined)
|
||||
return extension;
|
||||
file = file.get_parent();
|
||||
@@ -147,8 +165,8 @@ function versionCheck(required, current) {
|
||||
let requiredArray = required[i].split('.');
|
||||
if (requiredArray[0] == major &&
|
||||
requiredArray[1] == minor &&
|
||||
(requiredArray[2] == point ||
|
||||
(requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
|
||||
((requiredArray[2] === undefined && parseInt(minor) % 2 == 0) ||
|
||||
requiredArray[2] == point))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -161,54 +179,50 @@ function isOutOfDate(extension) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function createExtensionObject(uuid, dir, type) {
|
||||
let info;
|
||||
function serializeExtension(extension) {
|
||||
let obj = {};
|
||||
Lang.copyProperties(extension.metadata, obj);
|
||||
|
||||
let metadataFile = dir.get_child('metadata.json');
|
||||
if (!metadataFile.query_exists(null)) {
|
||||
throw new Error('Missing metadata.json');
|
||||
}
|
||||
SERIALIZED_PROPERTIES.forEach(prop => {
|
||||
obj[prop] = extension[prop];
|
||||
});
|
||||
|
||||
let metadataContents, success, tag;
|
||||
try {
|
||||
[success, metadataContents, tag] = metadataFile.load_contents(null);
|
||||
if (metadataContents instanceof Uint8Array)
|
||||
metadataContents = imports.byteArray.toString(metadataContents);
|
||||
} catch (e) {
|
||||
throw new Error('Failed to load metadata.json: ' + e);
|
||||
}
|
||||
let meta;
|
||||
try {
|
||||
meta = JSON.parse(metadataContents);
|
||||
} catch (e) {
|
||||
throw new Error('Failed to parse metadata.json: ' + e);
|
||||
}
|
||||
|
||||
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
|
||||
for (let i = 0; i < requiredProperties.length; i++) {
|
||||
let prop = requiredProperties[i];
|
||||
if (!meta[prop]) {
|
||||
throw new Error('missing "' + prop + '" property in metadata.json');
|
||||
let res = {};
|
||||
for (let key in obj) {
|
||||
let val = obj[key];
|
||||
let type;
|
||||
switch (typeof val) {
|
||||
case 'string':
|
||||
type = 's';
|
||||
break;
|
||||
case 'number':
|
||||
type = 'd';
|
||||
break;
|
||||
case 'boolean':
|
||||
type = 'b';
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
res[key] = GLib.Variant.new(type, val);
|
||||
}
|
||||
|
||||
if (uuid != meta.uuid) {
|
||||
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
||||
return res;
|
||||
}
|
||||
|
||||
function deserializeExtension(variant) {
|
||||
let res = { metadata: {} };
|
||||
for (let prop in variant) {
|
||||
let val = variant[prop].unpack();
|
||||
if (SERIALIZED_PROPERTIES.includes(prop))
|
||||
res[prop] = val;
|
||||
else
|
||||
res.metadata[prop] = val;
|
||||
}
|
||||
|
||||
let extension = {};
|
||||
|
||||
extension.metadata = meta;
|
||||
extension.uuid = meta.uuid;
|
||||
extension.type = type;
|
||||
extension.dir = dir;
|
||||
extension.path = dir.get_path();
|
||||
extension.error = '';
|
||||
extension.hasPrefs = dir.get_child('prefs.js').query_exists(null);
|
||||
|
||||
extensions[uuid] = extension;
|
||||
|
||||
return extension;
|
||||
// add the 2 additional properties to create a valid extension object, as createExtensionObject()
|
||||
res.uuid = res.metadata.uuid;
|
||||
res.dir = Gio.File.new_for_path(res.path);
|
||||
return res;
|
||||
}
|
||||
|
||||
function installImporter(extension) {
|
||||
@@ -219,36 +233,3 @@ function installImporter(extension) {
|
||||
extension.imports = imports[extension.uuid];
|
||||
imports.searchPath = oldSearchPath;
|
||||
}
|
||||
|
||||
var ExtensionFinder = class {
|
||||
_loadExtension(extensionDir, info, perUserDir) {
|
||||
let fileType = info.get_file_type();
|
||||
if (fileType != Gio.FileType.DIRECTORY)
|
||||
return;
|
||||
let uuid = info.get_name();
|
||||
let existing = extensions[uuid];
|
||||
if (existing) {
|
||||
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
|
||||
return;
|
||||
}
|
||||
|
||||
let extension;
|
||||
let type = extensionDir.has_prefix(perUserDir) ? ExtensionType.PER_USER
|
||||
: ExtensionType.SYSTEM;
|
||||
try {
|
||||
extension = createExtensionObject(uuid, extensionDir, type);
|
||||
} catch(e) {
|
||||
logError(e, 'Could not load extension %s'.format(uuid));
|
||||
return;
|
||||
}
|
||||
this.emit('extension-found', extension);
|
||||
}
|
||||
|
||||
scanExtensions() {
|
||||
let perUserDir = Gio.File.new_for_path(global.userdatadir);
|
||||
FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
|
||||
this._loadExtension(dir, info, perUserDir);
|
||||
});
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ExtensionFinder.prototype);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported collectFromDatadirs, deleteGFile, recursivelyDeleteDir,
|
||||
recursivelyMoveDir, loadInterfaceXML */
|
||||
|
||||
const { Gio, GLib } = imports.gi;
|
||||
const Config = imports.misc.config;
|
||||
@@ -36,7 +38,7 @@ function recursivelyDeleteDir(dir, deleteParent) {
|
||||
let children = dir.enumerate_children('standard::name,standard::type',
|
||||
Gio.FileQueryInfoFlags.NONE, null);
|
||||
|
||||
let info, child;
|
||||
let info;
|
||||
while ((info = children.next_file(null)) != null) {
|
||||
let type = info.get_file_type();
|
||||
let child = dir.get_child(info.get_name());
|
||||
@@ -57,7 +59,7 @@ function recursivelyMoveDir(srcDir, destDir) {
|
||||
if (!destDir.query_exists(null))
|
||||
destDir.make_directory_with_parents(null);
|
||||
|
||||
let info, child;
|
||||
let info;
|
||||
while ((info = children.next_file(null)) != null) {
|
||||
let type = info.get_file_type();
|
||||
let srcChild = srcDir.get_child(info.get_name());
|
||||
@@ -84,13 +86,13 @@ function loadInterfaceXML(iface) {
|
||||
let f = Gio.File.new_for_uri(uri);
|
||||
|
||||
try {
|
||||
let [ok, bytes] = f.load_contents(null);
|
||||
let [ok_, bytes] = f.load_contents(null);
|
||||
if (bytes instanceof Uint8Array)
|
||||
xml = imports.byteArray.toString(bytes)
|
||||
xml = imports.byteArray.toString(bytes);
|
||||
else
|
||||
xml = bytes.toString();
|
||||
} catch (e) {
|
||||
log('Failed to load D-Bus interface ' + iface);
|
||||
log(`Failed to load D-Bus interface ${iface}`);
|
||||
}
|
||||
|
||||
return xml;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported PresenceStatus, Presence, Inhibitor, SessionManager */
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ var HistoryManager = class {
|
||||
this._historyIndex = 0;
|
||||
if (this._key) {
|
||||
this._history = global.settings.get_strv(this._key);
|
||||
global.settings.connect('changed::' + this._key,
|
||||
global.settings.connect(`changed::${this._key}`,
|
||||
this._historyChanged.bind(this));
|
||||
|
||||
} else {
|
||||
@@ -28,7 +28,7 @@ var HistoryManager = class {
|
||||
this._entry = params.entry;
|
||||
|
||||
if (this._entry) {
|
||||
this._entry.connect('key-press-event',
|
||||
this._entry.connect('key-press-event',
|
||||
this._onEntryKeyPress.bind(this));
|
||||
}
|
||||
}
|
||||
@@ -66,7 +66,7 @@ var HistoryManager = class {
|
||||
this._indexChanged();
|
||||
}
|
||||
|
||||
return this._historyIndex ? this._history[this._historyIndex -1] : null;
|
||||
return this._historyIndex ? this._history[this._historyIndex - 1] : null;
|
||||
}
|
||||
|
||||
addItem(input) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported getIBusManager */
|
||||
|
||||
const { Gio, GLib, IBus } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
||||
@@ -18,9 +18,9 @@ function _checkIBusVersion(requiredMajor, requiredMinor, requiredMicro) {
|
||||
IBus.MICRO_VERSION >= requiredMicro))
|
||||
return;
|
||||
|
||||
throw "Found IBus version %d.%d.%d but required is %d.%d.%d".
|
||||
format(IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MINOR_VERSION,
|
||||
requiredMajor, requiredMinor, requiredMicro);
|
||||
throw "Found IBus version %d.%d.%d but required is %d.%d.%d"
|
||||
.format(IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MINOR_VERSION,
|
||||
requiredMajor, requiredMinor, requiredMicro);
|
||||
}
|
||||
|
||||
function getIBusManager() {
|
||||
@@ -42,7 +42,7 @@ var IBusManager = class {
|
||||
this._candidatePopup = new IBusCandidatePopup.CandidatePopup();
|
||||
|
||||
this._panelService = null;
|
||||
this._engines = {};
|
||||
this._engines = new Map();
|
||||
this._ready = false;
|
||||
this._registerPropertiesId = 0;
|
||||
this._currentEngineName = null;
|
||||
@@ -58,54 +58,79 @@ var IBusManager = class {
|
||||
this._spawn();
|
||||
}
|
||||
|
||||
_spawn() {
|
||||
_spawn(extraArgs = []) {
|
||||
try {
|
||||
Gio.Subprocess.new(['ibus-daemon', '--xim', '--panel', 'disable'],
|
||||
Gio.SubprocessFlags.NONE);
|
||||
} catch(e) {
|
||||
log('Failed to launch ibus-daemon: ' + e.message);
|
||||
let cmdLine = ['ibus-daemon', '--panel', 'disable', ...extraArgs];
|
||||
Gio.Subprocess.new(cmdLine, Gio.SubprocessFlags.NONE);
|
||||
} catch (e) {
|
||||
log(`Failed to launch ibus-daemon: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
restartDaemon(extraArgs = []) {
|
||||
this._spawn(['-r', ...extraArgs]);
|
||||
}
|
||||
|
||||
_clear() {
|
||||
if (this._cancellable) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable = null;
|
||||
}
|
||||
|
||||
if (this._preloadEnginesId) {
|
||||
GLib.source_remove(this._preloadEnginesId);
|
||||
this._preloadEnginesId = 0;
|
||||
}
|
||||
|
||||
if (this._panelService)
|
||||
this._panelService.destroy();
|
||||
|
||||
this._panelService = null;
|
||||
this._candidatePopup.setPanelService(null);
|
||||
this._engines = {};
|
||||
this._engines.clear();
|
||||
this._ready = false;
|
||||
this._registerPropertiesId = 0;
|
||||
this._currentEngineName = null;
|
||||
|
||||
this.emit('ready', false);
|
||||
|
||||
this._spawn();
|
||||
}
|
||||
|
||||
_onConnected() {
|
||||
this._ibus.list_engines_async(-1, null, this._initEngines.bind(this));
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
this._ibus.list_engines_async(-1, this._cancellable,
|
||||
this._initEngines.bind(this));
|
||||
this._ibus.request_name_async(IBus.SERVICE_PANEL,
|
||||
IBus.BusNameFlag.REPLACE_EXISTING,
|
||||
-1, null,
|
||||
this._initPanelService.bind(this));
|
||||
IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable,
|
||||
this._initPanelService.bind(this));
|
||||
}
|
||||
|
||||
_initEngines(ibus, result) {
|
||||
let enginesList = this._ibus.list_engines_async_finish(result);
|
||||
if (enginesList) {
|
||||
try {
|
||||
let enginesList = this._ibus.list_engines_async_finish(result);
|
||||
for (let i = 0; i < enginesList.length; ++i) {
|
||||
let name = enginesList[i].get_name();
|
||||
this._engines[name] = enginesList[i];
|
||||
this._engines.set(name, enginesList[i]);
|
||||
}
|
||||
this._updateReadiness();
|
||||
} else {
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
|
||||
logError(e);
|
||||
this._clear();
|
||||
}
|
||||
}
|
||||
|
||||
_initPanelService(ibus, result) {
|
||||
let success = this._ibus.request_name_async_finish(result);
|
||||
let success = false;
|
||||
try {
|
||||
success = !!this._ibus.request_name_async_finish(result);
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
return;
|
||||
logError(e);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
|
||||
object_path: IBus.PATH_PANEL });
|
||||
@@ -119,7 +144,7 @@ var IBusManager = class {
|
||||
if (!GLib.str_has_suffix(path, '/InputContext_1'))
|
||||
this.emit ('focus-in');
|
||||
});
|
||||
this._panelService.connect('focus-out', () => { this.emit('focus-out'); });
|
||||
this._panelService.connect('focus-out', () => this.emit('focus-out'));
|
||||
|
||||
try {
|
||||
// IBus versions older than 1.5.10 have a bug which
|
||||
@@ -132,13 +157,13 @@ var IBusManager = class {
|
||||
} catch (e) {
|
||||
}
|
||||
// If an engine is already active we need to get its properties
|
||||
this._ibus.get_global_engine_async(-1, null, (i, result) => {
|
||||
this._ibus.get_global_engine_async(-1, this._cancellable, (_bus, result) => {
|
||||
let engine;
|
||||
try {
|
||||
engine = this._ibus.get_global_engine_async_finish(result);
|
||||
if (!engine)
|
||||
return;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
this._engineChanged(this._ibus, engine.get_name());
|
||||
@@ -150,8 +175,7 @@ var IBusManager = class {
|
||||
}
|
||||
|
||||
_updateReadiness() {
|
||||
this._ready = (Object.keys(this._engines).length > 0 &&
|
||||
this._panelService != null);
|
||||
this._ready = this._engines.size > 0 && this._panelService != null;
|
||||
this.emit('ready', this._ready);
|
||||
}
|
||||
|
||||
@@ -189,10 +213,10 @@ var IBusManager = class {
|
||||
}
|
||||
|
||||
getEngineDesc(id) {
|
||||
if (!this._ready || !this._engines.hasOwnProperty(id))
|
||||
if (!this._ready || !this._engines.has(id))
|
||||
return null;
|
||||
|
||||
return this._engines[id];
|
||||
return this._engines.get(id);
|
||||
}
|
||||
|
||||
setEngine(id, callback) {
|
||||
@@ -205,8 +229,18 @@ var IBusManager = class {
|
||||
return;
|
||||
}
|
||||
|
||||
this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
|
||||
null, callback || null);
|
||||
this._ibus.set_global_engine_async(id,
|
||||
this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
|
||||
this._cancellable, (_bus, res) => {
|
||||
try {
|
||||
this._ibus.set_global_engine_async_finish(res);
|
||||
} catch (e) {
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
logError(e);
|
||||
}
|
||||
if (callback)
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
preloadEngines(ids) {
|
||||
@@ -214,21 +248,23 @@ var IBusManager = class {
|
||||
return;
|
||||
|
||||
if (this._preloadEnginesId != 0) {
|
||||
Mainloop.source_remove(this._preloadEnginesId);
|
||||
GLib.source_remove(this._preloadEnginesId);
|
||||
this._preloadEnginesId = 0;
|
||||
}
|
||||
|
||||
this._preloadEnginesId =
|
||||
Mainloop.timeout_add_seconds(this._PRELOAD_ENGINES_DELAY_TIME,
|
||||
() => {
|
||||
this._ibus.preload_engines_async(
|
||||
ids,
|
||||
-1,
|
||||
null,
|
||||
null);
|
||||
this._preloadEnginesId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
GLib.timeout_add_seconds(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
this._PRELOAD_ENGINES_DELAY_TIME,
|
||||
() => {
|
||||
this._ibus.preload_engines_async(
|
||||
ids,
|
||||
-1,
|
||||
this._cancellable,
|
||||
null);
|
||||
this._preloadEnginesId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(IBusManager.prototype);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
const { Clutter, GLib, GObject, IBus } = imports.gi;
|
||||
/* exported InputMethod */
|
||||
const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
|
||||
|
||||
const Keyboard = imports.ui.status.keyboard;
|
||||
|
||||
@@ -35,15 +36,7 @@ class InputMethod extends Clutter.InputMethod {
|
||||
}
|
||||
|
||||
_updateCapabilities() {
|
||||
let caps = 0;
|
||||
|
||||
if (this.can_show_preedit)
|
||||
caps |= IBus.Capabilite.PREEDIT_TEXT;
|
||||
|
||||
if (this._currentFocus)
|
||||
caps |= IBus.Capabilite.FOCUS | IBus.Capabilite.SURROUNDING_TEXT;
|
||||
else
|
||||
caps |= IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.AUXILIARY_TEXT | IBus.Capabilite.LOOKUP_TABLE | IBus.Capabilite.PROPERTY;
|
||||
let caps = IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.FOCUS | IBus.Capabilite.SURROUNDING_TEXT;
|
||||
|
||||
if (this._context)
|
||||
this._context.set_capabilities(caps);
|
||||
@@ -54,12 +47,22 @@ class InputMethod extends Clutter.InputMethod {
|
||||
}
|
||||
|
||||
_onConnected() {
|
||||
this._ibus.create_input_context_async ('gnome-shell', -1, null,
|
||||
this._setContext.bind(this));
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
this._ibus.create_input_context_async ('gnome-shell', -1,
|
||||
this._cancellable, this._setContext.bind(this));
|
||||
}
|
||||
|
||||
_setContext(bus, res) {
|
||||
this._context = this._ibus.create_input_context_async_finish(res);
|
||||
try {
|
||||
this._context = this._ibus.create_input_context_async_finish(res);
|
||||
} catch (e) {
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||
logError(e);
|
||||
this._clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._context.connect('commit-text', this._onCommitText.bind(this));
|
||||
this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
|
||||
this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this));
|
||||
@@ -71,10 +74,15 @@ class InputMethod extends Clutter.InputMethod {
|
||||
}
|
||||
|
||||
_clear() {
|
||||
if (this._cancellable) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable = null;
|
||||
}
|
||||
|
||||
this._context = null;
|
||||
this._hints = 0;
|
||||
this._purpose = 0;
|
||||
this._preeditStr = ''
|
||||
this._preeditStr = '';
|
||||
this._preeditPos = 0;
|
||||
this._preeditVisible = false;
|
||||
}
|
||||
@@ -84,15 +92,15 @@ class InputMethod extends Clutter.InputMethod {
|
||||
this.emit('request-surrounding');
|
||||
}
|
||||
|
||||
_onCommitText(context, text) {
|
||||
_onCommitText(_context, text) {
|
||||
this.commit(text.get_text());
|
||||
}
|
||||
|
||||
_onDeleteSurroundingText(context) {
|
||||
_onDeleteSurroundingText() {
|
||||
this.delete_surrounding();
|
||||
}
|
||||
|
||||
_onUpdatePreeditText(context, text, pos, visible) {
|
||||
_onUpdatePreeditText(_context, text, pos, visible) {
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
@@ -108,17 +116,17 @@ class InputMethod extends Clutter.InputMethod {
|
||||
this._preeditVisible = visible;
|
||||
}
|
||||
|
||||
_onShowPreeditText(context) {
|
||||
_onShowPreeditText() {
|
||||
this._preeditVisible = true;
|
||||
this.set_preedit_text(this._preeditStr, this._preeditPos);
|
||||
}
|
||||
|
||||
_onHidePreeditText(context) {
|
||||
_onHidePreeditText() {
|
||||
this.set_preedit_text(null, this._preeditPos);
|
||||
this._preeditVisible = false;
|
||||
}
|
||||
|
||||
_onForwardKeyEvent(context, keyval, keycode, state) {
|
||||
_onForwardKeyEvent(_context, keyval, keycode, state) {
|
||||
let press = (state & IBus.ModifierType.RELEASE_MASK) == 0;
|
||||
state &= ~(IBus.ModifierType.RELEASE_MASK);
|
||||
|
||||
@@ -136,7 +144,6 @@ class InputMethod extends Clutter.InputMethod {
|
||||
this._currentFocus = focus;
|
||||
if (this._context) {
|
||||
this._context.focus_in();
|
||||
this._updateCapabilities();
|
||||
this._emitRequestSurrounding();
|
||||
}
|
||||
|
||||
@@ -148,10 +155,8 @@ class InputMethod extends Clutter.InputMethod {
|
||||
|
||||
vfunc_focus_out() {
|
||||
this._currentFocus = null;
|
||||
if (this._context) {
|
||||
if (this._context)
|
||||
this._context.focus_out();
|
||||
this._updateCapabilities();
|
||||
}
|
||||
|
||||
if (this._preeditStr) {
|
||||
// Unset any preedit text
|
||||
@@ -254,17 +259,19 @@ class InputMethod extends Clutter.InputMethod {
|
||||
if (event.type() == Clutter.EventType.KEY_RELEASE)
|
||||
state |= IBus.ModifierType.RELEASE_MASK;
|
||||
|
||||
this._context.process_key_event_async(event.get_key_symbol(),
|
||||
event.get_key_code() - 8, // Convert XKB keycodes to evcodes
|
||||
state, -1, null,
|
||||
(context, res) => {
|
||||
try {
|
||||
let retval = context.process_key_event_async_finish(res);
|
||||
this.notify_key_event(event, retval);
|
||||
} catch (e) {
|
||||
log('Error processing key on IM: ' + e.message);
|
||||
}
|
||||
});
|
||||
this._context.process_key_event_async(
|
||||
event.get_key_symbol(),
|
||||
event.get_key_code() - 8, // Convert XKB keycodes to evcodes
|
||||
state, -1, this._cancellable,
|
||||
(context, res) => {
|
||||
try {
|
||||
let retval = context.process_key_event_async_finish(res);
|
||||
this.notify_key_event(event, retval);
|
||||
} catch (e) {
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||
log(`Error processing key on IM: ${e.message}`);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported IntrospectService */
|
||||
const { Gio, GLib, Meta, Shell } = imports.gi;
|
||||
|
||||
const INTROSPECT_SCHEMA = 'org.gnome.shell';
|
||||
@@ -46,11 +47,11 @@ var IntrospectService = class {
|
||||
}
|
||||
|
||||
_isIntrospectEnabled() {
|
||||
return this._settings.get_boolean(INTROSPECT_KEY);
|
||||
return this._settings.get_boolean(INTROSPECT_KEY);
|
||||
}
|
||||
|
||||
_isSenderWhitelisted(sender) {
|
||||
return APP_WHITELIST.includes(sender);
|
||||
return APP_WHITELIST.includes(sender);
|
||||
}
|
||||
|
||||
_getSandboxedAppId(app) {
|
||||
@@ -126,7 +127,8 @@ var IntrospectService = class {
|
||||
let apps = this._appSystem.get_running();
|
||||
let windowsList = {};
|
||||
|
||||
if (!this._isIntrospectEnabled()) {
|
||||
if (!this._isIntrospectEnabled() &&
|
||||
!this._isSenderWhitelisted(invocation.get_sender())) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'App introspection not allowed');
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/* exported getCompletions, getCommonPrefix, getDeclaredConstants */
|
||||
|
||||
// Returns a list of potential completions for text. Completions either
|
||||
// follow a dot (e.g. foo.ba -> bar) or they are picked from globalCompletionList (e.g. fo -> foo)
|
||||
@@ -8,7 +9,7 @@
|
||||
// This function is likely the one you want to call from external modules
|
||||
function getCompletions(text, commandHeader, globalCompletionList) {
|
||||
let methods = [];
|
||||
let expr, base;
|
||||
let expr_, base;
|
||||
let attrHead = '';
|
||||
if (globalCompletionList == null) {
|
||||
globalCompletionList = [];
|
||||
@@ -21,7 +22,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
|
||||
// Look for expressions like "Main.panel.foo" and match Main.panel and foo
|
||||
let matches = text.match(/(.*)\.(.*)/);
|
||||
if (matches) {
|
||||
[expr, base, attrHead] = matches;
|
||||
[expr_, base, attrHead] = matches;
|
||||
|
||||
methods = getPropertyNamesFromExpression(base, commandHeader).filter(
|
||||
attr => attr.slice(0, attrHead.length) == attrHead
|
||||
@@ -32,7 +33,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
|
||||
// not proceeded by a dot and match them against global constants
|
||||
matches = text.match(/^(\w*)$/);
|
||||
if (text == '' || matches) {
|
||||
[expr, attrHead] = matches;
|
||||
[expr_, attrHead] = matches;
|
||||
methods = globalCompletionList.filter(
|
||||
attr => attr.slice(0, attrHead.length) == attrHead
|
||||
);
|
||||
@@ -51,14 +52,14 @@ function getCompletions(text, commandHeader, globalCompletionList) {
|
||||
// if we encounter anything that isn't a letter, '.', ')', or ']',
|
||||
// we should stop parsing.
|
||||
function isStopChar(c) {
|
||||
return !c.match(/[\w\.\)\]]/);
|
||||
return !c.match(/[\w.)\]]/);
|
||||
}
|
||||
|
||||
// Given the ending position of a quoted string, find where it starts
|
||||
function findMatchingQuote(expr, offset) {
|
||||
let quoteChar = expr.charAt(offset);
|
||||
for (let i = offset - 1; i >= 0; --i) {
|
||||
if (expr.charAt(i) == quoteChar && expr.charAt(i-1) != '\\'){
|
||||
if (expr.charAt(i) == quoteChar && expr.charAt(i - 1) != '\\') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -68,7 +69,7 @@ function findMatchingQuote(expr, offset) {
|
||||
// Given the ending position of a regex, find where it starts
|
||||
function findMatchingSlash(expr, offset) {
|
||||
for (let i = offset - 1; i >= 0; --i) {
|
||||
if (expr.charAt(i) == '/' && expr.charAt(i-1) != '\\'){
|
||||
if (expr.charAt(i) == '/' && expr.charAt(i - 1) != '\\') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -81,7 +82,7 @@ function findMatchingSlash(expr, offset) {
|
||||
// findMatchingBrace("[(])", 3) returns 1.
|
||||
function findMatchingBrace(expr, offset) {
|
||||
let closeBrace = expr.charAt(offset);
|
||||
let openBrace = ({')': '(', ']': '['})[closeBrace];
|
||||
let openBrace = ({ ')': '(', ']': '[' })[closeBrace];
|
||||
|
||||
function findTheBrace(expr, offset) {
|
||||
if (offset < 0) {
|
||||
@@ -117,11 +118,11 @@ function getExpressionOffset(expr, offset) {
|
||||
while (offset >= 0) {
|
||||
let currChar = expr.charAt(offset);
|
||||
|
||||
if (isStopChar(currChar)){
|
||||
if (isStopChar(currChar)) {
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
if (currChar.match(/[\)\]]/)) {
|
||||
if (currChar.match(/[)\]]/)) {
|
||||
offset = findMatchingBrace(expr, offset);
|
||||
}
|
||||
|
||||
@@ -151,15 +152,11 @@ function getAllProps(obj) {
|
||||
// e.g., expr="({ foo: null, bar: null, 4: null })" will
|
||||
// return ["foo", "bar", ...] but the list will not include "4",
|
||||
// since methods accessed with '.' notation must star with a letter or _.
|
||||
function getPropertyNamesFromExpression(expr, commandHeader) {
|
||||
if (commandHeader == null) {
|
||||
commandHeader = '';
|
||||
}
|
||||
|
||||
function getPropertyNamesFromExpression(expr, commandHeader = '') {
|
||||
let obj = {};
|
||||
if (!isUnsafeExpression(expr)) {
|
||||
try {
|
||||
obj = eval(commandHeader + expr);
|
||||
obj = eval(commandHeader + expr);
|
||||
} catch (e) {
|
||||
return [];
|
||||
}
|
||||
@@ -168,14 +165,14 @@ function getPropertyNamesFromExpression(expr, commandHeader) {
|
||||
}
|
||||
|
||||
let propsUnique = {};
|
||||
if (typeof obj === 'object'){
|
||||
if (typeof obj === 'object') {
|
||||
let allProps = getAllProps(obj);
|
||||
// Get only things we are allowed to complete following a '.'
|
||||
allProps = allProps.filter( isValidPropertyName );
|
||||
|
||||
// Make sure propsUnique contains one key for every
|
||||
// property so we end up with a unique list of properties
|
||||
allProps.map(p => propsUnique[p] = null);
|
||||
allProps.map(p => (propsUnique[p] = null));
|
||||
}
|
||||
return Object.keys(propsUnique).sort();
|
||||
}
|
||||
@@ -220,7 +217,7 @@ function isUnsafeExpression(str) {
|
||||
prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing
|
||||
prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing
|
||||
|
||||
if (prunedStr.match(/=/)) {
|
||||
if (prunedStr.match(/[=]/)) {
|
||||
return true;
|
||||
} else if (prunedStr.match(/;/)) {
|
||||
// If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well
|
||||
@@ -234,10 +231,10 @@ function isUnsafeExpression(str) {
|
||||
function getDeclaredConstants(str) {
|
||||
let ret = [];
|
||||
str.split(';').forEach(s => {
|
||||
let base, keyword;
|
||||
let base_, keyword;
|
||||
let match = s.match(/const\s+(\w+)\s*=/);
|
||||
if (match) {
|
||||
[base, keyword] = match;
|
||||
[base_, keyword] = match;
|
||||
ret.push(keyword);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
|
||||
|
||||
const { GLib, GnomeDesktop, Meta } = imports.gi;
|
||||
|
||||
@@ -60,7 +61,7 @@ var KeyboardManager = class {
|
||||
this._currentKeymap.options == options)
|
||||
return;
|
||||
|
||||
this._currentKeymap = {layouts, variants, options};
|
||||
this._currentKeymap = { layouts, variants, options };
|
||||
Meta.get_backend().set_keymap(layouts, variants, options);
|
||||
}
|
||||
|
||||
@@ -125,7 +126,7 @@ var KeyboardManager = class {
|
||||
|
||||
_getLocaleLayout() {
|
||||
let locale = GLib.get_language_names()[0];
|
||||
if (locale.indexOf('_') == -1)
|
||||
if (!locale.includes('_'))
|
||||
locale = DEFAULT_LOCALE;
|
||||
|
||||
let [found, , id] = GnomeDesktop.get_input_source_from_locale(locale);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported canLock, getLoginManager, registerSessionWithGDM */
|
||||
|
||||
const { GLib, Gio } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
@@ -43,7 +44,7 @@ function canLock() {
|
||||
|
||||
let version = result.deep_unpack()[0].deep_unpack();
|
||||
return haveSystemd() && versionCompare('3.5.91', version);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +110,7 @@ var LoginManagerSystemd = class {
|
||||
let sessionId = GLib.getenv('XDG_SESSION_ID');
|
||||
if (!sessionId) {
|
||||
log('Unset XDG_SESSION_ID, getCurrentSessionProxy() called outside a user session. Asking logind directly.');
|
||||
let [session, objectPath] = this._userProxy.Display;
|
||||
let [session, objectPath_] = this._userProxy.Display;
|
||||
if (session) {
|
||||
log(`Will monitor session ${session}`);
|
||||
sessionId = session;
|
||||
@@ -182,10 +183,10 @@ var LoginManagerSystemd = class {
|
||||
(proxy, result) => {
|
||||
let fd = -1;
|
||||
try {
|
||||
let [outVariant, fdList] = proxy.call_with_unix_fd_list_finish(result);
|
||||
let [outVariant_, fdList] = proxy.call_with_unix_fd_list_finish(result);
|
||||
fd = fdList.steal_fds()[0];
|
||||
callback(new Gio.UnixInputStream({ fd: fd }));
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
logError(e, "Error getting systemd inhibitor");
|
||||
callback(null);
|
||||
}
|
||||
@@ -199,7 +200,7 @@ var LoginManagerSystemd = class {
|
||||
Signals.addSignalMethods(LoginManagerSystemd.prototype);
|
||||
|
||||
var LoginManagerDummy = class {
|
||||
getCurrentSessionProxy(callback) {
|
||||
getCurrentSessionProxy(_callback) {
|
||||
// we could return a DummySession object that fakes whatever callers
|
||||
// expect (at the time of writing: connect() and connectSignal()
|
||||
// methods), but just never calling the callback should be safer
|
||||
|
||||
@@ -26,33 +26,33 @@ function _getMobileProvidersDatabase() {
|
||||
}
|
||||
|
||||
// _findProviderForMccMnc:
|
||||
// @operator_name: operator name
|
||||
// @operator_code: operator code
|
||||
// @operatorName: operator name
|
||||
// @operatorCode: operator code
|
||||
//
|
||||
// Given an operator name string (which may not be a real operator name) and an
|
||||
// operator code string, tries to find a proper operator name to display.
|
||||
//
|
||||
function _findProviderForMccMnc(operator_name, operator_code) {
|
||||
if (operator_name) {
|
||||
if (operator_name.length != 0 &&
|
||||
(operator_name.length > 6 || operator_name.length < 5)) {
|
||||
function _findProviderForMccMnc(operatorName, operatorCode) {
|
||||
if (operatorName) {
|
||||
if (operatorName.length != 0 &&
|
||||
(operatorName.length > 6 || operatorName.length < 5)) {
|
||||
// this looks like a valid name, i.e. not an MCCMNC (that some
|
||||
// devices return when not yet connected
|
||||
return operator_name;
|
||||
return operatorName;
|
||||
}
|
||||
|
||||
if (isNaN(parseInt(operator_name))) {
|
||||
if (isNaN(parseInt(operatorName))) {
|
||||
// name is definitely not a MCCMNC, so it may be a name
|
||||
// after all; return that
|
||||
return operator_name;
|
||||
return operatorName;
|
||||
}
|
||||
}
|
||||
|
||||
let needle;
|
||||
if ((!operator_name || operator_name.length == 0) && operator_code)
|
||||
needle = operator_code;
|
||||
else if (operator_name && (operator_name.length == 6 || operator_name.length == 5))
|
||||
needle = operator_name;
|
||||
if ((!operatorName || operatorName.length == 0) && operatorCode)
|
||||
needle = operatorCode;
|
||||
else if (operatorName && (operatorName.length == 6 || operatorName.length == 5))
|
||||
needle = operatorName;
|
||||
else // nothing to search
|
||||
return null;
|
||||
|
||||
@@ -84,9 +84,9 @@ function _findProviderForSid(sid) {
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Support for the old ModemManager interface (MM < 0.7)
|
||||
//------------------------------------------------------------------------------
|
||||
// ----------------------------------------------------- //
|
||||
// Support for the old ModemManager interface (MM < 0.7) //
|
||||
// ----------------------------------------------------- //
|
||||
|
||||
|
||||
// The following are not the complete interfaces, just the methods we need
|
||||
@@ -110,7 +110,7 @@ var ModemGsm = class {
|
||||
this.signal_quality = quality;
|
||||
this.emit('notify::signal-quality');
|
||||
});
|
||||
this._proxy.connectSignal('RegistrationInfo', (proxy, sender, [status, code, name]) => {
|
||||
this._proxy.connectSignal('RegistrationInfo', (proxy, sender, [_status, code, name]) => {
|
||||
this.operator_name = _findProviderForMccMnc(name, code);
|
||||
this.emit('notify::operator-name');
|
||||
});
|
||||
@@ -120,7 +120,7 @@ var ModemGsm = class {
|
||||
return;
|
||||
}
|
||||
|
||||
let [status, code, name] = result;
|
||||
let [status_, code, name] = result;
|
||||
this.operator_name = _findProviderForMccMnc(name, code);
|
||||
this.emit('notify::operator-name');
|
||||
});
|
||||
@@ -171,9 +171,9 @@ var ModemCdma = class {
|
||||
// it will return an error if the device is not connected
|
||||
this.operator_name = null;
|
||||
} else {
|
||||
let [bandClass, band, sid] = result;
|
||||
let [bandClass_, band_, sid] = result;
|
||||
|
||||
this.operator_name = _findProviderForSid(sid)
|
||||
this.operator_name = _findProviderForSid(sid);
|
||||
}
|
||||
this.emit('notify::operator-name');
|
||||
});
|
||||
@@ -182,9 +182,9 @@ var ModemCdma = class {
|
||||
Signals.addSignalMethods(ModemCdma.prototype);
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Support for the new ModemManager1 interface (MM >= 0.7)
|
||||
//------------------------------------------------------------------------------
|
||||
// ------------------------------------------------------- //
|
||||
// Support for the new ModemManager1 interface (MM >= 0.7) //
|
||||
// ------------------------------------------------------- //
|
||||
|
||||
const BroadbandModemInterface = loadInterfaceXML('org.freedesktop.ModemManager1.Modem');
|
||||
const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface);
|
||||
@@ -224,23 +224,23 @@ var BroadbandModem = class {
|
||||
}
|
||||
|
||||
_reloadSignalQuality() {
|
||||
let [quality, recent] = this._proxy.SignalQuality;
|
||||
let [quality, recent_] = this._proxy.SignalQuality;
|
||||
this.signal_quality = quality;
|
||||
this.emit('notify::signal-quality');
|
||||
}
|
||||
|
||||
_reloadOperatorName() {
|
||||
let new_name = "";
|
||||
let newName = "";
|
||||
if (this.operator_name_3gpp && this.operator_name_3gpp.length > 0)
|
||||
new_name += this.operator_name_3gpp;
|
||||
newName += this.operator_name_3gpp;
|
||||
|
||||
if (this.operator_name_cdma && this.operator_name_cdma.length > 0) {
|
||||
if (new_name != "")
|
||||
new_name += ", ";
|
||||
new_name += this.operator_name_cdma;
|
||||
if (newName != "")
|
||||
newName += ", ";
|
||||
newName += this.operator_name_cdma;
|
||||
}
|
||||
|
||||
this.operator_name = new_name;
|
||||
this.operator_name = newName;
|
||||
this.emit('notify::operator-name');
|
||||
}
|
||||
|
||||
|
||||
@@ -77,54 +77,51 @@ var ObjectManager = class {
|
||||
let info = this._interfaceInfos[interfaceName];
|
||||
|
||||
if (!info) {
|
||||
if (onFinished)
|
||||
onFinished();
|
||||
return;
|
||||
if (onFinished)
|
||||
onFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
let proxy = new Gio.DBusProxy({ g_connection: this._connection,
|
||||
g_name: this._serviceName,
|
||||
g_object_path: objectPath,
|
||||
g_interface_name: interfaceName,
|
||||
g_interface_info: info,
|
||||
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
|
||||
g_name: this._serviceName,
|
||||
g_object_path: objectPath,
|
||||
g_interface_name: interfaceName,
|
||||
g_interface_info: info,
|
||||
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
|
||||
|
||||
proxy.init_async(GLib.PRIORITY_DEFAULT,
|
||||
this._cancellable,
|
||||
(initable, result) => {
|
||||
let error = null;
|
||||
try {
|
||||
initable.init_finish(result);
|
||||
} catch(e) {
|
||||
logError(e, 'could not initialize proxy for interface ' + interfaceName);
|
||||
proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => {
|
||||
try {
|
||||
initable.init_finish(result);
|
||||
} catch (e) {
|
||||
logError(e, `could not initialize proxy for interface ${interfaceName}`);
|
||||
|
||||
if (onFinished)
|
||||
onFinished();
|
||||
return;
|
||||
}
|
||||
if (onFinished)
|
||||
onFinished();
|
||||
return;
|
||||
}
|
||||
|
||||
let isNewObject;
|
||||
if (!this._objects[objectPath]) {
|
||||
this._objects[objectPath] = {};
|
||||
isNewObject = true;
|
||||
} else {
|
||||
isNewObject = false;
|
||||
}
|
||||
let isNewObject;
|
||||
if (!this._objects[objectPath]) {
|
||||
this._objects[objectPath] = {};
|
||||
isNewObject = true;
|
||||
} else {
|
||||
isNewObject = false;
|
||||
}
|
||||
|
||||
this._objects[objectPath][interfaceName] = proxy;
|
||||
this._objects[objectPath][interfaceName] = proxy;
|
||||
|
||||
if (!this._interfaces[interfaceName])
|
||||
this._interfaces[interfaceName] = [];
|
||||
if (!this._interfaces[interfaceName])
|
||||
this._interfaces[interfaceName] = [];
|
||||
|
||||
this._interfaces[interfaceName].push(proxy);
|
||||
this._interfaces[interfaceName].push(proxy);
|
||||
|
||||
if (isNewObject)
|
||||
this.emit('object-added', objectPath);
|
||||
if (isNewObject)
|
||||
this.emit('object-added', objectPath);
|
||||
|
||||
this.emit('interface-added', interfaceName, proxy);
|
||||
this.emit('interface-added', interfaceName, proxy);
|
||||
|
||||
if (onFinished)
|
||||
onFinished();
|
||||
if (onFinished)
|
||||
onFinished();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -155,11 +152,10 @@ var ObjectManager = class {
|
||||
}
|
||||
|
||||
_onManagerProxyLoaded(initable, result) {
|
||||
let error = null;
|
||||
try {
|
||||
initable.init_finish(result);
|
||||
} catch(e) {
|
||||
logError(e, 'could not initialize object manager for object ' + this._serviceName);
|
||||
} catch (e) {
|
||||
logError(e, `could not initialize object manager for object ${this._serviceName}`);
|
||||
|
||||
this._tryToCompleteLoad();
|
||||
return;
|
||||
@@ -197,7 +193,7 @@ var ObjectManager = class {
|
||||
this._managerProxy.GetManagedObjectsRemote((result, error) => {
|
||||
if (!result) {
|
||||
if (error) {
|
||||
logError(error, 'could not get remote objects for service ' + this._serviceName + ' path ' + this._managerPath);
|
||||
logError(error, `could not get remote objects for service ${this._serviceName} path ${this._managerPath}`);
|
||||
}
|
||||
|
||||
this._tryToCompleteLoad();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported parse */
|
||||
|
||||
// parse:
|
||||
// @params: caller-provided parameter object, or %null
|
||||
@@ -14,22 +15,13 @@
|
||||
//
|
||||
// Return value: a new object, containing the merged parameters from
|
||||
// @params and @defaults
|
||||
function parse(params, defaults, allowExtras) {
|
||||
let ret = {}, prop;
|
||||
|
||||
if (!params)
|
||||
params = {};
|
||||
|
||||
for (prop in params) {
|
||||
if (!(prop in defaults) && !allowExtras)
|
||||
throw new Error('Unrecognized parameter "' + prop + '"');
|
||||
ret[prop] = params[prop];
|
||||
function parse(params = {}, defaults, allowExtras) {
|
||||
if (!allowExtras) {
|
||||
for (let prop in params)
|
||||
if (!(prop in defaults))
|
||||
throw new Error(`Unrecognized parameter "${prop}"`);
|
||||
}
|
||||
|
||||
for (prop in defaults) {
|
||||
if (!(prop in params))
|
||||
ret[prop] = defaults[prop];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
let defaultsCopy = Object.assign({}, defaults);
|
||||
return Object.assign(defaultsCopy, params);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported PermissionStore */
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
|
||||
@@ -12,4 +13,4 @@ function PermissionStore(initCallback, cancellable) {
|
||||
'org.freedesktop.impl.portal.PermissionStore',
|
||||
'/org/freedesktop/impl/portal/PermissionStore',
|
||||
initCallback, cancellable);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported getSmartcardManager */
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Signals = imports.signals;
|
||||
@@ -29,7 +30,7 @@ var SmartcardManager = class {
|
||||
this._objectManager = new ObjectManager.ObjectManager({ connection: Gio.DBus.session,
|
||||
name: "org.gnome.SettingsDaemon.Smartcard",
|
||||
objectPath: '/org/gnome/SettingsDaemon/Smartcard',
|
||||
knownInterfaces: [ SmartcardTokenIface ],
|
||||
knownInterfaces: [SmartcardTokenIface],
|
||||
onLoaded: this._onLoaded.bind(this) });
|
||||
this._insertedTokens = {};
|
||||
this._loginToken = null;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported getDefault */
|
||||
const { AccountsService, Clutter, Gdm, Gio, GLib, GObject, Meta } = imports.gi;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
@@ -83,48 +84,54 @@ const SystemActions = GObject.registerClass({
|
||||
this._canHaveSuspend = true;
|
||||
|
||||
this._actions = new Map();
|
||||
this._actions.set(POWER_OFF_ACTION_ID,
|
||||
{ // Translators: The name of the power-off action in search
|
||||
name: C_("search-result", "Power Off"),
|
||||
iconName: 'system-shutdown-symbolic',
|
||||
// Translators: A list of keywords that match the power-off action, separated by semicolons
|
||||
keywords: _("power off;shutdown;reboot;restart").split(/[; ]/),
|
||||
available: false });
|
||||
this._actions.set(LOCK_SCREEN_ACTION_ID,
|
||||
{ // Translators: The name of the lock screen action in search
|
||||
name: C_("search-result", "Lock Screen"),
|
||||
iconName: 'system-lock-screen-symbolic',
|
||||
// Translators: A list of keywords that match the lock screen action, separated by semicolons
|
||||
keywords: _("lock screen").split(/[; ]/),
|
||||
available: false });
|
||||
this._actions.set(LOGOUT_ACTION_ID,
|
||||
{ // Translators: The name of the logout action in search
|
||||
name: C_("search-result", "Log Out"),
|
||||
iconName: 'application-exit-symbolic',
|
||||
// Translators: A list of keywords that match the logout action, separated by semicolons
|
||||
keywords: _("logout;log out;sign off").split(/[; ]/),
|
||||
available: false });
|
||||
this._actions.set(SUSPEND_ACTION_ID,
|
||||
{ // Translators: The name of the suspend action in search
|
||||
name: C_("search-result", "Suspend"),
|
||||
iconName: 'media-playback-pause-symbolic',
|
||||
// Translators: A list of keywords that match the suspend action, separated by semicolons
|
||||
keywords: _("suspend;sleep").split(/[; ]/),
|
||||
available: false });
|
||||
this._actions.set(SWITCH_USER_ACTION_ID,
|
||||
{ // Translators: The name of the switch user action in search
|
||||
name: C_("search-result", "Switch User"),
|
||||
iconName: 'system-switch-user-symbolic',
|
||||
// Translators: A list of keywords that match the switch user action, separated by semicolons
|
||||
keywords: _("switch user").split(/[; ]/),
|
||||
available: false });
|
||||
this._actions.set(LOCK_ORIENTATION_ACTION_ID,
|
||||
{ // Translators: The name of the lock orientation action in search
|
||||
name: C_("search-result", "Lock Orientation"),
|
||||
iconName: '',
|
||||
// Translators: A list of keywords that match the lock orientation action, separated by semicolons
|
||||
keywords: _("lock orientation;screen;rotation").split(/[; ]/),
|
||||
available: false });
|
||||
this._actions.set(POWER_OFF_ACTION_ID, {
|
||||
// Translators: The name of the power-off action in search
|
||||
name: C_("search-result", "Power Off"),
|
||||
iconName: 'system-shutdown-symbolic',
|
||||
// Translators: A list of keywords that match the power-off action, separated by semicolons
|
||||
keywords: _("power off;shutdown;reboot;restart").split(/[; ]/),
|
||||
available: false
|
||||
});
|
||||
this._actions.set(LOCK_SCREEN_ACTION_ID, {
|
||||
// Translators: The name of the lock screen action in search
|
||||
name: C_("search-result", "Lock Screen"),
|
||||
iconName: 'system-lock-screen-symbolic',
|
||||
// Translators: A list of keywords that match the lock screen action, separated by semicolons
|
||||
keywords: _("lock screen").split(/[; ]/),
|
||||
available: false
|
||||
});
|
||||
this._actions.set(LOGOUT_ACTION_ID, {
|
||||
// Translators: The name of the logout action in search
|
||||
name: C_("search-result", "Log Out"),
|
||||
iconName: 'application-exit-symbolic',
|
||||
// Translators: A list of keywords that match the logout action, separated by semicolons
|
||||
keywords: _("logout;log out;sign off").split(/[; ]/),
|
||||
available: false
|
||||
});
|
||||
this._actions.set(SUSPEND_ACTION_ID, {
|
||||
// Translators: The name of the suspend action in search
|
||||
name: C_("search-result", "Suspend"),
|
||||
iconName: 'media-playback-pause-symbolic',
|
||||
// Translators: A list of keywords that match the suspend action, separated by semicolons
|
||||
keywords: _("suspend;sleep").split(/[; ]/),
|
||||
available: false
|
||||
});
|
||||
this._actions.set(SWITCH_USER_ACTION_ID, {
|
||||
// Translators: The name of the switch user action in search
|
||||
name: C_("search-result", "Switch User"),
|
||||
iconName: 'system-switch-user-symbolic',
|
||||
// Translators: A list of keywords that match the switch user action, separated by semicolons
|
||||
keywords: _("switch user").split(/[; ]/),
|
||||
available: false
|
||||
});
|
||||
this._actions.set(LOCK_ORIENTATION_ACTION_ID, {
|
||||
// Translators: The name of the lock orientation action in search
|
||||
name: C_("search-result", "Lock Orientation"),
|
||||
iconName: '',
|
||||
// Translators: A list of keywords that match the lock orientation action, separated by semicolons
|
||||
keywords: _("lock orientation;screen;rotation").split(/[; ]/),
|
||||
available: false
|
||||
});
|
||||
|
||||
this._loginScreenSettings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
|
||||
this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
|
||||
@@ -137,92 +144,96 @@ const SystemActions = GObject.registerClass({
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
|
||||
this._userManager.connect('notify::is-loaded',
|
||||
() => { this._updateMultiUser(); });
|
||||
() => this._updateMultiUser());
|
||||
this._userManager.connect('notify::has-multiple-users',
|
||||
() => { this._updateMultiUser(); });
|
||||
() => this._updateMultiUser());
|
||||
this._userManager.connect('user-added',
|
||||
() => { this._updateMultiUser(); });
|
||||
() => this._updateMultiUser());
|
||||
this._userManager.connect('user-removed',
|
||||
() => { this._updateMultiUser(); });
|
||||
() => this._updateMultiUser());
|
||||
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_USER_SWITCH_KEY,
|
||||
() => { this._updateSwitchUser(); });
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
||||
() => { this._updateLogout(); });
|
||||
global.settings.connect('changed::' + ALWAYS_SHOW_LOG_OUT_KEY,
|
||||
() => { this._updateLogout(); });
|
||||
this._lockdownSettings.connect(`changed::${DISABLE_USER_SWITCH_KEY}`,
|
||||
() => this._updateSwitchUser());
|
||||
this._lockdownSettings.connect(`changed::${DISABLE_LOG_OUT_KEY}`,
|
||||
() => this._updateLogout());
|
||||
global.settings.connect(`changed::${ALWAYS_SHOW_LOG_OUT_KEY}`,
|
||||
() => this._updateLogout());
|
||||
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
|
||||
() => { this._updateLockScreen(); });
|
||||
this._lockdownSettings.connect(`changed::${DISABLE_LOCK_SCREEN_KEY}`,
|
||||
() => this._updateLockScreen());
|
||||
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
||||
() => { this._updateHaveShutdown(); });
|
||||
this._lockdownSettings.connect(`changed::${DISABLE_LOG_OUT_KEY}`,
|
||||
() => this._updateHaveShutdown());
|
||||
|
||||
this.forceUpdate();
|
||||
|
||||
this._orientationSettings.connect('changed::orientation-lock',
|
||||
() => { this._updateOrientationLock();
|
||||
this._updateOrientationLockIcon(); });
|
||||
() => {
|
||||
this._updateOrientationLock();
|
||||
this._updateOrientationLockIcon();
|
||||
});
|
||||
Main.layoutManager.connect('monitors-changed',
|
||||
() => { this._updateOrientationLock(); });
|
||||
Gio.DBus.system.watch_name(SENSOR_BUS_NAME,
|
||||
Gio.BusNameWatcherFlags.NONE,
|
||||
() => { this._sensorProxyAppeared(); },
|
||||
() => {
|
||||
this._sensorProxy = null;
|
||||
this._updateOrientationLock();
|
||||
});
|
||||
() => this._updateOrientationLock());
|
||||
this._sensorProxy = new SensorProxy(Gio.DBus.system,
|
||||
SENSOR_BUS_NAME,
|
||||
SENSOR_OBJECT_PATH,
|
||||
(proxy, error) => {
|
||||
if (error)
|
||||
log(error.message);
|
||||
},
|
||||
null,
|
||||
Gio.DBusProxyFlags.DO_NOT_AUTO_START);
|
||||
this._sensorProxy.connect('g-properties-changed', () => {
|
||||
this._updateOrientationLock();
|
||||
});
|
||||
this._sensorProxy.connect('notify::g-name-owner', () => {
|
||||
this._updateOrientationLock();
|
||||
});
|
||||
this._updateOrientationLock();
|
||||
this._updateOrientationLockIcon();
|
||||
|
||||
Main.sessionMode.connect('updated', () => { this._sessionUpdated(); });
|
||||
Main.sessionMode.connect('updated', () => this._sessionUpdated());
|
||||
this._sessionUpdated();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get can_power_off() {
|
||||
return this._actions.get(POWER_OFF_ACTION_ID).available;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get can_suspend() {
|
||||
return this._actions.get(SUSPEND_ACTION_ID).available;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get can_lock_screen() {
|
||||
return this._actions.get(LOCK_SCREEN_ACTION_ID).available;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get can_switch_user() {
|
||||
return this._actions.get(SWITCH_USER_ACTION_ID).available;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get can_logout() {
|
||||
return this._actions.get(LOGOUT_ACTION_ID).available;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get can_lock_orientation() {
|
||||
return this._actions.get(LOCK_ORIENTATION_ACTION_ID).available;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get orientation_lock_icon() {
|
||||
return this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName;
|
||||
}
|
||||
|
||||
_sensorProxyAppeared() {
|
||||
this._sensorProxy = new SensorProxy(Gio.DBus.system, SENSOR_BUS_NAME, SENSOR_OBJECT_PATH,
|
||||
(proxy, error) => {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._sensorProxy.connect('g-properties-changed',
|
||||
() => { this._updateOrientationLock(); });
|
||||
this._updateOrientationLock();
|
||||
});
|
||||
}
|
||||
|
||||
_updateOrientationLock() {
|
||||
let available = false;
|
||||
if (this._sensorProxy)
|
||||
if (this._sensorProxy.g_name_owner)
|
||||
available = this._sensorProxy.HasAccelerometer &&
|
||||
this._monitorManager.get_is_builtin_display_on();
|
||||
|
||||
@@ -233,8 +244,9 @@ const SystemActions = GObject.registerClass({
|
||||
|
||||
_updateOrientationLockIcon() {
|
||||
let locked = this._orientationSettings.get_boolean('orientation-lock');
|
||||
let iconName = locked ? 'rotation-locked-symbolic'
|
||||
: 'rotation-allowed-symbolic';
|
||||
let iconName = locked
|
||||
? 'rotation-locked-symbolic'
|
||||
: 'rotation-allowed-symbolic';
|
||||
this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName = iconName;
|
||||
|
||||
this.notify('orientation-lock-icon');
|
||||
@@ -257,11 +269,11 @@ const SystemActions = GObject.registerClass({
|
||||
|
||||
getMatchingActions(terms) {
|
||||
// terms is a list of strings
|
||||
terms = terms.map((term) => { return term.toLowerCase(); });
|
||||
terms = terms.map(term => term.toLowerCase());
|
||||
|
||||
let results = [];
|
||||
|
||||
for (let [key, {available, keywords}] of this._actions)
|
||||
for (let [key, { available, keywords }] of this._actions)
|
||||
if (available && terms.every(t => keywords.some(k => k.startsWith(t))))
|
||||
results.push(key);
|
||||
|
||||
@@ -278,24 +290,24 @@ const SystemActions = GObject.registerClass({
|
||||
|
||||
activateAction(id) {
|
||||
switch (id) {
|
||||
case POWER_OFF_ACTION_ID:
|
||||
this.activatePowerOff();
|
||||
break;
|
||||
case LOCK_SCREEN_ACTION_ID:
|
||||
this.activateLockScreen();
|
||||
break;
|
||||
case LOGOUT_ACTION_ID:
|
||||
this.activateLogout();
|
||||
break;
|
||||
case SUSPEND_ACTION_ID:
|
||||
this.activateSuspend();
|
||||
break;
|
||||
case SWITCH_USER_ACTION_ID:
|
||||
this.activateSwitchUser();
|
||||
break;
|
||||
case LOCK_ORIENTATION_ACTION_ID:
|
||||
this.activateLockOrientation();
|
||||
break;
|
||||
case POWER_OFF_ACTION_ID:
|
||||
this.activatePowerOff();
|
||||
break;
|
||||
case LOCK_SCREEN_ACTION_ID:
|
||||
this.activateLockScreen();
|
||||
break;
|
||||
case LOGOUT_ACTION_ID:
|
||||
this.activateLogout();
|
||||
break;
|
||||
case SUSPEND_ACTION_ID:
|
||||
this.activateSuspend();
|
||||
break;
|
||||
case SWITCH_USER_ACTION_ID:
|
||||
this.activateSwitchUser();
|
||||
break;
|
||||
case LOCK_ORIENTATION_ACTION_ID:
|
||||
this.activateLockOrientation();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
165
js/misc/util.js
165
js/misc/util.js
@@ -1,23 +1,23 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
|
||||
formatTime, formatTimeSpan, createTimeLabel, insertSorted,
|
||||
makeCloseButton, ensureActorVisibleInScrollView */
|
||||
|
||||
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
|
||||
const Gettext = imports.gettext;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
var SCROLL_TIME = 0.1;
|
||||
var SCROLL_TIME = 100;
|
||||
|
||||
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
|
||||
const _balancedParens = '\\([^\\s()<>]+\\)';
|
||||
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
|
||||
const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]';
|
||||
const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u200E\u200F\u201C\u201D\u2018\u2019\u202A\u202C]';
|
||||
|
||||
const _urlRegexp = new RegExp(
|
||||
'(^|' + _leadingJunk + ')' +
|
||||
`(^|${_leadingJunk})` +
|
||||
'(' +
|
||||
'(?:' +
|
||||
'(?:http|https|ftp)://' + // scheme://
|
||||
@@ -29,12 +29,12 @@ const _urlRegexp = new RegExp(
|
||||
'(?:' + // one or more:
|
||||
'[^\\s()<>]+' + // run of non-space non-()
|
||||
'|' + // or
|
||||
_balancedParens + // balanced parens
|
||||
`${_balancedParens}` + // balanced parens
|
||||
')+' +
|
||||
'(?:' + // end with:
|
||||
_balancedParens + // balanced parens
|
||||
`${_balancedParens}` + // balanced parens
|
||||
'|' + // or
|
||||
_notTrailingJunk + // last non-junk char
|
||||
`${_notTrailingJunk}` + // last non-junk char
|
||||
')' +
|
||||
')', 'gi');
|
||||
|
||||
@@ -69,16 +69,16 @@ function spawn(argv) {
|
||||
}
|
||||
|
||||
// spawnCommandLine:
|
||||
// @command_line: a command line
|
||||
// @commandLine: a command line
|
||||
//
|
||||
// Runs @command_line in the background, handling any errors that
|
||||
// Runs @commandLine in the background, handling any errors that
|
||||
// occur when trying to parse or start the program.
|
||||
function spawnCommandLine(command_line) {
|
||||
function spawnCommandLine(commandLine) {
|
||||
try {
|
||||
let [success, argv] = GLib.shell_parse_argv(command_line);
|
||||
let [success_, argv] = GLib.shell_parse_argv(commandLine);
|
||||
trySpawn(argv);
|
||||
} catch (err) {
|
||||
_handleSpawnError(command_line, err);
|
||||
_handleSpawnError(commandLine, err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ function spawnApp(argv) {
|
||||
|
||||
let context = global.create_app_launch_context(0, -1);
|
||||
app.launch([], context);
|
||||
} catch(err) {
|
||||
} catch (err) {
|
||||
_handleSpawnError(argv[0], err);
|
||||
}
|
||||
}
|
||||
@@ -103,13 +103,12 @@ function spawnApp(argv) {
|
||||
//
|
||||
// Runs @argv in the background. If launching @argv fails,
|
||||
// this will throw an error.
|
||||
function trySpawn(argv)
|
||||
{
|
||||
var success, pid;
|
||||
function trySpawn(argv) {
|
||||
var success_, pid;
|
||||
try {
|
||||
[success, pid] = GLib.spawn_async(null, argv, null,
|
||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
||||
null);
|
||||
[success_, pid] = GLib.spawn_async(null, argv, null,
|
||||
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
||||
null);
|
||||
} catch (err) {
|
||||
/* Rewrite the error in case of ENOENT */
|
||||
if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
|
||||
@@ -135,19 +134,19 @@ function trySpawn(argv)
|
||||
}
|
||||
|
||||
// trySpawnCommandLine:
|
||||
// @command_line: a command line
|
||||
// @commandLine: a command line
|
||||
//
|
||||
// Runs @command_line in the background. If launching @command_line
|
||||
// Runs @commandLine in the background. If launching @commandLine
|
||||
// fails, this will throw an error.
|
||||
function trySpawnCommandLine(command_line) {
|
||||
let success, argv;
|
||||
function trySpawnCommandLine(commandLine) {
|
||||
let success_, argv;
|
||||
|
||||
try {
|
||||
[success, argv] = GLib.shell_parse_argv(command_line);
|
||||
[success_, argv] = GLib.shell_parse_argv(commandLine);
|
||||
} catch (err) {
|
||||
// Replace "Error invoking GLib.shell_parse_argv: " with
|
||||
// something nicer
|
||||
err.message = err.message.replace(/[^:]*: /, _("Could not parse command:") + "\n");
|
||||
err.message = err.message.replace(/[^:]*: /, `${_("Could not parse command:")}\n`);
|
||||
throw err;
|
||||
}
|
||||
|
||||
@@ -222,7 +221,7 @@ function formatTime(time, params) {
|
||||
/* Translators: Time in 24h format */
|
||||
format = N_("%H\u2236%M");
|
||||
// Show the word "Yesterday" and time if date is on yesterday
|
||||
else if (daysAgo <2)
|
||||
else if (daysAgo < 2)
|
||||
/* Translators: this is the word "Yesterday" followed by a
|
||||
time string in 24h format. i.e. "Yesterday, 14:30" */
|
||||
// xgettext:no-c-format
|
||||
@@ -251,7 +250,7 @@ function formatTime(time, params) {
|
||||
/* Translators: Time in 12h format */
|
||||
format = N_("%l\u2236%M %p");
|
||||
// Show the word "Yesterday" and time if date is on yesterday
|
||||
else if (daysAgo <2)
|
||||
else if (daysAgo < 2)
|
||||
/* Translators: this is the word "Yesterday" followed by a
|
||||
time string in 12h format. i.e. "Yesterday, 2:30 pm" */
|
||||
// xgettext:no-c-format
|
||||
@@ -289,7 +288,7 @@ function createTimeLabel(date, params) {
|
||||
let id = _desktopSettings.connect('changed::clock-format', () => {
|
||||
label.text = formatTime(date, params);
|
||||
});
|
||||
label.connect('destroy', () => { _desktopSettings.disconnect(id); });
|
||||
label.connect('destroy', () => _desktopSettings.disconnect(id));
|
||||
return label;
|
||||
}
|
||||
|
||||
@@ -314,7 +313,8 @@ function lowerBound(array, val, cmp) {
|
||||
if (array.length == 0)
|
||||
return 0;
|
||||
|
||||
min = 0; max = array.length;
|
||||
min = 0;
|
||||
max = array.length;
|
||||
while (min < (max - 1)) {
|
||||
mid = Math.floor((min + max) / 2);
|
||||
v = cmp(array[mid], val);
|
||||
@@ -346,7 +346,7 @@ function insertSorted(array, val, cmp) {
|
||||
var CloseButton = GObject.registerClass(
|
||||
class CloseButton extends St.Button {
|
||||
_init(boxpointer) {
|
||||
super._init({ style_class: 'notification-close'});
|
||||
super._init({ style_class: 'notification-close' });
|
||||
|
||||
// This is a bit tricky. St.Bin has its own x-align/y-align properties
|
||||
// that compete with Clutter's properties. This should be fixed for
|
||||
@@ -380,7 +380,7 @@ class CloseButton extends St.Button {
|
||||
let themeNode = this.get_theme_node();
|
||||
|
||||
let offY = this._computeBoxPointerOffset();
|
||||
this.translation_x = themeNode.get_length('-shell-close-overlap-x')
|
||||
this.translation_x = themeNode.get_length('-shell-close-overlap-x');
|
||||
this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY;
|
||||
}
|
||||
|
||||
@@ -396,7 +396,7 @@ function makeCloseButton(boxpointer) {
|
||||
|
||||
function ensureActorVisibleInScrollView(scrollView, actor) {
|
||||
let adjustment = scrollView.vscroll.adjustment;
|
||||
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
||||
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
|
||||
|
||||
let offset = 0;
|
||||
let vfade = scrollView.get_effect("fade");
|
||||
@@ -424,97 +424,8 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
|
||||
else
|
||||
return;
|
||||
|
||||
Tweener.addTween(adjustment,
|
||||
{ value: value,
|
||||
time: SCROLL_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
adjustment.ease(value, {
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
duration: SCROLL_TIME
|
||||
});
|
||||
}
|
||||
|
||||
var AppSettingsMonitor = class {
|
||||
constructor(appId, schemaId) {
|
||||
this._appId = appId;
|
||||
this._schemaId = schemaId;
|
||||
|
||||
this._app = null;
|
||||
this._settings = null;
|
||||
this._handlers = [];
|
||||
|
||||
this._schemaSource = Gio.SettingsSchemaSource.get_default();
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('installed-changed',
|
||||
this._onInstalledChanged.bind(this));
|
||||
this._onInstalledChanged();
|
||||
}
|
||||
|
||||
get available() {
|
||||
return this._app != null && this._settings != null;
|
||||
}
|
||||
|
||||
activateApp() {
|
||||
if (this._app)
|
||||
this._app.activate();
|
||||
}
|
||||
|
||||
watchSetting(key, callback) {
|
||||
let handler = { id: 0, key: key, callback: callback };
|
||||
this._handlers.push(handler);
|
||||
|
||||
this._connectHandler(handler);
|
||||
}
|
||||
|
||||
_connectHandler(handler) {
|
||||
if (!this._settings || handler.id > 0)
|
||||
return;
|
||||
|
||||
handler.id = this._settings.connect('changed::' + handler.key,
|
||||
handler.callback);
|
||||
handler.callback(this._settings, handler.key);
|
||||
}
|
||||
|
||||
_disconnectHandler(handler) {
|
||||
if (this._settings && handler.id > 0)
|
||||
this._settings.disconnect(handler.id);
|
||||
handler.id = 0;
|
||||
}
|
||||
|
||||
_onInstalledChanged() {
|
||||
let hadApp = (this._app != null);
|
||||
this._app = this._appSystem.lookup_app(this._appId);
|
||||
let haveApp = (this._app != null);
|
||||
|
||||
if (hadApp == haveApp)
|
||||
return;
|
||||
|
||||
if (haveApp)
|
||||
this._checkSettings();
|
||||
else
|
||||
this._setSettings(null);
|
||||
}
|
||||
|
||||
_setSettings(settings) {
|
||||
this._handlers.forEach((handler) => { this._disconnectHandler(handler); });
|
||||
|
||||
let hadSettings = (this._settings != null);
|
||||
this._settings = settings;
|
||||
let haveSettings = (this._settings != null);
|
||||
|
||||
this._handlers.forEach((handler) => { this._connectHandler(handler); });
|
||||
|
||||
if (hadSettings != haveSettings)
|
||||
this.emit('available-changed');
|
||||
}
|
||||
|
||||
_checkSettings() {
|
||||
let schema = this._schemaSource.lookup(this._schemaId, true);
|
||||
if (schema) {
|
||||
this._setSettings(new Gio.Settings({ settings_schema: schema }));
|
||||
} else if (this._app) {
|
||||
Mainloop.timeout_add_seconds(1, () => {
|
||||
this._checkSettings();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(AppSettingsMonitor.prototype);
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const { Geoclue, Gio, GLib, GWeather } = imports.gi;
|
||||
const { Geoclue, Gio, GLib, GWeather, Shell } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const PermissionStore = imports.misc.permissionStore;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
|
||||
|
||||
const WEATHER_BUS_NAME = 'org.gnome.Weather';
|
||||
const WEATHER_OBJECT_PATH = '/org/gnome/Weather';
|
||||
const WEATHER_INTEGRATION_IFACE = 'org.gnome.Shell.WeatherIntegration';
|
||||
|
||||
const WEATHER_APP_ID = 'org.gnome.Weather.desktop';
|
||||
|
||||
// Minimum time between updates to show loading indication
|
||||
var UPDATE_THRESHOLD = 10 * GLib.TIME_SPAN_MINUTE;
|
||||
@@ -26,7 +35,7 @@ var WeatherClient = class {
|
||||
this._weatherAuthorized = false;
|
||||
this._permStore = new PermissionStore.PermissionStore((proxy, error) => {
|
||||
if (error) {
|
||||
log('Failed to connect to permissionStore: ' + error.message);
|
||||
log(`Failed to connect to permissionStore: ${error.message}`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -40,7 +49,7 @@ var WeatherClient = class {
|
||||
|
||||
this._permStore.LookupRemote('gnome', 'geolocation', (res, error) => {
|
||||
if (error)
|
||||
log('Error looking up permission: ' + error.message);
|
||||
log(`Error looking up permission: ${error.message}`);
|
||||
|
||||
let [perms, data] = error ? [{}, null] : res;
|
||||
let params = ['gnome', 'geolocation', false, data, perms];
|
||||
@@ -66,17 +75,38 @@ var WeatherClient = class {
|
||||
this.emit('changed');
|
||||
});
|
||||
|
||||
this._weatherAppMon = new Util.AppSettingsMonitor('org.gnome.Weather.desktop',
|
||||
'org.gnome.Weather');
|
||||
this._weatherAppMon.connect('available-changed', () => { this.emit('changed'); });
|
||||
this._weatherAppMon.watchSetting('automatic-location',
|
||||
this._onAutomaticLocationChanged.bind(this));
|
||||
this._weatherAppMon.watchSetting('locations',
|
||||
this._onLocationsChanged.bind(this));
|
||||
this._weatherApp = null;
|
||||
this._weatherProxy = null;
|
||||
|
||||
let nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
|
||||
Gio.DBusProxy.new(
|
||||
Gio.DBus.session,
|
||||
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
|
||||
nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
|
||||
WEATHER_BUS_NAME,
|
||||
WEATHER_OBJECT_PATH,
|
||||
WEATHER_INTEGRATION_IFACE,
|
||||
null,
|
||||
this._onWeatherProxyReady.bind(this));
|
||||
|
||||
this._settings = new Gio.Settings({
|
||||
schema_id: 'org.gnome.shell.weather'
|
||||
});
|
||||
this._settings.connect('changed::automatic-location',
|
||||
this._onAutomaticLocationChanged.bind(this));
|
||||
this._onAutomaticLocationChanged();
|
||||
this._settings.connect('changed::locations',
|
||||
this._onLocationsChanged.bind(this));
|
||||
this._onLocationsChanged();
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('installed-changed',
|
||||
this._onInstalledChanged.bind(this));
|
||||
this._onInstalledChanged();
|
||||
}
|
||||
|
||||
get available() {
|
||||
return this._weatherAppMon.available;
|
||||
return this._weatherApp != null;
|
||||
}
|
||||
|
||||
get loading() {
|
||||
@@ -92,7 +122,8 @@ var WeatherClient = class {
|
||||
}
|
||||
|
||||
activateApp() {
|
||||
this._weatherAppMon.activateApp();
|
||||
if (this._weatherApp)
|
||||
this._weatherApp.activate();
|
||||
}
|
||||
|
||||
update() {
|
||||
@@ -114,6 +145,38 @@ var WeatherClient = class {
|
||||
this._weatherAuthorized;
|
||||
}
|
||||
|
||||
_onWeatherProxyReady(o, res) {
|
||||
try {
|
||||
this._weatherProxy = Gio.DBusProxy.new_finish(res);
|
||||
} catch (e) {
|
||||
log(`Failed to create GNOME Weather proxy: ${e}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._weatherProxy.connect('g-properties-changed',
|
||||
this._onWeatherPropertiesChanged.bind(this));
|
||||
this._onWeatherPropertiesChanged();
|
||||
}
|
||||
|
||||
_onWeatherPropertiesChanged() {
|
||||
if (this._weatherProxy.g_name_owner == null)
|
||||
return;
|
||||
|
||||
this._settings.set_boolean('automatic-location',
|
||||
this._weatherProxy.AutomaticLocation);
|
||||
this._settings.set_value('locations',
|
||||
new GLib.Variant('av', this._weatherProxy.Locations));
|
||||
}
|
||||
|
||||
_onInstalledChanged() {
|
||||
let hadApp = (this._weatherApp != null);
|
||||
this._weatherApp = this._appSystem.lookup_app(WEATHER_APP_ID);
|
||||
let haveApp = (this._weatherApp != null);
|
||||
|
||||
if (hadApp !== haveApp)
|
||||
this.emit('changed');
|
||||
}
|
||||
|
||||
_loadInfo() {
|
||||
let id = this._weatherInfo.connect('updated', () => {
|
||||
this._weatherInfo.disconnect(id);
|
||||
@@ -178,8 +241,8 @@ var WeatherClient = class {
|
||||
(o, res) => {
|
||||
try {
|
||||
this._gclueService = Geoclue.Simple.new_finish(res);
|
||||
} catch(e) {
|
||||
log('Failed to connect to Geoclue2 service: ' + e.message);
|
||||
} catch (e) {
|
||||
log(`Failed to connect to Geoclue2 service: ${e.message}`);
|
||||
this._setLocation(this._mostRecentLocation);
|
||||
return;
|
||||
}
|
||||
@@ -198,8 +261,8 @@ var WeatherClient = class {
|
||||
this._setLocation(location);
|
||||
}
|
||||
|
||||
_onAutomaticLocationChanged(settings, key) {
|
||||
let useAutoLocation = settings.get_boolean(key);
|
||||
_onAutomaticLocationChanged() {
|
||||
let useAutoLocation = this._settings.get_boolean('automatic-location');
|
||||
if (this._autoLocationRequested == useAutoLocation)
|
||||
return;
|
||||
|
||||
@@ -217,8 +280,9 @@ var WeatherClient = class {
|
||||
this._setLocation(this._mostRecentLocation);
|
||||
}
|
||||
|
||||
_onLocationsChanged(settings, key) {
|
||||
let serialized = settings.get_value(key).deep_unpack().shift();
|
||||
_onLocationsChanged() {
|
||||
let locations = this._settings.get_value('locations').deep_unpack();
|
||||
let serialized = locations.shift();
|
||||
let mostRecentLocation = null;
|
||||
|
||||
if (serialized)
|
||||
@@ -234,7 +298,7 @@ var WeatherClient = class {
|
||||
}
|
||||
|
||||
_onPermStoreChanged(proxy, sender, params) {
|
||||
let [table, id, deleted, data, perms] = params;
|
||||
let [table, id, deleted_, data_, perms] = params;
|
||||
|
||||
if (table != 'gnome' || id != 'geolocation')
|
||||
return;
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported run, script_overviewShowStart, script_overviewShowDone,
|
||||
script_applicationsShowStart, script_applicationsShowDone,
|
||||
script_afterShowHide, malloc_usedSize, glx_swapComplete,
|
||||
clutter_stagePaintDone */
|
||||
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
|
||||
|
||||
const System = imports.system;
|
||||
|
||||
@@ -19,7 +24,7 @@ var METRICS = {
|
||||
units: "frames / s" },
|
||||
overviewLatencySubsequent:
|
||||
{ description: "Time to first frame after triggering overview, second time",
|
||||
units: "us"},
|
||||
units: "us" },
|
||||
overviewFpsSubsequent:
|
||||
{ description: "Frames rate when going to the overview, second time",
|
||||
units: "frames / s" },
|
||||
@@ -52,7 +57,7 @@ var METRICS = {
|
||||
units: "us" },
|
||||
applicationsShowTimeSubsequent:
|
||||
{ description: "Time to switch to applications view, second time",
|
||||
units: "us"}
|
||||
units: "us" }
|
||||
};
|
||||
|
||||
let WINDOW_CONFIGS = [
|
||||
@@ -121,10 +126,12 @@ function *run() {
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
Scripting.scriptEvent('applicationsShowStart');
|
||||
Main.overview._dash.showAppsButton.checked = true;
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
Main.overview.dash.showAppsButton.checked = true;
|
||||
yield Scripting.waitLeisure();
|
||||
Scripting.scriptEvent('applicationsShowDone');
|
||||
Main.overview._dash.showAppsButton.checked = false;
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
Main.overview.dash.showAppsButton.checked = false;
|
||||
yield Scripting.waitLeisure();
|
||||
}
|
||||
}
|
||||
@@ -136,7 +143,6 @@ let overviewFrames;
|
||||
let overviewLatency;
|
||||
let mallocUsedSize = 0;
|
||||
let overviewShowCount = 0;
|
||||
let firstOverviewUsedSize;
|
||||
let haveSwapComplete = false;
|
||||
let applicationsShowStart;
|
||||
let applicationsShowCount = 0;
|
||||
@@ -148,7 +154,7 @@ function script_overviewShowStart(time) {
|
||||
overviewFrames = 0;
|
||||
}
|
||||
|
||||
function script_overviewShowDone(time) {
|
||||
function script_overviewShowDone(_time) {
|
||||
// We've set up the state at the end of the zoom out, but we
|
||||
// need to wait for one more frame to paint before we count
|
||||
// ourselves as done.
|
||||
@@ -167,7 +173,7 @@ function script_applicationsShowDone(time) {
|
||||
METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
|
||||
}
|
||||
|
||||
function script_afterShowHide(time) {
|
||||
function script_afterShowHide(_time) {
|
||||
if (overviewShowCount == 1) {
|
||||
METRICS.usedAfterOverview.value = mallocUsedSize;
|
||||
} else {
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
/* exported run, script_desktopShown, script_overviewShowStart,
|
||||
script_overviewShowDone, script_applicationsShowStart,
|
||||
script_applicationsShowDone, script_mainViewDrawStart,
|
||||
script_mainViewDrawDone, script_overviewDrawStart,
|
||||
script_overviewDrawDone, script_redrawTestStart,
|
||||
script_redrawTestDone, script_collectTimings,
|
||||
script_geditLaunch, script_geditFirstFrame,
|
||||
clutter_stagePaintStart, clutter_paintCompletedTimestamp */
|
||||
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^clutter"] }] */
|
||||
const { Clutter, Gio, Shell } = imports.gi;
|
||||
const Main = imports.ui.main;
|
||||
const Scripting = imports.ui.scripting;
|
||||
@@ -30,7 +39,7 @@ var METRICS = {
|
||||
geditStartTime:
|
||||
{ description: "Time from gedit launch to window drawn",
|
||||
units: "us" },
|
||||
}
|
||||
};
|
||||
|
||||
function waitAndDraw(milliseconds) {
|
||||
let cb;
|
||||
@@ -38,7 +47,7 @@ function waitAndDraw(milliseconds) {
|
||||
let timeline = new Clutter.Timeline({ duration: milliseconds });
|
||||
timeline.start();
|
||||
|
||||
timeline.connect('new-frame', (timeline, frame) => {
|
||||
timeline.connect('new-frame', (_timeline, _frame) => {
|
||||
global.stage.queue_redraw();
|
||||
});
|
||||
|
||||
@@ -48,7 +57,7 @@ function waitAndDraw(milliseconds) {
|
||||
cb();
|
||||
});
|
||||
|
||||
return callback => { cb = callback; };
|
||||
return callback => (cb = callback);
|
||||
}
|
||||
|
||||
function waitSignal(object, signal) {
|
||||
@@ -60,7 +69,7 @@ function waitSignal(object, signal) {
|
||||
cb();
|
||||
});
|
||||
|
||||
return callback => { cb = callback; };
|
||||
return callback => (cb = callback);
|
||||
}
|
||||
|
||||
function extractBootTimestamp() {
|
||||
@@ -73,8 +82,8 @@ function extractBootTimestamp() {
|
||||
let result = null;
|
||||
|
||||
let datastream = Gio.DataInputStream.new(sp.get_stdout_pipe());
|
||||
while (true) {
|
||||
let [line, length] = datastream.read_line_utf8(null);
|
||||
while (true) { // eslint-disable-line no-constant-condition
|
||||
let [line, length_] = datastream.read_line_utf8(null);
|
||||
if (line === null)
|
||||
break;
|
||||
|
||||
@@ -117,7 +126,8 @@ function *run() {
|
||||
yield Scripting.sleep(1000);
|
||||
|
||||
Scripting.scriptEvent('applicationsShowStart');
|
||||
Main.overview._dash.showAppsButton.checked = true;
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
Main.overview.dash.showAppsButton.checked = true;
|
||||
|
||||
yield Scripting.waitLeisure();
|
||||
Scripting.scriptEvent('applicationsShowDone');
|
||||
@@ -127,9 +137,9 @@ function *run() {
|
||||
Main.overview.hide();
|
||||
yield Scripting.waitLeisure();
|
||||
|
||||
////////////////////////////////////////
|
||||
// Tests of redraw speed
|
||||
////////////////////////////////////////
|
||||
// --------------------- //
|
||||
// Tests of redraw speed //
|
||||
// --------------------- //
|
||||
|
||||
global.frame_timestamps = true;
|
||||
global.frame_finish_timestamp = true;
|
||||
@@ -157,7 +167,7 @@ function *run() {
|
||||
Main.overview.hide();
|
||||
|
||||
yield Scripting.createTestWindow({ maximized: true,
|
||||
redraws: true});
|
||||
redraws: true });
|
||||
yield Scripting.waitTestWindows();
|
||||
|
||||
yield Scripting.sleep(1000);
|
||||
@@ -176,8 +186,6 @@ function *run() {
|
||||
|
||||
yield Scripting.sleep(1000);
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let app = appSys.lookup_app('org.gnome.gedit.desktop');
|
||||
|
||||
@@ -234,31 +242,31 @@ function script_applicationsShowDone(time) {
|
||||
METRICS.applicationsShowTime.value = time - applicationsShowStart;
|
||||
}
|
||||
|
||||
function script_mainViewDrawStart(time) {
|
||||
function script_mainViewDrawStart(_time) {
|
||||
redrawTiming = 'mainView';
|
||||
}
|
||||
|
||||
function script_mainViewDrawDone(time) {
|
||||
function script_mainViewDrawDone(_time) {
|
||||
redrawTiming = null;
|
||||
}
|
||||
|
||||
function script_overviewDrawStart(time) {
|
||||
function script_overviewDrawStart(_time) {
|
||||
redrawTiming = 'overview';
|
||||
}
|
||||
|
||||
function script_overviewDrawDone(time) {
|
||||
function script_overviewDrawDone(_time) {
|
||||
redrawTiming = null;
|
||||
}
|
||||
|
||||
function script_redrawTestStart(time) {
|
||||
function script_redrawTestStart(_time) {
|
||||
redrawTiming = 'application';
|
||||
}
|
||||
|
||||
function script_redrawTestDone(time) {
|
||||
function script_redrawTestDone(_time) {
|
||||
redrawTiming = null;
|
||||
}
|
||||
|
||||
function script_collectTimings(time) {
|
||||
function script_collectTimings(_time) {
|
||||
for (let timing in redrawTimes) {
|
||||
let times = redrawTimes[timing];
|
||||
times.sort((a, b) => a - b);
|
||||
@@ -269,11 +277,11 @@ function script_collectTimings(time) {
|
||||
if (len == 0)
|
||||
median = -1;
|
||||
else if (len % 2 == 1)
|
||||
median = times[(len - 1)/ 2];
|
||||
median = times[(len - 1) / 2];
|
||||
else
|
||||
median = Math.round((times[len / 2 - 1] + times[len / 2]) / 2);
|
||||
|
||||
METRICS[timing + 'RedrawTime'].value = median;
|
||||
METRICS[`${timing}RedrawTime`].value = median;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported main */
|
||||
const Format = imports.format;
|
||||
const Gettext = imports.gettext;
|
||||
const { Gio, GLib, GObject, Gtk, Pango, Soup, WebKit2: WebKit } = imports.gi;
|
||||
@@ -19,7 +20,6 @@ const PortalHelperSecurityLevel = {
|
||||
INSECURE: 2
|
||||
};
|
||||
|
||||
const INACTIVITY_TIMEOUT = 30000; //ms
|
||||
const CONNECTIVITY_CHECK_HOST = 'nmcheck.gnome.org';
|
||||
const CONNECTIVITY_CHECK_URI = 'http://' + CONNECTIVITY_CHECK_HOST;
|
||||
const CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT = 30 * GLib.USEC_PER_SEC;
|
||||
@@ -59,7 +59,7 @@ class PortalHeaderBar extends Gtk.HeaderBar {
|
||||
single_line_mode: true,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
valign: Gtk.Align.BASELINE,
|
||||
selectable: true});
|
||||
selectable: true });
|
||||
this.subtitleLabel.get_style_context().add_class('subtitle');
|
||||
hbox.add(this.subtitleLabel);
|
||||
|
||||
@@ -152,7 +152,7 @@ class PortalWindow extends Gtk.ApplicationWindow {
|
||||
this._webView.load_uri(this._originalUrl);
|
||||
}
|
||||
|
||||
vfunc_delete_event(event) {
|
||||
vfunc_delete_event(_event) {
|
||||
if (this._recheckAtExit)
|
||||
this._doneCallback(PortalHelperResult.RECHECK);
|
||||
else
|
||||
@@ -178,7 +178,7 @@ class PortalWindow extends Gtk.ApplicationWindow {
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
|
||||
}
|
||||
|
||||
_onLoadFailedWithTlsErrors(view, failingURI, certificate, errors) {
|
||||
_onLoadFailedWithTlsErrors(view, failingURI, certificate, _errors) {
|
||||
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
|
||||
let uri = new Soup.URI(failingURI);
|
||||
this._webContext.allow_tls_certificate_for_host(certificate, uri.get_host());
|
||||
@@ -265,7 +265,7 @@ class WebPortalHelper extends Gtk.Application {
|
||||
this._queue = [];
|
||||
|
||||
let action = new Gio.SimpleAction({ name: 'quit' });
|
||||
action.connect('activate', () => { this.active_window.destroyWindow(); });
|
||||
action.connect('activate', () => this.active_window.destroyWindow());
|
||||
this.add_action(action);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported AccessDialogDBus */
|
||||
const { Clutter, Gio, GLib, GObject, Shell } = imports.gi;
|
||||
|
||||
const CheckBox = imports.ui.checkBox;
|
||||
@@ -55,8 +56,8 @@ class AccessDialog extends ModalDialog.ModalDialog {
|
||||
|
||||
let check = new CheckBox.CheckBox();
|
||||
check.getLabelActor().text = name;
|
||||
check.actor.checked = selected == "true";
|
||||
content.insertBeforeBody(check.actor);
|
||||
check.checked = selected == "true";
|
||||
content.insertBeforeBody(check);
|
||||
|
||||
this._choices.set(id, check);
|
||||
}
|
||||
@@ -69,7 +70,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
|
||||
this.addButton({ label: grantLabel,
|
||||
action: () => {
|
||||
this._sendResponse(DialogResponse.OK);
|
||||
}});
|
||||
} });
|
||||
}
|
||||
|
||||
open() {
|
||||
@@ -79,7 +80,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
|
||||
this._requestExported = this._request.export(connection, this._handle);
|
||||
}
|
||||
|
||||
CloseAsync(invocation, params) {
|
||||
CloseAsync(invocation, _params) {
|
||||
if (this._invocation.get_sender() != invocation.get_sender()) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
@@ -98,7 +99,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
|
||||
let results = {};
|
||||
if (response == DialogResponse.OK) {
|
||||
for (let [id, check] of this._choices) {
|
||||
let checked = check.actor.checked ? 'true' : 'false';
|
||||
let checked = check.checked ? 'true' : 'false';
|
||||
results[id] = new GLib.Variant('s', checked);
|
||||
}
|
||||
}
|
||||
@@ -132,10 +133,10 @@ var AccessDialogDBus = class {
|
||||
return;
|
||||
}
|
||||
|
||||
let [handle, appId, parentWindow, title, subtitle, body, options] = params;
|
||||
let [handle, appId, parentWindow_, title, subtitle, body, options] = params;
|
||||
// We probably want to use parentWindow and global.display.focus_window
|
||||
// for this check in the future
|
||||
if (appId && appId + '.desktop' != this._windowTracker.focus_app.id) {
|
||||
if (appId && `${appId}.desktop` != this._windowTracker.focus_app.id) {
|
||||
invocation.return_error_literal(Gio.DBusError,
|
||||
Gio.DBusError.ACCESS_DENIED,
|
||||
'Only the focused app is allowed to show a system access dialog');
|
||||
@@ -146,7 +147,7 @@ var AccessDialogDBus = class {
|
||||
subtitle, body, options);
|
||||
dialog.open();
|
||||
|
||||
dialog.connect('closed', () => { this._accessDialog = null; });
|
||||
dialog.connect('closed', () => (this._accessDialog = null));
|
||||
|
||||
this._accessDialog = dialog;
|
||||
}
|
||||
|
||||
225
js/ui/altTab.js
225
js/ui/altTab.js
@@ -1,17 +1,17 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported AppSwitcherPopup, GroupCyclerPopup, WindowSwitcherPopup,
|
||||
WindowCyclerPopup */
|
||||
|
||||
const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const SwitcherPopup = imports.ui.switcherPopup;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
var APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
|
||||
|
||||
var THUMBNAIL_DEFAULT_SIZE = 256;
|
||||
var THUMBNAIL_POPUP_TIME = 500; // milliseconds
|
||||
var THUMBNAIL_FADE_TIME = 0.1; // seconds
|
||||
var THUMBNAIL_FADE_TIME = 100; // milliseconds
|
||||
|
||||
var WINDOW_PREVIEW_SIZE = 128;
|
||||
var APP_ICON_SIZE = 96;
|
||||
@@ -28,15 +28,21 @@ var AppIconMode = {
|
||||
function _createWindowClone(window, size) {
|
||||
let [width, height] = window.get_size();
|
||||
let scale = Math.min(1.0, size / width, size / height);
|
||||
return new Clutter.Clone({ source: window,
|
||||
width: width * scale,
|
||||
height: height * scale,
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
// usual hack for the usual bug in ClutterBinLayout...
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
};
|
||||
|
||||
let cloneWidth = size;
|
||||
let cloneHeight = size;
|
||||
|
||||
if (width > height)
|
||||
cloneHeight = size * (height / width);
|
||||
else
|
||||
cloneWidth = size * (width / height);
|
||||
|
||||
return new Clutter.Actor({
|
||||
content: window.content,
|
||||
width: cloneWidth,
|
||||
height: cloneHeight,
|
||||
});
|
||||
}
|
||||
|
||||
function getWindows(workspace) {
|
||||
// We ignore skip-taskbar windows in switchers, but if they are attached
|
||||
@@ -87,9 +93,9 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
let hPadding = leftPadding + rightPadding;
|
||||
|
||||
let icon = this._items[this._selectedIndex];
|
||||
let [posX, posY] = icon.get_transformed_position();
|
||||
let [posX] = icon.get_transformed_position();
|
||||
let thumbnailCenter = posX + icon.width / 2;
|
||||
let [childMinWidth, childNaturalWidth] = this._thumbnails.get_preferred_width(-1);
|
||||
let [, childNaturalWidth] = this._thumbnails.get_preferred_width(-1);
|
||||
childBox.x1 = Math.max(primary.x + leftPadding, Math.floor(thumbnailCenter - childNaturalWidth / 2));
|
||||
if (childBox.x1 + childNaturalWidth > primary.x + primary.width - hPadding) {
|
||||
let offset = childBox.x1 + childNaturalWidth - primary.width + hPadding;
|
||||
@@ -103,7 +109,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
childBox.x2 = primary.x + primary.width - rightPadding;
|
||||
childBox.y1 = this._switcherList.allocation.y2 + spacing;
|
||||
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
|
||||
let [childMinHeight, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
|
||||
let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
|
||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||
this._thumbnails.allocate(childBox, flags);
|
||||
}
|
||||
@@ -291,7 +297,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
if (this._thumbnails)
|
||||
this._destroyThumbnails();
|
||||
if (this._thumbnailTimeoutId != 0)
|
||||
Mainloop.source_remove(this._thumbnailTimeoutId);
|
||||
GLib.source_remove(this._thumbnailTimeoutId);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -326,7 +332,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
}
|
||||
|
||||
if (this._thumbnailTimeoutId != 0) {
|
||||
Mainloop.source_remove(this._thumbnailTimeoutId);
|
||||
GLib.source_remove(this._thumbnailTimeoutId);
|
||||
this._thumbnailTimeoutId = 0;
|
||||
}
|
||||
|
||||
@@ -343,7 +349,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
this._thumbnails.highlight(window, forceAppFocus);
|
||||
} else if (this._items[this._selectedIndex].cachedWindows.length > 1 &&
|
||||
!forceAppFocus) {
|
||||
this._thumbnailTimeoutId = Mainloop.timeout_add (
|
||||
this._thumbnailTimeoutId = GLib.timeout_add(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
THUMBNAIL_POPUP_TIME,
|
||||
this._timeoutPopupThumbnails.bind(this));
|
||||
GLib.Source.set_name_by_id(this._thumbnailTimeoutId, '[gnome-shell] this._timeoutPopupThumbnails');
|
||||
@@ -360,15 +367,15 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
|
||||
_destroyThumbnails() {
|
||||
let thumbnailsActor = this._thumbnails;
|
||||
Tweener.addTween(thumbnailsActor,
|
||||
{ opacity: 0,
|
||||
time: THUMBNAIL_FADE_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: () => {
|
||||
thumbnailsActor.destroy();
|
||||
this.thumbnailsVisible = false;
|
||||
}
|
||||
});
|
||||
this._thumbnails.ease({
|
||||
opacity: 0,
|
||||
duration: THUMBNAIL_FADE_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
thumbnailsActor.destroy();
|
||||
this.thumbnailsVisible = false;
|
||||
}
|
||||
});
|
||||
this._thumbnails = null;
|
||||
if (this._switcherList._items[this._selectedIndex])
|
||||
this._switcherList._items[this._selectedIndex].remove_accessible_state (Atk.StateType.EXPANDED);
|
||||
@@ -391,38 +398,39 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
this._thumbnails.get_allocation_box();
|
||||
|
||||
this._thumbnails.opacity = 0;
|
||||
Tweener.addTween(this._thumbnails,
|
||||
{ opacity: 255,
|
||||
time: THUMBNAIL_FADE_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: () => { this.thumbnailsVisible = true; }
|
||||
});
|
||||
this._thumbnails.ease({
|
||||
opacity: 255,
|
||||
duration: THUMBNAIL_FADE_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
this.thumbnailsVisible = true;
|
||||
}
|
||||
});
|
||||
|
||||
this._switcherList._items[this._selectedIndex].add_accessible_state (Atk.StateType.EXPANDED);
|
||||
}
|
||||
});
|
||||
|
||||
class CyclerHighlight {
|
||||
constructor() {
|
||||
var CyclerHighlight = GObject.registerClass(
|
||||
class CyclerHighlight extends St.Widget {
|
||||
_init() {
|
||||
super._init({ layout_manager: new Clutter.BinLayout() });
|
||||
this._window = null;
|
||||
|
||||
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
|
||||
this._clone = new Clutter.Clone();
|
||||
this.actor.add_actor(this._clone);
|
||||
this._clone = new Clutter.Actor();
|
||||
this.add_actor(this._clone);
|
||||
|
||||
this._highlight = new St.Widget({ style_class: 'cycler-highlight' });
|
||||
this.actor.add_actor(this._highlight);
|
||||
this.add_actor(this._highlight);
|
||||
|
||||
let coordinate = Clutter.BindCoordinate.ALL;
|
||||
let constraint = new Clutter.BindConstraint({ coordinate: coordinate });
|
||||
this._clone.bind_property('source', constraint, 'source', 0);
|
||||
|
||||
this.actor.add_constraint(constraint);
|
||||
this.add_constraint(constraint);
|
||||
|
||||
this.actor.connect('notify::allocation',
|
||||
this._onAllocationChanged.bind(this));
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
this.connect('notify::allocation', this._onAllocationChanged.bind(this));
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
}
|
||||
|
||||
set window(w) {
|
||||
@@ -431,16 +439,16 @@ class CyclerHighlight {
|
||||
|
||||
this._window = w;
|
||||
|
||||
if (this._clone.source)
|
||||
this._clone.source.sync_visibility();
|
||||
if (this._clone.content)
|
||||
this._clone.content.window_actor.sync_visibility();
|
||||
|
||||
let windowActor = this._window ? this._window.get_compositor_private()
|
||||
: null;
|
||||
let windowActor = this._window
|
||||
? this._window.get_compositor_private() : null;
|
||||
|
||||
if (windowActor)
|
||||
windowActor.hide();
|
||||
|
||||
this._clone.source = windowActor;
|
||||
this._clone.content = windowActor.content;
|
||||
}
|
||||
|
||||
_onAllocationChanged() {
|
||||
@@ -448,7 +456,7 @@ class CyclerHighlight {
|
||||
this._highlight.set_size(0, 0);
|
||||
this._highlight.hide();
|
||||
} else {
|
||||
let [x, y] = this.actor.allocation.get_origin();
|
||||
let [x, y] = this.allocation.get_origin();
|
||||
let rect = this._window.get_frame_rect();
|
||||
this._highlight.set_size(rect.width, rect.height);
|
||||
this._highlight.set_position(rect.x - x, rect.y - y);
|
||||
@@ -459,7 +467,7 @@ class CyclerHighlight {
|
||||
_onDestroy() {
|
||||
this.window = null;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
// We don't show an actual popup, so just provide what SwitcherPopup
|
||||
// expects instead of inheriting from SwitcherList
|
||||
@@ -469,7 +477,7 @@ var CyclerList = GObject.registerClass({
|
||||
'item-removed': { param_types: [GObject.TYPE_INT] },
|
||||
'item-highlighted': { param_types: [GObject.TYPE_INT] } },
|
||||
}, class CyclerList extends St.Widget {
|
||||
highlight(index, justOutline) {
|
||||
highlight(index, _justOutline) {
|
||||
this.emit('item-highlighted', index);
|
||||
}
|
||||
});
|
||||
@@ -486,7 +494,7 @@ var CyclerPopup = GObject.registerClass({
|
||||
return;
|
||||
|
||||
this._highlight = new CyclerHighlight();
|
||||
global.window_group.add_actor(this._highlight.actor);
|
||||
global.window_group.add_actor(this._highlight);
|
||||
|
||||
this._switcherList = new CyclerList();
|
||||
this._switcherList.connect('item-highlighted', (list, index) => {
|
||||
@@ -494,9 +502,9 @@ var CyclerPopup = GObject.registerClass({
|
||||
});
|
||||
}
|
||||
|
||||
_highlightItem(index, justOutline) {
|
||||
_highlightItem(index, _justOutline) {
|
||||
this._highlight.window = this._items[index];
|
||||
global.window_group.set_child_above_sibling(this._highlight.actor, null);
|
||||
global.window_group.set_child_above_sibling(this._highlight, null);
|
||||
}
|
||||
|
||||
_finish() {
|
||||
@@ -526,7 +534,7 @@ var CyclerPopup = GObject.registerClass({
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
this._highlight.actor.destroy();
|
||||
this._highlight.destroy();
|
||||
|
||||
super._onDestroy();
|
||||
}
|
||||
@@ -645,8 +653,9 @@ class WindowCyclerPopup extends CyclerPopup {
|
||||
}
|
||||
});
|
||||
|
||||
var AppIcon = GObject.registerClass(
|
||||
class AppIcon extends St.BoxLayout {
|
||||
var AppIcon = GObject.registerClass({
|
||||
GTypeName: 'AltTab_AppIcon'
|
||||
}, class AppIcon extends St.BoxLayout {
|
||||
_init(app) {
|
||||
super._init({ style_class: 'alt-tab-app',
|
||||
vertical: true });
|
||||
@@ -660,17 +669,10 @@ class AppIcon extends St.BoxLayout {
|
||||
this.add(this.label, { x_fill: false });
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
set_size(size) {
|
||||
this.icon = this.app.create_icon_texture(size);
|
||||
this._iconBin.child = this.icon;
|
||||
this._iconBin.set_size(size, size);
|
||||
}
|
||||
|
||||
vfunc_get_preferred_width(forHeight) {
|
||||
let [minWidth, ] = super.vfunc_get_preferred_width(forHeight);
|
||||
|
||||
minWidth = Math.max(minWidth, forHeight);
|
||||
return [minWidth, minWidth];
|
||||
}
|
||||
});
|
||||
|
||||
@@ -715,7 +717,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
|
||||
_onDestroy() {
|
||||
if (this._mouseTimeOutId != 0)
|
||||
Mainloop.source_remove(this._mouseTimeOutId);
|
||||
GLib.source_remove(this._mouseTimeOutId);
|
||||
|
||||
this.icons.forEach(icon => {
|
||||
icon.app.disconnect(icon._stateChangedId);
|
||||
@@ -724,15 +726,16 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
|
||||
_setIconSize() {
|
||||
let j = 0;
|
||||
while(this._items.length > 1 && this._items[j].style_class != 'item-box') {
|
||||
j++;
|
||||
while (this._items.length > 1 && this._items[j].style_class != 'item-box') {
|
||||
j++;
|
||||
}
|
||||
let themeNode = this._items[j].get_theme_node();
|
||||
this._list.ensure_style();
|
||||
|
||||
let iconPadding = themeNode.get_horizontal_padding();
|
||||
let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT);
|
||||
let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
|
||||
let iconSpacing = iconNaturalHeight + iconPadding + iconBorder;
|
||||
let [, labelNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
|
||||
let iconSpacing = labelNaturalHeight + iconPadding + iconBorder;
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
|
||||
// We just assume the whole screen here due to weirdness happing with the passed width
|
||||
@@ -745,7 +748,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
let iconSize = baseIconSizes[0];
|
||||
|
||||
if (this._items.length > 1) {
|
||||
for(let i = 0; i < baseIconSizes.length; i++) {
|
||||
for (let i = 0; i < baseIconSizes.length; i++) {
|
||||
iconSize = baseIconSizes[i];
|
||||
let height = iconSizes[i] + iconSpacing;
|
||||
let w = height * this._items.length + totalSpacing;
|
||||
@@ -756,7 +759,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
|
||||
this._iconSize = iconSize;
|
||||
|
||||
for(let i = 0; i < this.icons.length; i++) {
|
||||
for (let i = 0; i < this.icons.length; i++) {
|
||||
if (this.icons[i].icon != null)
|
||||
break;
|
||||
this.icons[i].set_size(iconSize);
|
||||
@@ -793,21 +796,24 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
// activation when the thumbnail list is open
|
||||
_onItemEnter(index) {
|
||||
if (this._mouseTimeOutId != 0)
|
||||
Mainloop.source_remove(this._mouseTimeOutId);
|
||||
GLib.source_remove(this._mouseTimeOutId);
|
||||
if (this._altTabPopup.thumbnailsVisible) {
|
||||
this._mouseTimeOutId = Mainloop.timeout_add(APP_ICON_HOVER_TIMEOUT,
|
||||
() => {
|
||||
this._enterItem(index);
|
||||
this._mouseTimeOutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
this._mouseTimeOutId = GLib.timeout_add(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
APP_ICON_HOVER_TIMEOUT,
|
||||
() => {
|
||||
this._enterItem(index);
|
||||
this._mouseTimeOutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
GLib.Source.set_name_by_id(this._mouseTimeOutId, '[gnome-shell] this._enterItem');
|
||||
} else
|
||||
this._itemEntered(index);
|
||||
} else {
|
||||
this._itemEntered(index);
|
||||
}
|
||||
}
|
||||
|
||||
_enterItem(index) {
|
||||
let [x, y, mask] = global.get_pointer();
|
||||
let [x, y] = global.get_pointer();
|
||||
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
|
||||
if (this._items[index].contains(pickedActor))
|
||||
this._itemEntered(index);
|
||||
@@ -848,9 +854,8 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
this._removeIcon(app);
|
||||
});
|
||||
|
||||
let n = this._arrows.length;
|
||||
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
||||
arrow.connect('repaint', () => { SwitcherPopup.drawArrow(arrow, St.Side.BOTTOM); });
|
||||
arrow.connect('repaint', () => SwitcherPopup.drawArrow(arrow, St.Side.BOTTOM));
|
||||
this.add_actor(arrow);
|
||||
this._arrows.push(arrow);
|
||||
|
||||
@@ -877,9 +882,9 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
|
||||
_init(windows) {
|
||||
super._init(false);
|
||||
|
||||
this._labels = new Array();
|
||||
this._thumbnailBins = new Array();
|
||||
this._clones = new Array();
|
||||
this._labels = [];
|
||||
this._thumbnailBins = [];
|
||||
this._clones = [];
|
||||
this._windows = windows;
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
@@ -915,7 +920,7 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
|
||||
return;
|
||||
let totalPadding = this._items[0].get_theme_node().get_horizontal_padding() + this._items[0].get_theme_node().get_vertical_padding();
|
||||
totalPadding += this.get_theme_node().get_horizontal_padding() + this.get_theme_node().get_vertical_padding();
|
||||
let [labelMinHeight, labelNaturalHeight] = this._labels[0].get_preferred_height(-1);
|
||||
let [, labelNaturalHeight] = this._labels[0].get_preferred_height(-1);
|
||||
let spacing = this._items[0].child.get_theme_node().get_length('spacing');
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
let thumbnailSize = THUMBNAIL_DEFAULT_SIZE * scaleFactor;
|
||||
@@ -940,7 +945,7 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
|
||||
}
|
||||
|
||||
// Make sure we only do this once
|
||||
this._thumbnailBins = new Array();
|
||||
this._thumbnailBins = [];
|
||||
}
|
||||
|
||||
_removeThumbnail(source, clone) {
|
||||
@@ -991,32 +996,32 @@ class WindowIcon extends St.BoxLayout {
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
|
||||
switch (mode) {
|
||||
case AppIconMode.THUMBNAIL_ONLY:
|
||||
size = WINDOW_PREVIEW_SIZE;
|
||||
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
|
||||
break;
|
||||
case AppIconMode.THUMBNAIL_ONLY:
|
||||
size = WINDOW_PREVIEW_SIZE;
|
||||
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
|
||||
break;
|
||||
|
||||
case AppIconMode.BOTH:
|
||||
size = WINDOW_PREVIEW_SIZE;
|
||||
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
|
||||
case AppIconMode.BOTH:
|
||||
size = WINDOW_PREVIEW_SIZE;
|
||||
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
|
||||
|
||||
if (this.app)
|
||||
this._icon.add_actor(this._createAppIcon(this.app,
|
||||
APP_ICON_SIZE_SMALL));
|
||||
break;
|
||||
if (this.app)
|
||||
this._icon.add_actor(this._createAppIcon(this.app,
|
||||
APP_ICON_SIZE_SMALL));
|
||||
break;
|
||||
|
||||
case AppIconMode.APP_ICON_ONLY:
|
||||
size = APP_ICON_SIZE;
|
||||
this._icon.add_actor(this._createAppIcon(this.app, size));
|
||||
case AppIconMode.APP_ICON_ONLY:
|
||||
size = APP_ICON_SIZE;
|
||||
this._icon.add_actor(this._createAppIcon(this.app, size));
|
||||
}
|
||||
|
||||
this._icon.set_size(size * scaleFactor, size * scaleFactor);
|
||||
}
|
||||
|
||||
_createAppIcon(app, size) {
|
||||
let appIcon = app ? app.create_icon_texture(size)
|
||||
: new St.Icon({ icon_name: 'icon-missing',
|
||||
icon_size: size });
|
||||
let appIcon = app
|
||||
? app.create_icon_texture(size)
|
||||
: new St.Icon({ icon_name: 'icon-missing', icon_size: size });
|
||||
appIcon.x_expand = appIcon.y_expand = true;
|
||||
appIcon.x_align = appIcon.y_align = Clutter.ActorAlign.END;
|
||||
|
||||
@@ -1043,8 +1048,8 @@ class WindowList extends SwitcherPopup.SwitcherList {
|
||||
this.addItem(icon, icon.label);
|
||||
this.icons.push(icon);
|
||||
|
||||
icon._unmanagedSignalId = icon.window.connect('unmanaged', (window) => {
|
||||
this._removeWindow(window)
|
||||
icon._unmanagedSignalId = icon.window.connect('unmanaged', window => {
|
||||
this._removeWindow(window);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1080,7 +1085,7 @@ class WindowList extends SwitcherPopup.SwitcherList {
|
||||
childBox.y1 = childBox.y2 - this._label.height;
|
||||
this._label.allocate(childBox, flags);
|
||||
|
||||
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM)
|
||||
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM);
|
||||
childBox.x1 = box.x1;
|
||||
childBox.x2 = box.x2;
|
||||
childBox.y1 = box.y1;
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Animation, AnimatedIcon, Spinner */
|
||||
|
||||
const { GLib, Gio, St } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const Tweener = imports.ui.tweener;
|
||||
const { Clutter, GLib, GObject, Gio, St } = imports.gi;
|
||||
|
||||
var ANIMATED_ICON_UPDATE_TIMEOUT = 16;
|
||||
var SPINNER_ANIMATION_TIME = 0.3;
|
||||
var SPINNER_ANIMATION_DELAY = 1.0;
|
||||
var SPINNER_ANIMATION_TIME = 300;
|
||||
var SPINNER_ANIMATION_DELAY = 1000;
|
||||
|
||||
var Animation = class {
|
||||
constructor(file, width, height, speed) {
|
||||
this.actor = new St.Bin();
|
||||
this.actor.set_size(width, height);
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
this.actor.connect('notify::size', this._syncAnimationSize.bind(this));
|
||||
this.actor.connect('resource-scale-changed',
|
||||
var Animation = GObject.registerClass(
|
||||
class Animation extends St.Bin {
|
||||
_init(file, width, height, speed) {
|
||||
super._init({ width: width, height: height });
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
this.connect('resource-scale-changed',
|
||||
this._loadFile.bind(this, file, width, height));
|
||||
|
||||
let themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||
@@ -46,7 +43,7 @@ var Animation = class {
|
||||
|
||||
stop() {
|
||||
if (this._timeoutId > 0) {
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
GLib.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
}
|
||||
|
||||
@@ -54,20 +51,30 @@ var Animation = class {
|
||||
}
|
||||
|
||||
_loadFile(file, width, height) {
|
||||
let [validResourceScale, resourceScale] = this.actor.get_resource_scale();
|
||||
let [validResourceScale, resourceScale] = this.get_resource_scale();
|
||||
let wasPlaying = this._isPlaying;
|
||||
|
||||
if (this._isPlaying)
|
||||
this.stop();
|
||||
|
||||
this._isLoaded = false;
|
||||
this.actor.destroy_all_children();
|
||||
this.destroy_all_children();
|
||||
|
||||
if (!validResourceScale)
|
||||
if (!validResourceScale) {
|
||||
if (wasPlaying)
|
||||
this.play();
|
||||
return;
|
||||
}
|
||||
|
||||
let texture_cache = St.TextureCache.get_default();
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._animations = texture_cache.load_sliced_image(file, width, height,
|
||||
scaleFactor, resourceScale,
|
||||
this._animationsLoaded.bind(this));
|
||||
this.actor.set_child(this._animations);
|
||||
this._animations = textureCache.load_sliced_image(file, width, height,
|
||||
scaleFactor, resourceScale,
|
||||
this._animationsLoaded.bind(this));
|
||||
this.set_child(this._animations);
|
||||
|
||||
if (wasPlaying)
|
||||
this.play();
|
||||
}
|
||||
|
||||
_showFrame(frame) {
|
||||
@@ -91,7 +98,7 @@ var Animation = class {
|
||||
if (!this._isLoaded)
|
||||
return;
|
||||
|
||||
let [width, height] = this.actor.get_size();
|
||||
let [width, height] = this.get_size();
|
||||
|
||||
for (let i = 0; i < this._animations.get_n_children(); ++i)
|
||||
this._animations.get_child_at_index(i).set_size(width, height);
|
||||
@@ -114,20 +121,22 @@ var Animation = class {
|
||||
themeContext.disconnect(this._scaleChangedId);
|
||||
this._scaleChangedId = 0;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var AnimatedIcon = class extends Animation {
|
||||
constructor(file, size) {
|
||||
super(file, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
|
||||
var AnimatedIcon = GObject.registerClass(
|
||||
class AnimatedIcon extends Animation {
|
||||
_init(file, size) {
|
||||
super._init(file, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var Spinner = class extends AnimatedIcon {
|
||||
constructor(size, animate=false) {
|
||||
var Spinner = GObject.registerClass(
|
||||
class Spinner extends AnimatedIcon {
|
||||
_init(size, animate = false) {
|
||||
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
|
||||
super(file, size);
|
||||
super._init(file, size);
|
||||
|
||||
this.actor.opacity = 0;
|
||||
this.opacity = 0;
|
||||
this._animate = animate;
|
||||
}
|
||||
|
||||
@@ -137,37 +146,35 @@ var Spinner = class extends AnimatedIcon {
|
||||
}
|
||||
|
||||
play() {
|
||||
Tweener.removeTweens(this.actor);
|
||||
this.remove_all_transitions();
|
||||
|
||||
if (this._animate) {
|
||||
super.play();
|
||||
Tweener.addTween(this.actor, {
|
||||
this.ease({
|
||||
opacity: 255,
|
||||
delay: SPINNER_ANIMATION_DELAY,
|
||||
time: SPINNER_ANIMATION_TIME,
|
||||
transition: 'linear'
|
||||
duration: SPINNER_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.LINEAR
|
||||
});
|
||||
} else {
|
||||
this.actor.opacity = 255;
|
||||
this.opacity = 255;
|
||||
super.play();
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
Tweener.removeTweens(this.actor);
|
||||
this.remove_all_transitions();
|
||||
|
||||
if (this._animate) {
|
||||
Tweener.addTween(this.actor, {
|
||||
this.ease({
|
||||
opacity: 0,
|
||||
time: SPINNER_ANIMATION_TIME,
|
||||
transition: 'linear',
|
||||
onComplete: () => {
|
||||
this.stop(false);
|
||||
}
|
||||
duration: SPINNER_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
onComplete: () => super.stop()
|
||||
});
|
||||
} else {
|
||||
this.actor.opacity = 0;
|
||||
this.opacity = 0;
|
||||
super.stop();
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
1549
js/ui/appDisplay.js
1549
js/ui/appDisplay.js
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported getAppFavorites */
|
||||
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
@@ -63,7 +64,7 @@ class AppFavorites {
|
||||
constructor() {
|
||||
this.FAVORITE_APPS_KEY = 'favorite-apps';
|
||||
this._favorites = {};
|
||||
global.settings.connect('changed::' + this.FAVORITE_APPS_KEY, this._onFavsChanged.bind(this));
|
||||
global.settings.connect(`changed::${this.FAVORITE_APPS_KEY}`, this._onFavsChanged.bind(this));
|
||||
this.reload();
|
||||
}
|
||||
|
||||
@@ -146,12 +147,11 @@ class AppFavorites {
|
||||
|
||||
let app = Shell.AppSystem.get_default().lookup_app(appId);
|
||||
|
||||
Main.overview.setMessage(_("%s has been added to your favorites.").format(app.get_name()),
|
||||
{ forFeedback: true,
|
||||
undoCallback: () => {
|
||||
this._removeFavorite(appId);
|
||||
}
|
||||
});
|
||||
let msg = _("%s has been added to your favorites.").format(app.get_name());
|
||||
Main.overview.setMessage(msg, {
|
||||
forFeedback: true,
|
||||
undoCallback: () => this._removeFavorite(appId),
|
||||
});
|
||||
}
|
||||
|
||||
addFavorite(appId) {
|
||||
@@ -180,14 +180,13 @@ class AppFavorites {
|
||||
if (!this._removeFavorite(appId))
|
||||
return;
|
||||
|
||||
Main.overview.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
|
||||
{ forFeedback: true,
|
||||
undoCallback: () => {
|
||||
this._addFavorite(appId, pos);
|
||||
}
|
||||
});
|
||||
let msg = _("%s has been removed from your favorites.").format(app.get_name());
|
||||
Main.overview.setMessage(msg, {
|
||||
forFeedback: true,
|
||||
undoCallback: () => this._addFavorite(appId, pos),
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
Signals.addSignalMethods(AppFavorites.prototype);
|
||||
|
||||
var appFavoritesInstance = null;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported AudioDeviceSelectionDBus */
|
||||
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
@@ -34,7 +35,7 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
|
||||
throw new Error('Too few devices for a selection');
|
||||
}
|
||||
|
||||
_buildLayout(devices) {
|
||||
_buildLayout() {
|
||||
let title = new St.Label({ style_class: 'audio-selection-title',
|
||||
text: _("Select Audio Device"),
|
||||
x_align: Clutter.ActorAlign.CENTER });
|
||||
@@ -54,28 +55,28 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
|
||||
}
|
||||
|
||||
_getDeviceLabel(device) {
|
||||
switch(device) {
|
||||
case AudioDevice.HEADPHONES:
|
||||
return _("Headphones");
|
||||
case AudioDevice.HEADSET:
|
||||
return _("Headset");
|
||||
case AudioDevice.MICROPHONE:
|
||||
return _("Microphone");
|
||||
default:
|
||||
return null;
|
||||
switch (device) {
|
||||
case AudioDevice.HEADPHONES:
|
||||
return _("Headphones");
|
||||
case AudioDevice.HEADSET:
|
||||
return _("Headset");
|
||||
case AudioDevice.MICROPHONE:
|
||||
return _("Microphone");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
_getDeviceIcon(device) {
|
||||
switch(device) {
|
||||
case AudioDevice.HEADPHONES:
|
||||
return 'audio-headphones-symbolic';
|
||||
case AudioDevice.HEADSET:
|
||||
return 'audio-headset-symbolic';
|
||||
case AudioDevice.MICROPHONE:
|
||||
return 'audio-input-microphone-symbolic';
|
||||
default:
|
||||
return null;
|
||||
switch (device) {
|
||||
case AudioDevice.HEADPHONES:
|
||||
return 'audio-headphones-symbolic';
|
||||
case AudioDevice.HEADSET:
|
||||
return 'audio-headset-symbolic';
|
||||
case AudioDevice.MICROPHONE:
|
||||
return 'audio-input-microphone-symbolic';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +86,7 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
|
||||
box.connect('notify::height', () => {
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
box.width = box.height;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -110,11 +112,11 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
|
||||
}
|
||||
|
||||
_openSettings() {
|
||||
let desktopFile = 'gnome-sound-panel.desktop'
|
||||
let desktopFile = 'gnome-sound-panel.desktop';
|
||||
let app = Shell.AppSystem.get_default().lookup_app(desktopFile);
|
||||
|
||||
if (!app) {
|
||||
log('Settings panel for desktop file ' + desktopFile + ' could not be loaded!');
|
||||
log(`Settings panel for desktop file ${desktopFile} could not be loaded!`);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -159,12 +161,12 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
|
||||
|
||||
let [deviceNames] = params;
|
||||
let devices = 0;
|
||||
deviceNames.forEach(n => { devices |= AudioDevice[n.toUpperCase()]; });
|
||||
deviceNames.forEach(n => (devices |= AudioDevice[n.toUpperCase()]));
|
||||
|
||||
let dialog;
|
||||
try {
|
||||
dialog = new AudioDeviceSelectionDialog(devices);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
invocation.return_value(null);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported SystemBackground */
|
||||
|
||||
// READ THIS FIRST
|
||||
// Background handling is a maze of objects, both objects in this file, and
|
||||
@@ -93,13 +94,12 @@
|
||||
// MetaBackgroundImage MetaBackgroundImage
|
||||
// MetaBackgroundImage MetaBackgroundImage
|
||||
|
||||
const { Clutter, GDesktopEnums, Gio, GLib, GnomeDesktop, Meta } = imports.gi;
|
||||
const { Clutter, GDesktopEnums, Gio, GLib, GObject, GnomeDesktop, Meta } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
var DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
||||
|
||||
@@ -108,10 +108,9 @@ const PRIMARY_COLOR_KEY = 'primary-color';
|
||||
const SECONDARY_COLOR_KEY = 'secondary-color';
|
||||
const COLOR_SHADING_TYPE_KEY = 'color-shading-type';
|
||||
const BACKGROUND_STYLE_KEY = 'picture-options';
|
||||
const PICTURE_OPACITY_KEY = 'picture-opacity';
|
||||
const PICTURE_URI_KEY = 'picture-uri';
|
||||
|
||||
var FADE_ANIMATION_TIME = 1.0;
|
||||
var FADE_ANIMATION_TIME = 1000;
|
||||
|
||||
// These parameters affect how often we redraw.
|
||||
// The first is how different (percent crossfaded) the slide show
|
||||
@@ -222,16 +221,17 @@ function getBackgroundCache() {
|
||||
return _backgroundCache;
|
||||
}
|
||||
|
||||
var Background = class Background {
|
||||
constructor(params) {
|
||||
var Background = GObject.registerClass({
|
||||
Signals: { 'loaded': {}, 'bg-changed': {} }
|
||||
}, class Background extends Meta.Background {
|
||||
_init(params) {
|
||||
params = Params.parse(params, { monitorIndex: 0,
|
||||
layoutManager: Main.layoutManager,
|
||||
settings: null,
|
||||
file: null,
|
||||
style: null });
|
||||
|
||||
this.background = new Meta.Background({ meta_display: global.display });
|
||||
this.background._delegate = this;
|
||||
super._init({ meta_display: global.display });
|
||||
|
||||
this._settings = params.settings;
|
||||
this._file = params.file;
|
||||
@@ -264,8 +264,6 @@ var Background = class Background {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.background = null;
|
||||
|
||||
this._cancellable.cancel();
|
||||
this._removeAnimationTimeout();
|
||||
|
||||
@@ -302,9 +300,11 @@ var Background = class Background {
|
||||
|
||||
this._changedIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
this._changedIdleId = 0;
|
||||
this.emit('changed');
|
||||
this.emit('bg-changed');
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
GLib.Source.set_name_by_id(this._changedIdleId,
|
||||
'[gnome-shell] Background._emitChangedSignal');
|
||||
}
|
||||
|
||||
updateResolution() {
|
||||
@@ -330,23 +330,23 @@ var Background = class Background {
|
||||
this.emit('loaded');
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
GLib.Source.set_name_by_id(id, '[gnome-shell] this.emit');
|
||||
GLib.Source.set_name_by_id(id, '[gnome-shell] Background._setLoaded Idle');
|
||||
}
|
||||
|
||||
_loadPattern() {
|
||||
let colorString, res, color, secondColor;
|
||||
let colorString, res_, color, secondColor;
|
||||
|
||||
colorString = this._settings.get_string(PRIMARY_COLOR_KEY);
|
||||
[res, color] = Clutter.Color.from_string(colorString);
|
||||
[res_, color] = Clutter.Color.from_string(colorString);
|
||||
colorString = this._settings.get_string(SECONDARY_COLOR_KEY);
|
||||
[res, secondColor] = Clutter.Color.from_string(colorString);
|
||||
[res_, secondColor] = Clutter.Color.from_string(colorString);
|
||||
|
||||
let shadingType = this._settings.get_enum(COLOR_SHADING_TYPE_KEY);
|
||||
|
||||
if (shadingType == GDesktopEnums.BackgroundShading.SOLID)
|
||||
this.background.set_color(color);
|
||||
this.set_color(color);
|
||||
else
|
||||
this.background.set_gradient(shadingType, color, secondColor);
|
||||
this.set_gradient(shadingType, color, secondColor);
|
||||
}
|
||||
|
||||
_watchFile(file) {
|
||||
@@ -382,13 +382,13 @@ var Background = class Background {
|
||||
let finish = () => {
|
||||
this._setLoaded();
|
||||
if (files.length > 1) {
|
||||
this.background.set_blend(files[0], files[1],
|
||||
this._animation.transitionProgress,
|
||||
this._style);
|
||||
this.set_blend(files[0], files[1],
|
||||
this._animation.transitionProgress,
|
||||
this._style);
|
||||
} else if (files.length > 0) {
|
||||
this.background.set_file(files[0], this._style);
|
||||
this.set_file(files[0], this._style);
|
||||
} else {
|
||||
this.background.set_file(null, this._style);
|
||||
this.set_file(null, this._style);
|
||||
}
|
||||
this._queueUpdateAnimation();
|
||||
};
|
||||
@@ -433,41 +433,42 @@ var Background = class Background {
|
||||
return;
|
||||
|
||||
this._updateAnimationTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
interval,
|
||||
() => {
|
||||
this._updateAnimationTimeoutId = 0;
|
||||
this._updateAnimation();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
interval,
|
||||
() => {
|
||||
this._updateAnimationTimeoutId = 0;
|
||||
this._updateAnimation();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
GLib.Source.set_name_by_id(this._updateAnimationTimeoutId, '[gnome-shell] this._updateAnimation');
|
||||
}
|
||||
|
||||
_loadAnimation(file) {
|
||||
this._cache.getAnimation({ file: file,
|
||||
settingsSchema: this._settings.schema_id,
|
||||
onLoaded: animation => {
|
||||
this._animation = animation;
|
||||
this._cache.getAnimation({
|
||||
file: file,
|
||||
settingsSchema: this._settings.schema_id,
|
||||
onLoaded: animation => {
|
||||
this._animation = animation;
|
||||
|
||||
if (!this._animation || this._cancellable.is_cancelled()) {
|
||||
this._setLoaded();
|
||||
return;
|
||||
}
|
||||
if (!this._animation || this._cancellable.is_cancelled()) {
|
||||
this._setLoaded();
|
||||
return;
|
||||
}
|
||||
|
||||
this._updateAnimation();
|
||||
this._watchFile(file);
|
||||
}
|
||||
});
|
||||
this._updateAnimation();
|
||||
this._watchFile(file);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_loadImage(file) {
|
||||
this.background.set_file(file, this._style);
|
||||
this.set_file(file, this._style);
|
||||
this._watchFile(file);
|
||||
|
||||
let cache = Meta.BackgroundImageCache.get_default();
|
||||
let image = cache.load(file);
|
||||
if (image.is_loaded())
|
||||
if (image.is_loaded()) {
|
||||
this._setLoaded();
|
||||
else {
|
||||
} else {
|
||||
let id = image.connect('loaded', () => {
|
||||
this._setLoaded();
|
||||
image.disconnect(id);
|
||||
@@ -494,13 +495,14 @@ var Background = class Background {
|
||||
|
||||
this._loadFile(this._file);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Background.prototype);
|
||||
});
|
||||
|
||||
let _systemBackground;
|
||||
|
||||
var SystemBackground = class SystemBackground {
|
||||
constructor() {
|
||||
var SystemBackground = GObject.registerClass({
|
||||
Signals: { 'loaded': {} }
|
||||
}, class SystemBackground extends Meta.BackgroundActor {
|
||||
_init() {
|
||||
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/noise-texture.png');
|
||||
|
||||
if (_systemBackground == null) {
|
||||
@@ -509,9 +511,11 @@ var SystemBackground = class SystemBackground {
|
||||
_systemBackground.set_file(file, GDesktopEnums.BackgroundStyle.WALLPAPER);
|
||||
}
|
||||
|
||||
this.actor = new Meta.BackgroundActor({ meta_display: global.display,
|
||||
monitor: 0,
|
||||
background: _systemBackground });
|
||||
super._init({
|
||||
meta_display: global.display,
|
||||
monitor: 0,
|
||||
background: _systemBackground
|
||||
});
|
||||
|
||||
let cache = Meta.BackgroundImageCache.get_default();
|
||||
let image = cache.load(file);
|
||||
@@ -530,8 +534,7 @@ var SystemBackground = class SystemBackground {
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(SystemBackground.prototype);
|
||||
});
|
||||
|
||||
var BackgroundSource = class BackgroundSource {
|
||||
constructor(layoutManager, settingsSchema) {
|
||||
@@ -567,7 +570,7 @@ var BackgroundSource = class BackgroundSource {
|
||||
|
||||
// We don't watch changes to settings here,
|
||||
// instead we rely on Background to watch those
|
||||
// and emit 'changed' at the right time
|
||||
// and emit 'bg-changed' at the right time
|
||||
|
||||
if (this._overrideImage != null) {
|
||||
file = Gio.File.new_for_path(this._overrideImage);
|
||||
@@ -596,7 +599,7 @@ var BackgroundSource = class BackgroundSource {
|
||||
style: style
|
||||
});
|
||||
|
||||
background._changedId = background.connect('changed', () => {
|
||||
background._changedId = background.connect('bg-changed', () => {
|
||||
background.disconnect(background._changedId);
|
||||
background.destroy();
|
||||
delete this._backgrounds[monitorIndex];
|
||||
@@ -634,9 +637,9 @@ var Animation = class Animation {
|
||||
}
|
||||
|
||||
load(callback) {
|
||||
this._show = new GnomeDesktop.BGSlideShow({ filename: this.file.get_path() });
|
||||
this._show = new GnomeDesktop.BGSlideShow({ file: this.file });
|
||||
|
||||
this._show.load_async(null, (object, result) => {
|
||||
this._show.load_async(null, () => {
|
||||
this.loaded = true;
|
||||
if (callback)
|
||||
callback();
|
||||
@@ -652,7 +655,7 @@ var Animation = class Animation {
|
||||
if (this._show.get_num_slides() < 1)
|
||||
return;
|
||||
|
||||
let [progress, duration, isFixed, filename1, filename2] = this._show.get_current_slide(monitor.width, monitor.height);
|
||||
let [progress, duration, isFixed_, filename1, filename2] = this._show.get_current_slide(monitor.width, monitor.height);
|
||||
|
||||
this.transitionDuration = duration;
|
||||
this.transitionProgress = progress;
|
||||
@@ -711,14 +714,12 @@ var BackgroundManager = class BackgroundManager {
|
||||
this._newBackgroundActor = null;
|
||||
this.emit('changed');
|
||||
|
||||
Tweener.addTween(oldBackgroundActor,
|
||||
{ opacity: 0,
|
||||
time: FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete() {
|
||||
oldBackgroundActor.destroy();
|
||||
}
|
||||
});
|
||||
oldBackgroundActor.ease({
|
||||
opacity: 0,
|
||||
duration: FADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => oldBackgroundActor.destroy()
|
||||
});
|
||||
}
|
||||
|
||||
_updateBackgroundActor() {
|
||||
@@ -735,7 +736,7 @@ var BackgroundManager = class BackgroundManager {
|
||||
|
||||
this._newBackgroundActor = newBackgroundActor;
|
||||
|
||||
let background = newBackgroundActor.background._delegate;
|
||||
let background = newBackgroundActor.background;
|
||||
|
||||
if (background.isLoaded) {
|
||||
this._swapBackgroundActor();
|
||||
@@ -752,13 +753,14 @@ var BackgroundManager = class BackgroundManager {
|
||||
|
||||
_createBackgroundActor() {
|
||||
let background = this._backgroundSource.getBackground(this._monitorIndex);
|
||||
let backgroundActor = new Meta.BackgroundActor({ meta_display: global.display,
|
||||
monitor: this._monitorIndex,
|
||||
background: background.background,
|
||||
vignette: this._vignette,
|
||||
vignette_sharpness: 0.5,
|
||||
brightness: 0.5,
|
||||
});
|
||||
let backgroundActor = new Meta.BackgroundActor({
|
||||
meta_display: global.display,
|
||||
monitor: this._monitorIndex,
|
||||
background,
|
||||
vignette: this._vignette,
|
||||
vignette_sharpness: 0.5,
|
||||
brightness: 0.5,
|
||||
});
|
||||
|
||||
this._container.add_child(backgroundActor);
|
||||
|
||||
@@ -768,7 +770,7 @@ var BackgroundManager = class BackgroundManager {
|
||||
backgroundActor.lower_bottom();
|
||||
}
|
||||
|
||||
let changeSignalId = background.connect('changed', () => {
|
||||
let changeSignalId = background.connect('bg-changed', () => {
|
||||
background.disconnect(changeSignalId);
|
||||
changeSignalId = null;
|
||||
this._updateBackgroundActor();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported addBackgroundMenu */
|
||||
|
||||
const { Clutter, St } = imports.gi;
|
||||
|
||||
@@ -30,7 +31,7 @@ function addBackgroundMenu(actor, layoutManager) {
|
||||
|
||||
function openMenu(x, y) {
|
||||
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
|
||||
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
|
||||
actor._backgroundMenu.open(BoxPointer.PopupAnimation.FULL);
|
||||
}
|
||||
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
|
||||
@@ -1,74 +1,106 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/* exported BarLevel */
|
||||
|
||||
const { Atk, Clutter, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
const { Atk, Clutter, GObject, St } = imports.gi;
|
||||
|
||||
var BarLevel = class {
|
||||
constructor(value, params) {
|
||||
if (isNaN(value))
|
||||
// Avoid spreading NaNs around
|
||||
throw TypeError('The bar level value must be a number');
|
||||
var BarLevel = GObject.registerClass({
|
||||
Properties: {
|
||||
'value': GObject.ParamSpec.double(
|
||||
'value', 'value', 'value',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 2, 0),
|
||||
'maximum-value': GObject.ParamSpec.double(
|
||||
'maximum-value', 'maximum-value', 'maximum-value',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
1, 2, 1),
|
||||
'overdrive-start': GObject.ParamSpec.double(
|
||||
'overdrive-start', 'overdrive-start', 'overdrive-start',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
1, 2, 1)
|
||||
}
|
||||
}, class BarLevel extends St.DrawingArea {
|
||||
_init(params) {
|
||||
this._maxValue = 1;
|
||||
this._value = Math.max(Math.min(value, this._maxValue), 0);
|
||||
this._value = 0;
|
||||
this._overdriveStart = 1;
|
||||
this._barLevelWidth = 0;
|
||||
|
||||
if (params == undefined)
|
||||
params = {}
|
||||
|
||||
this.actor = new St.DrawingArea({ styleClass: params['styleClass'] || 'barlevel',
|
||||
can_focus: params['canFocus'] || false,
|
||||
reactive: params['reactive'] || false,
|
||||
accessible_role: params['accessibleRole'] || Atk.Role.LEVEL_BAR });
|
||||
this.actor.connect('repaint', this._barLevelRepaint.bind(this));
|
||||
this.actor.connect('allocation-changed', (actor, box) => {
|
||||
let defaultParams = {
|
||||
style_class: 'barlevel',
|
||||
accessible_role: Atk.Role.LEVEL_BAR
|
||||
};
|
||||
super._init(Object.assign(defaultParams, params));
|
||||
this.connect('allocation-changed', (actor, box) => {
|
||||
this._barLevelWidth = box.get_width();
|
||||
});
|
||||
|
||||
this._customAccessible = St.GenericAccessible.new_for_actor(this.actor);
|
||||
this.actor.set_accessible(this._customAccessible);
|
||||
this._customAccessible = St.GenericAccessible.new_for_actor(this);
|
||||
this.set_accessible(this._customAccessible);
|
||||
|
||||
this._customAccessible.connect('get-current-value', this._getCurrentValue.bind(this));
|
||||
this._customAccessible.connect('get-minimum-value', this._getMinimumValue.bind(this));
|
||||
this._customAccessible.connect('get-maximum-value', this._getMaximumValue.bind(this));
|
||||
this._customAccessible.connect('set-current-value', this._setCurrentValue.bind(this));
|
||||
|
||||
this.connect('value-changed', this._valueChanged.bind(this));
|
||||
this.connect('notify::value', this._valueChanged.bind(this));
|
||||
}
|
||||
|
||||
setValue(value) {
|
||||
if (isNaN(value))
|
||||
throw TypeError('The bar level value must be a number');
|
||||
|
||||
this._value = Math.max(Math.min(value, this._maxValue), 0);
|
||||
this.actor.queue_repaint();
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
setMaximumValue(value) {
|
||||
if (isNaN(value))
|
||||
throw TypeError('The bar level max value must be a number');
|
||||
set value(value) {
|
||||
value = Math.max(Math.min(value, this._maxValue), 0);
|
||||
|
||||
this._maxValue = Math.max(value, 1);
|
||||
if (this._value == value)
|
||||
return;
|
||||
|
||||
this._value = value;
|
||||
this.notify('value');
|
||||
this.queue_repaint();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get maximum_value() {
|
||||
return this._maxValue;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
set maximum_value(value) {
|
||||
value = Math.max(value, 1);
|
||||
|
||||
if (this._maxValue == value)
|
||||
return;
|
||||
|
||||
this._maxValue = value;
|
||||
this._overdriveStart = Math.min(this._overdriveStart, this._maxValue);
|
||||
this.actor.queue_repaint();
|
||||
this.notify('maximum-value');
|
||||
this.queue_repaint();
|
||||
}
|
||||
|
||||
setOverdriveStart(value) {
|
||||
if (isNaN(value))
|
||||
throw TypeError('The overdrive limit value must be a number');
|
||||
// eslint-disable-next-line camelcase
|
||||
get overdrive_start() {
|
||||
return this._overdriveStart;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
set overdrive_start(value) {
|
||||
if (this._overdriveStart == value)
|
||||
return;
|
||||
|
||||
if (value > this._maxValue)
|
||||
throw new Error(`Tried to set overdrive value to ${value}, ` +
|
||||
`which is a number greater than the maximum allowed value ${this._maxValue}`);
|
||||
|
||||
this._overdriveStart = value;
|
||||
this._value = Math.max(Math.min(value, this._maxValue), 0);
|
||||
this.actor.queue_repaint();
|
||||
this.notify('overdrive-start');
|
||||
this.queue_repaint();
|
||||
}
|
||||
|
||||
_barLevelRepaint(area) {
|
||||
let cr = area.get_context();
|
||||
let themeNode = area.get_theme_node();
|
||||
let [width, height] = area.get_surface_size();
|
||||
vfunc_repaint() {
|
||||
let cr = this.get_context();
|
||||
let themeNode = this.get_theme_node();
|
||||
let [width, height] = this.get_surface_size();
|
||||
|
||||
let barLevelHeight = themeNode.get_length('-barlevel-height');
|
||||
let barLevelBorderRadius = Math.min(width, barLevelHeight) / 2;
|
||||
@@ -105,7 +137,7 @@ var BarLevel = class {
|
||||
overdriveSeparatorWidth = themeNode.get_length('-barlevel-overdrive-separator-width');
|
||||
|
||||
/* background bar */
|
||||
cr.arc(width - barLevelBorderRadius - barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * 3 / 4, TAU * 1 / 4);
|
||||
cr.arc(width - barLevelBorderRadius - barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4));
|
||||
cr.lineTo(endX, (height + barLevelHeight) / 2);
|
||||
cr.lineTo(endX, (height - barLevelHeight) / 2);
|
||||
cr.lineTo(width - barLevelBorderRadius - barLevelBorderWidth, (height - barLevelHeight) / 2);
|
||||
@@ -117,12 +149,12 @@ var BarLevel = class {
|
||||
|
||||
/* normal progress bar */
|
||||
let x = Math.min(endX, overdriveSeparatorX - overdriveSeparatorWidth / 2);
|
||||
cr.arc(barLevelBorderRadius + barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * 1 / 4, TAU * 3 / 4);
|
||||
cr.arc(barLevelBorderRadius + barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * (1 / 4), TAU * (3 / 4));
|
||||
cr.lineTo(x, (height - barLevelHeight) / 2);
|
||||
cr.lineTo(x, (height + barLevelHeight) / 2);
|
||||
cr.lineTo(barLevelBorderRadius + barLevelBorderWidth, (height + barLevelHeight) / 2);
|
||||
if (this._value > 0)
|
||||
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
||||
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
||||
cr.fillPreserve();
|
||||
Clutter.cairo_set_source_color(cr, barLevelActiveBorderColor);
|
||||
cr.setLineWidth(barLevelBorderWidth);
|
||||
@@ -145,17 +177,17 @@ var BarLevel = class {
|
||||
|
||||
/* end progress bar arc */
|
||||
if (this._value > 0) {
|
||||
if (this._value <= this._overdriveStart)
|
||||
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
||||
else
|
||||
Clutter.cairo_set_source_color(cr, barLevelOverdriveColor);
|
||||
cr.arc(endX, height / 2, barLevelBorderRadius, TAU * 3 / 4, TAU * 1 / 4);
|
||||
cr.lineTo(Math.floor(endX), (height + barLevelHeight) / 2);
|
||||
cr.lineTo(Math.floor(endX), (height - barLevelHeight) / 2);
|
||||
cr.lineTo(endX, (height - barLevelHeight) / 2);
|
||||
cr.fillPreserve();
|
||||
cr.setLineWidth(barLevelBorderWidth);
|
||||
cr.stroke();
|
||||
if (this._value <= this._overdriveStart)
|
||||
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
|
||||
else
|
||||
Clutter.cairo_set_source_color(cr, barLevelOverdriveColor);
|
||||
cr.arc(endX, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4));
|
||||
cr.lineTo(Math.floor(endX), (height + barLevelHeight) / 2);
|
||||
cr.lineTo(Math.floor(endX), (height - barLevelHeight) / 2);
|
||||
cr.lineTo(endX, (height - barLevelHeight) / 2);
|
||||
cr.fillPreserve();
|
||||
cr.setLineWidth(barLevelBorderWidth);
|
||||
cr.stroke();
|
||||
}
|
||||
|
||||
/* draw overdrive separator */
|
||||
@@ -175,32 +207,27 @@ var BarLevel = class {
|
||||
cr.$dispose();
|
||||
}
|
||||
|
||||
_getCurrentValue(actor) {
|
||||
_getCurrentValue() {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
_getOverdriveStart(actor) {
|
||||
_getOverdriveStart() {
|
||||
return this._overdriveStart;
|
||||
}
|
||||
|
||||
_getMinimumValue(actor) {
|
||||
_getMinimumValue() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_getMaximumValue(actor) {
|
||||
_getMaximumValue() {
|
||||
return this._maxValue;
|
||||
}
|
||||
|
||||
_setCurrentValue(actor, value) {
|
||||
_setCurrentValue(_actor, value) {
|
||||
this._value = value;
|
||||
}
|
||||
|
||||
_valueChanged(barLevel, value, property) {
|
||||
_valueChanged() {
|
||||
this._customAccessible.notify("accessible-value");
|
||||
}
|
||||
|
||||
get value() {
|
||||
return this._value;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(BarLevel.prototype);
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported BoxPointer */
|
||||
|
||||
const { Clutter, GObject, Meta, Shell, St } = imports.gi;
|
||||
const { Clutter, GObject, Shell, St } = imports.gi;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
var PopupAnimation = {
|
||||
NONE: 0,
|
||||
@@ -12,7 +12,7 @@ var PopupAnimation = {
|
||||
FULL: ~0,
|
||||
};
|
||||
|
||||
var POPUP_ANIMATION_TIME = 0.15;
|
||||
var POPUP_ANIMATION_TIME = 150;
|
||||
|
||||
/**
|
||||
* BoxPointer:
|
||||
@@ -46,12 +46,18 @@ var BoxPointer = GObject.registerClass({
|
||||
this.add_actor(this._border);
|
||||
this.bin.raise(this._border);
|
||||
this._sourceAlignment = 0.5;
|
||||
this._capturedEventId = 0;
|
||||
this._muteInput();
|
||||
this._muteInput = true;
|
||||
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
}
|
||||
|
||||
vfunc_captured_event() {
|
||||
if (this._muteInput)
|
||||
return Clutter.EVENT_STOP;
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
if (this._sourceActorDestroyId) {
|
||||
this._sourceActor.disconnect(this._sourceActorDestroyId);
|
||||
@@ -63,19 +69,6 @@ var BoxPointer = GObject.registerClass({
|
||||
return this._arrowSide;
|
||||
}
|
||||
|
||||
_muteInput() {
|
||||
if (this._capturedEventId == 0)
|
||||
this._capturedEventId = this.connect('captured-event',
|
||||
() => Clutter.EVENT_STOP);
|
||||
}
|
||||
|
||||
_unmuteInput() {
|
||||
if (this._capturedEventId != 0) {
|
||||
this.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
open(animate, onComplete) {
|
||||
let themeNode = this.get_theme_node();
|
||||
let rise = themeNode.get_length('-arrow-rise');
|
||||
@@ -90,31 +83,33 @@ var BoxPointer = GObject.registerClass({
|
||||
|
||||
if (animate & PopupAnimation.SLIDE) {
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
this.translation_y = -rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
this.translation_y = rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
this.translation_x = -rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
this.translation_x = rise;
|
||||
break;
|
||||
case St.Side.TOP:
|
||||
this.translation_y = -rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
this.translation_y = rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
this.translation_x = -rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
this.translation_x = rise;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Tweener.addTween(this, { opacity: 255,
|
||||
translation_x: 0,
|
||||
translation_y: 0,
|
||||
transition: 'linear',
|
||||
onComplete: () => {
|
||||
this._unmuteInput();
|
||||
if (onComplete)
|
||||
onComplete();
|
||||
},
|
||||
time: animationTime });
|
||||
this.ease({
|
||||
opacity: 255,
|
||||
translation_x: 0,
|
||||
translation_y: 0,
|
||||
duration: animationTime,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
onComplete: () => {
|
||||
this._muteInput = false;
|
||||
if (onComplete)
|
||||
onComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
close(animate, onComplete) {
|
||||
@@ -130,38 +125,39 @@ var BoxPointer = GObject.registerClass({
|
||||
|
||||
if (animate & PopupAnimation.SLIDE) {
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
translationY = rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
translationY = -rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
translationX = rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
translationX = -rise;
|
||||
break;
|
||||
case St.Side.TOP:
|
||||
translationY = rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
translationY = -rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
translationX = rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
translationX = -rise;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._muteInput();
|
||||
this._muteInput = true;
|
||||
|
||||
Tweener.removeTweens(this);
|
||||
Tweener.addTween(this, { opacity: fade ? 0 : 255,
|
||||
translation_x: translationX,
|
||||
translation_y: translationY,
|
||||
transition: 'linear',
|
||||
time: animationTime,
|
||||
onComplete: () => {
|
||||
this.hide();
|
||||
this.opacity = 0;
|
||||
this.translation_x = 0;
|
||||
this.translation_y = 0;
|
||||
if (onComplete)
|
||||
onComplete();
|
||||
}
|
||||
});
|
||||
this.remove_all_transitions();
|
||||
this.ease({
|
||||
opacity: fade ? 0 : 255,
|
||||
translation_x: translationX,
|
||||
translation_y: translationY,
|
||||
duration: animationTime,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
onComplete: () => {
|
||||
this.hide();
|
||||
this.opacity = 0;
|
||||
this.translation_x = 0;
|
||||
this.translation_y = 0;
|
||||
if (onComplete)
|
||||
onComplete();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_adjustAllocationForArrow(isWidth, minSize, natSize) {
|
||||
@@ -169,8 +165,8 @@ var BoxPointer = GObject.registerClass({
|
||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||
minSize += borderWidth * 2;
|
||||
natSize += borderWidth * 2;
|
||||
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM))
|
||||
|| (isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
|
||||
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM)) ||
|
||||
(isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
|
||||
let rise = themeNode.get_length('-arrow-rise');
|
||||
minSize += rise;
|
||||
natSize += rise;
|
||||
@@ -220,18 +216,18 @@ var BoxPointer = GObject.registerClass({
|
||||
childBox.x2 = availWidth - borderWidth;
|
||||
childBox.y2 = availHeight - borderWidth;
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
childBox.y1 += rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
childBox.y2 -= rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
childBox.x1 += rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
childBox.x2 -= rise;
|
||||
break;
|
||||
case St.Side.TOP:
|
||||
childBox.y1 += rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
childBox.y2 -= rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
childBox.x1 += rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
childBox.x2 -= rise;
|
||||
break;
|
||||
}
|
||||
this.bin.allocate(childBox, flags);
|
||||
|
||||
@@ -264,7 +260,7 @@ var BoxPointer = GObject.registerClass({
|
||||
let borderRadius = themeNode.get_length('-arrow-border-radius');
|
||||
|
||||
let halfBorder = borderWidth / 2;
|
||||
let halfBase = Math.floor(base/2);
|
||||
let halfBase = Math.floor(base / 2);
|
||||
|
||||
let backgroundColor = themeNode.get_color('-arrow-background-color');
|
||||
|
||||
@@ -345,7 +341,7 @@ var BoxPointer = GObject.registerClass({
|
||||
if (!skipTopRight) {
|
||||
cr.lineTo(x2 - borderRadius, y1);
|
||||
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
|
||||
3*Math.PI/2, Math.PI*2);
|
||||
3 * Math.PI / 2, Math.PI * 2);
|
||||
}
|
||||
|
||||
if (this._arrowSide == St.Side.RIGHT && rise) {
|
||||
@@ -366,7 +362,7 @@ var BoxPointer = GObject.registerClass({
|
||||
if (!skipBottomRight) {
|
||||
cr.lineTo(x2, y2 - borderRadius);
|
||||
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
|
||||
0, Math.PI/2);
|
||||
0, Math.PI / 2);
|
||||
}
|
||||
|
||||
if (this._arrowSide == St.Side.BOTTOM && rise) {
|
||||
@@ -387,7 +383,7 @@ var BoxPointer = GObject.registerClass({
|
||||
if (!skipBottomLeft) {
|
||||
cr.lineTo(x1 + borderRadius, y2);
|
||||
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
|
||||
Math.PI/2, Math.PI);
|
||||
Math.PI / 2, Math.PI);
|
||||
}
|
||||
|
||||
if (this._arrowSide == St.Side.LEFT && rise) {
|
||||
@@ -396,7 +392,7 @@ var BoxPointer = GObject.registerClass({
|
||||
cr.lineTo(x1 - rise, y1);
|
||||
cr.lineTo(x1 + borderRadius, y1);
|
||||
} else if (skipBottomLeft) {
|
||||
cr.lineTo(x1 - rise, y2)
|
||||
cr.lineTo(x1 - rise, y2);
|
||||
cr.lineTo(x1 - rise, y2 - halfBase);
|
||||
} else {
|
||||
cr.lineTo(x1, this._arrowOrigin + halfBase);
|
||||
@@ -408,7 +404,7 @@ var BoxPointer = GObject.registerClass({
|
||||
if (!skipTopLeft) {
|
||||
cr.lineTo(x1, y1 + borderRadius);
|
||||
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
|
||||
Math.PI, 3*Math.PI/2);
|
||||
Math.PI, 3 * Math.PI / 2);
|
||||
}
|
||||
|
||||
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||
@@ -437,7 +433,7 @@ var BoxPointer = GObject.registerClass({
|
||||
this._sourceActorDestroyId = this._sourceActor.connect('destroy', () => {
|
||||
this._sourceActor = null;
|
||||
delete this._sourceActorDestroyId;
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -469,7 +465,7 @@ var BoxPointer = GObject.registerClass({
|
||||
let sourceAllocation = this._sourceAllocation;
|
||||
let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment;
|
||||
let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
|
||||
let [minWidth, minHeight, natWidth, natHeight] = this.get_preferred_size();
|
||||
let [, , natWidth, natHeight] = this.get_preferred_size();
|
||||
|
||||
// We also want to keep it onscreen, and separated from the
|
||||
// edge by the same distance as the main part of the box is
|
||||
@@ -513,7 +509,7 @@ var BoxPointer = GObject.registerClass({
|
||||
// of the box to maintain the arrow's accuracy.
|
||||
|
||||
let arrowOrigin;
|
||||
let halfBase = Math.floor(arrowBase/2);
|
||||
let halfBase = Math.floor(arrowBase / 2);
|
||||
let halfBorder = borderWidth / 2;
|
||||
let halfMargin = margin / 2;
|
||||
let [x1, y1] = [halfBorder, halfBorder];
|
||||
@@ -594,7 +590,7 @@ var BoxPointer = GObject.registerClass({
|
||||
|
||||
_calculateArrowSide(arrowSide) {
|
||||
let sourceAllocation = this._sourceAllocation;
|
||||
let [minWidth, minHeight, boxWidth, boxHeight] = this.get_preferred_size();
|
||||
let [, , boxWidth, boxHeight] = this.get_preferred_size();
|
||||
let workarea = this._workArea;
|
||||
|
||||
switch (arrowSide) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Calendar, CalendarMessageList */
|
||||
|
||||
const { Clutter, Gio, GLib, Shell, St } = imports.gi;
|
||||
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
@@ -17,7 +18,7 @@ var ELLIPSIS_CHAR = '\u2026';
|
||||
|
||||
var MESSAGE_ICON_SIZE = -1; // pick up from CSS
|
||||
|
||||
var NC_ = (context, str) => context + '\u0004' + str;
|
||||
var NC_ = (context, str) => `${context}\u0004${str}`;
|
||||
|
||||
function sameYear(dateA, dateB) {
|
||||
return (dateA.getYear() == dateB.getYear());
|
||||
@@ -38,7 +39,7 @@ function isToday(date) {
|
||||
function _isWorkDay(date) {
|
||||
/* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
|
||||
let days = C_('calendar-no-work', "06");
|
||||
return days.indexOf(date.getDay().toString()) == -1;
|
||||
return !days.includes(date.getDay().toString());
|
||||
}
|
||||
|
||||
function _getBeginningOfDay(date) {
|
||||
@@ -109,15 +110,15 @@ var EmptyEventSource = class EmptyEventSource {
|
||||
destroy() {
|
||||
}
|
||||
|
||||
requestRange(begin, end) {
|
||||
requestRange(_begin, _end) {
|
||||
}
|
||||
|
||||
getEvents(begin, end) {
|
||||
getEvents(_begin, _end) {
|
||||
let result = [];
|
||||
return result;
|
||||
}
|
||||
|
||||
hasEvents(day) {
|
||||
hasEvents(_day) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -143,8 +144,7 @@ function _datesEqual(a, b) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function _dateIntervalsOverlap(a0, a1, b0, b1)
|
||||
{
|
||||
function _dateIntervalsOverlap(a0, a1, b0, b1) {
|
||||
if (a1 <= b0)
|
||||
return false;
|
||||
else if (b1 <= a0)
|
||||
@@ -168,7 +168,7 @@ var DBusEventSource = class DBusEventSource {
|
||||
try {
|
||||
this._dbusProxy.init_finish(result);
|
||||
loaded = true;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
|
||||
// Ignore timeouts and install signals as normal, because with high
|
||||
// probability the service will appear later on, and we will get a
|
||||
@@ -178,7 +178,7 @@ var DBusEventSource = class DBusEventSource {
|
||||
// about the HasCalendars property and would cause an exception trying
|
||||
// to read it)
|
||||
} else {
|
||||
log('Error loading calendars: ' + e.message);
|
||||
log(`Error loading calendars: ${e.message}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -221,13 +221,13 @@ var DBusEventSource = class DBusEventSource {
|
||||
this._lastRequestEnd = null;
|
||||
}
|
||||
|
||||
_onNameAppeared(owner) {
|
||||
_onNameAppeared() {
|
||||
this._initialized = true;
|
||||
this._resetCache();
|
||||
this._loadEvents(true);
|
||||
}
|
||||
|
||||
_onNameVanished(oldOwner) {
|
||||
_onNameVanished() {
|
||||
this._resetCache();
|
||||
this.emit('changed');
|
||||
}
|
||||
@@ -236,22 +236,20 @@ var DBusEventSource = class DBusEventSource {
|
||||
this._loadEvents(false);
|
||||
}
|
||||
|
||||
_onEventsReceived(results, error) {
|
||||
_onEventsReceived(results, _error) {
|
||||
let newEvents = [];
|
||||
let appointments = results ? results[0] : null;
|
||||
if (appointments != null) {
|
||||
for (let n = 0; n < appointments.length; n++) {
|
||||
let a = appointments[n];
|
||||
let date = new Date(a[4] * 1000);
|
||||
let end = new Date(a[5] * 1000);
|
||||
let id = a[0];
|
||||
let summary = a[1];
|
||||
let allDay = a[3];
|
||||
let event = new CalendarEvent(id, date, end, summary, allDay);
|
||||
newEvents.push(event);
|
||||
}
|
||||
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
|
||||
let appointments = results[0] || [];
|
||||
for (let n = 0; n < appointments.length; n++) {
|
||||
let a = appointments[n];
|
||||
let date = new Date(a[4] * 1000);
|
||||
let end = new Date(a[5] * 1000);
|
||||
let id = a[0];
|
||||
let summary = a[1];
|
||||
let allDay = a[3];
|
||||
let event = new CalendarEvent(id, date, end, summary, allDay);
|
||||
newEvents.push(event);
|
||||
}
|
||||
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
|
||||
|
||||
this._events = newEvents;
|
||||
this.isLoading = false;
|
||||
@@ -263,7 +261,7 @@ var DBusEventSource = class DBusEventSource {
|
||||
if (!this._initialized)
|
||||
return;
|
||||
|
||||
if (this._curRequestBegin && this._curRequestEnd){
|
||||
if (this._curRequestBegin && this._curRequestEnd) {
|
||||
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
||||
this._curRequestEnd.getTime() / 1000,
|
||||
forceReload,
|
||||
@@ -285,7 +283,7 @@ var DBusEventSource = class DBusEventSource {
|
||||
|
||||
getEvents(begin, end) {
|
||||
let result = [];
|
||||
for(let n = 0; n < this._events.length; n++) {
|
||||
for (let n = 0; n < this._events.length; n++) {
|
||||
let event = this._events[n];
|
||||
|
||||
if (_dateIntervalsOverlap (event.date, event.end, begin, end)) {
|
||||
@@ -315,12 +313,14 @@ var DBusEventSource = class DBusEventSource {
|
||||
};
|
||||
Signals.addSignalMethods(DBusEventSource.prototype);
|
||||
|
||||
var Calendar = class Calendar {
|
||||
constructor() {
|
||||
var Calendar = GObject.registerClass({
|
||||
Signals: { 'selected-date-changed': { param_types: [GLib.DateTime.$gtype] } }
|
||||
}, class Calendar extends St.Widget {
|
||||
_init() {
|
||||
this._weekStart = Shell.util_get_week_start();
|
||||
this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.calendar' });
|
||||
|
||||
this._settings.connect('changed::' + SHOW_WEEKDATE_KEY, this._onSettingsChange.bind(this));
|
||||
this._settings.connect(`changed::${SHOW_WEEKDATE_KEY}`, this._onSettingsChange.bind(this));
|
||||
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
|
||||
|
||||
/**
|
||||
@@ -346,12 +346,11 @@ var Calendar = class Calendar {
|
||||
|
||||
this._shouldDateGrabFocus = false;
|
||||
|
||||
this.actor = new St.Widget({ style_class: 'calendar',
|
||||
layout_manager: new Clutter.TableLayout(),
|
||||
reactive: true });
|
||||
|
||||
this.actor.connect('scroll-event',
|
||||
this._onScroll.bind(this));
|
||||
super._init({
|
||||
style_class: 'calendar',
|
||||
layout_manager: new Clutter.TableLayout(),
|
||||
reactive: true
|
||||
});
|
||||
|
||||
this._buildHeader ();
|
||||
}
|
||||
@@ -375,7 +374,10 @@ var Calendar = class Calendar {
|
||||
|
||||
this._selectedDate = date;
|
||||
this._update();
|
||||
this.emit('selected-date-changed', new Date(this._selectedDate));
|
||||
|
||||
let datetime = GLib.DateTime.new_from_unix_local(
|
||||
this._selectedDate.getTime() / 1000);
|
||||
this.emit('selected-date-changed', datetime);
|
||||
}
|
||||
|
||||
updateTimeZone() {
|
||||
@@ -386,9 +388,9 @@ var Calendar = class Calendar {
|
||||
}
|
||||
|
||||
_buildHeader() {
|
||||
let layout = this.actor.layout_manager;
|
||||
let layout = this.layout_manager;
|
||||
let offsetCols = this._useWeekdate ? 1 : 0;
|
||||
this.actor.destroy_all_children();
|
||||
this.destroy_all_children();
|
||||
|
||||
// Top line of the calendar '<| September 2009 |>'
|
||||
this._topBox = new St.BoxLayout();
|
||||
@@ -402,8 +404,8 @@ var Calendar = class Calendar {
|
||||
this._topBox.add(this._backButton);
|
||||
this._backButton.connect('clicked', this._onPrevMonthButtonClicked.bind(this));
|
||||
|
||||
this._monthLabel = new St.Label({style_class: 'calendar-month-label',
|
||||
can_focus: true });
|
||||
this._monthLabel = new St.Label({ style_class: 'calendar-month-label',
|
||||
can_focus: true });
|
||||
this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
|
||||
|
||||
this._forwardButton = new St.Button({ style_class: 'calendar-change-month-forward pager-button',
|
||||
@@ -430,7 +432,7 @@ var Calendar = class Calendar {
|
||||
can_focus: true });
|
||||
label.accessible_name = iter.toLocaleFormat('%A');
|
||||
let col;
|
||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
||||
if (this.get_text_direction() == Clutter.TextDirection.RTL)
|
||||
col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
|
||||
else
|
||||
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
|
||||
@@ -439,11 +441,11 @@ var Calendar = class Calendar {
|
||||
}
|
||||
|
||||
// All the children after this are days, and get removed when we update the calendar
|
||||
this._firstDayIndex = this.actor.get_n_children();
|
||||
this._firstDayIndex = this.get_n_children();
|
||||
}
|
||||
|
||||
_onScroll(actor, event) {
|
||||
switch (event.get_scroll_direction()) {
|
||||
vfunc_scroll_event(scrollEvent) {
|
||||
switch (scrollEvent.direction) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
case Clutter.ScrollDirection.LEFT:
|
||||
this._onPrevMonthButtonClicked();
|
||||
@@ -466,8 +468,7 @@ var Calendar = class Calendar {
|
||||
let day = 32 - new Date(newDate.getFullYear() - 1, 11, 32).getDate();
|
||||
newDate = new Date(newDate.getFullYear() - 1, 11, day);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
newDate.setMonth(oldMonth - 1);
|
||||
if (newDate.getMonth() != oldMonth - 1) {
|
||||
let day = 32 - new Date(newDate.getFullYear(), oldMonth - 1, 32).getDate();
|
||||
@@ -490,8 +491,7 @@ var Calendar = class Calendar {
|
||||
let day = 32 - new Date(newDate.getFullYear() + 1, 0, 32).getDate();
|
||||
newDate = new Date(newDate.getFullYear() + 1, 0, day);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
newDate.setMonth(oldMonth + 1);
|
||||
if (newDate.getMonth() != oldMonth + 1) {
|
||||
let day = 32 - new Date(newDate.getFullYear(), oldMonth + 1, 32).getDate();
|
||||
@@ -515,7 +515,7 @@ var Calendar = class Calendar {
|
||||
let now = new Date();
|
||||
|
||||
// Remove everything but the topBox and the weekday labels
|
||||
let children = this.actor.get_children();
|
||||
let children = this.get_children();
|
||||
for (let i = this._firstDayIndex; i < children.length; i++)
|
||||
children[i].destroy();
|
||||
|
||||
@@ -546,20 +546,18 @@ var Calendar = class Calendar {
|
||||
this._calendarBegin = new Date(beginDate);
|
||||
this._markedAsToday = now;
|
||||
|
||||
let year = beginDate.getYear();
|
||||
|
||||
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
|
||||
let startsOnWeekStart = daysToWeekStart == 0;
|
||||
let weekPadding = startsOnWeekStart ? 7 : 0;
|
||||
|
||||
beginDate.setTime(beginDate.getTime() - (weekPadding + daysToWeekStart) * MSECS_IN_DAY);
|
||||
|
||||
let layout = this.actor.layout_manager;
|
||||
let layout = this.layout_manager;
|
||||
let iter = new Date(beginDate);
|
||||
let row = 2;
|
||||
// nRows here means 6 weeks + one header + one navbar
|
||||
let nRows = 8;
|
||||
while (row < 8) {
|
||||
while (row < nRows) {
|
||||
// xgettext:no-javascript-format
|
||||
let button = new St.Button({ label: iter.toLocaleFormat(C_("date day number format", "%d")),
|
||||
can_focus: true });
|
||||
@@ -585,12 +583,13 @@ var Calendar = class Calendar {
|
||||
|
||||
// Hack used in lieu of border-collapse - see gnome-shell.css
|
||||
if (row == 2)
|
||||
styleClass = 'calendar-day-top ' + styleClass;
|
||||
styleClass = `calendar-day-top ${styleClass}`;
|
||||
|
||||
let leftMost = rtl ? iter.getDay() == (this._weekStart + 6) % 7
|
||||
: iter.getDay() == this._weekStart;
|
||||
let leftMost = rtl
|
||||
? iter.getDay() == (this._weekStart + 6) % 7
|
||||
: iter.getDay() == this._weekStart;
|
||||
if (leftMost)
|
||||
styleClass = 'calendar-day-left ' + styleClass;
|
||||
styleClass = `calendar-day-left ${styleClass}`;
|
||||
|
||||
if (sameDay(now, iter))
|
||||
styleClass += ' calendar-today';
|
||||
@@ -648,17 +647,17 @@ var Calendar = class Calendar {
|
||||
button.add_style_pseudo_class('selected');
|
||||
if (this._shouldDateGrabFocus)
|
||||
button.grab_key_focus();
|
||||
}
|
||||
else
|
||||
} else {
|
||||
button.remove_style_pseudo_class('selected');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Calendar.prototype);
|
||||
});
|
||||
|
||||
var EventMessage = class EventMessage extends MessageList.Message {
|
||||
constructor(event, date) {
|
||||
super('', event.summary);
|
||||
var EventMessage = GObject.registerClass(
|
||||
class EventMessage extends MessageList.Message {
|
||||
_init(event, date) {
|
||||
super._init('', event.summary);
|
||||
|
||||
this._event = event;
|
||||
this._date = date;
|
||||
@@ -667,11 +666,12 @@ var EventMessage = class EventMessage extends MessageList.Message {
|
||||
|
||||
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
|
||||
this.setIcon(this._icon);
|
||||
}
|
||||
|
||||
this.actor.connect('style-changed', () => {
|
||||
let iconVisible = this.actor.get_parent().has_style_pseudo_class('first-child');
|
||||
this._icon.opacity = (iconVisible ? 255 : 0);
|
||||
});
|
||||
vfunc_style_changed() {
|
||||
let iconVisible = this.get_parent().has_style_pseudo_class('first-child');
|
||||
this._icon.opacity = (iconVisible ? 255 : 0);
|
||||
super.vfunc_style_changed();
|
||||
}
|
||||
|
||||
_formatEventTime() {
|
||||
@@ -686,32 +686,33 @@ var EventMessage = class EventMessage extends MessageList.Message {
|
||||
*/
|
||||
title = C_("event list time", "All Day");
|
||||
} else {
|
||||
let date = this._event.date >= periodBegin ? this._event.date
|
||||
: this._event.end;
|
||||
let date = this._event.date >= periodBegin
|
||||
? this._event.date
|
||||
: this._event.end;
|
||||
title = Util.formatTime(date, { timeOnly: true });
|
||||
}
|
||||
|
||||
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
|
||||
if (this._event.date < periodBegin && !this._event.allDay) {
|
||||
if (rtl)
|
||||
title = title + ELLIPSIS_CHAR;
|
||||
title = `${title}${ELLIPSIS_CHAR}`;
|
||||
else
|
||||
title = ELLIPSIS_CHAR + title;
|
||||
title = `${ELLIPSIS_CHAR}${title}`;
|
||||
}
|
||||
if (this._event.end > periodEnd && !this._event.allDay) {
|
||||
if (rtl)
|
||||
title = ELLIPSIS_CHAR + title;
|
||||
title = `${ELLIPSIS_CHAR}${title}`;
|
||||
else
|
||||
title = title + ELLIPSIS_CHAR;
|
||||
title = `${title}${ELLIPSIS_CHAR}`;
|
||||
}
|
||||
return title;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var NotificationMessage =
|
||||
var NotificationMessage = GObject.registerClass(
|
||||
class NotificationMessage extends MessageList.Message {
|
||||
constructor(notification) {
|
||||
super(notification.title, notification.bannerBodyText);
|
||||
_init(notification) {
|
||||
super._init(notification.title, notification.bannerBodyText);
|
||||
this.setUseBodyMarkup(notification.bannerBodyMarkup);
|
||||
|
||||
this.notification = notification;
|
||||
@@ -741,14 +742,14 @@ class NotificationMessage extends MessageList.Message {
|
||||
return this.notification.source.createIcon(MESSAGE_ICON_SIZE);
|
||||
}
|
||||
|
||||
_onUpdated(n, clear) {
|
||||
_onUpdated(n, _clear) {
|
||||
this.setIcon(this._getIcon());
|
||||
this.setTitle(n.title);
|
||||
this.setBody(n.bannerBodyText);
|
||||
this.setUseBodyMarkup(n.bannerBodyMarkup);
|
||||
}
|
||||
|
||||
_onClicked() {
|
||||
vfunc_clicked() {
|
||||
this.notification.activate();
|
||||
}
|
||||
|
||||
@@ -770,11 +771,12 @@ class NotificationMessage extends MessageList.Message {
|
||||
canClose() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var EventsSection = class EventsSection extends MessageList.MessageListSection {
|
||||
constructor() {
|
||||
super();
|
||||
var EventsSection = GObject.registerClass(
|
||||
class EventsSection extends MessageList.MessageListSection {
|
||||
_init() {
|
||||
super._init();
|
||||
|
||||
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
|
||||
this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
|
||||
@@ -786,7 +788,7 @@ var EventsSection = class EventsSection extends MessageList.MessageListSection {
|
||||
label: '',
|
||||
x_align: St.Align.START,
|
||||
can_focus: true });
|
||||
this.actor.insert_child_below(this._title, null);
|
||||
this.insert_child_below(this._title, null);
|
||||
|
||||
this._title.connect('clicked', this._onTitleClicked.bind(this));
|
||||
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
|
||||
@@ -905,12 +907,29 @@ var EventsSection = class EventsSection extends MessageList.MessageListSection {
|
||||
|
||||
super._sync();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var NotificationSection =
|
||||
var TimeLabel = GObject.registerClass(
|
||||
class NotificationTimeLabel extends St.Label {
|
||||
_init(datetime) {
|
||||
super._init({
|
||||
style_class: 'event-time',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
y_align: Clutter.ActorAlign.END
|
||||
});
|
||||
this._datetime = datetime;
|
||||
}
|
||||
|
||||
vfunc_map() {
|
||||
this.text = Util.formatTimeSpan(this._datetime);
|
||||
super.vfunc_map();
|
||||
}
|
||||
});
|
||||
|
||||
var NotificationSection = GObject.registerClass(
|
||||
class NotificationSection extends MessageList.MessageListSection {
|
||||
constructor() {
|
||||
super();
|
||||
_init() {
|
||||
super._init();
|
||||
|
||||
this._sources = new Map();
|
||||
this._nUrgent = 0;
|
||||
@@ -919,8 +938,6 @@ class NotificationSection extends MessageList.MessageListSection {
|
||||
Main.messageTray.getSources().forEach(source => {
|
||||
this._sourceAdded(Main.messageTray, source);
|
||||
});
|
||||
|
||||
this.actor.connect('notify::mapped', this._onMapped.bind(this));
|
||||
}
|
||||
|
||||
get allowed() {
|
||||
@@ -928,17 +945,6 @@ class NotificationSection extends MessageList.MessageListSection {
|
||||
!Main.sessionMode.isGreeter;
|
||||
}
|
||||
|
||||
_createTimeLabel(datetime) {
|
||||
let label = new St.Label({ style_class: 'event-time',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
y_align: Clutter.ActorAlign.END });
|
||||
label.connect('notify::mapped', () => {
|
||||
if (label.mapped)
|
||||
label.text = Util.formatTimeSpan(datetime);
|
||||
});
|
||||
return label;
|
||||
}
|
||||
|
||||
_sourceAdded(tray, source) {
|
||||
let obj = {
|
||||
destroyId: 0,
|
||||
@@ -956,13 +962,13 @@ class NotificationSection extends MessageList.MessageListSection {
|
||||
|
||||
_onNotificationAdded(source, notification) {
|
||||
let message = new NotificationMessage(notification);
|
||||
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
|
||||
message.setSecondaryActor(new TimeLabel(notification.datetime));
|
||||
|
||||
let isUrgent = notification.urgency == MessageTray.Urgency.CRITICAL;
|
||||
|
||||
let updatedId = notification.connect('updated', () => {
|
||||
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
|
||||
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.actor.mapped);
|
||||
message.setSecondaryActor(new TimeLabel(notification.datetime));
|
||||
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.mapped);
|
||||
});
|
||||
let destroyId = notification.connect('destroy', () => {
|
||||
notification.disconnect(destroyId);
|
||||
@@ -982,7 +988,7 @@ class NotificationSection extends MessageList.MessageListSection {
|
||||
}
|
||||
|
||||
let index = isUrgent ? 0 : this._nUrgent;
|
||||
this.addMessageAtIndex(message, index, this.actor.mapped);
|
||||
this.addMessageAtIndex(message, index, this.mapped);
|
||||
}
|
||||
|
||||
_onSourceDestroy(source, obj) {
|
||||
@@ -992,25 +998,23 @@ class NotificationSection extends MessageList.MessageListSection {
|
||||
this._sources.delete(source);
|
||||
}
|
||||
|
||||
_onMapped() {
|
||||
if (!this.actor.mapped)
|
||||
return;
|
||||
|
||||
for (let message of this._messages.keys())
|
||||
vfunc_map() {
|
||||
this._messages.forEach(message => {
|
||||
if (message.notification.urgency != MessageTray.Urgency.CRITICAL)
|
||||
message.notification.acknowledged = true;
|
||||
});
|
||||
super.vfunc_map();
|
||||
}
|
||||
|
||||
_shouldShow() {
|
||||
return !this.empty && isToday(this._date);
|
||||
}
|
||||
};
|
||||
|
||||
var Placeholder = class Placeholder {
|
||||
constructor() {
|
||||
this.actor = new St.BoxLayout({ style_class: 'message-list-placeholder',
|
||||
vertical: true });
|
||||
});
|
||||
|
||||
var Placeholder = GObject.registerClass(
|
||||
class Placeholder extends St.BoxLayout {
|
||||
_init() {
|
||||
super._init({ style_class: 'message-list-placeholder', vertical: true });
|
||||
this._date = new Date();
|
||||
|
||||
let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
|
||||
@@ -1019,10 +1023,10 @@ var Placeholder = class Placeholder {
|
||||
this._otherIcon = new Gio.FileIcon({ file: otherFile });
|
||||
|
||||
this._icon = new St.Icon();
|
||||
this.actor.add_actor(this._icon);
|
||||
this.add_actor(this._icon);
|
||||
|
||||
this._label = new St.Label();
|
||||
this.actor.add_actor(this._label);
|
||||
this.add_actor(this._label);
|
||||
|
||||
this._sync();
|
||||
}
|
||||
@@ -1049,20 +1053,24 @@ var Placeholder = class Placeholder {
|
||||
this._label.text = _("No Events");
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var CalendarMessageList = class CalendarMessageList {
|
||||
constructor() {
|
||||
this.actor = new St.Widget({ style_class: 'message-list',
|
||||
layout_manager: new Clutter.BinLayout(),
|
||||
x_expand: true, y_expand: true });
|
||||
var CalendarMessageList = GObject.registerClass(
|
||||
class CalendarMessageList extends St.Widget {
|
||||
_init() {
|
||||
super._init({
|
||||
style_class: 'message-list',
|
||||
layout_manager: new Clutter.BinLayout(),
|
||||
x_expand: true,
|
||||
y_expand: true
|
||||
});
|
||||
|
||||
this._placeholder = new Placeholder();
|
||||
this.actor.add_actor(this._placeholder.actor);
|
||||
this.add_actor(this._placeholder);
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true,
|
||||
x_expand: true, y_expand: true });
|
||||
this.actor.add_actor(box);
|
||||
this.add_actor(box);
|
||||
|
||||
this._scrollView = new St.ScrollView({ style_class: 'vfade',
|
||||
overlay_scrollbars: true,
|
||||
@@ -1076,17 +1084,21 @@ var CalendarMessageList = class CalendarMessageList {
|
||||
can_focus: true });
|
||||
this._clearButton.set_x_align(Clutter.ActorAlign.END);
|
||||
this._clearButton.connect('clicked', () => {
|
||||
let sections = [...this._sections.keys()];
|
||||
sections.forEach((s) => { s.clear(); });
|
||||
this._sectionList.get_children().forEach(s => s.clear());
|
||||
});
|
||||
box.add_actor(this._clearButton);
|
||||
|
||||
this._placeholder.bind_property('visible',
|
||||
this._clearButton, 'visible',
|
||||
GObject.BindingFlags.INVERT_BOOLEAN);
|
||||
|
||||
this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections',
|
||||
vertical: true,
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.START });
|
||||
this._sectionList.connect('actor-added', this._sync.bind(this));
|
||||
this._sectionList.connect('actor-removed', this._sync.bind(this));
|
||||
this._scrollView.add_actor(this._sectionList);
|
||||
this._sections = new Map();
|
||||
|
||||
this._mediaSection = new Mpris.MediaSection();
|
||||
this._addSection(this._mediaSection);
|
||||
@@ -1101,59 +1113,35 @@ var CalendarMessageList = class CalendarMessageList {
|
||||
}
|
||||
|
||||
_addSection(section) {
|
||||
let obj = {
|
||||
destroyId: 0,
|
||||
visibleId: 0,
|
||||
emptyChangedId: 0,
|
||||
canClearChangedId: 0,
|
||||
keyFocusId: 0
|
||||
};
|
||||
obj.destroyId = section.actor.connect('destroy', () => {
|
||||
this._removeSection(section);
|
||||
});
|
||||
obj.visibleId = section.actor.connect('notify::visible',
|
||||
this._sync.bind(this));
|
||||
obj.emptyChangedId = section.connect('empty-changed',
|
||||
this._sync.bind(this));
|
||||
obj.canClearChangedId = section.connect('can-clear-changed',
|
||||
this._sync.bind(this));
|
||||
obj.keyFocusId = section.connect('key-focus-in',
|
||||
this._onKeyFocusIn.bind(this));
|
||||
let connectionsIds = [];
|
||||
|
||||
this._sections.set(section, obj);
|
||||
this._sectionList.add_actor(section.actor);
|
||||
this._sync();
|
||||
}
|
||||
for (let prop of ['visible', 'empty', 'can-clear']) {
|
||||
connectionsIds.push(
|
||||
section.connect(`notify::${prop}`, this._sync.bind(this)));
|
||||
}
|
||||
connectionsIds.push(section.connect('message-focused', (_s, messageActor) => {
|
||||
Util.ensureActorVisibleInScrollView(this._scrollView, messageActor);
|
||||
}));
|
||||
|
||||
_removeSection(section) {
|
||||
let obj = this._sections.get(section);
|
||||
section.actor.disconnect(obj.destroyId);
|
||||
section.actor.disconnect(obj.visibleId);
|
||||
section.disconnect(obj.emptyChangedId);
|
||||
section.disconnect(obj.canClearChangedId);
|
||||
section.disconnect(obj.keyFocusId);
|
||||
connectionsIds.push(section.connect('destroy', (section) => {
|
||||
connectionsIds.forEach(id => section.disconnect(id));
|
||||
this._sectionList.remove_actor(section);
|
||||
}));
|
||||
|
||||
this._sections.delete(section);
|
||||
this._sectionList.remove_actor(section.actor);
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_onKeyFocusIn(section, actor) {
|
||||
Util.ensureActorVisibleInScrollView(this._scrollView, actor);
|
||||
this._sectionList.add_actor(section);
|
||||
}
|
||||
|
||||
_sync() {
|
||||
let sections = [...this._sections.keys()];
|
||||
let sections = this._sectionList.get_children();
|
||||
let visible = sections.some(s => s.allowed);
|
||||
this.actor.visible = visible;
|
||||
this.visible = visible;
|
||||
if (!visible)
|
||||
return;
|
||||
|
||||
let empty = sections.every(s => s.empty || !s.actor.visible);
|
||||
this._placeholder.actor.visible = empty;
|
||||
this._clearButton.visible = !empty;
|
||||
let empty = sections.every(s => s.empty || !s.visible);
|
||||
this._placeholder.visible = empty;
|
||||
|
||||
let canClear = sections.some(s => s.canClear && s.actor.visible);
|
||||
let canClear = sections.some(s => s.canClear && s.visible);
|
||||
this._clearButton.reactive = canClear;
|
||||
}
|
||||
|
||||
@@ -1162,8 +1150,7 @@ var CalendarMessageList = class CalendarMessageList {
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
for (let section of this._sections.keys())
|
||||
section.setDate(date);
|
||||
this._sectionList.get_children().forEach(s => s.setDate(date));
|
||||
this._placeholder.setDate(date);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
const { Clutter, Pango, St } = imports.gi;
|
||||
/* exported CheckBox */
|
||||
const { Clutter, GObject, Pango, St } = imports.gi;
|
||||
|
||||
var CheckBox = class CheckBox {
|
||||
constructor(label) {
|
||||
var CheckBox = GObject.registerClass(
|
||||
class CheckBox extends St.Button {
|
||||
_init(label) {
|
||||
let container = new St.BoxLayout();
|
||||
this.actor = new St.Button({ style_class: 'check-box',
|
||||
child: container,
|
||||
button_mask: St.ButtonMask.ONE,
|
||||
toggle_mode: true,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
super._init({
|
||||
style_class: 'check-box',
|
||||
child: container,
|
||||
button_mask: St.ButtonMask.ONE,
|
||||
toggle_mode: true,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: true
|
||||
});
|
||||
|
||||
this._box = new St.Bin();
|
||||
this._box.set_y_align(Clutter.ActorAlign.START);
|
||||
@@ -31,4 +35,4 @@ var CheckBox = class CheckBox {
|
||||
getLabelActor() {
|
||||
return this._label;
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported CloseDialog */
|
||||
|
||||
const { Clutter, Gio, GLib, GObject, Meta, Shell } = imports.gi;
|
||||
|
||||
const Dialog = imports.ui.dialog;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
var FROZEN_WINDOW_BRIGHTNESS = -0.3
|
||||
var DIALOG_TRANSITION_TIME = 0.15
|
||||
var FROZEN_WINDOW_BRIGHTNESS = -0.3;
|
||||
var DIALOG_TRANSITION_TIME = 150;
|
||||
var ALIVE_TIMEOUT = 5000;
|
||||
|
||||
var CloseDialog = GObject.registerClass({
|
||||
Implements: [ Meta.CloseDialog ],
|
||||
Implements: [Meta.CloseDialog],
|
||||
Properties: {
|
||||
'window': GObject.ParamSpec.override('window', Meta.CloseDialog)
|
||||
},
|
||||
@@ -56,12 +56,12 @@ var CloseDialog = GObject.registerClass({
|
||||
this._dialog.height = windowActor.height;
|
||||
|
||||
this._dialog.addContent(this._createDialogContent());
|
||||
this._dialog.addButton({ label: _('Force Quit'),
|
||||
action: this._onClose.bind(this),
|
||||
this._dialog.addButton({ label: _('Force Quit'),
|
||||
action: this._onClose.bind(this),
|
||||
default: true });
|
||||
this._dialog.addButton({ label: _('Wait'),
|
||||
this._dialog.addButton({ label: _('Wait'),
|
||||
action: this._onWait.bind(this),
|
||||
key: Clutter.Escape });
|
||||
key: Clutter.Escape });
|
||||
|
||||
global.focus_manager.add_group(this._dialog);
|
||||
}
|
||||
@@ -148,12 +148,12 @@ var CloseDialog = GObject.registerClass({
|
||||
this._dialog.scale_y = 0;
|
||||
this._dialog.set_pivot_point(0.5, 0.5);
|
||||
|
||||
Tweener.addTween(this._dialog,
|
||||
{ scale_y: 1,
|
||||
transition: 'linear',
|
||||
time: DIALOG_TRANSITION_TIME,
|
||||
onComplete: this._onFocusChanged.bind(this)
|
||||
});
|
||||
this._dialog.ease({
|
||||
scale_y: 1,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
duration: DIALOG_TRANSITION_TIME,
|
||||
onComplete: this._onFocusChanged.bind(this)
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_hide() {
|
||||
@@ -165,7 +165,7 @@ var CloseDialog = GObject.registerClass({
|
||||
GLib.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
|
||||
global.display.disconnect(this._windowFocusChangedId)
|
||||
global.display.disconnect(this._windowFocusChangedId);
|
||||
this._windowFocusChangedId = 0;
|
||||
|
||||
global.stage.disconnect(this._keyFocusChangedId);
|
||||
@@ -175,14 +175,12 @@ var CloseDialog = GObject.registerClass({
|
||||
this._dialog = null;
|
||||
this._removeWindowEffect();
|
||||
|
||||
Tweener.addTween(dialog,
|
||||
{ scale_y: 0,
|
||||
transition: 'linear',
|
||||
time: DIALOG_TRANSITION_TIME,
|
||||
onComplete: () => {
|
||||
dialog.destroy();
|
||||
}
|
||||
});
|
||||
dialog.ease({
|
||||
scale_y: 0,
|
||||
mode: Clutter.AnimationMode.LINEAR,
|
||||
duration: DIALOG_TRANSITION_TIME,
|
||||
onComplete: () => dialog.destroy()
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_focus() {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported ComponentManager */
|
||||
const Main = imports.ui.main;
|
||||
|
||||
var ComponentManager = class {
|
||||
@@ -13,13 +14,13 @@ var ComponentManager = class {
|
||||
let newEnabledComponents = Main.sessionMode.components;
|
||||
|
||||
newEnabledComponents.filter(
|
||||
name => this._enabledComponents.indexOf(name) == -1
|
||||
name => !this._enabledComponents.includes(name)
|
||||
).forEach(name => {
|
||||
this._enableComponent(name);
|
||||
});
|
||||
|
||||
this._enabledComponents.filter(
|
||||
name => newEnabledComponents.indexOf(name) == -1
|
||||
name => !newEnabledComponents.includes(name)
|
||||
).forEach(name => {
|
||||
this._disableComponent(name);
|
||||
});
|
||||
@@ -37,8 +38,8 @@ var ComponentManager = class {
|
||||
if (component)
|
||||
return component;
|
||||
|
||||
if (Main.sessionMode.isLocked)
|
||||
return null;
|
||||
if (Main.sessionMode.isLocked)
|
||||
return null;
|
||||
|
||||
let constructor = this._importComponent(name);
|
||||
component = new constructor();
|
||||
@@ -48,7 +49,7 @@ var ComponentManager = class {
|
||||
|
||||
_enableComponent(name) {
|
||||
let component = this._ensureComponent(name);
|
||||
if (component)
|
||||
if (component)
|
||||
component.enable();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Component */
|
||||
|
||||
const { Gio, GLib } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
@@ -38,7 +38,7 @@ var AutomountManager = class {
|
||||
this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', this._onDriveDisconnected.bind(this));
|
||||
this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', this._onDriveEjectButton.bind(this));
|
||||
|
||||
this._mountAllId = Mainloop.idle_add(this._startupMountAll.bind(this));
|
||||
this._mountAllId = GLib.idle_add(GLib.PRIORITY_DEFAULT, this._startupMountAll.bind(this));
|
||||
GLib.Source.set_name_by_id(this._mountAllId, '[gnome-shell] this._startupMountAll');
|
||||
}
|
||||
|
||||
@@ -50,12 +50,12 @@ var AutomountManager = class {
|
||||
this._volumeMonitor.disconnect(this._driveEjectButtonId);
|
||||
|
||||
if (this._mountAllId > 0) {
|
||||
Mainloop.source_remove(this._mountAllId);
|
||||
GLib.source_remove(this._mountAllId);
|
||||
this._mountAllId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_InhibitorsChanged(object, senderName, [inhibtor]) {
|
||||
_InhibitorsChanged(_object, _senderName, [_inhibitor]) {
|
||||
this._session.IsInhibitedRemote(GNOME_SESSION_AUTOMOUNT_INHIBIT,
|
||||
(result, error) => {
|
||||
if (!error) {
|
||||
@@ -109,25 +109,23 @@ var AutomountManager = class {
|
||||
// we force stop/eject in this case, so we don't have to pass a
|
||||
// mount operation object
|
||||
if (drive.can_stop()) {
|
||||
drive.stop
|
||||
(Gio.MountUnmountFlags.FORCE, null, null,
|
||||
(drive, res) => {
|
||||
try {
|
||||
drive.stop_finish(res);
|
||||
} catch (e) {
|
||||
log("Unable to stop the drive after drive-eject-button " + e.toString());
|
||||
}
|
||||
});
|
||||
drive.stop(Gio.MountUnmountFlags.FORCE, null, null,
|
||||
(drive, res) => {
|
||||
try {
|
||||
drive.stop_finish(res);
|
||||
} catch (e) {
|
||||
log(`Unable to stop the drive after drive-eject-button ${e.toString()}`);
|
||||
}
|
||||
});
|
||||
} else if (drive.can_eject()) {
|
||||
drive.eject_with_operation
|
||||
(Gio.MountUnmountFlags.FORCE, null, null,
|
||||
(drive, res) => {
|
||||
try {
|
||||
drive.eject_with_operation_finish(res);
|
||||
} catch (e) {
|
||||
log("Unable to eject the drive after drive-eject-button " + e.toString());
|
||||
}
|
||||
});
|
||||
drive.eject_with_operation(Gio.MountUnmountFlags.FORCE, null, null,
|
||||
(drive, res) => {
|
||||
try {
|
||||
drive.eject_with_operation_finish(res);
|
||||
} catch (e) {
|
||||
log(`Unable to eject the drive after drive-eject-button ${e.toString()}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +156,7 @@ var AutomountManager = class {
|
||||
!volume.should_automount() ||
|
||||
!volume.can_mount()) {
|
||||
// allow the autorun to run anyway; this can happen if the
|
||||
// mount gets added programmatically later, even if
|
||||
// mount gets added programmatically later, even if
|
||||
// should_automount() or can_mount() are false, like for
|
||||
// blank optical media.
|
||||
this._allowAutorun(volume);
|
||||
@@ -213,7 +211,7 @@ var AutomountManager = class {
|
||||
}
|
||||
|
||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
|
||||
log('Unable to mount volume ' + volume.get_name() + ': ' + e.toString());
|
||||
log(`Unable to mount volume ${volume.get_name()}: ${e.toString()}`);
|
||||
this._closeOperation(volume);
|
||||
}
|
||||
}
|
||||
@@ -221,17 +219,17 @@ var AutomountManager = class {
|
||||
|
||||
_onVolumeRemoved(monitor, volume) {
|
||||
if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) {
|
||||
Mainloop.source_remove(volume._allowAutorunExpireId);
|
||||
GLib.source_remove(volume._allowAutorunExpireId);
|
||||
delete volume._allowAutorunExpireId;
|
||||
}
|
||||
this._volumeQueue =
|
||||
this._volumeQueue =
|
||||
this._volumeQueue.filter(element => (element != volume));
|
||||
}
|
||||
|
||||
_reaskPassword(volume) {
|
||||
let prevOperation = this._activeOperations.get(volume);
|
||||
let existingDialog = prevOperation ? prevOperation.borrowDialog() : null;
|
||||
let operation =
|
||||
let operation =
|
||||
new ShellMountOperation.ShellMountOperation(volume,
|
||||
{ existingDialog: existingDialog });
|
||||
this._mountVolume(volume, operation);
|
||||
@@ -250,7 +248,7 @@ var AutomountManager = class {
|
||||
}
|
||||
|
||||
_allowAutorunExpire(volume) {
|
||||
let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => {
|
||||
let id = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, AUTORUN_EXPIRE_TIMEOUT_SECS, () => {
|
||||
volume.allowAutorun = false;
|
||||
delete volume._allowAutorunExpireId;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Component */
|
||||
|
||||
const { Gio, St } = imports.gi;
|
||||
const { Gio, GObject, St } = imports.gi;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Main = imports.ui.main;
|
||||
@@ -40,7 +41,7 @@ function isMountRootHidden(root) {
|
||||
let path = root.get_path();
|
||||
|
||||
// skip any mounts in hidden directory hierarchies
|
||||
return (path.indexOf('/.') != -1);
|
||||
return (path.includes('/.'));
|
||||
}
|
||||
|
||||
function isMountNonLocal(mount) {
|
||||
@@ -62,18 +63,15 @@ function startAppForMount(app, mount) {
|
||||
files.push(root);
|
||||
|
||||
try {
|
||||
retval = app.launch(files,
|
||||
retval = app.launch(files,
|
||||
global.create_app_launch_context(0, -1));
|
||||
} catch (e) {
|
||||
log('Unable to launch the application ' + app.get_name()
|
||||
+ ': ' + e.toString());
|
||||
log(`Unable to launch the application ${app.get_name()}: ${e}`);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/******************************************/
|
||||
|
||||
const HotplugSnifferIface = loadInterfaceXML('org.gnome.Shell.HotplugSniffer');
|
||||
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
|
||||
function HotplugSniffer() {
|
||||
@@ -107,8 +105,7 @@ var ContentTypeDiscoverer = class {
|
||||
try {
|
||||
contentTypes = mount.guess_content_type_finish(res);
|
||||
} catch (e) {
|
||||
log('Unable to guess content types on added mount ' + mount.get_name()
|
||||
+ ': ' + e.toString());
|
||||
log(`Unable to guess content types on added mount ${mount.get_name()}: ${e}`);
|
||||
}
|
||||
|
||||
if (contentTypes.length) {
|
||||
@@ -118,16 +115,13 @@ var ContentTypeDiscoverer = class {
|
||||
|
||||
let hotplugSniffer = new HotplugSniffer();
|
||||
hotplugSniffer.SniffURIRemote(root.get_uri(),
|
||||
([contentTypes]) => {
|
||||
this._emitCallback(mount, contentTypes);
|
||||
});
|
||||
([contentTypes]) => {
|
||||
this._emitCallback(mount, contentTypes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_emitCallback(mount, contentTypes) {
|
||||
if (!contentTypes)
|
||||
contentTypes = [];
|
||||
|
||||
_emitCallback(mount, contentTypes = []) {
|
||||
// we're not interested in win32 software content types here
|
||||
contentTypes = contentTypes.filter(
|
||||
type => (type != 'x-content/win32-software')
|
||||
@@ -192,15 +186,15 @@ var AutorunDispatcher = class {
|
||||
|
||||
_getAutorunSettingForType(contentType) {
|
||||
let runApp = this._settings.get_strv(SETTING_START_APP);
|
||||
if (runApp.indexOf(contentType) != -1)
|
||||
if (runApp.includes(contentType))
|
||||
return AutorunSetting.RUN;
|
||||
|
||||
let ignore = this._settings.get_strv(SETTING_IGNORE);
|
||||
if (ignore.indexOf(contentType) != -1)
|
||||
if (ignore.includes(contentType))
|
||||
return AutorunSetting.IGNORE;
|
||||
|
||||
let openFiles = this._settings.get_strv(SETTING_OPEN_FOLDER);
|
||||
if (openFiles.indexOf(contentType) != -1)
|
||||
if (openFiles.includes(contentType))
|
||||
return AutorunSetting.FILES;
|
||||
|
||||
return AutorunSetting.ASK;
|
||||
@@ -219,11 +213,11 @@ var AutorunDispatcher = class {
|
||||
}
|
||||
|
||||
_addSource(mount, apps) {
|
||||
// if we already have a source showing for this
|
||||
// if we already have a source showing for this
|
||||
// mount, return
|
||||
if (this._getSourceForMount(mount))
|
||||
return;
|
||||
|
||||
|
||||
// add a new source
|
||||
this._sources.push(new AutorunSource(this._manager, mount, apps));
|
||||
}
|
||||
@@ -268,7 +262,7 @@ var AutorunDispatcher = class {
|
||||
|
||||
removeMount(mount) {
|
||||
let source = this._getSourceForMount(mount);
|
||||
|
||||
|
||||
// if we aren't tracking this mount, don't do anything
|
||||
if (!source)
|
||||
return;
|
||||
@@ -278,9 +272,10 @@ var AutorunDispatcher = class {
|
||||
}
|
||||
};
|
||||
|
||||
var AutorunSource = class extends MessageTray.Source {
|
||||
constructor(manager, mount, apps) {
|
||||
super(mount.get_name());
|
||||
var AutorunSource = GObject.registerClass(
|
||||
class AutorunSource extends MessageTray.Source {
|
||||
_init(manager, mount, apps) {
|
||||
super._init(mount.get_name());
|
||||
|
||||
this._manager = manager;
|
||||
this.mount = mount;
|
||||
@@ -290,7 +285,7 @@ var AutorunSource = class extends MessageTray.Source {
|
||||
|
||||
// add ourselves as a source, and popup the notification
|
||||
Main.messageTray.add(this);
|
||||
this.notify(this._notification);
|
||||
this.showNotification(this._notification);
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
@@ -300,11 +295,12 @@ var AutorunSource = class extends MessageTray.Source {
|
||||
_createPolicy() {
|
||||
return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus');
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var AutorunNotification = class extends MessageTray.Notification {
|
||||
constructor(manager, source) {
|
||||
super(source, source.title);
|
||||
var AutorunNotification = GObject.registerClass(
|
||||
class AutorunNotification extends MessageTray.Notification {
|
||||
_init(manager, source) {
|
||||
super._init(source, source.title);
|
||||
|
||||
this._manager = manager;
|
||||
this._mount = source.mount;
|
||||
@@ -329,10 +325,10 @@ var AutorunNotification = class extends MessageTray.Notification {
|
||||
style_class: 'hotplug-notification-item-icon' });
|
||||
box.add(icon);
|
||||
|
||||
let label = new St.Bin({ y_align: St.Align.MIDDLE,
|
||||
child: new St.Label
|
||||
({ text: _("Open with %s").format(app.get_name()) })
|
||||
});
|
||||
let label = new St.Bin({
|
||||
y_align: St.Align.MIDDLE,
|
||||
child: new St.Label({ text: _("Open with %s").format(app.get_name()) }),
|
||||
});
|
||||
box.add(label);
|
||||
|
||||
let button = new St.Button({ child: box,
|
||||
@@ -356,6 +352,6 @@ var AutorunNotification = class extends MessageTray.Notification {
|
||||
let app = Gio.app_info_get_default_for_type('inode/directory', false);
|
||||
startAppForMount(app, this._mount);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var Component = AutorunManager;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Component */
|
||||
|
||||
const { Clutter, Gcr, Gio, GObject, Pango, Shell, St } = imports.gi;
|
||||
|
||||
@@ -76,13 +77,13 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
||||
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
|
||||
|
||||
if (rtl) {
|
||||
layout.attach(this._workSpinner.actor, 0, row, 1, 1);
|
||||
layout.attach(this._workSpinner, 0, row, 1, 1);
|
||||
layout.attach(this._passwordEntry, 1, row, 1, 1);
|
||||
layout.attach(label, 2, row, 1, 1);
|
||||
} else {
|
||||
layout.attach(label, 0, row, 1, 1);
|
||||
layout.attach(this._passwordEntry, 1, row, 1, 1);
|
||||
layout.attach(this._workSpinner.actor, 2, row, 1, 1);
|
||||
layout.attach(this._workSpinner, 2, row, 1, 1);
|
||||
}
|
||||
row++;
|
||||
} else {
|
||||
@@ -120,8 +121,8 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
||||
if (this.prompt.choice_visible) {
|
||||
let choice = new CheckBox.CheckBox();
|
||||
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
||||
layout.attach(choice.actor, rtl ? 0 : 1, row, 1, 1);
|
||||
this.prompt.bind_property('choice-chosen', choice, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
||||
layout.attach(choice, rtl ? 0 : 1, row, 1, 1);
|
||||
row++;
|
||||
}
|
||||
|
||||
@@ -162,7 +163,7 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
||||
// NOTE: ModalDialog.open() is safe to call if the dialog is
|
||||
// already open - it just returns true without side-effects
|
||||
if (this.open())
|
||||
return true;
|
||||
return true;
|
||||
|
||||
// The above fail if e.g. unable to get input grab
|
||||
//
|
||||
@@ -172,25 +173,25 @@ class KeyringDialog extends ModalDialog.ModalDialog {
|
||||
|
||||
log('keyringPrompt: Failed to show modal dialog.' +
|
||||
' Dismissing prompt request');
|
||||
this.prompt.cancel()
|
||||
this.prompt.cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
_onShowPassword(prompt) {
|
||||
_onShowPassword() {
|
||||
this._buildControlTable();
|
||||
this._ensureOpen();
|
||||
this._updateSensitivity(true);
|
||||
this._passwordEntry.grab_key_focus();
|
||||
}
|
||||
|
||||
_onShowConfirm(prompt) {
|
||||
_onShowConfirm() {
|
||||
this._buildControlTable();
|
||||
this._ensureOpen();
|
||||
this._updateSensitivity(true);
|
||||
this._continueButton.grab_key_focus();
|
||||
}
|
||||
|
||||
_onHidePrompt(prompt) {
|
||||
_onHidePrompt() {
|
||||
this.close();
|
||||
}
|
||||
|
||||
@@ -231,8 +232,9 @@ var KeyringPrompter = class {
|
||||
constructor() {
|
||||
this._prompter = new Gcr.SystemPrompter();
|
||||
this._prompter.connect('new-prompt', () => {
|
||||
let dialog = this._enabled ? new KeyringDialog()
|
||||
: new KeyringDummyDialog();
|
||||
let dialog = this._enabled
|
||||
? new KeyringDialog()
|
||||
: new KeyringDummyDialog();
|
||||
this._currentPrompt = dialog.prompt;
|
||||
return this._currentPrompt;
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Component */
|
||||
|
||||
const { Clutter, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
@@ -80,8 +81,9 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
secret.valid = secret.value.length > 0;
|
||||
this._updateOkButton();
|
||||
});
|
||||
} else
|
||||
} else {
|
||||
secret.valid = true;
|
||||
}
|
||||
|
||||
if (rtl) {
|
||||
layout.attach(secret.entry, 0, pos, 1, 1);
|
||||
@@ -105,21 +107,22 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
|
||||
contentBox.messageBox.add(descriptionLabel,
|
||||
{ y_fill: true,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START,
|
||||
expand: true });
|
||||
}
|
||||
|
||||
this._okButton = { label: _("Connect"),
|
||||
action: this._onOk.bind(this),
|
||||
default: true
|
||||
};
|
||||
this._okButton = {
|
||||
label: _("Connect"),
|
||||
action: this._onOk.bind(this),
|
||||
default: true,
|
||||
};
|
||||
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: this.cancel.bind(this),
|
||||
key: Clutter.KEY_Escape,
|
||||
},
|
||||
this._okButton]);
|
||||
this.setButtons([{
|
||||
label: _("Cancel"),
|
||||
action: this.cancel.bind(this),
|
||||
key: Clutter.KEY_Escape,
|
||||
}, this._okButton]);
|
||||
|
||||
this._updateOkButton();
|
||||
}
|
||||
@@ -161,9 +164,9 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
if (value.length == 64) {
|
||||
// must be composed of hexadecimal digits only
|
||||
for (let i = 0; i < 64; i++) {
|
||||
if (!((value[i] >= 'a' && value[i] <= 'f')
|
||||
|| (value[i] >= 'A' && value[i] <= 'F')
|
||||
|| (value[i] >= '0' && value[i] <= '9')))
|
||||
if (!((value[i] >= 'a' && value[i] <= 'f') ||
|
||||
(value[i] >= 'A' && value[i] <= 'F') ||
|
||||
(value[i] >= '0' && value[i] <= '9')))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -176,28 +179,29 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
let value = secret.value;
|
||||
if (secret.wep_key_type == NM.WepKeyType.KEY) {
|
||||
if (value.length == 10 || value.length == 26) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
if (!((value[i] >= 'a' && value[i] <= 'f')
|
||||
|| (value[i] >= 'A' && value[i] <= 'F')
|
||||
|| (value[i] >= '0' && value[i] <= '9')))
|
||||
return false;
|
||||
}
|
||||
} else if (value.length == 5 || value.length == 13) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
if (!((value[i] >= 'a' && value[i] <= 'z')
|
||||
|| (value[i] >= 'A' && value[i] <= 'Z')))
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
if (!((value[i] >= 'a' && value[i] <= 'f') ||
|
||||
(value[i] >= 'A' && value[i] <= 'F') ||
|
||||
(value[i] >= '0' && value[i] <= '9')))
|
||||
return false;
|
||||
}
|
||||
} else
|
||||
} else if (value.length == 5 || value.length == 13) {
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
if (!((value[i] >= 'a' && value[i] <= 'z') ||
|
||||
(value[i] >= 'A' && value[i] <= 'Z')))
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
} else if (secret.wep_key_type == NM.WepKeyType.PASSPHRASE) {
|
||||
if (value.length < 0 || value.length > 64)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else if (secret.wep_key_type == NM.WepKeyType.PASSPHRASE) {
|
||||
if (value.length < 0 || value.length > 64)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_getWirelessSecrets(secrets, wirelessSetting) {
|
||||
_getWirelessSecrets(secrets, _wirelessSetting) {
|
||||
let wirelessSecuritySetting = this._connection.get_setting_wireless_security();
|
||||
|
||||
if (this._settingName == '802-1x') {
|
||||
@@ -209,12 +213,13 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
// First the easy ones
|
||||
case 'wpa-none':
|
||||
case 'wpa-psk':
|
||||
case 'sae':
|
||||
secrets.push({ label: _("Password: "), key: 'psk',
|
||||
value: wirelessSecuritySetting.psk || '',
|
||||
validate: this._validateWpaPsk, password: true });
|
||||
break;
|
||||
case 'none': // static WEP
|
||||
secrets.push({ label: _("Key: "), key: 'wep-key' + wirelessSecuritySetting.wep_tx_keyidx,
|
||||
secrets.push({ label: _("Key: "), key: `wep-key${wirelessSecuritySetting.wep_tx_keyidx}`,
|
||||
value: wirelessSecuritySetting.get_wep_key(wirelessSecuritySetting.wep_tx_keyidx) || '',
|
||||
wep_key_type: wirelessSecuritySetting.wep_key_type,
|
||||
validate: this._validateStaticWep, password: true });
|
||||
@@ -230,13 +235,12 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
this._get8021xSecrets(secrets);
|
||||
break;
|
||||
default:
|
||||
log('Invalid wireless key management: ' + wirelessSecuritySetting.key_mgmt);
|
||||
log(`Invalid wireless key management: ${wirelessSecuritySetting.key_mgmt}`);
|
||||
}
|
||||
}
|
||||
|
||||
_get8021xSecrets(secrets) {
|
||||
let ieee8021xSetting = this._connection.get_setting_802_1x();
|
||||
let phase2method;
|
||||
|
||||
/* If hints were given we know exactly what we need to ask */
|
||||
if (this._settingName == "802-1x" && this._hints.length) {
|
||||
@@ -273,7 +277,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
value: ieee8021xSetting.private_key_password || '', password: true });
|
||||
break;
|
||||
default:
|
||||
log('Invalid EAP/IEEE802.1x method: ' + ieee8021xSetting.get_eap_method(0));
|
||||
log(`Invalid EAP/IEEE802.1x method: ${ieee8021xSetting.get_eap_method(0)}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,7 +308,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
let ssid;
|
||||
|
||||
let content = { };
|
||||
content.secrets = [ ];
|
||||
content.secrets = [];
|
||||
|
||||
switch (connectionType) {
|
||||
case '802-11-wireless':
|
||||
@@ -327,7 +331,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
this._getPPPoESecrets(content.secrets);
|
||||
break;
|
||||
case 'gsm':
|
||||
if (this._hints.indexOf('pin') != -1) {
|
||||
if (this._hints.includes('pin')) {
|
||||
let gsmSetting = this._connection.get_setting_gsm();
|
||||
content.title = _("PIN code required");
|
||||
content.message = _("PIN code is needed for the mobile broadband device");
|
||||
@@ -343,8 +347,8 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
|
||||
this._getMobileSecrets(content.secrets, connectionType);
|
||||
break;
|
||||
default:
|
||||
log('Invalid connection type: ' + connectionType);
|
||||
};
|
||||
log(`Invalid connection type: ${connectionType}`);
|
||||
}
|
||||
|
||||
return content;
|
||||
}
|
||||
@@ -359,16 +363,15 @@ var VPNRequestHandler = class {
|
||||
this._pluginOutBuffer = [];
|
||||
this._title = null;
|
||||
this._description = null;
|
||||
this._content = [ ];
|
||||
this._content = [];
|
||||
this._shellDialog = null;
|
||||
|
||||
let connectionSetting = connection.get_setting_connection();
|
||||
|
||||
let argv = [ authHelper.fileName,
|
||||
'-u', connectionSetting.uuid,
|
||||
'-n', connectionSetting.id,
|
||||
'-s', serviceType
|
||||
];
|
||||
let argv = [authHelper.fileName,
|
||||
'-u', connectionSetting.uuid,
|
||||
'-n', connectionSetting.id,
|
||||
'-s', serviceType];
|
||||
if (authHelper.externalUIMode)
|
||||
argv.push('--external-ui-mode');
|
||||
if (flags & NM.SecretAgentGetSecretsFlags.ALLOW_INTERACTION)
|
||||
@@ -385,7 +388,7 @@ var VPNRequestHandler = class {
|
||||
this._newStylePlugin = authHelper.externalUIMode;
|
||||
|
||||
try {
|
||||
let [success, pid, stdin, stdout, stderr] =
|
||||
let [success_, pid, stdin, stdout, stderr] =
|
||||
GLib.spawn_async_with_pipes(null, /* pwd */
|
||||
argv,
|
||||
null, /* envp */
|
||||
@@ -407,7 +410,7 @@ var VPNRequestHandler = class {
|
||||
this._vpnChildFinished.bind(this));
|
||||
|
||||
this._writeConnection();
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
logError(e, 'error while spawning VPN auth helper');
|
||||
|
||||
this._agent.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||
@@ -424,7 +427,7 @@ var VPNRequestHandler = class {
|
||||
} else {
|
||||
try {
|
||||
this._stdin.write('QUIT\n\n', null);
|
||||
} catch(e) { /* ignore broken pipe errors */ }
|
||||
} catch (e) { /* ignore broken pipe errors */ }
|
||||
}
|
||||
|
||||
this.destroy();
|
||||
@@ -444,7 +447,7 @@ var VPNRequestHandler = class {
|
||||
this._destroyed = true;
|
||||
}
|
||||
|
||||
_vpnChildFinished(pid, status, requestObj) {
|
||||
_vpnChildFinished(pid, status, _requestObj) {
|
||||
this._childWatch = 0;
|
||||
if (this._newStylePlugin) {
|
||||
// For new style plugin, all work is done in the async reading functions
|
||||
@@ -459,8 +462,9 @@ var VPNRequestHandler = class {
|
||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
||||
else
|
||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
|
||||
} else
|
||||
} else {
|
||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
this.destroy();
|
||||
}
|
||||
@@ -473,7 +477,7 @@ var VPNRequestHandler = class {
|
||||
if (line == '' && this._previousLine == '') {
|
||||
try {
|
||||
this._stdin.write('QUIT\n\n', null);
|
||||
} catch(e) { /* ignore broken pipe errors */ }
|
||||
} catch (e) { /* ignore broken pipe errors */ }
|
||||
} else {
|
||||
this._agent.set_password(this._requestId, this._previousLine, line);
|
||||
this._previousLine = undefined;
|
||||
@@ -485,7 +489,7 @@ var VPNRequestHandler = class {
|
||||
|
||||
_readStdoutOldStyle() {
|
||||
this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, (stream, result) => {
|
||||
let [line, len] = this._dataStdout.read_line_finish_utf8(result);
|
||||
let [line, len_] = this._dataStdout.read_line_finish_utf8(result);
|
||||
|
||||
if (line == null) {
|
||||
// end of file
|
||||
@@ -540,7 +544,7 @@ var VPNRequestHandler = class {
|
||||
message: keyfile.get_string(VPN_UI_GROUP, 'Description'),
|
||||
secrets: [] };
|
||||
|
||||
let [groups, len] = keyfile.get_groups();
|
||||
let [groups, len_] = keyfile.get_groups();
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
if (groups[i] == VPN_UI_GROUP)
|
||||
continue;
|
||||
@@ -549,11 +553,12 @@ var VPNRequestHandler = class {
|
||||
let shouldAsk = keyfile.get_boolean(groups[i], 'ShouldAsk');
|
||||
|
||||
if (shouldAsk) {
|
||||
contentOverride.secrets.push({ label: keyfile.get_string(groups[i], 'Label'),
|
||||
key: groups[i],
|
||||
value: value,
|
||||
password: keyfile.get_boolean(groups[i], 'IsSecret')
|
||||
});
|
||||
contentOverride.secrets.push({
|
||||
label: keyfile.get_string(groups[i], 'Label'),
|
||||
key: groups[i],
|
||||
value: value,
|
||||
password: keyfile.get_boolean(groups[i], 'IsSecret'),
|
||||
});
|
||||
} else {
|
||||
if (!value.length) // Ignore empty secrets
|
||||
continue;
|
||||
@@ -561,7 +566,7 @@ var VPNRequestHandler = class {
|
||||
this._agent.set_password(this._requestId, groups[i], value);
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// No output is a valid case it means "both secrets are stored"
|
||||
if (data.length > 0) {
|
||||
logError(e, 'error while reading VPN plugin output keyfile');
|
||||
@@ -587,15 +592,15 @@ var VPNRequestHandler = class {
|
||||
|
||||
try {
|
||||
vpnSetting.foreach_data_item((key, value) => {
|
||||
this._stdin.write('DATA_KEY=' + key + '\n', null);
|
||||
this._stdin.write('DATA_VAL=' + (value || '') + '\n\n', null);
|
||||
this._stdin.write(`DATA_KEY=${key}\n`, null);
|
||||
this._stdin.write(`DATA_VAL=${value || ''}\n\n`, null);
|
||||
});
|
||||
vpnSetting.foreach_secret((key, value) => {
|
||||
this._stdin.write('SECRET_KEY=' + key + '\n', null);
|
||||
this._stdin.write('SECRET_VAL=' + (value || '') + '\n\n', null);
|
||||
this._stdin.write(`SECRET_KEY=${key}\n`, null);
|
||||
this._stdin.write(`SECRET_VAL=${value || ''}\n\n`, null);
|
||||
});
|
||||
this._stdin.write('DONE\n\n', null);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
logError(e, 'internal error while writing connection to helper');
|
||||
|
||||
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||
@@ -607,10 +612,11 @@ Signals.addSignalMethods(VPNRequestHandler.prototype);
|
||||
|
||||
var NetworkAgent = class {
|
||||
constructor() {
|
||||
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent',
|
||||
capabilities: NM.SecretAgentCapabilities.VPN_HINTS,
|
||||
auto_register: false
|
||||
});
|
||||
this._native = new Shell.NetworkAgent({
|
||||
identifier: 'org.gnome.Shell.NetworkAgent',
|
||||
capabilities: NM.SecretAgentCapabilities.VPN_HINTS,
|
||||
auto_register: false,
|
||||
});
|
||||
|
||||
this._dialogs = { };
|
||||
this._vpnRequests = { };
|
||||
@@ -619,9 +625,9 @@ var NetworkAgent = class {
|
||||
this._pluginDir = Gio.file_new_for_path(Config.VPNDIR);
|
||||
try {
|
||||
let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null);
|
||||
monitor.connect('changed', () => { this._vpnCacheBuilt = false; });
|
||||
} catch(e) {
|
||||
log('Failed to create monitor for VPN plugin dir: ' + e.message);
|
||||
monitor.connect('changed', () => (this._vpnCacheBuilt = false));
|
||||
} catch (e) {
|
||||
log(`Failed to create monitor for VPN plugin dir: ${e.message}`);
|
||||
}
|
||||
|
||||
this._native.connect('new-request', this._newRequest.bind(this));
|
||||
@@ -632,7 +638,7 @@ var NetworkAgent = class {
|
||||
try {
|
||||
this._native.init_finish(res);
|
||||
this._initialized = true;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
this._native = null;
|
||||
logError(e, 'error initializing the NetworkManager Agent');
|
||||
}
|
||||
@@ -680,12 +686,13 @@ var NetworkAgent = class {
|
||||
let connectionSetting = connection.get_setting_connection();
|
||||
let connectionType = connectionSetting.get_connection_type();
|
||||
switch (connectionType) {
|
||||
case '802-11-wireless':
|
||||
case '802-11-wireless': {
|
||||
let wirelessSetting = connection.get_setting_wireless();
|
||||
let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data());
|
||||
title = _("Authentication required by wireless network");
|
||||
body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
|
||||
break;
|
||||
}
|
||||
case '802-3-ethernet':
|
||||
title = _("Wired 802.1X authentication");
|
||||
body = _("A password is required to connect to “%s”.".format(connection.get_id()));
|
||||
@@ -695,8 +702,7 @@ var NetworkAgent = class {
|
||||
body = _("A password is required to connect to “%s”.".format(connection.get_id()));
|
||||
break;
|
||||
case 'gsm':
|
||||
if (hints.indexOf('pin') != -1) {
|
||||
let gsmSetting = connection.get_setting_gsm();
|
||||
if (hints.includes('pin')) {
|
||||
title = _("PIN code required");
|
||||
body = _("PIN code is needed for the mobile broadband device");
|
||||
break;
|
||||
@@ -708,7 +714,7 @@ var NetworkAgent = class {
|
||||
body = _("A password is required to connect to “%s”.").format(connectionSetting.get_id());
|
||||
break;
|
||||
default:
|
||||
log('Invalid connection type: ' + connectionType);
|
||||
log(`Invalid connection type: ${connectionType}`);
|
||||
this._native.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||
return;
|
||||
}
|
||||
@@ -728,7 +734,7 @@ var NetworkAgent = class {
|
||||
});
|
||||
|
||||
Main.messageTray.add(source);
|
||||
source.notify(notification);
|
||||
source.showNotification(notification);
|
||||
}
|
||||
|
||||
_newRequest(agent, requestId, connection, settingName, hints, flags) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Component */
|
||||
|
||||
const { AccountsService, Clutter, Gio, GLib,
|
||||
GObject, Pango, PolkitAgent, Polkit, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Animation = imports.ui.animation;
|
||||
const Dialog = imports.ui.dialog;
|
||||
@@ -39,19 +39,19 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
this.contentLayout.add_actor(content);
|
||||
|
||||
if (userNames.length > 1) {
|
||||
log('polkitAuthenticationAgent: Received ' + userNames.length +
|
||||
' identities that can be used for authentication. Only ' +
|
||||
log(`polkitAuthenticationAgent: Received ${userNames.length} ` +
|
||||
'identities that can be used for authentication. Only ' +
|
||||
'considering one.');
|
||||
}
|
||||
|
||||
let userName = GLib.get_user_name();
|
||||
if (userNames.indexOf(userName) < 0)
|
||||
if (!userNames.includes(userName))
|
||||
userName = 'root';
|
||||
if (userNames.indexOf(userName) < 0)
|
||||
if (!userNames.includes(userName))
|
||||
userName = userNames[0];
|
||||
|
||||
this._user = AccountsService.UserManager.get_default().get_user(userName);
|
||||
let userRealName = this._user.get_real_name()
|
||||
let userRealName = this._user.get_real_name();
|
||||
this._userLoadedId = this._user.connect('notify::is_loaded',
|
||||
this._onUserChanged.bind(this));
|
||||
this._userChangedId = this._user.connect('changed',
|
||||
@@ -76,17 +76,17 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
this._userAvatar = new UserWidget.Avatar(this._user,
|
||||
{ iconSize: DIALOG_ICON_SIZE,
|
||||
styleClass: 'polkit-dialog-user-icon' });
|
||||
this._userAvatar.actor.hide();
|
||||
userBox.add(this._userAvatar.actor,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
this._userAvatar.hide();
|
||||
userBox.add(this._userAvatar,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label',
|
||||
text: userRealName }));
|
||||
userBox.add(userLabel,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.MIDDLE });
|
||||
}
|
||||
@@ -99,14 +99,14 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
this._passwordBox.add(this._passwordLabel, { y_fill: false, y_align: St.Align.MIDDLE });
|
||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||
text: "",
|
||||
can_focus: true});
|
||||
can_focus: true });
|
||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
|
||||
this._passwordBox.add(this._passwordEntry,
|
||||
{ expand: true });
|
||||
|
||||
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
|
||||
this._passwordBox.add(this._workSpinner.actor);
|
||||
this._passwordBox.add(this._workSpinner);
|
||||
|
||||
this.setInitialKeyFocus(this._passwordEntry);
|
||||
this._passwordBox.hide();
|
||||
@@ -128,7 +128,7 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
* gnome-shell.css sets the color to be transparent
|
||||
*/
|
||||
this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label',
|
||||
text: 'abc'});
|
||||
text: 'abc' });
|
||||
this._nullMessageLabel.add_style_class_name('hidden');
|
||||
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._nullMessageLabel.clutter_text.line_wrap = true;
|
||||
@@ -138,7 +138,7 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
this._cancelButton = this.addButton({ label: _("Cancel"),
|
||||
action: this.cancel.bind(this),
|
||||
key: Clutter.Escape });
|
||||
this._okButton = this.addButton({ label: _("Authenticate"),
|
||||
this._okButton = this.addButton({ label: _("Authenticate"),
|
||||
action: this._onAuthenticateButtonPressed.bind(this),
|
||||
default: true });
|
||||
|
||||
@@ -181,9 +181,9 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
//
|
||||
// We could add retrying if this turns out to be a problem
|
||||
|
||||
log('polkitAuthenticationAgent: Failed to show modal dialog.' +
|
||||
' Dismissing authentication request for action-id ' + this.actionId +
|
||||
' cookie ' + this._cookie);
|
||||
log('polkitAuthenticationAgent: Failed to show modal dialog. ' +
|
||||
`Dismissing authentication request for action-id ${this.actionId} ` +
|
||||
`cookie ${this._cookie}`);
|
||||
this._emitDone(true);
|
||||
}
|
||||
}
|
||||
@@ -251,14 +251,14 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
}
|
||||
}
|
||||
|
||||
_onSessionRequest(session, request, echo_on) {
|
||||
_onSessionRequest(session, request, echoOn) {
|
||||
// Cheap localization trick
|
||||
if (request == 'Password:' || request == 'Password: ')
|
||||
this._passwordLabel.set_text(_("Password:"));
|
||||
else
|
||||
this._passwordLabel.set_text(request);
|
||||
|
||||
if (echo_on)
|
||||
if (echoOn)
|
||||
this._passwordEntry.clutter_text.set_password_char('');
|
||||
else
|
||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||
@@ -305,7 +305,7 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
_onUserChanged() {
|
||||
if (this._user.is_loaded && this._userAvatar) {
|
||||
this._userAvatar.update();
|
||||
this._userAvatar.actor.show();
|
||||
this._userAvatar.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +343,7 @@ var AuthenticationAgent = class {
|
||||
enable() {
|
||||
try {
|
||||
this._native.register();
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
log('Failed to register AuthenticationAgent');
|
||||
}
|
||||
}
|
||||
@@ -351,7 +351,7 @@ var AuthenticationAgent = class {
|
||||
disable() {
|
||||
try {
|
||||
this._native.unregister();
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
log('Failed to unregister AuthenticationAgent');
|
||||
}
|
||||
}
|
||||
@@ -384,11 +384,11 @@ var AuthenticationAgent = class {
|
||||
this._currentDialog.performAuthentication();
|
||||
}
|
||||
|
||||
_onCancel(nativeAgent) {
|
||||
_onCancel(_nativeAgent) {
|
||||
this._completeRequest(false);
|
||||
}
|
||||
|
||||
_onDialogDone(dialog, dismissed) {
|
||||
_onDialogDone(_dialog, dismissed) {
|
||||
this._completeRequest(dismissed);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Component */
|
||||
|
||||
const { Clutter, Gio, GLib, GObject, St } = imports.gi;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
var Tpl = null;
|
||||
var Tp = null;
|
||||
try {
|
||||
({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi);
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
log('Telepathy is not available, chat integration will be disabled.');
|
||||
}
|
||||
|
||||
@@ -40,10 +40,8 @@ var NotificationDirection = {
|
||||
RECEIVED: 'chat-received'
|
||||
};
|
||||
|
||||
var N_ = s => s;
|
||||
|
||||
function makeMessageFromTpMessage(tpMessage, direction) {
|
||||
let [text, flags] = tpMessage.to_text();
|
||||
let [text, flags_] = tpMessage.to_text();
|
||||
|
||||
let timestamp = tpMessage.get_sent_timestamp();
|
||||
if (timestamp == 0)
|
||||
@@ -89,7 +87,7 @@ var TelepathyComponent = class {
|
||||
try {
|
||||
this._client.register();
|
||||
} catch (e) {
|
||||
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
||||
throw new Error(`Could not register Telepathy client. Error: ${e}`);
|
||||
}
|
||||
|
||||
if (!this._client.account_manager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
|
||||
@@ -149,20 +147,20 @@ class TelepathyClient extends Tp.BaseClient {
|
||||
this._delegatedChannelsCb.bind(this));
|
||||
}
|
||||
|
||||
vfunc_observe_channels(account, conn, channels,
|
||||
dispatchOp, requests, context) {
|
||||
vfunc_observe_channels(...args) {
|
||||
let [account, conn, channels, dispatchOp_, requests_, context] = args;
|
||||
let len = channels.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let channel = channels[i];
|
||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
||||
let [targetHandle_, targetHandleType] = channel.get_handle();
|
||||
|
||||
if (channel.get_invalidated())
|
||||
continue;
|
||||
continue;
|
||||
|
||||
/* Only observe contact text channels */
|
||||
if ((!(channel instanceof Tp.TextChannel)) ||
|
||||
targetHandleType != Tp.HandleType.CONTACT)
|
||||
continue;
|
||||
continue;
|
||||
|
||||
this._createChatSource(account, conn, channel, channel.get_target_contact());
|
||||
}
|
||||
@@ -182,8 +180,8 @@ class TelepathyClient extends Tp.BaseClient {
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_handle_channels(account, conn, channels, requests,
|
||||
user_action_time, context) {
|
||||
vfunc_handle_channels(...args) {
|
||||
let [account, conn, channels, requests_, userActionTime_, context] = args;
|
||||
this._handlingChannels(account, conn, channels, true);
|
||||
context.accept();
|
||||
}
|
||||
@@ -200,7 +198,7 @@ class TelepathyClient extends Tp.BaseClient {
|
||||
}
|
||||
|
||||
if (channel.get_invalidated())
|
||||
continue;
|
||||
continue;
|
||||
|
||||
// 'notify' will be true when coming from an actual HandleChannels
|
||||
// call, and not when from a successful Claim call. The point is
|
||||
@@ -217,13 +215,13 @@ class TelepathyClient extends Tp.BaseClient {
|
||||
// We are already handling the channel, display the source
|
||||
let source = this._chatSources[channel.get_object_path()];
|
||||
if (source)
|
||||
source.notify();
|
||||
source.showNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_add_dispatch_operation(account, conn, channels,
|
||||
dispatchOp, context) {
|
||||
vfunc_add_dispatch_operation(...args) {
|
||||
let [account, conn, channels, dispatchOp, context] = args;
|
||||
let channel = channels[0];
|
||||
let chanType = channel.get_channel_type();
|
||||
|
||||
@@ -241,7 +239,7 @@ class TelepathyClient extends Tp.BaseClient {
|
||||
}
|
||||
|
||||
_approveTextChannel(account, conn, channel, dispatchOp, context) {
|
||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
||||
let [targetHandle_, targetHandleType] = channel.get_handle();
|
||||
|
||||
if (targetHandleType != Tp.HandleType.CONTACT) {
|
||||
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
|
||||
@@ -255,22 +253,23 @@ class TelepathyClient extends Tp.BaseClient {
|
||||
dispatchOp.claim_with_finish(result);
|
||||
this._handlingChannels(account, conn, [channel], false);
|
||||
} catch (err) {
|
||||
log('Failed to Claim channel: ' + err);
|
||||
log(`Failed to Claim channel: ${err}`);
|
||||
}
|
||||
});
|
||||
|
||||
context.accept();
|
||||
}
|
||||
|
||||
_delegatedChannelsCb(client, channels) {
|
||||
_delegatedChannelsCb(_client, _channels) {
|
||||
// Nothing to do as we don't make a distinction between observed and
|
||||
// handled channels.
|
||||
}
|
||||
}) : null;
|
||||
|
||||
var ChatSource = class extends MessageTray.Source {
|
||||
constructor(account, conn, channel, contact, client) {
|
||||
super(contact.get_alias());
|
||||
var ChatSource = HAVE_TP ? GObject.registerClass(
|
||||
class ChatSource extends MessageTray.Source {
|
||||
_init(account, conn, channel, contact, client) {
|
||||
super._init(contact.get_alias());
|
||||
|
||||
this._account = account;
|
||||
this._contact = contact;
|
||||
@@ -328,7 +327,7 @@ var ChatSource = class extends MessageTray.Source {
|
||||
|
||||
// We ack messages when the user expands the new notification
|
||||
let id = this._banner.connect('expanded', this._ackMessages.bind(this));
|
||||
this._banner.actor.connect('destroy', () => {
|
||||
this._banner.connect('destroy', () => {
|
||||
this._banner.disconnect(id);
|
||||
this._banner = null;
|
||||
});
|
||||
@@ -362,28 +361,28 @@ var ChatSource = class extends MessageTray.Source {
|
||||
let presenceType = this._contact.get_presence_type();
|
||||
|
||||
switch (presenceType) {
|
||||
case Tp.ConnectionPresenceType.AVAILABLE:
|
||||
iconName = 'user-available';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.BUSY:
|
||||
iconName = 'user-busy';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.OFFLINE:
|
||||
iconName = 'user-offline';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.HIDDEN:
|
||||
iconName = 'user-invisible';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.AWAY:
|
||||
iconName = 'user-away';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.EXTENDED_AWAY:
|
||||
iconName = 'user-idle';
|
||||
break;
|
||||
default:
|
||||
iconName = 'user-offline';
|
||||
}
|
||||
return new Gio.ThemedIcon({ name: iconName });
|
||||
case Tp.ConnectionPresenceType.AVAILABLE:
|
||||
iconName = 'user-available';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.BUSY:
|
||||
iconName = 'user-busy';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.OFFLINE:
|
||||
iconName = 'user-offline';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.HIDDEN:
|
||||
iconName = 'user-invisible';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.AWAY:
|
||||
iconName = 'user-away';
|
||||
break;
|
||||
case Tp.ConnectionPresenceType.EXTENDED_AWAY:
|
||||
iconName = 'user-idle';
|
||||
break;
|
||||
default:
|
||||
iconName = 'user-offline';
|
||||
}
|
||||
return new Gio.ThemedIcon({ name: iconName });
|
||||
}
|
||||
|
||||
_updateAvatarIcon() {
|
||||
@@ -429,7 +428,7 @@ var ChatSource = class extends MessageTray.Source {
|
||||
}
|
||||
|
||||
_displayPendingMessages(logManager, result) {
|
||||
let [success, events] = logManager.get_filtered_events_finish(result);
|
||||
let [success_, events] = logManager.get_filtered_events_finish(result);
|
||||
|
||||
let logMessages = events.map(makeMessageFromTplEvent);
|
||||
this._ensureNotification();
|
||||
@@ -478,7 +477,7 @@ var ChatSource = class extends MessageTray.Source {
|
||||
this._notification.appendMessage(pendingMessages[i], true);
|
||||
|
||||
if (pendingMessages.length > 0)
|
||||
this.notify();
|
||||
this.showNotification();
|
||||
}
|
||||
|
||||
destroy(reason) {
|
||||
@@ -547,15 +546,15 @@ var ChatSource = class extends MessageTray.Source {
|
||||
// Wait a bit before notifying for the received message, a handler
|
||||
// could ack it in the meantime.
|
||||
if (this._notifyTimeoutId != 0)
|
||||
Mainloop.source_remove(this._notifyTimeoutId);
|
||||
this._notifyTimeoutId = Mainloop.timeout_add(500,
|
||||
GLib.source_remove(this._notifyTimeoutId);
|
||||
this._notifyTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500,
|
||||
this._notifyTimeout.bind(this));
|
||||
GLib.Source.set_name_by_id(this._notifyTimeoutId, '[gnome-shell] this._notifyTimeout');
|
||||
}
|
||||
|
||||
_notifyTimeout() {
|
||||
if (this._pendingMessages.length != 0)
|
||||
this.notify();
|
||||
this.showNotification();
|
||||
|
||||
this._notifyTimeoutId = 0;
|
||||
|
||||
@@ -564,14 +563,14 @@ var ChatSource = class extends MessageTray.Source {
|
||||
|
||||
// This is called for both messages we send from
|
||||
// our client and other clients as well.
|
||||
_messageSent(channel, message, flags, token) {
|
||||
_messageSent(channel, message, _flags, _token) {
|
||||
this._ensureNotification();
|
||||
message = makeMessageFromTpMessage(message, NotificationDirection.SENT);
|
||||
this._notification.appendMessage(message);
|
||||
}
|
||||
|
||||
notify() {
|
||||
super.notify(this._notification);
|
||||
showNotification() {
|
||||
super.showNotification(this._notification);
|
||||
}
|
||||
|
||||
respond(text) {
|
||||
@@ -585,7 +584,7 @@ var ChatSource = class extends MessageTray.Source {
|
||||
|
||||
let msg = Tp.ClientMessage.new_text(type, text);
|
||||
this._channel.send_message_async(msg, 0, (src, result) => {
|
||||
this._channel.send_message_finish(result);
|
||||
this._channel.send_message_finish(result);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -597,12 +596,12 @@ var ChatSource = class extends MessageTray.Source {
|
||||
// keep track of it with the ChatStateChanged signal but it is good
|
||||
// enough right now.
|
||||
if (state != this._chatState) {
|
||||
this._chatState = state;
|
||||
this._channel.set_chat_state_async(state, null);
|
||||
this._chatState = state;
|
||||
this._channel.set_chat_state_async(state, null);
|
||||
}
|
||||
}
|
||||
|
||||
_presenceChanged(contact, presence, status, message) {
|
||||
_presenceChanged(_contact, _presence, _status, _message) {
|
||||
if (this._notification)
|
||||
this._notification.update(this._notification.title,
|
||||
this._notification.bannerBodyText,
|
||||
@@ -627,12 +626,18 @@ var ChatSource = class extends MessageTray.Source {
|
||||
// 'pending-message-removed' for each one.
|
||||
this._channel.ack_all_pending_messages_async(null);
|
||||
}
|
||||
};
|
||||
}) : null;
|
||||
|
||||
var ChatNotification = class extends MessageTray.Notification {
|
||||
constructor(source) {
|
||||
super(source, source.title, null,
|
||||
{ secondaryGIcon: source.getSecondaryIcon() });
|
||||
var ChatNotification = HAVE_TP ? GObject.registerClass({
|
||||
Signals: {
|
||||
'message-removed': { param_types: [Tp.Message.$gtype] },
|
||||
'message-added': { param_types: [Tp.Message.$gtype] },
|
||||
'timestamp-changed': { param_types: [Tp.Message.$gtype] },
|
||||
}
|
||||
}, class ChatNotification extends MessageTray.Notification {
|
||||
_init(source) {
|
||||
super._init(source, source.title, null,
|
||||
{ secondaryGIcon: source.getSecondaryIcon() });
|
||||
this.setUrgency(MessageTray.Urgency.HIGH);
|
||||
this.setResident(true);
|
||||
|
||||
@@ -642,7 +647,7 @@ var ChatNotification = class extends MessageTray.Notification {
|
||||
|
||||
destroy(reason) {
|
||||
if (this._timestampTimeoutId)
|
||||
Mainloop.source_remove(this._timestampTimeoutId);
|
||||
GLib.source_remove(this._timestampTimeoutId);
|
||||
this._timestampTimeoutId = 0;
|
||||
super.destroy(reason);
|
||||
}
|
||||
@@ -655,7 +660,7 @@ var ChatNotification = class extends MessageTray.Notification {
|
||||
* sender: the name of the sender,
|
||||
* timestamp: the time the message was sent
|
||||
* direction: a #NotificationDirection
|
||||
*
|
||||
*
|
||||
* @noTimestamp: Whether to add a timestamp. If %true, no timestamp
|
||||
* will be added, regardless of the difference since the
|
||||
* last timestamp
|
||||
@@ -675,8 +680,8 @@ var ChatNotification = class extends MessageTray.Notification {
|
||||
{ datetime: GLib.DateTime.new_from_unix_local (message.timestamp),
|
||||
bannerMarkup: true });
|
||||
|
||||
let group = (message.direction == NotificationDirection.RECEIVED ?
|
||||
'received' : 'sent');
|
||||
let group = (message.direction == NotificationDirection.RECEIVED
|
||||
? 'received' : 'sent');
|
||||
|
||||
this._append({ body: messageBody,
|
||||
group: group,
|
||||
@@ -698,8 +703,8 @@ var ChatNotification = class extends MessageTray.Notification {
|
||||
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
|
||||
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
|
||||
|
||||
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
|
||||
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
|
||||
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME)
|
||||
? SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
|
||||
|
||||
let filteredHistory = this.messages.filter(item => item.realMessage);
|
||||
if (filteredHistory.length > maxLength) {
|
||||
@@ -730,7 +735,7 @@ var ChatNotification = class extends MessageTray.Notification {
|
||||
|
||||
// Reset the old message timeout
|
||||
if (this._timestampTimeoutId)
|
||||
Mainloop.source_remove(this._timestampTimeoutId);
|
||||
GLib.source_remove(this._timestampTimeoutId);
|
||||
this._timestampTimeoutId = 0;
|
||||
|
||||
let message = { realMessage: props.group != 'meta',
|
||||
@@ -748,7 +753,8 @@ var ChatNotification = class extends MessageTray.Notification {
|
||||
} else {
|
||||
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
|
||||
// from the timestamp of the message.
|
||||
this._timestampTimeoutId = Mainloop.timeout_add_seconds(
|
||||
this._timestampTimeoutId = GLib.timeout_add_seconds(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
|
||||
this.appendTimestamp.bind(this));
|
||||
GLib.Source.set_name_by_id(this._timestampTimeoutId, '[gnome-shell] this.appendTimestamp');
|
||||
@@ -783,7 +789,7 @@ var ChatNotification = class extends MessageTray.Notification {
|
||||
|
||||
this._filterMessages();
|
||||
}
|
||||
};
|
||||
}) : null;
|
||||
|
||||
var ChatLineBox = GObject.registerClass(
|
||||
class ChatLineBox extends St.BoxLayout {
|
||||
@@ -793,9 +799,10 @@ class ChatLineBox extends St.BoxLayout {
|
||||
}
|
||||
});
|
||||
|
||||
var ChatNotificationBanner = class extends MessageTray.NotificationBanner {
|
||||
constructor(notification) {
|
||||
super(notification);
|
||||
var ChatNotificationBanner = GObject.registerClass(
|
||||
class ChatNotificationBanner extends MessageTray.NotificationBanner {
|
||||
_init(notification) {
|
||||
super._init(notification);
|
||||
|
||||
this._responseEntry = new St.Entry({ style_class: 'chat-response',
|
||||
x_expand: true,
|
||||
@@ -880,8 +887,7 @@ var ChatNotificationBanner = class extends MessageTray.NotificationBanner {
|
||||
}
|
||||
|
||||
_addMessage(message) {
|
||||
let highlighter = new MessageList.URLHighlighter(message.body, true, true);
|
||||
let body = highlighter.actor;
|
||||
let body = new MessageList.URLHighlighter(message.body, true, true);
|
||||
|
||||
let styles = message.styles;
|
||||
for (let i = 0; i < styles.length; i++)
|
||||
@@ -953,14 +959,15 @@ var ChatNotificationBanner = class extends MessageTray.NotificationBanner {
|
||||
|
||||
// Remove composing timeout.
|
||||
if (this._composingTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._composingTimeoutId);
|
||||
GLib.source_remove(this._composingTimeoutId);
|
||||
this._composingTimeoutId = 0;
|
||||
}
|
||||
|
||||
if (text != '') {
|
||||
this.notification.source.setChatState(Tp.ChannelChatState.COMPOSING);
|
||||
|
||||
this._composingTimeoutId = Mainloop.timeout_add_seconds(
|
||||
this._composingTimeoutId = GLib.timeout_add_seconds(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
COMPOSING_STOP_TIMEOUT,
|
||||
this._composingStopTimeout.bind(this));
|
||||
GLib.Source.set_name_by_id(this._composingTimeoutId, '[gnome-shell] this._composingStopTimeout');
|
||||
@@ -968,6 +975,6 @@ var ChatNotificationBanner = class extends MessageTray.NotificationBanner {
|
||||
this.notification.source.setChatState(Tp.ChannelChatState.ACTIVE);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var Component = TelepathyComponent;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported CtrlAltTabManager */
|
||||
|
||||
const { Clutter, GObject, Meta, Shell, St } = imports.gi;
|
||||
|
||||
@@ -7,7 +8,6 @@ const SwitcherPopup = imports.ui.switcherPopup;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
var POPUP_APPICON_SIZE = 96;
|
||||
var POPUP_FADE_TIME = 0.1; // seconds
|
||||
|
||||
var SortGroup = {
|
||||
TOP: 0,
|
||||
@@ -33,7 +33,7 @@ var CtrlAltTabManager = class CtrlAltTabManager {
|
||||
item.iconName = icon;
|
||||
|
||||
this._items.push(item);
|
||||
root.connect('destroy', () => { this.removeGroup(root); });
|
||||
root.connect('destroy', () => this.removeGroup(root));
|
||||
if (root instanceof St.Widget)
|
||||
global.focus_manager.add_group(root);
|
||||
}
|
||||
@@ -64,9 +64,8 @@ var CtrlAltTabManager = class CtrlAltTabManager {
|
||||
if (a.sortGroup != b.sortGroup)
|
||||
return a.sortGroup - b.sortGroup;
|
||||
|
||||
let ax, bx, y;
|
||||
[ax, y] = a.proxy.get_transformed_position();
|
||||
[bx, y] = b.proxy.get_transformed_position();
|
||||
let [ax] = a.proxy.get_transformed_position();
|
||||
let [bx] = b.proxy.get_transformed_position();
|
||||
|
||||
return ax - bx;
|
||||
}
|
||||
|
||||
231
js/ui/dash.js
231
js/ui/dash.js
@@ -1,19 +1,18 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Dash */
|
||||
|
||||
const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
const { Clutter, GLib, GObject,
|
||||
Graphene, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
const DND = imports.ui.dnd;
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
var DASH_ANIMATION_TIME = 0.2;
|
||||
var DASH_ITEM_LABEL_SHOW_TIME = 0.15;
|
||||
var DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
||||
var DASH_ANIMATION_TIME = 200;
|
||||
var DASH_ITEM_LABEL_SHOW_TIME = 150;
|
||||
var DASH_ITEM_LABEL_HIDE_TIME = 100;
|
||||
var DASH_ITEM_HOVER_TIMEOUT = 300;
|
||||
|
||||
function getAppFromSource(source) {
|
||||
@@ -24,27 +23,56 @@ function getAppFromSource(source) {
|
||||
}
|
||||
}
|
||||
|
||||
var DashIcon = GObject.registerClass(
|
||||
class DashIcon extends AppDisplay.AppIcon {
|
||||
_init(app) {
|
||||
super._init(app, {
|
||||
setSizeManually: true,
|
||||
showLabel: false
|
||||
});
|
||||
}
|
||||
|
||||
// Disable all DnD methods
|
||||
_onDragBegin() {
|
||||
}
|
||||
|
||||
_onDragEnd() {
|
||||
}
|
||||
|
||||
handleDragOver() {
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
}
|
||||
|
||||
acceptDrop() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// A container like StBin, but taking the child's scale into account
|
||||
// when requesting a size
|
||||
var DashItemContainer = GObject.registerClass(
|
||||
class DashItemContainer extends St.Widget {
|
||||
_init() {
|
||||
super._init({ style_class: 'dash-item-container',
|
||||
pivot_point: new Clutter.Point({ x: .5, y: .5 }),
|
||||
pivot_point: new Graphene.Point({ x: .5, y: .5 }),
|
||||
scale_x: 0,
|
||||
scale_y: 0,
|
||||
opacity: 0,
|
||||
x_expand: true,
|
||||
x_align: Clutter.ActorAlign.CENTER });
|
||||
|
||||
this._labelText = "";
|
||||
this.label = new St.Label({ style_class: 'dash-label'});
|
||||
this.label = new St.Label({ style_class: 'dash-label' });
|
||||
this.label.hide();
|
||||
Main.layoutManager.addChrome(this.label);
|
||||
this.label_actor = this.label;
|
||||
|
||||
this.child = null;
|
||||
this._childScale = 0;
|
||||
this._childOpacity = 0;
|
||||
this.animatingOut = false;
|
||||
|
||||
this.connect('notify::scale-x', () => this.queue_relayout());
|
||||
this.connect('notify::scale-y', () => this.queue_relayout());
|
||||
|
||||
this.connect('destroy', () => {
|
||||
if (this.child != null)
|
||||
this.child.destroy();
|
||||
@@ -81,7 +109,7 @@ class DashItemContainer extends St.Widget {
|
||||
let itemHeight = this.allocation.y2 - this.allocation.y1;
|
||||
|
||||
let labelHeight = this.label.get_height();
|
||||
let yOffset = Math.floor((itemHeight - labelHeight) / 2)
|
||||
let yOffset = Math.floor((itemHeight - labelHeight) / 2);
|
||||
|
||||
let y = stageY + yOffset;
|
||||
|
||||
@@ -95,11 +123,11 @@ class DashItemContainer extends St.Widget {
|
||||
x = stageX + this.get_width() + xOffset;
|
||||
|
||||
this.label.set_position(x, y);
|
||||
Tweener.addTween(this.label,
|
||||
{ opacity: 255,
|
||||
time: DASH_ITEM_LABEL_SHOW_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
});
|
||||
this.label.ease({
|
||||
opacity: 255,
|
||||
duration: DASH_ITEM_LABEL_SHOW_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
}
|
||||
|
||||
setLabelText(text) {
|
||||
@@ -108,14 +136,12 @@ class DashItemContainer extends St.Widget {
|
||||
}
|
||||
|
||||
hideLabel() {
|
||||
Tweener.addTween(this.label,
|
||||
{ opacity: 0,
|
||||
time: DASH_ITEM_LABEL_HIDE_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: () => {
|
||||
this.label.hide();
|
||||
}
|
||||
});
|
||||
this.label.ease({
|
||||
opacity: 0,
|
||||
duration: DASH_ITEM_LABEL_HIDE_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => this.label.hide()
|
||||
});
|
||||
}
|
||||
|
||||
setChild(actor) {
|
||||
@@ -126,9 +152,6 @@ class DashItemContainer extends St.Widget {
|
||||
|
||||
this.child = actor;
|
||||
this.add_actor(this.child);
|
||||
|
||||
this.set_scale(this._childScale, this._childScale);
|
||||
this.set_opacity(this._childOpacity);
|
||||
}
|
||||
|
||||
show(animate) {
|
||||
@@ -136,12 +159,13 @@ class DashItemContainer extends St.Widget {
|
||||
return;
|
||||
|
||||
let time = animate ? DASH_ANIMATION_TIME : 0;
|
||||
Tweener.addTween(this,
|
||||
{ childScale: 1.0,
|
||||
childOpacity: 255,
|
||||
time: time,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
this.ease({
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
opacity: 255,
|
||||
duration: time,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
}
|
||||
|
||||
animateOutAndDestroy() {
|
||||
@@ -153,37 +177,14 @@ class DashItemContainer extends St.Widget {
|
||||
}
|
||||
|
||||
this.animatingOut = true;
|
||||
Tweener.addTween(this,
|
||||
{ childScale: 0.0,
|
||||
childOpacity: 0,
|
||||
time: DASH_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: () => {
|
||||
this.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
set childScale(scale) {
|
||||
this._childScale = scale;
|
||||
|
||||
this.set_scale(scale, scale);
|
||||
this.queue_relayout();
|
||||
}
|
||||
|
||||
get childScale() {
|
||||
return this._childScale;
|
||||
}
|
||||
|
||||
set childOpacity(opacity) {
|
||||
this._childOpacity = opacity;
|
||||
|
||||
this.set_opacity(opacity);
|
||||
this.queue_redraw();
|
||||
}
|
||||
|
||||
get childOpacity() {
|
||||
return this._childOpacity;
|
||||
this.ease({
|
||||
scale_x: 0,
|
||||
scale_y: 0,
|
||||
opacity: 0,
|
||||
duration: DASH_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => this.destroy()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -198,9 +199,9 @@ class ShowAppsIcon extends DashItemContainer {
|
||||
toggle_mode: true });
|
||||
this._iconActor = null;
|
||||
this.icon = new IconGrid.BaseIcon(_("Show Applications"),
|
||||
{ setSizeManually: true,
|
||||
showLabel: false,
|
||||
createIcon: this._createIcon.bind(this) });
|
||||
{ setSizeManually: true,
|
||||
showLabel: false,
|
||||
createIcon: this._createIcon.bind(this) });
|
||||
this.toggleButton.add_actor(this.icon);
|
||||
this.toggleButton._delegate = this;
|
||||
|
||||
@@ -241,14 +242,14 @@ class ShowAppsIcon extends DashItemContainer {
|
||||
this.setLabelText(_("Show Applications"));
|
||||
}
|
||||
|
||||
handleDragOver(source, actor, x, y, time) {
|
||||
handleDragOver(source, _actor, _x, _y, _time) {
|
||||
if (!this._canRemoveApp(getAppFromSource(source)))
|
||||
return DND.DragMotionResult.NO_DROP;
|
||||
|
||||
return DND.DragMotionResult.MOVE_DROP;
|
||||
}
|
||||
|
||||
acceptDrop(source, actor, x, y, time) {
|
||||
acceptDrop(source, _actor, _x, _y, _time) {
|
||||
let app = getAppFromSource(source);
|
||||
if (!this._canRemoveApp(app))
|
||||
return false;
|
||||
@@ -296,7 +297,7 @@ class DashActor extends St.Widget {
|
||||
this.set_allocation(box, flags);
|
||||
|
||||
let [appIcons, showAppsButton] = this.get_children();
|
||||
let [showAppsMinHeight, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
|
||||
let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = contentBox.x1;
|
||||
@@ -321,17 +322,19 @@ class DashActor extends St.Widget {
|
||||
let themeNode = this.get_theme_node();
|
||||
let adjustedForWidth = themeNode.adjust_for_width(forWidth);
|
||||
let [, showAppsButton] = this.get_children();
|
||||
let [minHeight, ] = showAppsButton.get_preferred_height(adjustedForWidth);
|
||||
[minHeight, ] = themeNode.adjust_preferred_height(minHeight, natHeight);
|
||||
let [minHeight] = showAppsButton.get_preferred_height(adjustedForWidth);
|
||||
[minHeight] = themeNode.adjust_preferred_height(minHeight, natHeight);
|
||||
|
||||
return [minHeight, natHeight];
|
||||
}
|
||||
});
|
||||
|
||||
const baseIconSizes = [ 16, 22, 24, 32, 48, 64 ];
|
||||
const baseIconSizes = [16, 22, 24, 32, 48, 64];
|
||||
|
||||
var Dash = class Dash {
|
||||
constructor() {
|
||||
var Dash = GObject.registerClass({
|
||||
Signals: { 'icon-size-changed': {} }
|
||||
}, class Dash extends St.Bin {
|
||||
_init() {
|
||||
this._maxHeight = -1;
|
||||
this.iconSize = 64;
|
||||
this._shownInitially = false;
|
||||
@@ -351,8 +354,7 @@ var Dash = class Dash {
|
||||
this._container.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
||||
|
||||
this._showAppsIcon = new ShowAppsIcon();
|
||||
this._showAppsIcon.childScale = 1;
|
||||
this._showAppsIcon.childOpacity = 255;
|
||||
this._showAppsIcon.show(false);
|
||||
this._showAppsIcon.icon.setIconSize(this.iconSize);
|
||||
this._hookUpLabel(this._showAppsIcon);
|
||||
|
||||
@@ -360,11 +362,11 @@ var Dash = class Dash {
|
||||
|
||||
this._container.add_actor(this._showAppsIcon);
|
||||
|
||||
this.actor = new St.Bin({ child: this._container });
|
||||
this.actor.connect('notify::height', () => {
|
||||
if (this._maxHeight != this.actor.height)
|
||||
super._init({ child: this._container });
|
||||
this.connect('notify::height', () => {
|
||||
if (this._maxHeight != this.height)
|
||||
this._queueRedisplay();
|
||||
this._maxHeight = this.actor.height;
|
||||
this._maxHeight = this.height;
|
||||
});
|
||||
|
||||
this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this));
|
||||
@@ -387,7 +389,7 @@ var Dash = class Dash {
|
||||
|
||||
// Translators: this is the name of the dock/favorites area on
|
||||
// the left of the overview
|
||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Dash"), 'user-bookmarks-symbolic');
|
||||
Main.ctrlAltTabManager.addGroup(this, _("Dash"), 'user-bookmarks-symbolic');
|
||||
}
|
||||
|
||||
_onDragBegin() {
|
||||
@@ -474,19 +476,7 @@ var Dash = class Dash {
|
||||
}
|
||||
|
||||
_createAppItem(app) {
|
||||
let appIcon = new AppDisplay.AppIcon(app,
|
||||
{ setSizeManually: true,
|
||||
showLabel: false });
|
||||
if (appIcon._draggable) {
|
||||
appIcon._draggable.connect('drag-begin',
|
||||
() => {
|
||||
appIcon.actor.opacity = 50;
|
||||
});
|
||||
appIcon._draggable.connect('drag-end',
|
||||
() => {
|
||||
appIcon.actor.opacity = 255;
|
||||
});
|
||||
}
|
||||
let appIcon = new DashIcon(app);
|
||||
|
||||
appIcon.connect('menu-state-changed',
|
||||
(appIcon, opened) => {
|
||||
@@ -494,11 +484,11 @@ var Dash = class Dash {
|
||||
});
|
||||
|
||||
let item = new DashItemContainer();
|
||||
item.setChild(appIcon.actor);
|
||||
item.setChild(appIcon);
|
||||
|
||||
// Override default AppIcon label_actor, now the
|
||||
// accessible_name is set at DashItemContainer.setLabelText
|
||||
appIcon.actor.label_actor = null;
|
||||
appIcon.label_actor = null;
|
||||
item.setLabelText(app.get_name());
|
||||
|
||||
appIcon.icon.setIconSize(this.iconSize);
|
||||
@@ -512,7 +502,7 @@ var Dash = class Dash {
|
||||
// that the notify::hover handler does everything we need to.
|
||||
if (opened) {
|
||||
if (this._showLabelTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._showLabelTimeoutId);
|
||||
GLib.source_remove(this._showLabelTimeoutId);
|
||||
this._showLabelTimeoutId = 0;
|
||||
}
|
||||
|
||||
@@ -526,7 +516,7 @@ var Dash = class Dash {
|
||||
if (shouldShow) {
|
||||
if (this._showLabelTimeoutId == 0) {
|
||||
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
||||
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
|
||||
this._showLabelTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout,
|
||||
() => {
|
||||
this._labelShowing = true;
|
||||
item.showLabel();
|
||||
@@ -535,17 +525,17 @@ var Dash = class Dash {
|
||||
});
|
||||
GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel');
|
||||
if (this._resetHoverTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._resetHoverTimeoutId);
|
||||
GLib.source_remove(this._resetHoverTimeoutId);
|
||||
this._resetHoverTimeoutId = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this._showLabelTimeoutId > 0)
|
||||
Mainloop.source_remove(this._showLabelTimeoutId);
|
||||
GLib.source_remove(this._showLabelTimeoutId);
|
||||
this._showLabelTimeoutId = 0;
|
||||
item.hideLabel();
|
||||
if (this._labelShowing) {
|
||||
this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
|
||||
this._resetHoverTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, DASH_ITEM_HOVER_TIMEOUT,
|
||||
() => {
|
||||
this._labelShowing = false;
|
||||
this._resetHoverTimeoutId = 0;
|
||||
@@ -633,12 +623,12 @@ var Dash = class Dash {
|
||||
icon.icon.set_size(icon.icon.width * scale,
|
||||
icon.icon.height * scale);
|
||||
|
||||
Tweener.addTween(icon.icon,
|
||||
{ width: targetWidth,
|
||||
height: targetHeight,
|
||||
time: DASH_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
});
|
||||
icon.icon.ease({
|
||||
width: targetWidth,
|
||||
height: targetHeight,
|
||||
duration: DASH_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,10 +638,10 @@ var Dash = class Dash {
|
||||
let running = this._appSystem.get_running();
|
||||
|
||||
let children = this._box.get_children().filter(actor => {
|
||||
return actor.child &&
|
||||
actor.child._delegate &&
|
||||
actor.child._delegate.app;
|
||||
});
|
||||
return actor.child &&
|
||||
actor.child._delegate &&
|
||||
actor.child._delegate.app;
|
||||
});
|
||||
// Apps currently in the dash
|
||||
let oldApps = children.map(actor => actor.child._delegate.app);
|
||||
// Apps supposed to be in the dash
|
||||
@@ -700,14 +690,14 @@ var Dash = class Dash {
|
||||
}
|
||||
|
||||
// App removed at oldIndex
|
||||
if (oldApp && newApps.indexOf(oldApp) == -1) {
|
||||
if (oldApp && !newApps.includes(oldApp)) {
|
||||
removedActors.push(children[oldIndex]);
|
||||
oldIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// App added at newIndex
|
||||
if (newApp && oldApps.indexOf(newApp) == -1) {
|
||||
if (newApp && !oldApps.includes(newApp)) {
|
||||
addedItems.push({ app: newApp,
|
||||
item: this._createAppItem(newApp),
|
||||
pos: newIndex });
|
||||
@@ -716,8 +706,8 @@ var Dash = class Dash {
|
||||
}
|
||||
|
||||
// App moved
|
||||
let nextApp = newApps.length > newIndex + 1 ? newApps[newIndex + 1]
|
||||
: null;
|
||||
let nextApp = newApps.length > newIndex + 1
|
||||
? newApps[newIndex + 1] : null;
|
||||
let insertHere = nextApp && nextApp == oldApp;
|
||||
let alreadyRemoved = removedActors.reduce((result, actor) => {
|
||||
let removedApp = actor.child._delegate.app;
|
||||
@@ -790,7 +780,7 @@ var Dash = class Dash {
|
||||
}
|
||||
}
|
||||
|
||||
handleDragOver(source, actor, x, y, time) {
|
||||
handleDragOver(source, actor, x, y, _time) {
|
||||
let app = getAppFromSource(source);
|
||||
|
||||
// Don't allow favoriting of transient apps
|
||||
@@ -868,7 +858,7 @@ var Dash = class Dash {
|
||||
}
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop(source, actor, x, y, time) {
|
||||
acceptDrop(source, _actor, _x, _y, _time) {
|
||||
let app = getAppFromSource(source);
|
||||
|
||||
// Don't allow favoriting of transient apps
|
||||
@@ -915,5 +905,4 @@ var Dash = class Dash {
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Dash.prototype);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported DateMenuButton */
|
||||
|
||||
const { Clutter, GLib, GnomeDesktop,
|
||||
const { Clutter, Gio, GLib, GnomeDesktop,
|
||||
GObject, GWeather, Shell, St } = imports.gi;
|
||||
|
||||
const Util = imports.misc.util;
|
||||
@@ -10,8 +11,13 @@ const Calendar = imports.ui.calendar;
|
||||
const Weather = imports.misc.weather;
|
||||
const System = imports.system;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
const MAX_FORECASTS = 5;
|
||||
|
||||
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
|
||||
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
|
||||
|
||||
function _isToday(date) {
|
||||
let now = new Date();
|
||||
return now.getYear() == date.getYear() &&
|
||||
@@ -19,22 +25,26 @@ function _isToday(date) {
|
||||
now.getDate() == date.getDate();
|
||||
}
|
||||
|
||||
var TodayButton = class TodayButton {
|
||||
constructor(calendar) {
|
||||
function _gDateTimeToDate(datetime) {
|
||||
return new Date(datetime.to_unix() * 1000 + datetime.get_microsecond() / 1000);
|
||||
}
|
||||
|
||||
var TodayButton = GObject.registerClass(
|
||||
class TodayButton extends St.Button {
|
||||
_init(calendar) {
|
||||
// Having the ability to go to the current date if the user is already
|
||||
// on the current date can be confusing. So don't make the button reactive
|
||||
// until the selected date changes.
|
||||
this.actor = new St.Button({ style_class: 'datemenu-today-button',
|
||||
x_expand: true, x_align: St.Align.START,
|
||||
can_focus: true,
|
||||
reactive: false
|
||||
});
|
||||
this.actor.connect('clicked', () => {
|
||||
this._calendar.setDate(new Date(), false);
|
||||
super._init({
|
||||
style_class: 'datemenu-today-button',
|
||||
x_align: St.Align.START,
|
||||
x_expand: true,
|
||||
can_focus: true,
|
||||
reactive: false
|
||||
});
|
||||
|
||||
let hbox = new St.BoxLayout({ vertical: true });
|
||||
this.actor.add_actor(hbox);
|
||||
this.add_actor(hbox);
|
||||
|
||||
this._dayLabel = new St.Label({ style_class: 'day-label',
|
||||
x_align: Clutter.ActorAlign.START });
|
||||
@@ -44,13 +54,17 @@ var TodayButton = class TodayButton {
|
||||
hbox.add_actor(this._dateLabel);
|
||||
|
||||
this._calendar = calendar;
|
||||
this._calendar.connect('selected-date-changed', (calendar, date) => {
|
||||
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
|
||||
// Make the button reactive only if the selected date is not the
|
||||
// current date.
|
||||
this.actor.reactive = !_isToday(date)
|
||||
this.reactive = !_isToday(_gDateTimeToDate(datetime));
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_clicked() {
|
||||
this._calendar.setDate(new Date(), false);
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
this._dayLabel.set_text(date.toLocaleFormat('%A'));
|
||||
|
||||
@@ -67,57 +81,72 @@ var TodayButton = class TodayButton {
|
||||
* date, e.g. "Tuesday February 17 2015".
|
||||
*/
|
||||
dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y"));
|
||||
this.actor.accessible_name = date.toLocaleFormat(dateFormat);
|
||||
this.accessible_name = date.toLocaleFormat(dateFormat);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var WorldClocksSection = class WorldClocksSection {
|
||||
constructor() {
|
||||
var WorldClocksSection = GObject.registerClass(
|
||||
class WorldClocksSection extends St.Button {
|
||||
_init() {
|
||||
super._init({
|
||||
style_class: 'world-clocks-button',
|
||||
x_fill: true,
|
||||
can_focus: true
|
||||
});
|
||||
this._clock = new GnomeDesktop.WallClock();
|
||||
this._clockNotifyId = 0;
|
||||
|
||||
this._locations = [];
|
||||
|
||||
this.actor = new St.Button({ style_class: 'world-clocks-button',
|
||||
x_fill: true,
|
||||
can_focus: true });
|
||||
this.actor.connect('clicked', () => {
|
||||
this._clockAppMon.activateApp();
|
||||
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
});
|
||||
|
||||
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
|
||||
this._grid = new St.Widget({ style_class: 'world-clocks-grid',
|
||||
layout_manager: layout });
|
||||
layout.hookup_style(this._grid);
|
||||
|
||||
this.actor.child = this._grid;
|
||||
this.child = this._grid;
|
||||
|
||||
this._clockAppMon = new Util.AppSettingsMonitor('org.gnome.clocks.desktop',
|
||||
'org.gnome.clocks');
|
||||
this._clockAppMon.connect('available-changed',
|
||||
this._sync.bind(this));
|
||||
this._clockAppMon.watchSetting('world-clocks',
|
||||
this._clocksChanged.bind(this));
|
||||
this._clocksApp = null;
|
||||
this._clocksProxy = new ClocksProxy(
|
||||
Gio.DBus.session,
|
||||
'org.gnome.clocks',
|
||||
'/org/gnome/clocks',
|
||||
this._onProxyReady.bind(this),
|
||||
null /* cancellable */,
|
||||
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES);
|
||||
|
||||
this._settings = new Gio.Settings({
|
||||
schema_id: 'org.gnome.shell.world-clocks'
|
||||
});
|
||||
this._settings.connect('changed', this._clocksChanged.bind(this));
|
||||
this._clocksChanged();
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appSystem.connect('installed-changed',
|
||||
this._sync.bind(this));
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_sync() {
|
||||
this.actor.visible = this._clockAppMon.available;
|
||||
vfunc_clicked() {
|
||||
if (this._clocksApp)
|
||||
this._clocksApp.activate();
|
||||
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
}
|
||||
|
||||
_clocksChanged(settings) {
|
||||
_sync() {
|
||||
this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop');
|
||||
this.visible = this._clocksApp != null;
|
||||
}
|
||||
|
||||
_clocksChanged() {
|
||||
this._grid.destroy_all_children();
|
||||
this._locations = [];
|
||||
|
||||
let world = GWeather.Location.get_world();
|
||||
let clocks = settings.get_value('world-clocks').deep_unpack();
|
||||
let clocks = this._settings.get_value('locations').deep_unpack();
|
||||
for (let i = 0; i < clocks.length; i++) {
|
||||
if (!clocks[i].location)
|
||||
continue;
|
||||
let l = world.deserialize(clocks[i].location);
|
||||
let l = world.deserialize(clocks[i]);
|
||||
if (l && l.get_timezone() != null)
|
||||
this._locations.push({ location: l });
|
||||
}
|
||||
@@ -128,13 +157,14 @@ var WorldClocksSection = class WorldClocksSection {
|
||||
});
|
||||
|
||||
let layout = this._grid.layout_manager;
|
||||
let title = (this._locations.length == 0) ? _("Add world clocks…")
|
||||
: _("World Clocks");
|
||||
let title = (this._locations.length == 0)
|
||||
? _("Add world clocks…")
|
||||
: _("World Clocks");
|
||||
let header = new St.Label({ style_class: 'world-clocks-header',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
text: title });
|
||||
layout.attach(header, 0, 0, 2, 1);
|
||||
this.actor.label_actor = header;
|
||||
this.label_actor = header;
|
||||
|
||||
let localOffset = GLib.DateTime.new_now_local().get_utc_offset();
|
||||
|
||||
@@ -196,30 +226,42 @@ var WorldClocksSection = class WorldClocksSection {
|
||||
l.actor.text = Util.formatTime(now, { timeOnly: true });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var WeatherSection = class WeatherSection {
|
||||
constructor() {
|
||||
_onProxyReady(proxy, error) {
|
||||
if (error) {
|
||||
log(`Failed to create GNOME Clocks proxy: ${error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._clocksProxy.connect('g-properties-changed',
|
||||
this._onClocksPropertiesChanged.bind(this));
|
||||
this._onClocksPropertiesChanged();
|
||||
}
|
||||
|
||||
_onClocksPropertiesChanged() {
|
||||
if (this._clocksProxy.g_name_owner == null)
|
||||
return;
|
||||
|
||||
this._settings.set_value('locations',
|
||||
new GLib.Variant('av', this._clocksProxy.Locations));
|
||||
}
|
||||
});
|
||||
|
||||
var WeatherSection = GObject.registerClass(
|
||||
class WeatherSection extends St.Button {
|
||||
_init() {
|
||||
super._init({
|
||||
style_class: 'weather-button',
|
||||
x_fill: true,
|
||||
can_focus: true
|
||||
});
|
||||
|
||||
this._weatherClient = new Weather.WeatherClient();
|
||||
|
||||
this.actor = new St.Button({ style_class: 'weather-button',
|
||||
x_fill: true,
|
||||
can_focus: true });
|
||||
this.actor.connect('clicked', () => {
|
||||
this._weatherClient.activateApp();
|
||||
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
});
|
||||
this.actor.connect('notify::mapped', () => {
|
||||
if (this.actor.mapped)
|
||||
this._weatherClient.update();
|
||||
});
|
||||
|
||||
let box = new St.BoxLayout({ style_class: 'weather-box',
|
||||
vertical: true });
|
||||
vertical: true });
|
||||
|
||||
this.actor.child = box;
|
||||
this.child = box;
|
||||
|
||||
let titleBox = new St.BoxLayout();
|
||||
titleBox.add_child(new St.Label({ style_class: 'weather-header',
|
||||
@@ -242,6 +284,18 @@ var WeatherSection = class WeatherSection {
|
||||
this._sync();
|
||||
}
|
||||
|
||||
vfunc_map() {
|
||||
this._weatherClient.update();
|
||||
super.vfunc_map();
|
||||
}
|
||||
|
||||
vfunc_clicked() {
|
||||
this._weatherClient.activateApp();
|
||||
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
}
|
||||
|
||||
_getInfos() {
|
||||
let info = this._weatherClient.info;
|
||||
let forecasts = info.get_forecast_list();
|
||||
@@ -249,12 +303,12 @@ var WeatherSection = class WeatherSection {
|
||||
let current = info;
|
||||
let infos = [info];
|
||||
for (let i = 0; i < forecasts.length; i++) {
|
||||
let [ok, timestamp] = forecasts[i].get_value_update();
|
||||
let [ok_, timestamp] = forecasts[i].get_value_update();
|
||||
let datetime = new Date(timestamp * 1000);
|
||||
if (!_isToday(datetime))
|
||||
continue; // Ignore forecasts from other days
|
||||
|
||||
[ok, timestamp] = current.get_value_update();
|
||||
[ok_, timestamp] = current.get_value_update();
|
||||
let currenttime = new Date(timestamp * 1000);
|
||||
if (currenttime.getHours() == datetime.getHours())
|
||||
continue; // Enforce a minimum interval of 1h
|
||||
@@ -275,7 +329,7 @@ var WeatherSection = class WeatherSection {
|
||||
|
||||
let col = 0;
|
||||
infos.forEach(fc => {
|
||||
let [ok, timestamp] = fc.get_value_update();
|
||||
let [ok_, timestamp] = fc.get_value_update();
|
||||
let timeStr = Util.formatTime(new Date(timestamp * 1000), {
|
||||
timeOnly: true
|
||||
});
|
||||
@@ -332,23 +386,27 @@ var WeatherSection = class WeatherSection {
|
||||
}
|
||||
|
||||
_sync() {
|
||||
this.actor.visible = this._weatherClient.available;
|
||||
this.visible = this._weatherClient.available;
|
||||
|
||||
if (!this.actor.visible)
|
||||
if (!this.visible)
|
||||
return;
|
||||
|
||||
this._titleLocation.visible = this._weatherClient.hasLocation;
|
||||
|
||||
this._updateForecasts();
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var MessagesIndicator = class MessagesIndicator {
|
||||
constructor() {
|
||||
this.actor = new St.Icon({ icon_name: 'message-indicator-symbolic',
|
||||
icon_size: 16,
|
||||
visible: false, y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
var MessagesIndicator = GObject.registerClass(
|
||||
class MessagesIndicator extends St.Icon {
|
||||
_init() {
|
||||
super._init({
|
||||
icon_name: 'message-indicator-symbolic',
|
||||
icon_size: 16,
|
||||
visible: false,
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER
|
||||
});
|
||||
|
||||
this._sources = [];
|
||||
|
||||
@@ -357,11 +415,11 @@ var MessagesIndicator = class MessagesIndicator {
|
||||
Main.messageTray.connect('queue-changed', this._updateCount.bind(this));
|
||||
|
||||
let sources = Main.messageTray.getSources();
|
||||
sources.forEach(source => { this._onSourceAdded(null, source); });
|
||||
sources.forEach(source => this._onSourceAdded(null, source));
|
||||
}
|
||||
|
||||
_onSourceAdded(tray, source) {
|
||||
source.connect('count-updated', this._updateCount.bind(this));
|
||||
source.connect('notify::count', this._updateCount.bind(this));
|
||||
this._sources.push(source);
|
||||
this._updateCount();
|
||||
}
|
||||
@@ -373,19 +431,19 @@ var MessagesIndicator = class MessagesIndicator {
|
||||
|
||||
_updateCount() {
|
||||
let count = 0;
|
||||
this._sources.forEach(source => { count += source.unseenCount; });
|
||||
this._sources.forEach(source => (count += source.unseenCount));
|
||||
count -= Main.messageTray.queueCount;
|
||||
|
||||
this.actor.visible = (count > 0);
|
||||
this.visible = (count > 0);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var IndicatorPad = GObject.registerClass(
|
||||
class IndicatorPad extends St.Widget {
|
||||
_init(actor) {
|
||||
this._source = actor;
|
||||
this._source.connect('notify::visible', () => { this.queue_relayout(); });
|
||||
this._source.connect('notify::size', () => { this.queue_relayout(); });
|
||||
this._source.connect('notify::visible', () => this.queue_relayout());
|
||||
this._source.connect('notify::size', () => this.queue_relayout());
|
||||
super._init();
|
||||
}
|
||||
|
||||
@@ -459,7 +517,6 @@ class CalendarColumnLayout extends Clutter.BoxLayout {
|
||||
var DateMenuButton = GObject.registerClass(
|
||||
class DateMenuButton extends PanelMenu.Button {
|
||||
_init() {
|
||||
let item;
|
||||
let hbox;
|
||||
let vbox;
|
||||
|
||||
@@ -472,9 +529,9 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
this._indicator = new MessagesIndicator();
|
||||
|
||||
let box = new St.BoxLayout();
|
||||
box.add_actor(new IndicatorPad(this._indicator.actor));
|
||||
box.add_actor(new IndicatorPad(this._indicator));
|
||||
box.add_actor(this._clockDisplay);
|
||||
box.add_actor(this._indicator.actor);
|
||||
box.add_actor(this._indicator);
|
||||
|
||||
this.label_actor = this._clockDisplay;
|
||||
this.add_actor(box);
|
||||
@@ -490,11 +547,11 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
bin.add_actor(hbox);
|
||||
|
||||
this._calendar = new Calendar.Calendar();
|
||||
this._calendar.connect('selected-date-changed',
|
||||
(calendar, date) => {
|
||||
layout.frozen = !_isToday(date);
|
||||
this._messageList.setDate(date);
|
||||
});
|
||||
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
|
||||
let date = _gDateTimeToDate(datetime);
|
||||
layout.frozen = !_isToday(date);
|
||||
this._messageList.setDate(date);
|
||||
});
|
||||
|
||||
this.menu.connect('open-state-changed', (menu, isOpen) => {
|
||||
// Whenever the menu is opened, select today
|
||||
@@ -508,19 +565,19 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
|
||||
// Fill up the first column
|
||||
this._messageList = new Calendar.CalendarMessageList();
|
||||
hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
|
||||
hbox.add(this._messageList, { expand: true, y_fill: false, y_align: St.Align.START });
|
||||
|
||||
// Fill up the second column
|
||||
let boxLayout = new CalendarColumnLayout(this._calendar.actor);
|
||||
let boxLayout = new CalendarColumnLayout(this._calendar);
|
||||
vbox = new St.Widget({ style_class: 'datemenu-calendar-column',
|
||||
layout_manager: boxLayout });
|
||||
boxLayout.hookup_style(vbox);
|
||||
hbox.add(vbox);
|
||||
|
||||
this._date = new TodayButton(this._calendar);
|
||||
vbox.add_actor(this._date.actor);
|
||||
vbox.add_actor(this._date);
|
||||
|
||||
vbox.add_actor(this._calendar.actor);
|
||||
vbox.add_actor(this._calendar);
|
||||
|
||||
this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade',
|
||||
x_expand: true, x_fill: true,
|
||||
@@ -533,10 +590,10 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
this._displaysSection.add_actor(displaysBox);
|
||||
|
||||
this._clocksItem = new WorldClocksSection();
|
||||
displaysBox.add(this._clocksItem.actor, { x_fill: true });
|
||||
displaysBox.add(this._clocksItem, { x_fill: true });
|
||||
|
||||
this._weatherItem = new WeatherSection();
|
||||
displaysBox.add(this._weatherItem.actor, { x_fill: true });
|
||||
displaysBox.add(this._weatherItem, { x_fill: true });
|
||||
|
||||
// Done with hbox for calendar and event list
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Dialog, MessageDialogContent */
|
||||
|
||||
const { Clutter, Gio, GObject, Pango, St } = imports.gi;
|
||||
|
||||
@@ -25,9 +26,9 @@ class Dialog extends St.Widget {
|
||||
|
||||
_createDialog() {
|
||||
this._dialog = new St.BoxLayout({ style_class: 'modal-dialog',
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
vertical: true });
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
vertical: true });
|
||||
|
||||
// modal dialogs are fixed width and grow vertically; set the request
|
||||
// mode accordingly so wrapped labels are handled correctly during
|
||||
@@ -38,13 +39,13 @@ class Dialog extends St.Widget {
|
||||
this.contentLayout = new St.BoxLayout({ vertical: true,
|
||||
style_class: "modal-dialog-content-box" });
|
||||
this._dialog.add(this.contentLayout,
|
||||
{ expand: true,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
{ expand: true,
|
||||
x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout({ homogeneous:true }) });
|
||||
this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout({ homogeneous: true }) });
|
||||
this._dialog.add(this.buttonLayout,
|
||||
{ x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.START });
|
||||
@@ -116,11 +117,11 @@ class Dialog extends St.Widget {
|
||||
|
||||
let button = new St.Button({ style_class: 'modal-dialog-linked-button',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
label: label });
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
label: label });
|
||||
button.connect('clicked', action);
|
||||
|
||||
buttonInfo['button'] = button;
|
||||
@@ -180,10 +181,8 @@ var MessageDialogContent = GObject.registerClass({
|
||||
this._subtitle.clutter_text.set(textProps);
|
||||
this._body.clutter_text.set(textProps);
|
||||
|
||||
if (!params.hasOwnProperty('style_class'))
|
||||
params.style_class = 'message-dialog-main-layout';
|
||||
|
||||
super._init(params);
|
||||
let defaultParams = { style_class: 'message-dialog-main-layout' };
|
||||
super._init(Object.assign(defaultParams, params));
|
||||
|
||||
this.messageBox = new St.BoxLayout({ style_class: 'message-dialog-content',
|
||||
x_expand: true,
|
||||
@@ -214,7 +213,10 @@ var MessageDialogContent = GObject.registerClass({
|
||||
}
|
||||
|
||||
set icon(icon) {
|
||||
Object.assign(this._icon, { gicon: icon, visible: icon != null });
|
||||
this._icon.set({
|
||||
gicon: icon,
|
||||
visible: icon != null
|
||||
});
|
||||
this.notify('icon');
|
||||
}
|
||||
|
||||
@@ -231,7 +233,10 @@ var MessageDialogContent = GObject.registerClass({
|
||||
}
|
||||
|
||||
_setLabel(label, prop, value) {
|
||||
Object.assign(label, { text: value || '', visible: value != null });
|
||||
label.set({
|
||||
text: value || '',
|
||||
visible: value != null
|
||||
});
|
||||
this.notify(prop);
|
||||
}
|
||||
|
||||
|
||||
104
js/ui/dnd.js
104
js/ui/dnd.js
@@ -1,18 +1,18 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported addDragMonitor, removeDragMonitor, makeDraggable */
|
||||
|
||||
const { Clutter, GLib, Meta, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
// Time to scale down to maxDragActorSize
|
||||
var SCALE_ANIMATION_TIME = 0.25;
|
||||
var SCALE_ANIMATION_TIME = 250;
|
||||
// Time to animate to original position on cancel
|
||||
var SNAP_BACK_ANIMATION_TIME = 0.25;
|
||||
var SNAP_BACK_ANIMATION_TIME = 250;
|
||||
// Time to animate to original position on success
|
||||
var REVERT_ANIMATION_TIME = 0.75;
|
||||
var REVERT_ANIMATION_TIME = 750;
|
||||
|
||||
var DragMotionResult = {
|
||||
NO_DROP: 0,
|
||||
@@ -111,9 +111,6 @@ var _Draggable = class _Draggable {
|
||||
if (event.get_button() != 1)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (Tweener.getTweenCount(actor))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
this._buttonDown = true;
|
||||
this._grabActor(event.get_device());
|
||||
|
||||
@@ -139,9 +136,6 @@ var _Draggable = class _Draggable {
|
||||
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (Tweener.getTweenCount(actor))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
this._buttonDown = true;
|
||||
this._grabActor(event.get_device(), event.get_event_sequence());
|
||||
|
||||
@@ -428,20 +422,22 @@ var _Draggable = class _Draggable {
|
||||
// to the final position because that tween would
|
||||
// fight with updates as the user continues dragging
|
||||
// the mouse; instead we do the position computations in
|
||||
// an onUpdate() function.
|
||||
Tweener.addTween(this._dragActor,
|
||||
{ scale_x: scale * origScale,
|
||||
scale_y: scale * origScale,
|
||||
time: SCALE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onUpdate() {
|
||||
let currentScale = this._dragActor.scale_x / origScale;
|
||||
this._dragOffsetX = currentScale * origDragOffsetX;
|
||||
this._dragOffsetY = currentScale * origDragOffsetY;
|
||||
this._dragActor.set_position(this._dragX + this._dragOffsetX,
|
||||
this._dragY + this._dragOffsetY);
|
||||
},
|
||||
onUpdateScope: this });
|
||||
// a ::new-frame handler.
|
||||
this._dragActor.ease({
|
||||
scale_x: scale * origScale,
|
||||
scale_y: scale * origScale,
|
||||
duration: SCALE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD
|
||||
});
|
||||
|
||||
this._dragActor.get_transition('scale-x').connect('new-frame', () => {
|
||||
let currentScale = this._dragActor.scale_x / origScale;
|
||||
this._dragOffsetX = currentScale * origDragOffsetX;
|
||||
this._dragOffsetY = currentScale * origDragOffsetY;
|
||||
this._dragActor.set_position(
|
||||
this._dragX + this._dragOffsetX,
|
||||
this._dragY + this._dragOffsetY);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,7 +500,7 @@ var _Draggable = class _Draggable {
|
||||
|
||||
while (target) {
|
||||
if (target._delegate && target._delegate.handleDragOver) {
|
||||
let [r, targX, targY] = target.transform_stage_point(this._dragX, this._dragY);
|
||||
let [r_, targX, targY] = target.transform_stage_point(this._dragX, this._dragY);
|
||||
// We currently loop through all parents on drag-over even if one of the children has handled it.
|
||||
// We can check the return value of the function and break the loop if it's true if we don't want
|
||||
// to continue checking the parents.
|
||||
@@ -561,11 +557,11 @@ var _Draggable = class _Draggable {
|
||||
let dropFunc = dragMonitors[i].dragDrop;
|
||||
if (dropFunc)
|
||||
switch (dropFunc(dropEvent)) {
|
||||
case DragDropResult.FAILURE:
|
||||
case DragDropResult.SUCCESS:
|
||||
return true;
|
||||
case DragDropResult.CONTINUE:
|
||||
continue;
|
||||
case DragDropResult.FAILURE:
|
||||
case DragDropResult.SUCCESS:
|
||||
return true;
|
||||
case DragDropResult.CONTINUE:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,7 +572,7 @@ var _Draggable = class _Draggable {
|
||||
|
||||
while (target) {
|
||||
if (target._delegate && target._delegate.acceptDrop) {
|
||||
let [r, targX, targY] = target.transform_stage_point(dropX, dropY);
|
||||
let [r_, targX, targY] = target.transform_stage_point(dropX, dropY);
|
||||
if (target._delegate.acceptDrop(this.actor._delegate,
|
||||
this._dragActor,
|
||||
targX,
|
||||
@@ -588,8 +584,9 @@ var _Draggable = class _Draggable {
|
||||
if (this._restoreOnSuccess) {
|
||||
this._restoreDragActor(event.get_time());
|
||||
return true;
|
||||
} else
|
||||
} else {
|
||||
this._dragActor.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
this._dragState = DragState.INIT;
|
||||
@@ -613,15 +610,15 @@ var _Draggable = class _Draggable {
|
||||
if (this._dragActorSource && this._dragActorSource.visible) {
|
||||
// Snap the clone back to its source
|
||||
[x, y] = this._dragActorSource.get_transformed_position();
|
||||
let [sourceScaledWidth, sourceScaledHeight] = this._dragActorSource.get_transformed_size();
|
||||
scale = sourceScaledWidth ? this._dragActor.width / sourceScaledWidth : 0;
|
||||
let [sourceScaledWidth] = this._dragActorSource.get_transformed_size();
|
||||
scale = sourceScaledWidth ? sourceScaledWidth / this._dragActor.width : 0;
|
||||
} else if (this._dragOrigParent) {
|
||||
// Snap the actor back to its original position within
|
||||
// its parent, adjusting for the fact that the parent
|
||||
// may have been moved or scaled
|
||||
let [parentX, parentY] = this._dragOrigParent.get_transformed_position();
|
||||
let [parentWidth, parentHeight] = this._dragOrigParent.get_size();
|
||||
let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size();
|
||||
let [parentWidth] = this._dragOrigParent.get_size();
|
||||
let [parentScaledWidth] = this._dragOrigParent.get_transformed_size();
|
||||
let parentScale = 1.0;
|
||||
if (parentWidth != 0)
|
||||
parentScale = parentScaledWidth / parentWidth;
|
||||
@@ -657,13 +654,13 @@ var _Draggable = class _Draggable {
|
||||
|
||||
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
|
||||
|
||||
this._animateDragEnd(eventTime,
|
||||
{ x: snapBackX,
|
||||
y: snapBackY,
|
||||
scale_x: snapBackScale,
|
||||
scale_y: snapBackScale,
|
||||
time: SNAP_BACK_ANIMATION_TIME,
|
||||
});
|
||||
this._animateDragEnd(eventTime, {
|
||||
x: snapBackX,
|
||||
y: snapBackY,
|
||||
scale_x: snapBackScale,
|
||||
scale_y: snapBackScale,
|
||||
duration: SNAP_BACK_ANIMATION_TIME
|
||||
});
|
||||
}
|
||||
|
||||
_restoreDragActor(eventTime) {
|
||||
@@ -675,26 +672,27 @@ var _Draggable = class _Draggable {
|
||||
this._dragActor.set_scale(restoreScale, restoreScale);
|
||||
this._dragActor.opacity = 0;
|
||||
|
||||
this._animateDragEnd(eventTime,
|
||||
{ time: REVERT_ANIMATION_TIME });
|
||||
this._animateDragEnd(eventTime, {
|
||||
duration: REVERT_ANIMATION_TIME
|
||||
});
|
||||
}
|
||||
|
||||
_animateDragEnd(eventTime, params) {
|
||||
this._animationInProgress = true;
|
||||
|
||||
params['opacity'] = this._dragOrigOpacity;
|
||||
params['transition'] = 'easeOutQuad';
|
||||
params['onComplete'] = this._onAnimationComplete;
|
||||
params['onCompleteScope'] = this;
|
||||
params['onCompleteParams'] = [this._dragActor, eventTime];
|
||||
|
||||
// start the animation
|
||||
Tweener.addTween(this._dragActor, params)
|
||||
this._dragActor.ease(Object.assign(params, {
|
||||
opacity: this._dragOrigOpacity,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
this._onAnimationComplete(this._dragActor, eventTime);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
_finishAnimation() {
|
||||
if (!this._animationInProgress)
|
||||
return
|
||||
return;
|
||||
|
||||
this._animationInProgress = false;
|
||||
if (!this._buttonDown)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported EdgeDragAction */
|
||||
|
||||
const { Clutter, GObject, Meta, St } = imports.gi;
|
||||
|
||||
@@ -16,7 +17,7 @@ var EdgeDragAction = GObject.registerClass({
|
||||
this._allowedModes = allowedModes;
|
||||
this.set_n_touch_points(1);
|
||||
|
||||
global.display.connect('grab-op-begin', () => { this.cancel(); });
|
||||
global.display.connect('grab-op-begin', () => this.cancel());
|
||||
}
|
||||
|
||||
_getMonitorRect(x, y) {
|
||||
@@ -26,7 +27,7 @@ var EdgeDragAction = GObject.registerClass({
|
||||
return global.display.get_monitor_geometry(monitorIndex);
|
||||
}
|
||||
|
||||
vfunc_gesture_prepare(actor) {
|
||||
vfunc_gesture_prepare(_actor) {
|
||||
if (this.get_n_current_points() == 0)
|
||||
return false;
|
||||
|
||||
@@ -42,7 +43,7 @@ var EdgeDragAction = GObject.registerClass({
|
||||
(this._side == St.Side.BOTTOM && y > monitorRect.y + monitorRect.height - EDGE_THRESHOLD));
|
||||
}
|
||||
|
||||
vfunc_gesture_progress(actor) {
|
||||
vfunc_gesture_progress(_actor) {
|
||||
let [startX, startY] = this.get_press_coords(0);
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let offsetX = Math.abs (x - startX);
|
||||
@@ -62,7 +63,7 @@ var EdgeDragAction = GObject.registerClass({
|
||||
return true;
|
||||
}
|
||||
|
||||
vfunc_gesture_end(actor) {
|
||||
vfunc_gesture_end(_actor) {
|
||||
let [startX, startY] = this.get_press_coords(0);
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let monitorRect = this._getMonitorRect(startX, startY);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported init, EndSessionDialog */
|
||||
/*
|
||||
* Copyright 2010-2016 Red Hat, Inc
|
||||
*
|
||||
@@ -16,8 +17,6 @@
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const { AccountsService, Clutter, Gio,
|
||||
GLib, GObject, Pango, Polkit, Shell, St } = imports.gi;
|
||||
|
||||
@@ -29,13 +28,9 @@ const UserWidget = imports.ui.userWidget;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
let _endSessionDialog = null;
|
||||
|
||||
const _ITEM_ICON_SIZE = 48;
|
||||
const _DIALOG_ICON_SIZE = 48;
|
||||
|
||||
var GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
|
||||
|
||||
const EndSessionDialogIface = loadInterfaceXML('org.gnome.SessionManager.EndSessionDialog');
|
||||
|
||||
const logoutDialogContent = {
|
||||
@@ -53,7 +48,7 @@ const logoutDialogContent = {
|
||||
},
|
||||
showBatteryWarning: false,
|
||||
confirmButtons: [{ signal: 'ConfirmedLogout',
|
||||
label: C_("button", "Log Out") }],
|
||||
label: C_("button", "Log Out") }],
|
||||
iconStyleClass: 'end-session-dialog-logout-icon',
|
||||
showOtherSessions: false,
|
||||
};
|
||||
@@ -69,9 +64,9 @@ const shutdownDialogContent = {
|
||||
checkBoxText: C_("checkbox", "Install pending software updates"),
|
||||
showBatteryWarning: true,
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: C_("button", "Restart") },
|
||||
label: C_("button", "Restart") },
|
||||
{ signal: 'ConfirmedShutdown',
|
||||
label: C_("button", "Power Off") }],
|
||||
label: C_("button", "Power Off") }],
|
||||
iconName: 'system-shutdown-symbolic',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon',
|
||||
showOtherSessions: true,
|
||||
@@ -86,7 +81,7 @@ const restartDialogContent = {
|
||||
},
|
||||
showBatteryWarning: false,
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: C_("button", "Restart") }],
|
||||
label: C_("button", "Restart") }],
|
||||
iconName: 'view-refresh-symbolic',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon',
|
||||
showOtherSessions: true,
|
||||
@@ -102,7 +97,7 @@ const restartUpdateDialogContent = {
|
||||
},
|
||||
showBatteryWarning: true,
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: C_("button", "Restart & Install") }],
|
||||
label: C_("button", "Restart & Install") }],
|
||||
unusedFutureButtonForTranslation: C_("button", "Install & Power Off"),
|
||||
unusedFutureCheckBoxForTranslation: C_("checkbox", "Power off after updates are installed"),
|
||||
iconName: 'view-refresh-symbolic',
|
||||
@@ -122,18 +117,18 @@ const restartUpgradeDialogContent = {
|
||||
disableTimer: true,
|
||||
showBatteryWarning: false,
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: C_("button", "Restart & Install") }],
|
||||
label: C_("button", "Restart & Install") }],
|
||||
iconName: 'view-refresh-symbolic',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon',
|
||||
showOtherSessions: true,
|
||||
};
|
||||
|
||||
const DialogType = {
|
||||
LOGOUT: 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */,
|
||||
SHUTDOWN: 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */,
|
||||
RESTART: 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */,
|
||||
UPDATE_RESTART: 3,
|
||||
UPGRADE_RESTART: 4
|
||||
LOGOUT: 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */,
|
||||
SHUTDOWN: 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */,
|
||||
RESTART: 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */,
|
||||
UPDATE_RESTART: 3,
|
||||
UPGRADE_RESTART: 4
|
||||
};
|
||||
|
||||
const DialogContent = {
|
||||
@@ -159,7 +154,7 @@ function findAppFromInhibitor(inhibitor) {
|
||||
let desktopFile;
|
||||
try {
|
||||
[desktopFile] = inhibitor.GetAppIdSync();
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// XXX -- sometimes JIT inhibitors generated by gnome-session
|
||||
// get removed too soon. Don't fail in this case.
|
||||
log('gnome-session gave us a dead inhibitor: %s'.format(inhibitor.get_object_path()));
|
||||
@@ -212,10 +207,10 @@ function _setCheckBoxLabel(checkBox, text) {
|
||||
|
||||
if (text) {
|
||||
label.set_text(text);
|
||||
checkBox.actor.show();
|
||||
checkBox.show();
|
||||
} else {
|
||||
label.set_text('');
|
||||
checkBox.actor.hide();
|
||||
checkBox.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +218,7 @@ function init() {
|
||||
// This always returns the same singleton object
|
||||
// By instantiating it initially, we register the
|
||||
// bus object, etc.
|
||||
_endSessionDialog = new EndSessionDialog();
|
||||
(new EndSessionDialog());
|
||||
}
|
||||
|
||||
var EndSessionDialog = GObject.registerClass(
|
||||
@@ -235,14 +230,13 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
this._loginManager = LoginManager.getLoginManager();
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
this._user = this._userManager.get_user(GLib.get_user_name());
|
||||
this._updatesPermission = null;
|
||||
|
||||
this._pkOfflineProxy = new PkOfflineProxy(Gio.DBus.system,
|
||||
'org.freedesktop.PackageKit',
|
||||
'/org/freedesktop/PackageKit',
|
||||
(proxy, error) => {
|
||||
if (error)
|
||||
log(error.message);
|
||||
});
|
||||
this._onPkOfflineProxyCreated.bind(this));
|
||||
|
||||
this._powerProxy = new UPowerProxy(Gio.DBus.system,
|
||||
'org.freedesktop.UPower',
|
||||
'/org/freedesktop/UPower',
|
||||
@@ -276,8 +270,8 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
|
||||
this._iconBin = new St.Bin();
|
||||
mainContentLayout.add(this._iconBin,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
|
||||
@@ -290,7 +284,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
|
||||
messageLayout.add(this._subjectLabel,
|
||||
{ x_fill: false,
|
||||
y_fill: false,
|
||||
y_fill: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
|
||||
@@ -299,12 +293,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
this._descriptionLabel.clutter_text.line_wrap = true;
|
||||
|
||||
messageLayout.add(this._descriptionLabel,
|
||||
{ y_fill: true,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._checkBox = new CheckBox.CheckBox();
|
||||
this._checkBox.actor.connect('clicked', this._sync.bind(this));
|
||||
messageLayout.add(this._checkBox.actor);
|
||||
this._checkBox.connect('clicked', this._sync.bind(this));
|
||||
messageLayout.add(this._checkBox);
|
||||
|
||||
this._batteryWarning = new St.Label({ style_class: 'end-session-dialog-warning',
|
||||
text: _("Running on battery power: please plug in before installing updates.") });
|
||||
@@ -337,16 +331,36 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
this._inhibitorSection.add_actor(this._sessionHeader);
|
||||
this._inhibitorSection.add_actor(this._sessionList);
|
||||
|
||||
try {
|
||||
this._updatesPermission = Polkit.Permission.new_sync("org.freedesktop.packagekit.trigger-offline-update", null, null);
|
||||
} catch(e) {
|
||||
log('No permission to trigger offline updates: %s'.format(e.toString()));
|
||||
}
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
|
||||
}
|
||||
|
||||
_onPkOfflineProxyCreated(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Creating a D-Bus proxy won't propagate SERVICE_UNKNOWN or NAME_HAS_NO_OWNER
|
||||
// errors if PackageKit is not available, but the GIO implementation will make
|
||||
// sure in that case that the proxy's g-name-owner is set to null, so check that.
|
||||
if (this._pkOfflineProxy.g_name_owner === null) {
|
||||
this._pkOfflineProxy = null;
|
||||
return;
|
||||
}
|
||||
|
||||
// It only makes sense to check for this permission if PackageKit is available.
|
||||
Polkit.Permission.new(
|
||||
'org.freedesktop.packagekit.trigger-offline-update', null, null,
|
||||
(source, res) => {
|
||||
try {
|
||||
this._updatesPermission = Polkit.Permission.new_finish(res);
|
||||
} catch (e) {
|
||||
log(`No permission to trigger offline updates: ${e}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
this._user.disconnect(this._userLoadedId);
|
||||
this._user.disconnect(this._userChangedId);
|
||||
@@ -362,12 +376,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
let subject = dialogContent.subject;
|
||||
|
||||
// Use different title when we are installing updates
|
||||
if (dialogContent.subjectWithUpdates && this._checkBox.actor.checked)
|
||||
if (dialogContent.subjectWithUpdates && this._checkBox.checked)
|
||||
subject = dialogContent.subjectWithUpdates;
|
||||
|
||||
if (dialogContent.showBatteryWarning) {
|
||||
// Warn when running on battery power
|
||||
if (this._powerProxy.OnBattery && this._checkBox.actor.checked)
|
||||
if (this._powerProxy.OnBattery && this._checkBox.checked)
|
||||
this._batteryWarning.opacity = 255;
|
||||
else
|
||||
this._batteryWarning.opacity = 0;
|
||||
@@ -391,7 +405,8 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
}
|
||||
|
||||
// Use a different description when we are installing a system upgrade
|
||||
if (dialogContent.upgradeDescription) {
|
||||
// if the PackageKit proxy is available (i.e. PackageKit is available).
|
||||
if (this._pkOfflineProxy && dialogContent.upgradeDescription) {
|
||||
let name = this._pkOfflineProxy.PreparedUpgrade['name'].deep_unpack();
|
||||
let version = this._pkOfflineProxy.PreparedUpgrade['version'].deep_unpack();
|
||||
|
||||
@@ -414,7 +429,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
let avatarWidget = new UserWidget.Avatar(this._user,
|
||||
{ iconSize: _DIALOG_ICON_SIZE,
|
||||
styleClass: dialogContent.iconStyleClass });
|
||||
this._iconBin.child = avatarWidget.actor;
|
||||
this._iconBin.child = avatarWidget;
|
||||
avatarWidget.update();
|
||||
}
|
||||
|
||||
@@ -428,20 +443,22 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
_updateButtons() {
|
||||
let dialogContent = DialogContent[this._type];
|
||||
let buttons = [{ action: this.cancel.bind(this),
|
||||
label: _("Cancel"),
|
||||
key: Clutter.Escape }];
|
||||
label: _("Cancel"),
|
||||
key: Clutter.Escape }];
|
||||
|
||||
for (let i = 0; i < dialogContent.confirmButtons.length; i++) {
|
||||
let signal = dialogContent.confirmButtons[i].signal;
|
||||
let label = dialogContent.confirmButtons[i].label;
|
||||
buttons.push({ action: () => {
|
||||
this.close(true);
|
||||
let signalId = this.connect('closed', () => {
|
||||
this.disconnect(signalId);
|
||||
this._confirm(signal);
|
||||
});
|
||||
},
|
||||
label: label });
|
||||
buttons.push({
|
||||
action: () => {
|
||||
this.close(true);
|
||||
let signalId = this.connect('closed', () => {
|
||||
this.disconnect(signalId);
|
||||
this._confirm(signal);
|
||||
});
|
||||
},
|
||||
label: label,
|
||||
});
|
||||
}
|
||||
|
||||
this.setButtons(buttons);
|
||||
@@ -468,27 +485,27 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
};
|
||||
|
||||
// Offline update not available; just emit the signal
|
||||
if (!this._checkBox.actor.visible) {
|
||||
if (!this._checkBox.visible) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger the offline update as requested
|
||||
if (this._checkBox.actor.checked) {
|
||||
if (this._checkBox.checked) {
|
||||
switch (signal) {
|
||||
case "ConfirmedReboot":
|
||||
this._triggerOfflineUpdateReboot(callback);
|
||||
break;
|
||||
case "ConfirmedShutdown":
|
||||
// To actually trigger the offline update, we need to
|
||||
// reboot to do the upgrade. When the upgrade is complete,
|
||||
// the computer will shut down automatically.
|
||||
signal = "ConfirmedReboot";
|
||||
this._triggerOfflineUpdateShutdown(callback);
|
||||
break;
|
||||
default:
|
||||
callback();
|
||||
break;
|
||||
case "ConfirmedReboot":
|
||||
this._triggerOfflineUpdateReboot(callback);
|
||||
break;
|
||||
case "ConfirmedShutdown":
|
||||
// To actually trigger the offline update, we need to
|
||||
// reboot to do the upgrade. When the upgrade is complete,
|
||||
// the computer will shut down automatically.
|
||||
signal = "ConfirmedReboot";
|
||||
this._triggerOfflineUpdateShutdown(callback);
|
||||
break;
|
||||
default:
|
||||
callback();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this._triggerOfflineUpdateCancel(callback);
|
||||
@@ -500,6 +517,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
}
|
||||
|
||||
_triggerOfflineUpdateReboot(callback) {
|
||||
// Handle this gracefully if PackageKit is not available.
|
||||
if (!this._pkOfflineProxy) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
this._pkOfflineProxy.TriggerRemote('reboot', (result, error) => {
|
||||
if (error)
|
||||
log(error.message);
|
||||
@@ -509,6 +532,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
}
|
||||
|
||||
_triggerOfflineUpdateShutdown(callback) {
|
||||
// Handle this gracefully if PackageKit is not available.
|
||||
if (!this._pkOfflineProxy) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
this._pkOfflineProxy.TriggerRemote('power-off', (result, error) => {
|
||||
if (error)
|
||||
log(error.message);
|
||||
@@ -518,6 +547,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
}
|
||||
|
||||
_triggerOfflineUpdateCancel(callback) {
|
||||
// Handle this gracefully if PackageKit is not available.
|
||||
if (!this._pkOfflineProxy) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
this._pkOfflineProxy.CancelRemote((result, error) => {
|
||||
if (error)
|
||||
log(error.message);
|
||||
@@ -530,7 +565,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
let startTime = GLib.get_monotonic_time();
|
||||
this._secondsLeft = this._totalSecondsToStayOpen;
|
||||
|
||||
this._timerId = Mainloop.timeout_add_seconds(1, () => {
|
||||
this._timerId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, () => {
|
||||
let currentTime = GLib.get_monotonic_time();
|
||||
let secondsElapsed = ((currentTime - startTime) / 1000000);
|
||||
|
||||
@@ -552,7 +587,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
|
||||
_stopTimer() {
|
||||
if (this._timerId > 0) {
|
||||
Mainloop.source_remove(this._timerId);
|
||||
GLib.source_remove(this._timerId);
|
||||
this._timerId = 0;
|
||||
}
|
||||
|
||||
@@ -585,7 +620,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
}
|
||||
|
||||
_onInhibitorLoaded(inhibitor) {
|
||||
if (this._applications.indexOf(inhibitor) < 0) {
|
||||
if (!this._applications.includes(inhibitor)) {
|
||||
// Stale inhibitor
|
||||
return;
|
||||
}
|
||||
@@ -621,7 +656,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
|
||||
let actor = new St.BoxLayout({ style_class: 'end-session-dialog-session-list-item',
|
||||
can_focus: true });
|
||||
actor.add(avatar.actor);
|
||||
actor.add(avatar);
|
||||
|
||||
let nameLabel = new St.Label({ text: userLabelText,
|
||||
style_class: 'end-session-dialog-session-list-item-name',
|
||||
@@ -637,7 +672,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
this._loginManager.listSessions(result => {
|
||||
let n = 0;
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
let[id, uid, userName, seat, sessionPath] = result[i];
|
||||
let [id_, uid_, userName, seat_, sessionPath] = result[i];
|
||||
let proxy = new LogindSession(Gio.DBus.system, 'org.freedesktop.login1', sessionPath);
|
||||
|
||||
if (proxy.Class != 'user')
|
||||
@@ -680,7 +715,8 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
||||
this._type = type;
|
||||
|
||||
if (this._type == DialogType.RESTART) {
|
||||
// Only consider updates and upgrades if PackageKit is available.
|
||||
if (this._pkOfflineProxy && this._type == DialogType.RESTART) {
|
||||
if (this._pkOfflineProxy.UpdateTriggered)
|
||||
this._type = DialogType.UPDATE_RESTART;
|
||||
else if (this._pkOfflineProxy.UpgradeTriggered)
|
||||
@@ -702,7 +738,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
let dialogContent = DialogContent[this._type];
|
||||
|
||||
for (let i = 0; i < inhibitorObjectPaths.length; i++) {
|
||||
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], (proxy, error) => {
|
||||
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], proxy => {
|
||||
this._onInhibitorLoaded(proxy);
|
||||
});
|
||||
|
||||
@@ -712,19 +748,20 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
if (dialogContent.showOtherSessions)
|
||||
this._loadSessions();
|
||||
|
||||
let updateTriggered = this._pkOfflineProxy.UpdateTriggered;
|
||||
let updatePrepared = this._pkOfflineProxy.UpdatePrepared;
|
||||
// Only consider updates and upgrades if PackageKit is available.
|
||||
let updateTriggered = this._pkOfflineProxy ? this._pkOfflineProxy.UpdateTriggered : false;
|
||||
let updatePrepared = this._pkOfflineProxy ? this._pkOfflineProxy.UpdatePrepared : false;
|
||||
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
|
||||
|
||||
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || '');
|
||||
this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
|
||||
this._checkBox.actor.checked = (updatePrepared && updateTriggered);
|
||||
this._checkBox.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
|
||||
this._checkBox.checked = (updatePrepared && updateTriggered);
|
||||
|
||||
// We show the warning either together with the checkbox, or when
|
||||
// updates have already been triggered, but the user doesn't have
|
||||
// enough permissions to cancel them.
|
||||
this._batteryWarning.visible = (dialogContent.showBatteryWarning &&
|
||||
(this._checkBox.actor.visible || updatePrepared && updateTriggered && !updatesAllowed));
|
||||
(this._checkBox.visible || updatePrepared && updateTriggered && !updatesAllowed));
|
||||
|
||||
this._updateButtons();
|
||||
|
||||
@@ -745,7 +782,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
||||
});
|
||||
}
|
||||
|
||||
Close(parameters, invocation) {
|
||||
Close(_parameters, _invocation) {
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported init */
|
||||
|
||||
const Config = imports.misc.config;
|
||||
|
||||
@@ -9,7 +10,7 @@ imports.gi.versions.Gtk = '3.0';
|
||||
imports.gi.versions.TelepathyGLib = '0.12';
|
||||
imports.gi.versions.TelepathyLogger = '0.2';
|
||||
|
||||
const { Clutter, GLib, Shell, St } = imports.gi;
|
||||
const { Clutter, GLib, Meta, Shell, St } = imports.gi;
|
||||
const Gettext = imports.gettext;
|
||||
|
||||
// We can't import shell JS modules yet, because they may have
|
||||
@@ -57,8 +58,132 @@ function _patchLayoutClass(layoutClass, styleProps) {
|
||||
};
|
||||
}
|
||||
|
||||
function _loggingFunc() {
|
||||
let fields = {'MESSAGE': [].join.call(arguments, ', ')};
|
||||
function _makeEaseCallback(params, cleanup) {
|
||||
let onComplete = params.onComplete;
|
||||
delete params.onComplete;
|
||||
|
||||
let onStopped = params.onStopped;
|
||||
delete params.onStopped;
|
||||
|
||||
return isFinished => {
|
||||
cleanup();
|
||||
|
||||
if (onStopped)
|
||||
onStopped(isFinished);
|
||||
if (onComplete && isFinished)
|
||||
onComplete();
|
||||
};
|
||||
}
|
||||
|
||||
function _getPropertyTarget(actor, propName) {
|
||||
if (!propName.startsWith('@'))
|
||||
return [actor, propName];
|
||||
|
||||
let [type, name, prop] = propName.split('.');
|
||||
switch (type) {
|
||||
case '@layout':
|
||||
return [actor.layout_manager, name];
|
||||
case '@actions':
|
||||
return [actor.get_action(name), prop];
|
||||
case '@constraints':
|
||||
return [actor.get_constraint(name), prop];
|
||||
case '@effects':
|
||||
return [actor.get_effect(name), prop];
|
||||
}
|
||||
|
||||
throw new Error(`Invalid property name ${propName}`);
|
||||
}
|
||||
|
||||
function _easeActor(actor, params) {
|
||||
actor.save_easing_state();
|
||||
|
||||
if (params.duration != undefined)
|
||||
actor.set_easing_duration(params.duration);
|
||||
delete params.duration;
|
||||
|
||||
if (params.delay != undefined)
|
||||
actor.set_easing_delay(params.delay);
|
||||
delete params.delay;
|
||||
|
||||
if (params.mode != undefined)
|
||||
actor.set_easing_mode(params.mode);
|
||||
delete params.mode;
|
||||
|
||||
let cleanup = () => Meta.enable_unredirect_for_display(global.display);
|
||||
let callback = _makeEaseCallback(params, cleanup);
|
||||
|
||||
// cancel overwritten transitions
|
||||
let animatedProps = Object.keys(params).map(p => p.replace('_', '-', 'g'));
|
||||
animatedProps.forEach(p => actor.remove_transition(p));
|
||||
|
||||
actor.set(params);
|
||||
actor.restore_easing_state();
|
||||
|
||||
let transition = animatedProps.map(p => actor.get_transition(p))
|
||||
.find(t => t !== null);
|
||||
|
||||
if (transition && transition.delay)
|
||||
transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
|
||||
else
|
||||
Meta.disable_unredirect_for_display(global.display);
|
||||
|
||||
if (transition)
|
||||
transition.connect('stopped', (t, finished) => callback(finished));
|
||||
else
|
||||
callback(true);
|
||||
}
|
||||
|
||||
function _easeActorProperty(actor, propName, target, params) {
|
||||
// Avoid pointless difference with ease()
|
||||
if (params.mode)
|
||||
params.progress_mode = params.mode;
|
||||
delete params.mode;
|
||||
|
||||
if (params.duration)
|
||||
params.duration = adjustAnimationTime(params.duration);
|
||||
let duration = Math.floor(params.duration || 0);
|
||||
|
||||
// Copy Clutter's behavior for implicit animations, see
|
||||
// should_skip_implicit_transition()
|
||||
if (actor instanceof Clutter.Actor && !actor.mapped)
|
||||
duration = 0;
|
||||
|
||||
let cleanup = () => Meta.enable_unredirect_for_display(global.display);
|
||||
let callback = _makeEaseCallback(params, cleanup);
|
||||
|
||||
// cancel overwritten transition
|
||||
actor.remove_transition(propName);
|
||||
|
||||
if (duration == 0) {
|
||||
let [obj, prop] = _getPropertyTarget(actor, propName);
|
||||
obj[prop] = target;
|
||||
|
||||
Meta.disable_unredirect_for_display(global.display);
|
||||
callback(true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let pspec = actor.find_property(propName);
|
||||
let transition = new Clutter.PropertyTransition(Object.assign({
|
||||
property_name: propName,
|
||||
interval: new Clutter.Interval({ value_type: pspec.value_type }),
|
||||
remove_on_complete: true
|
||||
}, params));
|
||||
actor.add_transition(propName, transition);
|
||||
|
||||
transition.set_to(target);
|
||||
|
||||
if (transition.delay)
|
||||
transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
|
||||
else
|
||||
Meta.disable_unredirect_for_display(global.display);
|
||||
|
||||
transition.connect('stopped', (t, finished) => callback(finished));
|
||||
}
|
||||
|
||||
function _loggingFunc(...args) {
|
||||
let fields = { 'MESSAGE': args.join(', ') };
|
||||
let domain = "GNOME Shell";
|
||||
|
||||
// If the caller is an extension, add it as metadata
|
||||
@@ -93,6 +218,27 @@ function init() {
|
||||
column_spacing: 'spacing-columns' });
|
||||
_patchLayoutClass(Clutter.BoxLayout, { spacing: 'spacing' });
|
||||
|
||||
let origSetEasingDuration = Clutter.Actor.prototype.set_easing_duration;
|
||||
Clutter.Actor.prototype.set_easing_duration = function(msecs) {
|
||||
origSetEasingDuration.call(this, adjustAnimationTime(msecs));
|
||||
};
|
||||
let origSetEasingDelay = Clutter.Actor.prototype.set_easing_delay;
|
||||
Clutter.Actor.prototype.set_easing_delay = function(msecs) {
|
||||
origSetEasingDelay.call(this, adjustAnimationTime(msecs));
|
||||
};
|
||||
|
||||
Clutter.Actor.prototype.ease = function(props, easingParams) {
|
||||
_easeActor(this, props, easingParams);
|
||||
};
|
||||
Clutter.Actor.prototype.ease_property = function(propName, target, params) {
|
||||
_easeActorProperty(this, propName, target, params);
|
||||
};
|
||||
St.Adjustment.prototype.ease = function(target, params) {
|
||||
// we're not an actor of course, but we implement the same
|
||||
// transition API as Clutter.Actor, so this works anyway
|
||||
_easeActorProperty(this, 'value', target, params);
|
||||
};
|
||||
|
||||
Clutter.Actor.prototype.toString = function() {
|
||||
return St.describe_actor(this);
|
||||
};
|
||||
@@ -106,15 +252,21 @@ function init() {
|
||||
}
|
||||
});
|
||||
|
||||
St.set_slow_down_factor = function(factor) {
|
||||
let { stack } = new Error();
|
||||
log(`St.set_slow_down_factor() is deprecated, use St.Settings.slow_down_factor\n${stack}`);
|
||||
St.Settings.get().slow_down_factor = factor;
|
||||
};
|
||||
|
||||
let origToString = Object.prototype.toString;
|
||||
Object.prototype.toString = function() {
|
||||
let base = origToString.call(this);
|
||||
try {
|
||||
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
||||
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
|
||||
return base.replace(/\]$/, ` delegate for ${this.actor.toString().substring(1)}`);
|
||||
else
|
||||
return base;
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
return base;
|
||||
}
|
||||
};
|
||||
@@ -128,7 +280,7 @@ function init() {
|
||||
if (slowdownEnv) {
|
||||
let factor = parseFloat(slowdownEnv);
|
||||
if (!isNaN(factor) && factor > 0.0)
|
||||
St.set_slow_down_factor(factor);
|
||||
St.Settings.get().slow_down_factor = factor;
|
||||
}
|
||||
|
||||
// OK, now things are initialized enough that we can import shell JS
|
||||
@@ -138,3 +290,17 @@ function init() {
|
||||
Tweener.init();
|
||||
String.prototype.format = Format.format;
|
||||
}
|
||||
|
||||
// adjustAnimationTime:
|
||||
// @msecs: time in milliseconds
|
||||
//
|
||||
// Adjust @msecs to account for St's enable-animations
|
||||
// and slow-down-factor settings
|
||||
function adjustAnimationTime(msecs) {
|
||||
let settings = St.Settings.get();
|
||||
|
||||
if (!settings.enable_animations)
|
||||
return 1;
|
||||
return settings.slow_down_factor * msecs;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported init, installExtension, uninstallExtension,
|
||||
checkForUpdates, updateExtension */
|
||||
|
||||
const { Clutter, Gio, GLib, GObject, Soup, St } = imports.gi;
|
||||
const { Clutter, Gio, GLib, GObject, Soup } = imports.gi;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const Dialog = imports.ui.dialog;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
|
||||
const _signals = ExtensionSystem._signals;
|
||||
|
||||
var REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
||||
var REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
||||
var REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
|
||||
var REPOSITORY_URL_UPDATE = REPOSITORY_URL_BASE + '/update-info/';
|
||||
var REPOSITORY_URL_DOWNLOAD = `${REPOSITORY_URL_BASE}/download-extension/%s.shell-extension.zip`;
|
||||
var REPOSITORY_URL_INFO = `${REPOSITORY_URL_BASE}/extension-info/`;
|
||||
var REPOSITORY_URL_UPDATE = `${REPOSITORY_URL_BASE}/update-info/`;
|
||||
|
||||
let _httpSession;
|
||||
|
||||
@@ -25,7 +26,7 @@ function installExtension(uuid, invocation) {
|
||||
|
||||
_httpSession.queue_message(message, (session, message) => {
|
||||
if (message.status_code != Soup.KnownStatusCode.OK) {
|
||||
ExtensionSystem.logExtensionError(uuid, 'downloading info: ' + message.status_code);
|
||||
Main.extensionManager.logExtensionError(uuid, `downloading info: ${message.status_code}`);
|
||||
invocation.return_dbus_error('org.gnome.Shell.DownloadInfoError', message.status_code.toString());
|
||||
return;
|
||||
}
|
||||
@@ -34,7 +35,7 @@ function installExtension(uuid, invocation) {
|
||||
try {
|
||||
info = JSON.parse(message.response_body.data);
|
||||
} catch (e) {
|
||||
ExtensionSystem.logExtensionError(uuid, 'parsing info: ' + e);
|
||||
Main.extensionManager.logExtensionError(uuid, `parsing info: ${e}`);
|
||||
invocation.return_dbus_error('org.gnome.Shell.ParseInfoError', e.toString());
|
||||
return;
|
||||
}
|
||||
@@ -45,7 +46,7 @@ function installExtension(uuid, invocation) {
|
||||
}
|
||||
|
||||
function uninstallExtension(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
let extension = Main.extensionManager.lookup(uuid);
|
||||
if (!extension)
|
||||
return false;
|
||||
|
||||
@@ -53,7 +54,7 @@ function uninstallExtension(uuid) {
|
||||
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||
return false;
|
||||
|
||||
if (!ExtensionSystem.unloadExtension(extension))
|
||||
if (!Main.extensionManager.unloadExtension(extension))
|
||||
return false;
|
||||
|
||||
FileUtils.recursivelyDeleteDir(extension.dir, true);
|
||||
@@ -114,10 +115,10 @@ function updateExtension(uuid) {
|
||||
|
||||
_httpSession.queue_message(message, (session, message) => {
|
||||
gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => {
|
||||
let oldExtension = ExtensionUtils.extensions[uuid];
|
||||
let oldExtension = Main.extensionManager.lookup(uuid);
|
||||
let extensionDir = oldExtension.dir;
|
||||
|
||||
if (!ExtensionSystem.unloadExtension(oldExtension))
|
||||
if (!Main.extensionManager.unloadExtension(oldExtension))
|
||||
return;
|
||||
|
||||
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
|
||||
@@ -126,11 +127,11 @@ function updateExtension(uuid) {
|
||||
let extension = null;
|
||||
|
||||
try {
|
||||
extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
|
||||
ExtensionSystem.loadExtension(extension);
|
||||
} catch(e) {
|
||||
extension = Main.extensionManager.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
|
||||
Main.extensionManager.loadExtension(extension);
|
||||
} catch (e) {
|
||||
if (extension)
|
||||
ExtensionSystem.unloadExtension(extension);
|
||||
Main.extensionManager.unloadExtension(extension);
|
||||
|
||||
logError(e, 'Error loading extension %s'.format(uuid));
|
||||
|
||||
@@ -139,7 +140,7 @@ function updateExtension(uuid) {
|
||||
|
||||
// Restore what was there before. We can't do much if we
|
||||
// fail here.
|
||||
ExtensionSystem.loadExtension(oldExtension);
|
||||
Main.extensionManager.loadExtension(oldExtension);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -152,9 +153,9 @@ function updateExtension(uuid) {
|
||||
|
||||
function checkForUpdates() {
|
||||
let metadatas = {};
|
||||
for (let uuid in ExtensionUtils.extensions) {
|
||||
metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata;
|
||||
}
|
||||
Main.extensionManager.getUuids().forEach(uuid => {
|
||||
metadatas[uuid] = Main.extensionManager.extensions[uuid].metadata;
|
||||
});
|
||||
|
||||
let params = { shell_version: Config.PACKAGE_VERSION,
|
||||
installed: JSON.stringify(metadatas) };
|
||||
@@ -185,36 +186,32 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
|
||||
this._info = info;
|
||||
this._invocation = invocation;
|
||||
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: this._onCancelButtonPressed.bind(this),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: _("Install"),
|
||||
action: this._onInstallButtonPressed.bind(this),
|
||||
default: true
|
||||
}]);
|
||||
this.setButtons([{
|
||||
label: _("Cancel"),
|
||||
action: this._onCancelButtonPressed.bind(this),
|
||||
key: Clutter.Escape,
|
||||
}, {
|
||||
label: _("Install"),
|
||||
action: this._onInstallButtonPressed.bind(this),
|
||||
default: true,
|
||||
}]);
|
||||
|
||||
let message = _("Download and install “%s” from extensions.gnome.org?").format(info.name);
|
||||
let content = new Dialog.MessageDialogContent({
|
||||
title: _("Download and install “%s” from extensions.gnome.org?").format(info.name),
|
||||
icon: new Gio.FileIcon({
|
||||
file: Gio.File.new_for_uri(`${REPOSITORY_URL_BASE}${info.icon}`)
|
||||
})
|
||||
});
|
||||
|
||||
let box = new St.BoxLayout({ style_class: 'message-dialog-main-layout',
|
||||
vertical: false });
|
||||
this.contentLayout.add(box);
|
||||
|
||||
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(REPOSITORY_URL_BASE + info.icon) })
|
||||
let icon = new St.Icon({ gicon: gicon });
|
||||
box.add(icon);
|
||||
|
||||
let label = new St.Label({ style_class: 'message-dialog-title headline',
|
||||
text: message });
|
||||
box.add(label);
|
||||
this.contentLayout.add(content);
|
||||
}
|
||||
|
||||
_onCancelButtonPressed(button, event) {
|
||||
_onCancelButtonPressed() {
|
||||
this.close();
|
||||
this._invocation.return_value(GLib.Variant.new('(s)', ['cancelled']));
|
||||
}
|
||||
|
||||
_onInstallButtonPressed(button, event) {
|
||||
_onInstallButtonPressed() {
|
||||
let params = { shell_version: Config.PACKAGE_VERSION };
|
||||
|
||||
let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
|
||||
@@ -226,21 +223,16 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
|
||||
function errback(code, message) {
|
||||
let msg = message ? message.toString() : '';
|
||||
log('Error while installing %s: %s (%s)'.format(uuid, code, msg));
|
||||
invocation.return_dbus_error('org.gnome.Shell.' + code, msg);
|
||||
invocation.return_dbus_error(`org.gnome.Shell.${code}`, msg);
|
||||
}
|
||||
|
||||
function callback() {
|
||||
// Add extension to 'enabled-extensions' for the user, always...
|
||||
let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
|
||||
if (enabledExtensions.indexOf(uuid) == -1) {
|
||||
enabledExtensions.push(uuid);
|
||||
global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||
}
|
||||
|
||||
try {
|
||||
let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
|
||||
ExtensionSystem.loadExtension(extension);
|
||||
} catch(e) {
|
||||
let extension = Main.extensionManager.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
|
||||
Main.extensionManager.loadExtension(extension);
|
||||
if (!Main.extensionManager.enableExtension(uuid))
|
||||
throw new Error(`Cannot add ${uuid} to enabled extensions gsettings key`);
|
||||
} catch (e) {
|
||||
uninstallExtension(uuid);
|
||||
errback('LoadExtensionError', e);
|
||||
return;
|
||||
|
||||
@@ -1,374 +1,519 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported init connect disconnect */
|
||||
|
||||
const { Gio, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
var ExtensionState = {
|
||||
ENABLED: 1,
|
||||
DISABLED: 2,
|
||||
ERROR: 3,
|
||||
OUT_OF_DATE: 4,
|
||||
DOWNLOADING: 5,
|
||||
INITIALIZED: 6,
|
||||
|
||||
// Used as an error state for operations on unknown extensions,
|
||||
// should never be in a real extensionMeta object.
|
||||
UNINSTALLED: 99
|
||||
};
|
||||
|
||||
// Arrays of uuids
|
||||
var enabledExtensions;
|
||||
// Contains the order that extensions were enabled in.
|
||||
var extensionOrder = [];
|
||||
|
||||
// We don't really have a class to add signals on. So, create
|
||||
// a simple dummy object, add the signal methods, and export those
|
||||
// publically.
|
||||
var _signals = {};
|
||||
Signals.addSignalMethods(_signals);
|
||||
|
||||
var connect = _signals.connect.bind(_signals);
|
||||
var disconnect = _signals.disconnect.bind(_signals);
|
||||
const { ExtensionState, ExtensionType } = ExtensionUtils;
|
||||
|
||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||
const DISABLED_EXTENSIONS_KEY = 'disabled-extensions';
|
||||
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
|
||||
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
|
||||
|
||||
var initted = false;
|
||||
var enabled;
|
||||
var ExtensionManager = class {
|
||||
constructor() {
|
||||
this._initialized = false;
|
||||
this._enabled = false;
|
||||
|
||||
function disableExtension(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return;
|
||||
this._extensions = new Map();
|
||||
this._enabledExtensions = [];
|
||||
this._extensionOrder = [];
|
||||
|
||||
if (extension.state != ExtensionState.ENABLED)
|
||||
return;
|
||||
|
||||
// "Rebase" the extension order by disabling and then enabling extensions
|
||||
// in order to help prevent conflicts.
|
||||
|
||||
// Example:
|
||||
// order = [A, B, C, D, E]
|
||||
// user disables C
|
||||
// this should: disable E, disable D, disable C, enable D, enable E
|
||||
|
||||
let orderIdx = extensionOrder.indexOf(uuid);
|
||||
let order = extensionOrder.slice(orderIdx + 1);
|
||||
let orderReversed = order.slice().reverse();
|
||||
|
||||
for (let i = 0; i < orderReversed.length; i++) {
|
||||
let uuid = orderReversed[i];
|
||||
try {
|
||||
ExtensionUtils.extensions[uuid].stateObj.disable();
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
}
|
||||
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
|
||||
}
|
||||
|
||||
if (extension.stylesheet) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
init() {
|
||||
this._sessionUpdated();
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.disable();
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
lookup(uuid) {
|
||||
return this._extensions.get(uuid);
|
||||
}
|
||||
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let uuid = order[i];
|
||||
try {
|
||||
ExtensionUtils.extensions[uuid].stateObj.enable();
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
}
|
||||
getUuids() {
|
||||
return [...this._extensions.keys()];
|
||||
}
|
||||
|
||||
extensionOrder.splice(orderIdx, 1);
|
||||
|
||||
if ( extension.state != ExtensionState.ERROR ) {
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
}
|
||||
|
||||
function enableExtension(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
if (extension.state == ExtensionState.INITIALIZED)
|
||||
initExtension(uuid);
|
||||
|
||||
if (extension.state != ExtensionState.DISABLED)
|
||||
return;
|
||||
|
||||
extensionOrder.push(uuid);
|
||||
|
||||
let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css'];
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
for (let i = 0; i < stylesheetNames.length; i++) {
|
||||
try {
|
||||
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
|
||||
theme.load_stylesheet(stylesheetFile);
|
||||
extension.stylesheet = stylesheetFile;
|
||||
break;
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
||||
continue; // not an error
|
||||
log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
|
||||
_callExtensionDisable(uuid) {
|
||||
let extension = this.lookup(uuid);
|
||||
if (!extension)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.enable();
|
||||
extension.state = ExtensionState.ENABLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
return;
|
||||
} catch(e) {
|
||||
if (extension.state != ExtensionState.ENABLED)
|
||||
return;
|
||||
|
||||
// "Rebase" the extension order by disabling and then enabling extensions
|
||||
// in order to help prevent conflicts.
|
||||
|
||||
// Example:
|
||||
// order = [A, B, C, D, E]
|
||||
// user disables C
|
||||
// this should: disable E, disable D, disable C, enable D, enable E
|
||||
|
||||
let orderIdx = this._extensionOrder.indexOf(uuid);
|
||||
let order = this._extensionOrder.slice(orderIdx + 1);
|
||||
let orderReversed = order.slice().reverse();
|
||||
|
||||
for (let i = 0; i < orderReversed.length; i++) {
|
||||
let uuid = orderReversed[i];
|
||||
try {
|
||||
this.lookup(uuid).stateObj.disable();
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.stylesheet) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
}
|
||||
logExtensionError(uuid, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function logExtensionError(uuid, error) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
if (!extension)
|
||||
return;
|
||||
try {
|
||||
extension.stateObj.disable();
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
|
||||
let message = '' + error;
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let uuid = order[i];
|
||||
try {
|
||||
this.lookup(uuid).stateObj.enable();
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
extension.state = ExtensionState.ERROR;
|
||||
if (!extension.errors)
|
||||
extension.errors = [];
|
||||
extension.errors.push(message);
|
||||
this._extensionOrder.splice(orderIdx, 1);
|
||||
|
||||
log('Extension "%s" had error: %s'.format(uuid, message));
|
||||
_signals.emit('extension-state-changed', { uuid: uuid,
|
||||
error: message,
|
||||
state: extension.state });
|
||||
}
|
||||
|
||||
function loadExtension(extension) {
|
||||
// Default to error, we set success as the last step
|
||||
extension.state = ExtensionState.ERROR;
|
||||
|
||||
let checkVersion = !global.settings.get_boolean(EXTENSION_DISABLE_VERSION_CHECK_KEY);
|
||||
|
||||
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
|
||||
extension.state = ExtensionState.OUT_OF_DATE;
|
||||
} else {
|
||||
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
|
||||
if (enabled) {
|
||||
if (!initExtension(extension.uuid))
|
||||
return;
|
||||
if (extension.state == ExtensionState.DISABLED)
|
||||
enableExtension(extension.uuid);
|
||||
} else {
|
||||
extension.state = ExtensionState.INITIALIZED;
|
||||
if (extension.state != ExtensionState.ERROR) {
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
}
|
||||
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
}
|
||||
_callExtensionEnable(uuid) {
|
||||
if (!Main.sessionMode.allowExtensions)
|
||||
return;
|
||||
|
||||
function unloadExtension(extension) {
|
||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||
// but it will be removed on next reboot, and hopefully nothing
|
||||
// broke too much.
|
||||
disableExtension(extension.uuid);
|
||||
let extension = this.lookup(uuid);
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
extension.state = ExtensionState.UNINSTALLED;
|
||||
_signals.emit('extension-state-changed', extension);
|
||||
if (extension.state == ExtensionState.INITIALIZED)
|
||||
this._callExtensionInit(uuid);
|
||||
|
||||
delete ExtensionUtils.extensions[extension.uuid];
|
||||
return true;
|
||||
}
|
||||
if (extension.state != ExtensionState.DISABLED)
|
||||
return;
|
||||
|
||||
function reloadExtension(oldExtension) {
|
||||
// Grab the things we'll need to pass to createExtensionObject
|
||||
// to reload it.
|
||||
let { uuid: uuid, dir: dir, type: type } = oldExtension;
|
||||
let stylesheetNames = [`${global.session_mode}.css`, 'stylesheet.css'];
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
for (let i = 0; i < stylesheetNames.length; i++) {
|
||||
try {
|
||||
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
|
||||
theme.load_stylesheet(stylesheetFile);
|
||||
extension.stylesheet = stylesheetFile;
|
||||
break;
|
||||
} catch (e) {
|
||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
|
||||
continue; // not an error
|
||||
this.logExtensionError(uuid, e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Then unload the old extension.
|
||||
unloadExtension(oldExtension);
|
||||
|
||||
// Now, recreate the extension and load it.
|
||||
let newExtension;
|
||||
try {
|
||||
newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
return;
|
||||
}
|
||||
|
||||
loadExtension(newExtension);
|
||||
}
|
||||
|
||||
function initExtension(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
let dir = extension.dir;
|
||||
|
||||
if (!extension)
|
||||
throw new Error("Extension was not properly created. Call loadExtension first");
|
||||
|
||||
let extensionJs = dir.get_child('extension.js');
|
||||
if (!extensionJs.query_exists(null)) {
|
||||
logExtensionError(uuid, new Error('Missing extension.js'));
|
||||
return false;
|
||||
}
|
||||
|
||||
let extensionModule;
|
||||
let extensionState = null;
|
||||
|
||||
ExtensionUtils.installImporter(extension);
|
||||
try {
|
||||
extensionModule = extension.imports.extension;
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extensionModule.init) {
|
||||
try {
|
||||
extensionState = extensionModule.init(extension);
|
||||
} catch(e) {
|
||||
logExtensionError(uuid, e);
|
||||
extension.stateObj.enable();
|
||||
extension.state = ExtensionState.ENABLED;
|
||||
this._extensionOrder.push(uuid);
|
||||
this.emit('extension-state-changed', extension);
|
||||
} catch (e) {
|
||||
if (extension.stylesheet) {
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
}
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
}
|
||||
|
||||
enableExtension(uuid) {
|
||||
if (!this._extensions.has(uuid))
|
||||
return false;
|
||||
|
||||
let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||
let disabledExtensions = global.settings.get_strv(DISABLED_EXTENSIONS_KEY);
|
||||
|
||||
if (disabledExtensions.includes(uuid)) {
|
||||
disabledExtensions = disabledExtensions.filter(item => item !== uuid);
|
||||
global.settings.set_strv(DISABLED_EXTENSIONS_KEY, disabledExtensions);
|
||||
}
|
||||
|
||||
if (!enabledExtensions.includes(uuid)) {
|
||||
enabledExtensions.push(uuid);
|
||||
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
disableExtension(uuid) {
|
||||
if (!this._extensions.has(uuid))
|
||||
return false;
|
||||
|
||||
let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||
let disabledExtensions = global.settings.get_strv(DISABLED_EXTENSIONS_KEY);
|
||||
|
||||
if (enabledExtensions.includes(uuid)) {
|
||||
enabledExtensions = enabledExtensions.filter(item => item !== uuid);
|
||||
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||
}
|
||||
|
||||
if (!disabledExtensions.includes(uuid)) {
|
||||
disabledExtensions.push(uuid);
|
||||
global.settings.set_strv(DISABLED_EXTENSIONS_KEY, disabledExtensions);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
logExtensionError(uuid, error) {
|
||||
let extension = this.lookup(uuid);
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
let message = `${error}`;
|
||||
|
||||
extension.error = message;
|
||||
extension.state = ExtensionState.ERROR;
|
||||
if (!extension.errors)
|
||||
extension.errors = [];
|
||||
extension.errors.push(message);
|
||||
|
||||
logError(error, `Extension ${uuid}`);
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
createExtensionObject(uuid, dir, type) {
|
||||
let metadataFile = dir.get_child('metadata.json');
|
||||
if (!metadataFile.query_exists(null)) {
|
||||
throw new Error('Missing metadata.json');
|
||||
}
|
||||
|
||||
let metadataContents, success_;
|
||||
try {
|
||||
[success_, metadataContents] = metadataFile.load_contents(null);
|
||||
if (metadataContents instanceof Uint8Array)
|
||||
metadataContents = imports.byteArray.toString(metadataContents);
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to load metadata.json: ${e}`);
|
||||
}
|
||||
let meta;
|
||||
try {
|
||||
meta = JSON.parse(metadataContents);
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to parse metadata.json: ${e}`);
|
||||
}
|
||||
|
||||
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
|
||||
for (let i = 0; i < requiredProperties.length; i++) {
|
||||
let prop = requiredProperties[i];
|
||||
if (!meta[prop]) {
|
||||
throw new Error(`missing "${prop}" property in metadata.json`);
|
||||
}
|
||||
}
|
||||
|
||||
if (uuid != meta.uuid) {
|
||||
throw new Error(`uuid "${meta.uuid}" from metadata.json does not match directory name "${uuid}"`);
|
||||
}
|
||||
|
||||
let extension = {
|
||||
metadata: meta,
|
||||
uuid: meta.uuid,
|
||||
type,
|
||||
dir,
|
||||
path: dir.get_path(),
|
||||
error: '',
|
||||
hasPrefs: dir.get_child('prefs.js').query_exists(null),
|
||||
canChange: false
|
||||
};
|
||||
this._extensions.set(uuid, extension);
|
||||
|
||||
return extension;
|
||||
}
|
||||
|
||||
loadExtension(extension) {
|
||||
// Default to error, we set success as the last step
|
||||
extension.state = ExtensionState.ERROR;
|
||||
|
||||
let checkVersion = !global.settings.get_boolean(EXTENSION_DISABLE_VERSION_CHECK_KEY);
|
||||
|
||||
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
|
||||
extension.state = ExtensionState.OUT_OF_DATE;
|
||||
} else {
|
||||
let enabled = this._enabledExtensions.includes(extension.uuid);
|
||||
if (enabled) {
|
||||
if (!this._callExtensionInit(extension.uuid))
|
||||
return;
|
||||
if (extension.state == ExtensionState.DISABLED)
|
||||
this._callExtensionEnable(extension.uuid);
|
||||
} else {
|
||||
extension.state = ExtensionState.INITIALIZED;
|
||||
}
|
||||
}
|
||||
|
||||
this._updateCanChange(extension);
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
unloadExtension(extension) {
|
||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||
// but it will be removed on next reboot, and hopefully nothing
|
||||
// broke too much.
|
||||
this._callExtensionDisable(extension.uuid);
|
||||
|
||||
extension.state = ExtensionState.UNINSTALLED;
|
||||
this.emit('extension-state-changed', extension);
|
||||
|
||||
this._extensions.delete(extension.uuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
reloadExtension(oldExtension) {
|
||||
// Grab the things we'll need to pass to createExtensionObject
|
||||
// to reload it.
|
||||
let { uuid, dir, type } = oldExtension;
|
||||
|
||||
// Then unload the old extension.
|
||||
this.unloadExtension(oldExtension);
|
||||
|
||||
// Now, recreate the extension and load it.
|
||||
let newExtension;
|
||||
try {
|
||||
newExtension = this.createExtensionObject(uuid, dir, type);
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadExtension(newExtension);
|
||||
}
|
||||
|
||||
_callExtensionInit(uuid) {
|
||||
if (!Main.sessionMode.allowExtensions)
|
||||
return false;
|
||||
|
||||
let extension = this.lookup(uuid);
|
||||
if (!extension)
|
||||
throw new Error("Extension was not properly created. Call createExtensionObject first");
|
||||
|
||||
let dir = extension.dir;
|
||||
let extensionJs = dir.get_child('extension.js');
|
||||
if (!extensionJs.query_exists(null)) {
|
||||
this.logExtensionError(uuid, new Error('Missing extension.js'));
|
||||
return false;
|
||||
}
|
||||
|
||||
let extensionModule;
|
||||
let extensionState = null;
|
||||
|
||||
ExtensionUtils.installImporter(extension);
|
||||
try {
|
||||
extensionModule = extension.imports.extension;
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (extensionModule.init) {
|
||||
try {
|
||||
extensionState = extensionModule.init(extension);
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!extensionState)
|
||||
extensionState = extensionModule;
|
||||
extension.stateObj = extensionState;
|
||||
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
this.emit('extension-loaded', uuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!extensionState)
|
||||
extensionState = extensionModule;
|
||||
extension.stateObj = extensionState;
|
||||
_getModeExtensions() {
|
||||
if (Array.isArray(Main.sessionMode.enabledExtensions))
|
||||
return Main.sessionMode.enabledExtensions;
|
||||
return [];
|
||||
}
|
||||
|
||||
extension.state = ExtensionState.DISABLED;
|
||||
_signals.emit('extension-loaded', uuid);
|
||||
return true;
|
||||
}
|
||||
_updateCanChange(extension) {
|
||||
let hasError =
|
||||
extension.state == ExtensionState.ERROR ||
|
||||
extension.state == ExtensionState.OUT_OF_DATE;
|
||||
|
||||
function getEnabledExtensions() {
|
||||
let extensions;
|
||||
if (Array.isArray(Main.sessionMode.enabledExtensions))
|
||||
extensions = Main.sessionMode.enabledExtensions;
|
||||
else
|
||||
extensions = [];
|
||||
let isMode = this._getModeExtensions().includes(extension.uuid);
|
||||
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY);
|
||||
|
||||
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
|
||||
return extensions;
|
||||
let changeKey = isMode
|
||||
? DISABLE_USER_EXTENSIONS_KEY
|
||||
: ENABLED_EXTENSIONS_KEY;
|
||||
|
||||
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
|
||||
}
|
||||
extension.canChange =
|
||||
!hasError &&
|
||||
global.settings.is_writable(changeKey) &&
|
||||
(isMode || !modeOnly);
|
||||
}
|
||||
|
||||
function onEnabledExtensionsChanged() {
|
||||
let newEnabledExtensions = getEnabledExtensions();
|
||||
_getEnabledExtensions() {
|
||||
let extensions = this._getModeExtensions();
|
||||
|
||||
if (!enabled)
|
||||
return;
|
||||
if (!global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
|
||||
extensions = extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
|
||||
|
||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||
// new setting, but not in the old one.
|
||||
newEnabledExtensions.filter(
|
||||
uuid => !enabledExtensions.includes(uuid)
|
||||
).forEach(uuid => {
|
||||
enableExtension(uuid);
|
||||
});
|
||||
// filter out 'disabled-extensions' which takes precedence
|
||||
let disabledExtensions = global.settings.get_strv(DISABLED_EXTENSIONS_KEY);
|
||||
return extensions.filter(item => !disabledExtensions.includes(item));
|
||||
}
|
||||
|
||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||
// old setting, but not in the new one.
|
||||
enabledExtensions.filter(
|
||||
item => !newEnabledExtensions.includes(item)
|
||||
).forEach(uuid => {
|
||||
disableExtension(uuid);
|
||||
});
|
||||
_onUserExtensionsEnabledChanged() {
|
||||
this._onEnabledExtensionsChanged();
|
||||
this._onSettingsWritableChanged();
|
||||
}
|
||||
|
||||
enabledExtensions = newEnabledExtensions;
|
||||
}
|
||||
_onEnabledExtensionsChanged() {
|
||||
let newEnabledExtensions = this._getEnabledExtensions();
|
||||
|
||||
function _onVersionValidationChanged() {
|
||||
// we want to reload all extensions, but only enable
|
||||
// extensions when allowed by the sessionMode, so
|
||||
// temporarily disable them all
|
||||
enabledExtensions = [];
|
||||
for (let uuid in ExtensionUtils.extensions)
|
||||
reloadExtension(ExtensionUtils.extensions[uuid]);
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
enabledExtensions.forEach(uuid => {
|
||||
enableExtension(uuid);
|
||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||
// new setting, but not in the old one.
|
||||
newEnabledExtensions.filter(
|
||||
uuid => !this._enabledExtensions.includes(uuid)
|
||||
).forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function _loadExtensions() {
|
||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||
global.settings.connect('changed::' + DISABLE_USER_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||
global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged);
|
||||
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
finder.connect('extension-found', (finder, extension) => {
|
||||
loadExtension(extension);
|
||||
});
|
||||
finder.scanExtensions();
|
||||
}
|
||||
|
||||
function enableAllExtensions() {
|
||||
if (enabled)
|
||||
return;
|
||||
|
||||
if (!initted) {
|
||||
_loadExtensions();
|
||||
initted = true;
|
||||
} else {
|
||||
enabledExtensions.forEach(uuid => {
|
||||
enableExtension(uuid);
|
||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||
// old setting, but not in the new one.
|
||||
this._extensionOrder.filter(
|
||||
uuid => !newEnabledExtensions.includes(uuid)
|
||||
).reverse().forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
|
||||
this._enabledExtensions = newEnabledExtensions;
|
||||
}
|
||||
enabled = true;
|
||||
}
|
||||
|
||||
function disableAllExtensions() {
|
||||
if (!enabled)
|
||||
return;
|
||||
_onSettingsWritableChanged() {
|
||||
for (let extension of this._extensions.values()) {
|
||||
this._updateCanChange(extension);
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
}
|
||||
|
||||
if (initted) {
|
||||
_onVersionValidationChanged() {
|
||||
// Disabling extensions modifies the order array, so use a copy
|
||||
let extensionOrder = this._extensionOrder.slice();
|
||||
|
||||
// Disable enabled extensions in the reverse order first to avoid
|
||||
// the "rebasing" done in _callExtensionDisable...
|
||||
extensionOrder.slice().reverse().forEach(uuid => {
|
||||
disableExtension(uuid);
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
|
||||
// ...and then reload and enable extensions in the correct order again.
|
||||
[...this._extensions.values()].sort((a, b) => {
|
||||
return extensionOrder.indexOf(a.uuid) - extensionOrder.indexOf(b.uuid);
|
||||
}).forEach(extension => this.reloadExtension(extension));
|
||||
}
|
||||
|
||||
_loadExtensions() {
|
||||
global.settings.connect(`changed::${ENABLED_EXTENSIONS_KEY}`,
|
||||
this._onEnabledExtensionsChanged.bind(this));
|
||||
global.settings.connect(`changed::${DISABLED_EXTENSIONS_KEY}`,
|
||||
this._onEnabledExtensionsChanged.bind(this));
|
||||
global.settings.connect(`changed::${DISABLE_USER_EXTENSIONS_KEY}`,
|
||||
this._onUserExtensionsEnabledChanged.bind(this));
|
||||
global.settings.connect(`changed::${EXTENSION_DISABLE_VERSION_CHECK_KEY}`,
|
||||
this._onVersionValidationChanged.bind(this));
|
||||
global.settings.connect(`writable-changed::${ENABLED_EXTENSIONS_KEY}`,
|
||||
this._onSettingsWritableChanged.bind(this));
|
||||
global.settings.connect(`writable-changed::${DISABLED_EXTENSIONS_KEY}`,
|
||||
this._onSettingsWritableChanged.bind(this));
|
||||
|
||||
this._enabledExtensions = this._getEnabledExtensions();
|
||||
|
||||
let perUserDir = Gio.File.new_for_path(global.userdatadir);
|
||||
FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
|
||||
let fileType = info.get_file_type();
|
||||
if (fileType != Gio.FileType.DIRECTORY)
|
||||
return;
|
||||
let uuid = info.get_name();
|
||||
let existing = this.lookup(uuid);
|
||||
if (existing) {
|
||||
log(`Extension ${uuid} already installed in ${existing.path}. ${dir.get_path()} will not be loaded`);
|
||||
return;
|
||||
}
|
||||
|
||||
let extension;
|
||||
let type = dir.has_prefix(perUserDir)
|
||||
? ExtensionType.PER_USER
|
||||
: ExtensionType.SYSTEM;
|
||||
try {
|
||||
extension = this.createExtensionObject(uuid, dir, type);
|
||||
} catch (e) {
|
||||
logError(e, `Could not load extension ${uuid}`);
|
||||
return;
|
||||
}
|
||||
this.loadExtension(extension);
|
||||
});
|
||||
}
|
||||
|
||||
enabled = false;
|
||||
}
|
||||
_enableAllExtensions() {
|
||||
if (this._enabled)
|
||||
return;
|
||||
|
||||
function _sessionUpdated() {
|
||||
// For now sessionMode.allowExtensions controls extensions from both the
|
||||
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
|
||||
// property; it might make sense to make enabledExtensions independent
|
||||
// from allowExtensions in the future
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
if (initted)
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
enableAllExtensions();
|
||||
} else {
|
||||
disableAllExtensions();
|
||||
if (!this._initialized) {
|
||||
this._loadExtensions();
|
||||
this._initialized = true;
|
||||
} else {
|
||||
this._enabledExtensions.forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
}
|
||||
this._enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
Main.sessionMode.connect('updated', _sessionUpdated);
|
||||
_sessionUpdated();
|
||||
}
|
||||
_disableAllExtensions() {
|
||||
if (!this._enabled)
|
||||
return;
|
||||
|
||||
if (this._initialized) {
|
||||
this._extensionOrder.slice().reverse().forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
}
|
||||
|
||||
this._enabled = false;
|
||||
}
|
||||
|
||||
_sessionUpdated() {
|
||||
// For now sessionMode.allowExtensions controls extensions from both the
|
||||
// 'enabled-extensions' preference and the sessionMode.enabledExtensions
|
||||
// property; it might make sense to make enabledExtensions independent
|
||||
// from allowExtensions in the future
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
// Take care of added or removed sessionMode extensions
|
||||
this._onEnabledExtensionsChanged();
|
||||
this._enableAllExtensions();
|
||||
} else {
|
||||
this._disableAllExtensions();
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ExtensionManager.prototype);
|
||||
|
||||
@@ -49,15 +49,15 @@ var FocusCaretTracker = class FocusCaretTracker {
|
||||
this._atspiInited = true;
|
||||
}
|
||||
|
||||
return this._atspiInited;
|
||||
return this._atspiInited;
|
||||
}
|
||||
|
||||
registerFocusListener() {
|
||||
if (!this._initAtspi() || this._focusListenerRegistered)
|
||||
return;
|
||||
|
||||
this._atspiListener.register(STATECHANGED + ':focused');
|
||||
this._atspiListener.register(STATECHANGED + ':selected');
|
||||
this._atspiListener.register(`${STATECHANGED}:focused`);
|
||||
this._atspiListener.register(`${STATECHANGED}:selected`);
|
||||
this._focusListenerRegistered = true;
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ var FocusCaretTracker = class FocusCaretTracker {
|
||||
if (!this._focusListenerRegistered)
|
||||
return;
|
||||
|
||||
this._atspiListener.deregister(STATECHANGED + ':focused');
|
||||
this._atspiListener.deregister(STATECHANGED + ':selected');
|
||||
this._atspiListener.deregister(`${STATECHANGED}:focused`);
|
||||
this._atspiListener.deregister(`${STATECHANGED}:selected`);
|
||||
this._focusListenerRegistered = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported GrabHelper */
|
||||
|
||||
const { Clutter, St } = imports.gi;
|
||||
|
||||
@@ -87,7 +88,7 @@ var GrabHelper = class GrabHelper {
|
||||
_isWithinGrabbedActor(actor) {
|
||||
let currentActor = this.currentGrab.actor;
|
||||
while (actor) {
|
||||
if (this._actors.indexOf(actor) != -1)
|
||||
if (this._actors.includes(actor))
|
||||
return true;
|
||||
if (actor == currentActor)
|
||||
return true;
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported CandidatePopup */
|
||||
|
||||
const { Clutter, IBus, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
const { Clutter, GObject, IBus, St } = imports.gi;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
var MAX_CANDIDATES_PER_PAGE = 16;
|
||||
|
||||
var DEFAULT_INDEX_LABELS = [ '1', '2', '3', '4', '5', '6', '7', '8',
|
||||
'9', '0', 'a', 'b', 'c', 'd', 'e', 'f' ];
|
||||
var DEFAULT_INDEX_LABELS = ['1', '2', '3', '4', '5', '6', '7', '8',
|
||||
'9', '0', 'a', 'b', 'c', 'd', 'e', 'f'];
|
||||
|
||||
var CandidateArea = class CandidateArea {
|
||||
constructor() {
|
||||
this.actor = new St.BoxLayout({ vertical: true,
|
||||
reactive: true,
|
||||
visible: false });
|
||||
var CandidateArea = GObject.registerClass({
|
||||
Signals: {
|
||||
'candidate-clicked': { param_types: [GObject.TYPE_UINT,
|
||||
GObject.TYPE_UINT,
|
||||
Clutter.ModifierType.$gtype] },
|
||||
'cursor-down': {},
|
||||
'cursor-up': {},
|
||||
'next-page': {},
|
||||
'previous-page': {},
|
||||
}
|
||||
}, class CandidateArea extends St.BoxLayout {
|
||||
_init() {
|
||||
super._init({
|
||||
vertical: true,
|
||||
reactive: true,
|
||||
visible: false
|
||||
});
|
||||
this._candidateBoxes = [];
|
||||
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
|
||||
let box = new St.BoxLayout({ style_class: 'candidate-box',
|
||||
@@ -26,7 +38,7 @@ var CandidateArea = class CandidateArea {
|
||||
box.add(box._indexLabel, { y_fill: false });
|
||||
box.add(box._candidateLabel, { y_fill: false });
|
||||
this._candidateBoxes.push(box);
|
||||
this.actor.add(box);
|
||||
this.add(box);
|
||||
|
||||
let j = i;
|
||||
box.connect('button-release-event', (actor, event) => {
|
||||
@@ -35,19 +47,6 @@ var CandidateArea = class CandidateArea {
|
||||
});
|
||||
}
|
||||
|
||||
this.actor.connect('scroll-event', (actor, event) => {
|
||||
let direction = event.get_scroll_direction();
|
||||
switch(direction) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
this.emit('cursor-up');
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
this.emit('cursor-down');
|
||||
break;
|
||||
};
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
});
|
||||
|
||||
this._buttonBox = new St.BoxLayout({ style_class: 'candidate-page-button-box' });
|
||||
|
||||
this._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous button' });
|
||||
@@ -58,7 +57,7 @@ var CandidateArea = class CandidateArea {
|
||||
this._nextButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' });
|
||||
this._buttonBox.add(this._nextButton, { expand: true });
|
||||
|
||||
this.actor.add(this._buttonBox);
|
||||
this.add(this._buttonBox);
|
||||
|
||||
this._previousButton.connect('clicked', () => {
|
||||
this.emit('previous-page');
|
||||
@@ -71,6 +70,18 @@ var CandidateArea = class CandidateArea {
|
||||
this._cursorPosition = 0;
|
||||
}
|
||||
|
||||
vfunc_scroll_event(scrollEvent) {
|
||||
switch (scrollEvent.direction) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
this.emit('cursor-up');
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
this.emit('cursor-down');
|
||||
break;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
|
||||
setOrientation(orientation) {
|
||||
if (this._orientation == orientation)
|
||||
return;
|
||||
@@ -78,15 +89,15 @@ var CandidateArea = class CandidateArea {
|
||||
this._orientation = orientation;
|
||||
|
||||
if (this._orientation == IBus.Orientation.HORIZONTAL) {
|
||||
this.actor.vertical = false;
|
||||
this.actor.remove_style_class_name('vertical');
|
||||
this.actor.add_style_class_name('horizontal');
|
||||
this.vertical = false;
|
||||
this.remove_style_class_name('vertical');
|
||||
this.add_style_class_name('horizontal');
|
||||
this._previousButton.child.icon_name = 'go-previous-symbolic';
|
||||
this._nextButton.child.icon_name = 'go-next-symbolic';
|
||||
} else { // VERTICAL || SYSTEM
|
||||
this.actor.vertical = true;
|
||||
this.actor.add_style_class_name('vertical');
|
||||
this.actor.remove_style_class_name('horizontal');
|
||||
this.vertical = true;
|
||||
this.add_style_class_name('vertical');
|
||||
this.remove_style_class_name('horizontal');
|
||||
this._previousButton.child.icon_name = 'go-up-symbolic';
|
||||
this._nextButton.child.icon_name = 'go-down-symbolic';
|
||||
}
|
||||
@@ -120,19 +131,23 @@ var CandidateArea = class CandidateArea {
|
||||
this._previousButton.reactive = wrapsAround || page > 0;
|
||||
this._nextButton.reactive = wrapsAround || page < nPages - 1;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(CandidateArea.prototype);
|
||||
});
|
||||
|
||||
var CandidatePopup = class CandidatePopup {
|
||||
constructor() {
|
||||
this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
|
||||
this._boxPointer.visible = false;
|
||||
this._boxPointer.style_class = 'candidate-popup-boxpointer';
|
||||
Main.layoutManager.addChrome(this._boxPointer);
|
||||
var CandidatePopup = GObject.registerClass(
|
||||
class IbusCandidatePopup extends BoxPointer.BoxPointer {
|
||||
_init() {
|
||||
super._init(St.Side.TOP);
|
||||
this.visible = false;
|
||||
this.style_class = 'candidate-popup-boxpointer';
|
||||
|
||||
this._dummyCursor = new St.Widget({ opacity: 0 });
|
||||
Main.layoutManager.uiGroup.add_actor(this._dummyCursor);
|
||||
|
||||
Main.layoutManager.addChrome(this);
|
||||
|
||||
let box = new St.BoxLayout({ style_class: 'candidate-popup-content',
|
||||
vertical: true });
|
||||
this._boxPointer.bin.set_child(box);
|
||||
this.bin.set_child(box);
|
||||
|
||||
this._preeditText = new St.Label({ style_class: 'candidate-popup-text',
|
||||
visible: false });
|
||||
@@ -143,7 +158,7 @@ var CandidatePopup = class CandidatePopup {
|
||||
box.add(this._auxText);
|
||||
|
||||
this._candidateArea = new CandidateArea();
|
||||
box.add(this._candidateArea.actor);
|
||||
box.add(this._candidateArea);
|
||||
|
||||
this._candidateArea.connect('previous-page', () => {
|
||||
this._panelService.page_up();
|
||||
@@ -181,7 +196,7 @@ var CandidatePopup = class CandidatePopup {
|
||||
let window = global.display.focus_window.get_compositor_private();
|
||||
this._setDummyCursorGeometry(window.x + x, window.y + y, w, h);
|
||||
});
|
||||
} catch(e) {
|
||||
} catch (e) {
|
||||
// Only recent IBus versions have support for this signal
|
||||
// which is used for wayland clients. In order to work
|
||||
// with older IBus versions we can silently ignore the
|
||||
@@ -198,30 +213,30 @@ var CandidatePopup = class CandidatePopup {
|
||||
this._setTextAttributes(this._preeditText.clutter_text,
|
||||
attrs);
|
||||
});
|
||||
panelService.connect('show-preedit-text', ps => {
|
||||
panelService.connect('show-preedit-text', () => {
|
||||
this._preeditText.show();
|
||||
this._updateVisibility();
|
||||
});
|
||||
panelService.connect('hide-preedit-text', ps => {
|
||||
panelService.connect('hide-preedit-text', () => {
|
||||
this._preeditText.hide();
|
||||
this._updateVisibility();
|
||||
});
|
||||
panelService.connect('update-auxiliary-text', (ps, text, visible) => {
|
||||
panelService.connect('update-auxiliary-text', (_ps, text, visible) => {
|
||||
this._auxText.visible = visible;
|
||||
this._updateVisibility();
|
||||
|
||||
this._auxText.text = text.get_text();
|
||||
});
|
||||
panelService.connect('show-auxiliary-text', ps => {
|
||||
panelService.connect('show-auxiliary-text', () => {
|
||||
this._auxText.show();
|
||||
this._updateVisibility();
|
||||
});
|
||||
panelService.connect('hide-auxiliary-text', ps => {
|
||||
panelService.connect('hide-auxiliary-text', () => {
|
||||
this._auxText.hide();
|
||||
this._updateVisibility();
|
||||
});
|
||||
panelService.connect('update-lookup-table', (ps, lookupTable, visible) => {
|
||||
this._candidateArea.actor.visible = visible;
|
||||
panelService.connect('update-lookup-table', (_ps, lookupTable, visible) => {
|
||||
this._candidateArea.visible = visible;
|
||||
this._updateVisibility();
|
||||
|
||||
let nCandidates = lookupTable.get_number_of_candidates();
|
||||
@@ -235,7 +250,7 @@ var CandidatePopup = class CandidatePopup {
|
||||
let indexes = [];
|
||||
let indexLabel;
|
||||
for (let i = 0; (indexLabel = lookupTable.get_label(i)); ++i)
|
||||
indexes.push(indexLabel.get_text());
|
||||
indexes.push(indexLabel.get_text());
|
||||
|
||||
Main.keyboard.resetSuggestions();
|
||||
|
||||
@@ -256,38 +271,40 @@ var CandidatePopup = class CandidatePopup {
|
||||
this._candidateArea.setOrientation(lookupTable.get_orientation());
|
||||
this._candidateArea.updateButtons(lookupTable.is_round(), page, nPages);
|
||||
});
|
||||
panelService.connect('show-lookup-table', ps => {
|
||||
this._candidateArea.actor.show();
|
||||
panelService.connect('show-lookup-table', () => {
|
||||
this._candidateArea.show();
|
||||
this._updateVisibility();
|
||||
});
|
||||
panelService.connect('hide-lookup-table', ps => {
|
||||
this._candidateArea.actor.hide();
|
||||
panelService.connect('hide-lookup-table', () => {
|
||||
this._candidateArea.hide();
|
||||
this._updateVisibility();
|
||||
});
|
||||
panelService.connect('focus-out', ps => {
|
||||
this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
|
||||
panelService.connect('focus-out', () => {
|
||||
this.close(BoxPointer.PopupAnimation.NONE);
|
||||
Main.keyboard.resetSuggestions();
|
||||
});
|
||||
}
|
||||
|
||||
_setDummyCursorGeometry(x, y, w, h) {
|
||||
Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
|
||||
if (this._boxPointer.visible)
|
||||
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
|
||||
this._dummyCursor.set_position(Math.round(x), Math.round(y));
|
||||
this._dummyCursor.set_size(Math.round(w), Math.round(h));
|
||||
|
||||
if (this.visible)
|
||||
this.setPosition(this._dummyCursor, 0);
|
||||
}
|
||||
|
||||
_updateVisibility() {
|
||||
let isVisible = (!Main.keyboard.visible &&
|
||||
(this._preeditText.visible ||
|
||||
this._auxText.visible ||
|
||||
this._candidateArea.actor.visible));
|
||||
this._candidateArea.visible));
|
||||
|
||||
if (isVisible) {
|
||||
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
|
||||
this._boxPointer.open(BoxPointer.PopupAnimation.NONE);
|
||||
this._boxPointer.raise_top();
|
||||
this.setPosition(this._dummyCursor, 0);
|
||||
this.open(BoxPointer.PopupAnimation.NONE);
|
||||
this.raise_top();
|
||||
} else {
|
||||
this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
|
||||
this.close(BoxPointer.PopupAnimation.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,4 +314,4 @@ var CandidatePopup = class CandidatePopup {
|
||||
if (attr.get_attr_type() == IBus.AttrType.BACKGROUND)
|
||||
clutterText.set_selection(attr.get_start_index(), attr.get_end_index());
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported BaseIcon, IconGrid, PaginatedIconGrid */
|
||||
|
||||
const { Clutter, GObject, Meta, St } = imports.gi;
|
||||
const { Clutter, GLib, GObject, Graphene, Meta, St } = imports.gi;
|
||||
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
var ICON_SIZE = 96;
|
||||
var MIN_ICON_SIZE = 16;
|
||||
|
||||
var EXTRA_SPACE_ANIMATION_TIME = 0.25;
|
||||
var EXTRA_SPACE_ANIMATION_TIME = 250;
|
||||
|
||||
var ANIMATION_TIME_IN = 0.350;
|
||||
var ANIMATION_TIME_OUT = 1/2 * ANIMATION_TIME_IN;
|
||||
var ANIMATION_MAX_DELAY_FOR_ITEM = 2/3 * ANIMATION_TIME_IN;
|
||||
var ANIMATION_BASE_DELAY_FOR_ITEM = 1/4 * ANIMATION_MAX_DELAY_FOR_ITEM;
|
||||
var ANIMATION_MAX_DELAY_OUT_FOR_ITEM = 2/3 * ANIMATION_TIME_OUT;
|
||||
var ANIMATION_FADE_IN_TIME_FOR_ITEM = 1/4 * ANIMATION_TIME_IN;
|
||||
var ANIMATION_TIME_IN = 350;
|
||||
var ANIMATION_TIME_OUT = 1 / 2 * ANIMATION_TIME_IN;
|
||||
var ANIMATION_MAX_DELAY_FOR_ITEM = 2 / 3 * ANIMATION_TIME_IN;
|
||||
var ANIMATION_BASE_DELAY_FOR_ITEM = 1 / 4 * ANIMATION_MAX_DELAY_FOR_ITEM;
|
||||
var ANIMATION_MAX_DELAY_OUT_FOR_ITEM = 2 / 3 * ANIMATION_TIME_OUT;
|
||||
var ANIMATION_FADE_IN_TIME_FOR_ITEM = 1 / 4 * ANIMATION_TIME_IN;
|
||||
|
||||
var ANIMATION_BOUNCE_ICON_SCALE = 1.1;
|
||||
|
||||
@@ -26,7 +26,7 @@ var AnimationDirection = {
|
||||
};
|
||||
|
||||
var APPICON_ANIMATION_OUT_SCALE = 3;
|
||||
var APPICON_ANIMATION_OUT_TIME = 0.25;
|
||||
var APPICON_ANIMATION_OUT_TIME = 250;
|
||||
|
||||
var BaseIcon = GObject.registerClass(
|
||||
class BaseIcon extends St.Bin {
|
||||
@@ -56,6 +56,10 @@ class BaseIcon extends St.Bin {
|
||||
|
||||
if (params.showLabel) {
|
||||
this.label = new St.Label({ text: label });
|
||||
this.label.clutter_text.set({
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER
|
||||
});
|
||||
this._box.add_actor(this.label);
|
||||
} else {
|
||||
this.label = null;
|
||||
@@ -71,14 +75,14 @@ class BaseIcon extends St.Bin {
|
||||
this._iconThemeChangedId = cache.connect('icon-theme-changed', this._onIconThemeChanged.bind(this));
|
||||
}
|
||||
|
||||
vfunc_get_preferred_width(forHeight) {
|
||||
vfunc_get_preferred_width(_forHeight) {
|
||||
// Return the actual height to keep the squared aspect
|
||||
return this.get_preferred_height(-1);
|
||||
}
|
||||
|
||||
// This can be overridden by a subclass, or by the createIcon
|
||||
// parameter to _init()
|
||||
createIcon(size) {
|
||||
createIcon(_size) {
|
||||
throw new GObject.NotImplementedError(`createIcon in ${this.constructor.name}`);
|
||||
}
|
||||
|
||||
@@ -137,17 +141,30 @@ class BaseIcon extends St.Bin {
|
||||
// animating.
|
||||
zoomOutActor(this.child);
|
||||
}
|
||||
|
||||
animateZoomOutAtPos(x, y) {
|
||||
zoomOutActorAtPos(this.child, x, y);
|
||||
}
|
||||
|
||||
update() {
|
||||
this._createIconTexture(this.iconSize);
|
||||
}
|
||||
});
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(Math.min(value, max), min);
|
||||
};
|
||||
}
|
||||
|
||||
function zoomOutActor(actor) {
|
||||
let [x, y] = actor.get_transformed_position();
|
||||
zoomOutActorAtPos(actor, x, y);
|
||||
}
|
||||
|
||||
function zoomOutActorAtPos(actor, x, y) {
|
||||
let actorClone = new Clutter.Clone({ source: actor,
|
||||
reactive: false });
|
||||
let [width, height] = actor.get_transformed_size();
|
||||
let [x, y] = actor.get_transformed_position();
|
||||
|
||||
actorClone.set_size(width, height);
|
||||
actorClone.set_position(x, y);
|
||||
actorClone.opacity = 255;
|
||||
@@ -164,23 +181,21 @@ function zoomOutActor(actor) {
|
||||
let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth);
|
||||
let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight);
|
||||
|
||||
Tweener.addTween(actorClone,
|
||||
{ time: APPICON_ANIMATION_OUT_TIME,
|
||||
scale_x: APPICON_ANIMATION_OUT_SCALE,
|
||||
scale_y: APPICON_ANIMATION_OUT_SCALE,
|
||||
translation_x: containedX - scaledX,
|
||||
translation_y: containedY - scaledY,
|
||||
opacity: 0,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete() {
|
||||
actorClone.destroy();
|
||||
}
|
||||
});
|
||||
actorClone.ease({
|
||||
scale_x: APPICON_ANIMATION_OUT_SCALE,
|
||||
scale_y: APPICON_ANIMATION_OUT_SCALE,
|
||||
translation_x: containedX - scaledX,
|
||||
translation_y: containedY - scaledY,
|
||||
opacity: 0,
|
||||
duration: APPICON_ANIMATION_OUT_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => actorClone.destroy()
|
||||
});
|
||||
}
|
||||
|
||||
var IconGrid = GObject.registerClass({
|
||||
Signals: {'animation-done': {},
|
||||
'child-focused': { param_types: [Clutter.Actor.$gtype]} },
|
||||
Signals: { 'animation-done': {},
|
||||
'child-focused': { param_types: [Clutter.Actor.$gtype] } },
|
||||
}, class IconGrid extends St.Widget {
|
||||
_init(params) {
|
||||
super._init({ style_class: 'icon-grid',
|
||||
@@ -206,6 +221,8 @@ var IconGrid = GObject.registerClass({
|
||||
this.rightPadding = 0;
|
||||
this.leftPadding = 0;
|
||||
|
||||
this._updateIconSizesLaterId = 0;
|
||||
|
||||
this._items = [];
|
||||
this._clonesAnimating = [];
|
||||
// Pulled from CSS, but hardcode some defaults here
|
||||
@@ -214,15 +231,23 @@ var IconGrid = GObject.registerClass({
|
||||
this._fixedHItemSize = this._fixedVItemSize = undefined;
|
||||
this.connect('style-changed', this._onStyleChanged.bind(this));
|
||||
|
||||
// Cancel animations when hiding the overview, to avoid icons
|
||||
// swarming into the void ...
|
||||
this.connect('notify::mapped', () => {
|
||||
if (!this.mapped)
|
||||
this._cancelAnimation();
|
||||
});
|
||||
|
||||
this.connect('actor-added', this._childAdded.bind(this));
|
||||
this.connect('actor-removed', this._childRemoved.bind(this));
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
}
|
||||
|
||||
vfunc_unmap() {
|
||||
// Cancel animations when hiding the overview, to avoid icons
|
||||
// swarming into the void ...
|
||||
this._resetAnimationActors();
|
||||
super.vfunc_unmap();
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
if (this._updateIconSizesLaterId) {
|
||||
Meta.later_remove (this._updateIconSizesLaterId);
|
||||
this._updateIconSizesLaterId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_keyFocusIn(actor) {
|
||||
@@ -231,22 +256,35 @@ var IconGrid = GObject.registerClass({
|
||||
|
||||
_childAdded(grid, child) {
|
||||
child._iconGridKeyFocusInId = child.connect('key-focus-in', this._keyFocusIn.bind(this));
|
||||
|
||||
child._paintVisible = child.opacity > 0;
|
||||
child._opacityChangedId = child.connect('notify::opacity', () => {
|
||||
let paintVisible = child._paintVisible;
|
||||
child._paintVisible = child.opacity > 0;
|
||||
if (paintVisible !== child._paintVisible)
|
||||
this.queue_relayout();
|
||||
});
|
||||
}
|
||||
|
||||
_childRemoved(grid, child) {
|
||||
child.disconnect(child._iconGridKeyFocusInId);
|
||||
delete child._iconGridKeyFocusInId;
|
||||
|
||||
child.disconnect(child._opacityChangedId);
|
||||
delete child._opacityChangedId;
|
||||
delete child._paintVisible;
|
||||
}
|
||||
|
||||
vfunc_get_preferred_width(forHeight) {
|
||||
vfunc_get_preferred_width(_forHeight) {
|
||||
if (this._fillParent)
|
||||
// Ignore all size requests of children and request a size of 0;
|
||||
// later we'll allocate as many children as fit the parent
|
||||
return [0, 0];
|
||||
|
||||
let nChildren = this.get_n_children();
|
||||
let nColumns = this._colLimit ? Math.min(this._colLimit,
|
||||
nChildren)
|
||||
: nChildren;
|
||||
let nColumns = this._colLimit
|
||||
? Math.min(this._colLimit, nChildren)
|
||||
: nChildren;
|
||||
let totalSpacing = Math.max(0, nColumns - 1) * this._getSpacing();
|
||||
// Kind of a lie, but not really an issue right now. If
|
||||
// we wanted to support some sort of hidden/overflow that would
|
||||
@@ -276,7 +314,7 @@ var IconGrid = GObject.registerClass({
|
||||
if (forWidth < 0)
|
||||
nColumns = children.length;
|
||||
else
|
||||
[nColumns, ] = this._computeLayout(forWidth);
|
||||
[nColumns] = this._computeLayout(forWidth);
|
||||
|
||||
let nRows;
|
||||
if (nColumns > 0)
|
||||
@@ -311,15 +349,15 @@ var IconGrid = GObject.registerClass({
|
||||
let [nColumns, usedWidth] = this._computeLayout(availWidth);
|
||||
|
||||
let leftEmptySpace;
|
||||
switch(this._xAlign) {
|
||||
case St.Align.START:
|
||||
leftEmptySpace = 0;
|
||||
break;
|
||||
case St.Align.MIDDLE:
|
||||
leftEmptySpace = Math.floor((availWidth - usedWidth) / 2);
|
||||
break;
|
||||
case St.Align.END:
|
||||
leftEmptySpace = availWidth - usedWidth;
|
||||
switch (this._xAlign) {
|
||||
case St.Align.START:
|
||||
leftEmptySpace = 0;
|
||||
break;
|
||||
case St.Align.MIDDLE:
|
||||
leftEmptySpace = Math.floor((availWidth - usedWidth) / 2);
|
||||
break;
|
||||
case St.Align.END:
|
||||
leftEmptySpace = availWidth - usedWidth;
|
||||
}
|
||||
|
||||
let animating = this._clonesAnimating.length > 0;
|
||||
@@ -364,7 +402,7 @@ var IconGrid = GObject.registerClass({
|
||||
let allocationBox = this.get_allocation_box();
|
||||
let paintBox = themeNode.get_paint_box(allocationBox);
|
||||
|
||||
let origin = new Clutter.Vertex();
|
||||
let origin = new Graphene.Point3D();
|
||||
origin.x = paintBox.x1 - allocationBox.x1;
|
||||
origin.y = paintBox.y1 - allocationBox.y1;
|
||||
origin.z = 0.0;
|
||||
@@ -377,15 +415,15 @@ var IconGrid = GObject.registerClass({
|
||||
return true;
|
||||
|
||||
for (let child = this.get_first_child();
|
||||
child != null;
|
||||
child = child.get_next_sibling()) {
|
||||
child != null;
|
||||
child = child.get_next_sibling()) {
|
||||
|
||||
if (!child.visible || !child.opacity)
|
||||
continue;
|
||||
|
||||
let childVolume = child.get_transformed_paint_volume(this);
|
||||
if (!childVolume)
|
||||
return false
|
||||
return false;
|
||||
|
||||
paintVolume.union(childVolume);
|
||||
}
|
||||
@@ -398,21 +436,20 @@ var IconGrid = GObject.registerClass({
|
||||
* set of items to be animated.
|
||||
*/
|
||||
_getChildrenToAnimate() {
|
||||
return this._getVisibleChildren();
|
||||
return this._getVisibleChildren().filter(child => child.opacity > 0);
|
||||
}
|
||||
|
||||
_cancelAnimation() {
|
||||
this._clonesAnimating.forEach(clone => { clone.destroy(); });
|
||||
this._clonesAnimating = [];
|
||||
}
|
||||
|
||||
_animationDone() {
|
||||
_resetAnimationActors() {
|
||||
this._clonesAnimating.forEach(clone => {
|
||||
clone.source.reactive = true;
|
||||
clone.source.opacity = 255;
|
||||
clone.destroy();
|
||||
});
|
||||
this._clonesAnimating = [];
|
||||
}
|
||||
|
||||
_animationDone() {
|
||||
this._resetAnimationActors();
|
||||
this.emit('animation-done');
|
||||
}
|
||||
|
||||
@@ -421,7 +458,7 @@ var IconGrid = GObject.registerClass({
|
||||
throw new GObject.NotImplementedError("Pulse animation only implements " +
|
||||
"'in' animation direction");
|
||||
|
||||
this._cancelAnimation();
|
||||
this._resetAnimationActors();
|
||||
|
||||
let actors = this._getChildrenToAnimate();
|
||||
if (actors.length == 0) {
|
||||
@@ -444,30 +481,32 @@ var IconGrid = GObject.registerClass({
|
||||
let delay = index / actors.length * maxDelay;
|
||||
let bounceUpTime = ANIMATION_TIME_IN / 4;
|
||||
let isLastItem = index == actors.length - 1;
|
||||
Tweener.addTween(actor,
|
||||
{ time: bounceUpTime,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
scale_x: ANIMATION_BOUNCE_ICON_SCALE,
|
||||
scale_y: ANIMATION_BOUNCE_ICON_SCALE,
|
||||
onComplete: () => {
|
||||
Tweener.addTween(actor,
|
||||
{ time: ANIMATION_TIME_IN - bounceUpTime,
|
||||
transition: 'easeInOutQuad',
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
onComplete: () => {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
actor.ease({
|
||||
scale_x: ANIMATION_BOUNCE_ICON_SCALE,
|
||||
scale_y: ANIMATION_BOUNCE_ICON_SCALE,
|
||||
duration: bounceUpTime,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
delay: delay,
|
||||
onComplete: () => {
|
||||
let duration = ANIMATION_TIME_IN - bounceUpTime;
|
||||
actor.ease({
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
duration,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
onComplete: () => {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
actor.reactive = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
animateSpring(animationDirection, sourceActor) {
|
||||
this._cancelAnimation();
|
||||
this._resetAnimationActors();
|
||||
|
||||
let actors = this._getChildrenToAnimate();
|
||||
if (actors.length == 0) {
|
||||
@@ -504,7 +543,7 @@ var IconGrid = GObject.registerClass({
|
||||
this._clonesAnimating.push(actorClone);
|
||||
Main.uiGroup.add_actor(actorClone);
|
||||
|
||||
let [width, height,,] = this._getAllocatedChildSizeAndSpacing(actor);
|
||||
let [width, height] = this._getAllocatedChildSizeAndSpacing(actor);
|
||||
actorClone.set_size(width, height);
|
||||
let scaleX = sourceScaledWidth / width;
|
||||
let scaleY = sourceScaledHeight / height;
|
||||
@@ -521,21 +560,25 @@ var IconGrid = GObject.registerClass({
|
||||
|
||||
let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM;
|
||||
let [finalX, finalY] = actor._transformedPosition;
|
||||
movementParams = { time: ANIMATION_TIME_IN,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
x: finalX,
|
||||
y: finalY,
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
onComplete: () => {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
}};
|
||||
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
opacity: 255 };
|
||||
movementParams = {
|
||||
x: finalX,
|
||||
y: finalY,
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
duration: ANIMATION_TIME_IN,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
delay
|
||||
};
|
||||
|
||||
if (isLastItem)
|
||||
movementParams.onComplete = this._animationDone.bind(this);
|
||||
|
||||
fadeParams = {
|
||||
opacity: 255,
|
||||
duration: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
delay
|
||||
};
|
||||
} else {
|
||||
let isLastItem = actor._distance == maxDist;
|
||||
|
||||
@@ -543,26 +586,29 @@ var IconGrid = GObject.registerClass({
|
||||
actorClone.set_position(startX, startY);
|
||||
|
||||
let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM;
|
||||
movementParams = { time: ANIMATION_TIME_OUT,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
x: adjustedSourcePositionX,
|
||||
y: adjustedSourcePositionY,
|
||||
scale_x: scaleX,
|
||||
scale_y: scaleY,
|
||||
onComplete: () => {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
}};
|
||||
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
opacity: 0 };
|
||||
movementParams = {
|
||||
x: adjustedSourcePositionX,
|
||||
y: adjustedSourcePositionY,
|
||||
scale_x: scaleX,
|
||||
scale_y: scaleY,
|
||||
duration: ANIMATION_TIME_OUT,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
delay
|
||||
};
|
||||
|
||||
if (isLastItem)
|
||||
movementParams.onComplete = this._animationDone.bind(this);
|
||||
|
||||
fadeParams = {
|
||||
opacity: 0,
|
||||
duration: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Tweener.addTween(actorClone, movementParams);
|
||||
Tweener.addTween(actorClone, fadeParams);
|
||||
actorClone.ease(movementParams);
|
||||
actorClone.ease(fadeParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,6 +648,8 @@ var IconGrid = GObject.registerClass({
|
||||
}
|
||||
|
||||
_computeLayout(forWidth) {
|
||||
this.ensure_style();
|
||||
|
||||
let nColumns = 0;
|
||||
let usedWidth = this.leftPadding + this.rightPadding;
|
||||
let spacing = this._getSpacing();
|
||||
@@ -669,13 +717,13 @@ var IconGrid = GObject.registerClass({
|
||||
|
||||
this._items.push(item);
|
||||
if (index !== undefined)
|
||||
this.insert_child_at_index(item.actor, index);
|
||||
this.insert_child_at_index(item, index);
|
||||
else
|
||||
this.add_actor(item.actor);
|
||||
this.add_actor(item);
|
||||
}
|
||||
|
||||
removeItem(item) {
|
||||
this.remove_child(item.actor);
|
||||
this.remove_child(item);
|
||||
}
|
||||
|
||||
getItemAtIndex(index) {
|
||||
@@ -710,8 +758,8 @@ var IconGrid = GObject.registerClass({
|
||||
if (this._padWithSpacing) {
|
||||
// minRows + 1 because we want to put spacing before the first row, so it is like we have one more row
|
||||
// to divide the empty space
|
||||
maxVSpacing = Math.floor(maxEmptyVArea / (this._minRows +1));
|
||||
maxHSpacing = Math.floor(maxEmptyHArea / (this._minColumns +1));
|
||||
maxVSpacing = Math.floor(maxEmptyVArea / (this._minRows + 1));
|
||||
maxHSpacing = Math.floor(maxEmptyHArea / (this._minColumns + 1));
|
||||
} else {
|
||||
if (this._minRows <= 1)
|
||||
maxVSpacing = maxEmptyVArea;
|
||||
@@ -743,36 +791,39 @@ var IconGrid = GObject.registerClass({
|
||||
this._fixedHItemSize = this._hItemSize;
|
||||
this._fixedVItemSize = this._vItemSize;
|
||||
this._updateSpacingForSize(availWidth, availHeight);
|
||||
let spacing = this._getSpacing();
|
||||
|
||||
if (this.columnsForWidth(availWidth) < this._minColumns || this.rowsForHeight(availHeight) < this._minRows) {
|
||||
let neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth ;
|
||||
let neededHeight = this.usedHeightForNRows(this._minRows) - availHeight ;
|
||||
let neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth;
|
||||
let neededHeight = this.usedHeightForNRows(this._minRows) - availHeight;
|
||||
|
||||
let neededSpacePerItem = (neededWidth > neededHeight) ? Math.ceil(neededWidth / this._minColumns)
|
||||
: Math.ceil(neededHeight / this._minRows);
|
||||
let neededSpacePerItem = (neededWidth > neededHeight)
|
||||
? Math.ceil(neededWidth / this._minColumns)
|
||||
: Math.ceil(neededHeight / this._minRows);
|
||||
this._fixedHItemSize = Math.max(this._hItemSize - neededSpacePerItem, MIN_ICON_SIZE);
|
||||
this._fixedVItemSize = Math.max(this._vItemSize - neededSpacePerItem, MIN_ICON_SIZE);
|
||||
|
||||
this._updateSpacingForSize(availWidth, availHeight);
|
||||
}
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
this._updateIconSizes.bind(this));
|
||||
if (!this._updateIconSizesLaterId)
|
||||
this._updateIconSizesLaterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
this._updateIconSizes.bind(this));
|
||||
}
|
||||
|
||||
// Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up
|
||||
_updateIconSizes() {
|
||||
this._updateIconSizesLaterId = 0;
|
||||
let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
|
||||
let newIconSize = Math.floor(ICON_SIZE * scale);
|
||||
for (let i in this._items) {
|
||||
this._items[i].icon.setIconSize(newIconSize);
|
||||
}
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}
|
||||
});
|
||||
|
||||
var PaginatedIconGrid = GObject.registerClass({
|
||||
Signals: {'space-opened': {},
|
||||
'space-closed': {} },
|
||||
Signals: { 'space-opened': {},
|
||||
'space-closed': {} },
|
||||
}, class PaginatedIconGrid extends IconGrid {
|
||||
_init(params) {
|
||||
super._init(params);
|
||||
@@ -783,13 +834,13 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
this._childrenPerPage = 0;
|
||||
}
|
||||
|
||||
vfunc_get_preferred_height(forWidth) {
|
||||
vfunc_get_preferred_height(_forWidth) {
|
||||
let height = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * this._nPages + this._spaceBetweenPages * this._nPages;
|
||||
return [height, height];
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
if (this._childrenPerPage == 0)
|
||||
if (this._childrenPerPage == 0)
|
||||
log('computePages() must be called before allocate(); pagination will not work.');
|
||||
|
||||
this.set_allocation(box, flags);
|
||||
@@ -802,26 +853,24 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
}
|
||||
let children = this._getVisibleChildren();
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
let spacing = this._getSpacing();
|
||||
let [nColumns, usedWidth] = this._computeLayout(availWidth);
|
||||
|
||||
let leftEmptySpace;
|
||||
switch(this._xAlign) {
|
||||
case St.Align.START:
|
||||
leftEmptySpace = 0;
|
||||
break;
|
||||
case St.Align.MIDDLE:
|
||||
leftEmptySpace = Math.floor((availWidth - usedWidth) / 2);
|
||||
break;
|
||||
case St.Align.END:
|
||||
leftEmptySpace = availWidth - usedWidth;
|
||||
switch (this._xAlign) {
|
||||
case St.Align.START:
|
||||
leftEmptySpace = 0;
|
||||
break;
|
||||
case St.Align.MIDDLE:
|
||||
leftEmptySpace = Math.floor((availWidth - usedWidth) / 2);
|
||||
break;
|
||||
case St.Align.END:
|
||||
leftEmptySpace = availWidth - usedWidth;
|
||||
}
|
||||
|
||||
let x = box.x1 + leftEmptySpace + this.leftPadding;
|
||||
let y = box.y1 + this.topPadding;
|
||||
let columnIndex = 0;
|
||||
let rowIndex = 0;
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let childBox = this._calculateChildBox(children[i], x, y, box);
|
||||
@@ -831,21 +880,21 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
columnIndex++;
|
||||
if (columnIndex == nColumns) {
|
||||
columnIndex = 0;
|
||||
rowIndex++;
|
||||
}
|
||||
if (columnIndex == 0) {
|
||||
y += this._getVItemSize() + spacing;
|
||||
if ((i + 1) % this._childrenPerPage == 0)
|
||||
y += this._spaceBetweenPages - spacing + this.bottomPadding + this.topPadding;
|
||||
x = box.x1 + leftEmptySpace + this.leftPadding;
|
||||
} else
|
||||
} else {
|
||||
x += this._getHItemSize() + spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overridden from IconGrid
|
||||
_getChildrenToAnimate() {
|
||||
let children = this._getVisibleChildren();
|
||||
let children = super._getChildrenToAnimate();
|
||||
let firstIndex = this._childrenPerPage * this.currentPage;
|
||||
let lastIndex = firstIndex + this._childrenPerPage;
|
||||
|
||||
@@ -853,7 +902,7 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
}
|
||||
|
||||
_computePages(availWidthPerPage, availHeightPerPage) {
|
||||
let [nColumns, usedWidth] = this._computeLayout(availWidthPerPage);
|
||||
let [nColumns, usedWidth_] = this._computeLayout(availWidthPerPage);
|
||||
let nRows;
|
||||
let children = this._getVisibleChildren();
|
||||
if (nColumns > 0)
|
||||
@@ -863,7 +912,6 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
if (this._rowLimit)
|
||||
nRows = Math.min(nRows, this._rowLimit);
|
||||
|
||||
let spacing = this._getSpacing();
|
||||
// We want to contain the grid inside the parent box with padding
|
||||
this._rowsPerPage = this.rowsForHeight(availHeightPerPage);
|
||||
this._nPages = Math.ceil(nRows / this._rowsPerPage);
|
||||
@@ -892,7 +940,7 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
if (!this._nPages)
|
||||
return 0;
|
||||
|
||||
let firstPageItem = pageNumber * this._childrenPerPage
|
||||
let firstPageItem = pageNumber * this._childrenPerPage;
|
||||
let childBox = this._getVisibleChildren()[firstPageItem].get_allocation_box();
|
||||
return childBox.y1 - this.topPadding;
|
||||
}
|
||||
@@ -915,7 +963,7 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
*/
|
||||
openExtraSpace(sourceItem, side, nRows) {
|
||||
let children = this._getVisibleChildren();
|
||||
let index = children.indexOf(sourceItem.actor);
|
||||
let index = children.indexOf(sourceItem);
|
||||
if (index == -1)
|
||||
throw new Error('Item not found.');
|
||||
|
||||
@@ -925,8 +973,7 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
let childrenPerRow = this._childrenPerPage / this._rowsPerPage;
|
||||
let sourceRow = Math.floor((index - pageOffset) / childrenPerRow);
|
||||
|
||||
let nRowsAbove = (side == St.Side.TOP) ? sourceRow + 1
|
||||
: sourceRow;
|
||||
let nRowsAbove = (side == St.Side.TOP) ? sourceRow + 1 : sourceRow;
|
||||
let nRowsBelow = this._rowsPerPage - nRowsAbove;
|
||||
|
||||
let nRowsUp, nRowsDown;
|
||||
@@ -966,13 +1013,14 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
children[i].translation_y = 0;
|
||||
let params = { translation_y: translationY,
|
||||
time: EXTRA_SPACE_ANIMATION_TIME,
|
||||
transition: 'easeInOutQuad'
|
||||
};
|
||||
let params = {
|
||||
translation_y: translationY,
|
||||
duration: EXTRA_SPACE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD
|
||||
};
|
||||
if (i == (children.length - 1))
|
||||
params.onComplete = () => { this.emit('space-opened'); };
|
||||
Tweener.addTween(children[i], params);
|
||||
params.onComplete = () => this.emit('space-opened');
|
||||
children[i].ease(params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,12 +1033,12 @@ var PaginatedIconGrid = GObject.registerClass({
|
||||
for (let i = 0; i < this._translatedChildren.length; i++) {
|
||||
if (!this._translatedChildren[i].translation_y)
|
||||
continue;
|
||||
Tweener.addTween(this._translatedChildren[i],
|
||||
{ translation_y: 0,
|
||||
time: EXTRA_SPACE_ANIMATION_TIME,
|
||||
transition: 'easeInOutQuad',
|
||||
onComplete: () => { this.emit('space-closed'); }
|
||||
});
|
||||
this._translatedChildren[i].ease({
|
||||
translation_y: 0,
|
||||
duration: EXTRA_SPACE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
|
||||
onComplete: () => this.emit('space-closed')
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported InhibitShortcutsDialog */
|
||||
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell } = imports.gi;
|
||||
|
||||
const Dialog = imports.ui.dialog;
|
||||
@@ -75,8 +76,9 @@ var InhibitShortcutsDialog = GObject.registerClass({
|
||||
let name = this._app ? this._app.get_name() : this._window.title;
|
||||
|
||||
/* Translators: %s is an application name like "Settings" */
|
||||
let title = name ? _("%s wants to inhibit shortcuts").format(name)
|
||||
: _("Application wants to inhibit shortcuts");
|
||||
let title = name
|
||||
? _("%s wants to inhibit shortcuts").format(name)
|
||||
: _("Application wants to inhibit shortcuts");
|
||||
let icon = new Gio.ThemedIcon({ name: 'dialog-warning-symbolic' });
|
||||
|
||||
let contentParams = { icon, title };
|
||||
@@ -111,7 +113,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
|
||||
}
|
||||
|
||||
vfunc_show() {
|
||||
if (this._app && APP_WHITELIST.indexOf(this._app.get_id()) != -1) {
|
||||
if (this._app && APP_WHITELIST.includes(this._app.get_id())) {
|
||||
this._emitResponse(DialogResponse.ALLOW);
|
||||
return;
|
||||
}
|
||||
@@ -139,7 +141,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
|
||||
return;
|
||||
}
|
||||
|
||||
let [permissions, data] = res;
|
||||
let [permissions] = res;
|
||||
if (permissions[appId] === undefined) // Not found
|
||||
this._dialog.open();
|
||||
else if (permissions[appId] == GRANTED)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
/* exported KbdA11yDialog */
|
||||
const { Clutter, Gio, GObject } = imports.gi;
|
||||
|
||||
const Dialog = imports.ui.dialog;
|
||||
@@ -26,24 +27,24 @@ class KbdA11yDialog extends GObject.Object {
|
||||
|
||||
if (whatChanged & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) {
|
||||
key = KEY_SLOW_KEYS_ENABLED;
|
||||
enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) ? true : false;
|
||||
title = enabled ?
|
||||
_("Slow Keys Turned On") :
|
||||
_("Slow Keys Turned Off");
|
||||
enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) > 0;
|
||||
title = enabled
|
||||
? _("Slow Keys Turned On")
|
||||
: _("Slow Keys Turned Off");
|
||||
body = _("You just held down the Shift key for 8 seconds. This is the shortcut " +
|
||||
"for the Slow Keys feature, which affects the way your keyboard works.");
|
||||
|
||||
} else if (whatChanged & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) {
|
||||
key = KEY_STICKY_KEYS_ENABLED;
|
||||
enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) ? true : false;
|
||||
title = enabled ?
|
||||
_("Sticky Keys Turned On") :
|
||||
_("Sticky Keys Turned Off");
|
||||
body = enabled ?
|
||||
_("You just pressed the Shift key 5 times in a row. This is the shortcut " +
|
||||
"for the Sticky Keys feature, which affects the way your keyboard works.") :
|
||||
_("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " +
|
||||
"This turns off the Sticky Keys feature, which affects the way your keyboard works.");
|
||||
enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) > 0;
|
||||
title = enabled
|
||||
? _("Sticky Keys Turned On")
|
||||
: _("Sticky Keys Turned Off");
|
||||
body = enabled
|
||||
? _("You just pressed the Shift key 5 times in a row. This is the shortcut " +
|
||||
"for the Sticky Keys feature, which affects the way your keyboard works.")
|
||||
: _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " +
|
||||
"This turns off the Sticky Keys feature, which affects the way your keyboard works.");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user