Compare commits
679 Commits
3.5.90
...
3.7.2.1-br
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b45b241ce8 | ||
|
|
4233ca2983 | ||
|
|
5200da6eec | ||
|
|
b0523860d9 | ||
|
|
1a1215527f | ||
|
|
360c018c9e | ||
|
|
7bed964ab2 | ||
|
|
989d0a5682 | ||
|
|
b121c25184 | ||
|
|
e0d127b3e4 | ||
|
|
a0c56c74e1 | ||
|
|
f4b61a7f24 | ||
|
|
b2400fb883 | ||
|
|
f25832d1b6 | ||
|
|
cf363171aa | ||
|
|
38c8569d16 | ||
|
|
9791d15f39 | ||
|
|
80e7f5832b | ||
|
|
6e46ddaad3 | ||
|
|
8499e4aab2 | ||
|
|
5eae1851a1 | ||
|
|
c48a246ccb | ||
|
|
f084011a61 | ||
|
|
bd40cf194c | ||
|
|
2434af7e8a | ||
|
|
ced7fa9f01 | ||
|
|
28b559e812 | ||
|
|
76d776245b | ||
|
|
0d9f70492e | ||
|
|
b58f502dd6 | ||
|
|
5f367248c5 | ||
|
|
c2065cc3e2 | ||
|
|
034408971d | ||
|
|
490206b5b2 | ||
|
|
d8540819af | ||
|
|
d1a9aec526 | ||
|
|
e4b681a5a5 | ||
|
|
52036871d1 | ||
|
|
4fc6a804f5 | ||
|
|
08d2ca300a | ||
|
|
dc2ec0a8f9 | ||
|
|
2cfed952bb | ||
|
|
a7da137778 | ||
|
|
5ae2f87ce9 | ||
|
|
c4f6619fbd | ||
|
|
65edbc1424 | ||
|
|
1f2d7fa28f | ||
|
|
2407a0c4e2 | ||
|
|
7f8bfcc939 | ||
|
|
fae4cb9e56 | ||
|
|
063bbb02f2 | ||
|
|
15e1470c50 | ||
|
|
f602993aa9 | ||
|
|
271508c0a8 | ||
|
|
50f96d1c9c | ||
|
|
809544800b | ||
|
|
e757b06987 | ||
|
|
6f2da1baf1 | ||
|
|
f30dcad8a7 | ||
|
|
7dc235511e | ||
|
|
644c210fe2 | ||
|
|
68e8f98671 | ||
|
|
1228db6ac1 | ||
|
|
86596749fa | ||
|
|
76229a3601 | ||
|
|
95abdeb919 | ||
|
|
df0151d338 | ||
|
|
ee2f12fe81 | ||
|
|
10c104529f | ||
|
|
cbc8ec6508 | ||
|
|
8e7758e280 | ||
|
|
9aefbd189c | ||
|
|
b9d50584d8 | ||
|
|
e5f7390c09 | ||
|
|
797b1ff8bb | ||
|
|
09b738045c | ||
|
|
4fd690333a | ||
|
|
5ef5e25a7f | ||
|
|
87e8770cbc | ||
|
|
cac9d120be | ||
|
|
1ae0fadbf4 | ||
|
|
65497e089a | ||
|
|
2d763bd033 | ||
|
|
4ebf396cf5 | ||
|
|
6faa50d496 | ||
|
|
6fcd6298c8 | ||
|
|
5c16be5dbb | ||
|
|
e3abb6f178 | ||
|
|
70736be4eb | ||
|
|
1c3e7330f3 | ||
|
|
6e4c89b310 | ||
|
|
73b4a0ef5f | ||
|
|
d88002c4ed | ||
|
|
025c63c045 | ||
|
|
b189cbd46e | ||
|
|
a21ddb5914 | ||
|
|
e04a4c3923 | ||
|
|
ae0821e07b | ||
|
|
a508bece36 | ||
|
|
2c9969a8f4 | ||
|
|
dd9fc91f6f | ||
|
|
39d9838cc1 | ||
|
|
1397c7c624 | ||
|
|
c09fcba94f | ||
|
|
c77b38fc4f | ||
|
|
aef9b733e5 | ||
|
|
348208617b | ||
|
|
2c34c8e20f | ||
|
|
d19fa731d6 | ||
|
|
59bb1cc387 | ||
|
|
56909d0646 | ||
|
|
04da29c939 | ||
|
|
307f7a3024 | ||
|
|
e80bfa39f5 | ||
|
|
29714922ea | ||
|
|
88192114ac | ||
|
|
9d78208b76 | ||
|
|
d817bf0395 | ||
|
|
4d51056226 | ||
|
|
a607174a25 | ||
|
|
37d6a624b7 | ||
|
|
0c807bddaf | ||
|
|
a0470bfc66 | ||
|
|
b9463d23e8 | ||
|
|
04debd1623 | ||
|
|
9d31576cf5 | ||
|
|
8daca28a90 | ||
|
|
9899604261 | ||
|
|
687e1eabed | ||
|
|
eb09f34114 | ||
|
|
fbeb446ed7 | ||
|
|
92033ce0f5 | ||
|
|
9171bab5e5 | ||
|
|
f9819eb7b0 | ||
|
|
85728f0d15 | ||
|
|
9396849d56 | ||
|
|
6f5e5672bb | ||
|
|
b936e60876 | ||
|
|
fa4bd91213 | ||
|
|
81eeef7d3c | ||
|
|
a7b5134820 | ||
|
|
92a01c67ba | ||
|
|
71c23613b5 | ||
|
|
4f876995de | ||
|
|
9cf4a76196 | ||
|
|
9efe5287e4 | ||
|
|
8c4b34de4e | ||
|
|
93e3559dc3 | ||
|
|
caa0f63e1f | ||
|
|
a4e29e1244 | ||
|
|
599f2f43e3 | ||
|
|
3a453c5f73 | ||
|
|
98b313c75f | ||
|
|
8b796d80a7 | ||
|
|
719a8908a6 | ||
|
|
fed007ecae | ||
|
|
990443465f | ||
|
|
1f183b8a4e | ||
|
|
96556eb959 | ||
|
|
3ffeeac577 | ||
|
|
d7929a2340 | ||
|
|
667019a8c1 | ||
|
|
d9b46b4782 | ||
|
|
e249218a9d | ||
|
|
a2b1946b01 | ||
|
|
96a80f7ba0 | ||
|
|
9955fbf4f8 | ||
|
|
14966b0cd0 | ||
|
|
6e1a8f16a8 | ||
|
|
d106191e6a | ||
|
|
418cf6281e | ||
|
|
bdeb7d86b6 | ||
|
|
a0e0cc1038 | ||
|
|
78f6dec73b | ||
|
|
f6458f215f | ||
|
|
c7e0d547c4 | ||
|
|
fa54cfa0c3 | ||
|
|
31ea3f737c | ||
|
|
2a8a8065a8 | ||
|
|
d3ba002313 | ||
|
|
f18fd8d959 | ||
|
|
d54f7b13fb | ||
|
|
9c8b75206c | ||
|
|
15273c7f22 | ||
|
|
0ea8217c55 | ||
|
|
1735f28f5a | ||
|
|
8de4070f7f | ||
|
|
45e64f453f | ||
|
|
62dc5f2ac6 | ||
|
|
86c85a752e | ||
|
|
3de0ebf7fd | ||
|
|
1496ba0bbd | ||
|
|
f5974f6793 | ||
|
|
928ea3bb01 | ||
|
|
b7acb1d488 | ||
|
|
360d94dd67 | ||
|
|
671a813135 | ||
|
|
c005417f9b | ||
|
|
b5ec68bda3 | ||
|
|
b4ed29094d | ||
|
|
284ab031b8 | ||
|
|
6ad5064c09 | ||
|
|
3a8e723a36 | ||
|
|
dd3484b93f | ||
|
|
205773b700 | ||
|
|
f2039070e6 | ||
|
|
cf58a7eafd | ||
|
|
487749c25b | ||
|
|
48fb16b570 | ||
|
|
f94369dd6e | ||
|
|
fc0bd3b9e8 | ||
|
|
19946f1d19 | ||
|
|
562f56130a | ||
|
|
99f97adfc6 | ||
|
|
5ad7db722d | ||
|
|
a7d344d287 | ||
|
|
0ac215f9de | ||
|
|
4342155748 | ||
|
|
b561694bf0 | ||
|
|
cae9a8d608 | ||
|
|
88fbdba018 | ||
|
|
046067565a | ||
|
|
11299d9913 | ||
|
|
42ab233b08 | ||
|
|
4a92d7d1b2 | ||
|
|
2502ca6ccc | ||
|
|
651030ba93 | ||
|
|
8dfea9566e | ||
|
|
8cc54ce2a2 | ||
|
|
3abfcda8b5 | ||
|
|
cf0ae8f182 | ||
|
|
d90bf5c6dc | ||
|
|
955b550e95 | ||
|
|
b3cd46a5c8 | ||
|
|
3fdc8bfa3d | ||
|
|
e8f96a6e16 | ||
|
|
dc15df1aa7 | ||
|
|
05f5fac35b | ||
|
|
5bfcc5392d | ||
|
|
d2e830cce3 | ||
|
|
1e942be639 | ||
|
|
576009bad0 | ||
|
|
f71108a214 | ||
|
|
7109bd52f2 | ||
|
|
0f6effa263 | ||
|
|
8b0301ed00 | ||
|
|
4f56fb125e | ||
|
|
6487cd8c6f | ||
|
|
06e5c25383 | ||
|
|
36e5ae4a25 | ||
|
|
245e43ea8c | ||
|
|
52871c781a | ||
|
|
f994ada576 | ||
|
|
147a6e49dc | ||
|
|
be24ee435c | ||
|
|
9fac285b69 | ||
|
|
3ed5f9cd15 | ||
|
|
17e70ff8ec | ||
|
|
6dab119650 | ||
|
|
f80eb89d57 | ||
|
|
f6c2902fe4 | ||
|
|
1e890a8a0a | ||
|
|
aa1a84e677 | ||
|
|
9395f310d6 | ||
|
|
b99bb3d4bb | ||
|
|
4f66f096ff | ||
|
|
7f5f2284f3 | ||
|
|
59f9f4fca1 | ||
|
|
55284e418c | ||
|
|
20d4ffde6e | ||
|
|
78e5d4df9d | ||
|
|
1118ec9653 | ||
|
|
7d6c85be42 | ||
|
|
0192a6cb12 | ||
|
|
0e01a81219 | ||
|
|
36edf20273 | ||
|
|
a1bf19dbdf | ||
|
|
0ad739e78b | ||
|
|
ff9509b901 | ||
|
|
7e496b1979 | ||
|
|
448517032e | ||
|
|
a171e92e6c | ||
|
|
06e9bf9b0a | ||
|
|
7d9ec8cea0 | ||
|
|
5b4553ff0c | ||
|
|
d4ce7aef59 | ||
|
|
8b6df2e23f | ||
|
|
e2ff5846df | ||
|
|
24efeff788 | ||
|
|
4f359e62df | ||
|
|
e6fd2bed4d | ||
|
|
9fb6510135 | ||
|
|
7206b61838 | ||
|
|
e8ab0b3e8f | ||
|
|
843788580e | ||
|
|
4ceb3d890d | ||
|
|
3f8995b25e | ||
|
|
37e0cefc79 | ||
|
|
f026741dbb | ||
|
|
044b121e01 | ||
|
|
d57c3b4f89 | ||
|
|
960f7d5f2e | ||
|
|
2f61381651 | ||
|
|
ba6e931e21 | ||
|
|
440aa0d369 | ||
|
|
f42d4b5fa2 | ||
|
|
5d9fa2c484 | ||
|
|
f5c86fa171 | ||
|
|
f9019ce62d | ||
|
|
ee485e1728 | ||
|
|
8f2a6f8387 | ||
|
|
908bf3b117 | ||
|
|
6a739afd25 | ||
|
|
506490e32d | ||
|
|
846771f2a1 | ||
|
|
759b7584e0 | ||
|
|
e5cb224598 | ||
|
|
e32df1b405 | ||
|
|
db9f91b687 | ||
|
|
0941357068 | ||
|
|
d8993c52d0 | ||
|
|
6424b2dd03 | ||
|
|
2a4eb3ed1a | ||
|
|
c9fa00cce1 | ||
|
|
18eedbc02d | ||
|
|
ef9f63fe59 | ||
|
|
f8ce788425 | ||
|
|
6c1bd95643 | ||
|
|
2ed7ee8f71 | ||
|
|
2e63709450 | ||
|
|
6611d639a8 | ||
|
|
fe124e6ab3 | ||
|
|
fee0a8527d | ||
|
|
2f6b00403f | ||
|
|
dbe2c117e3 | ||
|
|
c4b1ccb6d6 | ||
|
|
2c70ee7e43 | ||
|
|
f7826616b8 | ||
|
|
9f476a12dd | ||
|
|
6f3cf0ae50 | ||
|
|
cd024e21f0 | ||
|
|
c4c470c1f3 | ||
|
|
dc9ad8df80 | ||
|
|
74d6225993 | ||
|
|
e1e0c5035d | ||
|
|
adf6d0eb82 | ||
|
|
90df435345 | ||
|
|
83d57211db | ||
|
|
0a8eeb2827 | ||
|
|
0c324c42f4 | ||
|
|
3adf54a952 | ||
|
|
8076c66a4c | ||
|
|
f9c583a636 | ||
|
|
30d536b19c | ||
|
|
1957899146 | ||
|
|
b52c83d88a | ||
|
|
27ff388413 | ||
|
|
d4306f7768 | ||
|
|
5d0a57c97d | ||
|
|
a87ba467ae | ||
|
|
7df7cd01eb | ||
|
|
098d805a8b | ||
|
|
4a21034a00 | ||
|
|
7904e359f2 | ||
|
|
0c8a94beb8 | ||
|
|
c13a573792 | ||
|
|
f9b42e12ae | ||
|
|
5c2031b768 | ||
|
|
49643882d4 | ||
|
|
175ddaa3a1 | ||
|
|
cc1d6e97b8 | ||
|
|
79b96ab301 | ||
|
|
44d9316023 | ||
|
|
5b0c9a74fb | ||
|
|
3429fc3e4c | ||
|
|
d11d8d5353 | ||
|
|
1742bd6ded | ||
|
|
9f6e118ea0 | ||
|
|
717bbd3bb5 | ||
|
|
e8ebe4de14 | ||
|
|
0ff614ccd4 | ||
|
|
d0a77b7e0c | ||
|
|
2815889090 | ||
|
|
1317956663 | ||
|
|
a2303d8895 | ||
|
|
2161c793dc | ||
|
|
a2f943db8f | ||
|
|
23a31b9c00 | ||
|
|
2591d1b94b | ||
|
|
300f97f102 | ||
|
|
7e3f6c3066 | ||
|
|
601d232064 | ||
|
|
8854ac84ad | ||
|
|
0302c3fbd4 | ||
|
|
6b6fdc6cfe | ||
|
|
7126ce86ec | ||
|
|
760bf52f75 | ||
|
|
6d791d31de | ||
|
|
21adc98d70 | ||
|
|
6fd7a56568 | ||
|
|
fba427fcaf | ||
|
|
7753361ffb | ||
|
|
c1590d9ed7 | ||
|
|
23c1138a58 | ||
|
|
2acb097662 | ||
|
|
449d116af2 | ||
|
|
110240981d | ||
|
|
ac5c6de929 | ||
|
|
51bdc44352 | ||
|
|
bafe34696d | ||
|
|
114f6f577f | ||
|
|
1f30670c1d | ||
|
|
10884ef7f5 | ||
|
|
5e12e5f42a | ||
|
|
e7a2e1f268 | ||
|
|
cc6744055f | ||
|
|
e6ba7c6e40 | ||
|
|
ea4855e908 | ||
|
|
5c7da4b0e6 | ||
|
|
9659d934ac | ||
|
|
de93677271 | ||
|
|
6ef3c628e6 | ||
|
|
f2af0be9ac | ||
|
|
ef7b74a104 | ||
|
|
906368d916 | ||
|
|
809cbf58c6 | ||
|
|
a5d60050a2 | ||
|
|
2c130c8668 | ||
|
|
c0ff02d9c7 | ||
|
|
cb627db392 | ||
|
|
33bd6bc75b | ||
|
|
ea5bf109cb | ||
|
|
b150a2842e | ||
|
|
2a46c39019 | ||
|
|
5ca5f026c5 | ||
|
|
15f22add79 | ||
|
|
131fa6a359 | ||
|
|
2d184e1842 | ||
|
|
95a55a2c1c | ||
|
|
8eecbb5c17 | ||
|
|
abfdcaa1b5 | ||
|
|
8ee74e5661 | ||
|
|
ff31ccdd30 | ||
|
|
f6645a41d2 | ||
|
|
daceb8105f | ||
|
|
4beba796d7 | ||
|
|
70c34baafb | ||
|
|
e71c016477 | ||
|
|
633bbd8a9e | ||
|
|
4c82df56e9 | ||
|
|
0d62ec5b03 | ||
|
|
38f943ef81 | ||
|
|
e421953fcd | ||
|
|
f39098a4f2 | ||
|
|
b203a95a78 | ||
|
|
2bb1a6792a | ||
|
|
e30d45a2b0 | ||
|
|
afcd90ae27 | ||
|
|
94c1d5a18c | ||
|
|
4254fa3d38 | ||
|
|
3b293e91e3 | ||
|
|
3d6320295e | ||
|
|
7654f1ca3e | ||
|
|
e62c66b153 | ||
|
|
638507caff | ||
|
|
107f5de58e | ||
|
|
b1451523ca | ||
|
|
f7a95b5edc | ||
|
|
be290fafe7 | ||
|
|
b7ae74edb9 | ||
|
|
b3041ae9fc | ||
|
|
7499b04638 | ||
|
|
bf2d2071fc | ||
|
|
488820daec | ||
|
|
77c15b76b5 | ||
|
|
e71129aa68 | ||
|
|
6f5b700833 | ||
|
|
9627864ca8 | ||
|
|
2a8625ffae | ||
|
|
ed82c3763c | ||
|
|
22266899dc | ||
|
|
9dfd1bfa41 | ||
|
|
409af28cb7 | ||
|
|
4fe604bfe8 | ||
|
|
49df72ceda | ||
|
|
2db029bcdb | ||
|
|
7fd128eabc | ||
|
|
5e3d8dd3eb | ||
|
|
785be2f327 | ||
|
|
8cf9baa132 | ||
|
|
09e3aed770 | ||
|
|
452ac297ab | ||
|
|
7ebb5c6a10 | ||
|
|
00e0d24a6a | ||
|
|
8a269041fb | ||
|
|
9f48adcff9 | ||
|
|
48e7d732b9 | ||
|
|
30048b74d1 | ||
|
|
c866b0dbfd | ||
|
|
1c79f18b13 | ||
|
|
6d704be88b | ||
|
|
5af389c087 | ||
|
|
475dde4193 | ||
|
|
8c534163e1 | ||
|
|
657887b241 | ||
|
|
10da35cbef | ||
|
|
00f15c1075 | ||
|
|
19f92df8ab | ||
|
|
8639cf8060 | ||
|
|
2501d29e9d | ||
|
|
8109dd684e | ||
|
|
5a259dd6b0 | ||
|
|
2ed28211ed | ||
|
|
9d0eaa216f | ||
|
|
58477282fe | ||
|
|
6b016c2528 | ||
|
|
b98c5f94ee | ||
|
|
ad8bdb929a | ||
|
|
5030d59fcc | ||
|
|
ec52928736 | ||
|
|
7f479e18e6 | ||
|
|
7999e9020d | ||
|
|
43ba93a817 | ||
|
|
b37e02c90a | ||
|
|
be5df17a4a | ||
|
|
ffbc1fd190 | ||
|
|
457fb604dd | ||
|
|
09c81f79f6 | ||
|
|
0725a7d836 | ||
|
|
f957ae71c3 | ||
|
|
011c9d1beb | ||
|
|
aed589a98d | ||
|
|
3830e90642 | ||
|
|
3710b88ab9 | ||
|
|
5c990f103e | ||
|
|
2890fc9d7d | ||
|
|
0223507a2e | ||
|
|
59412a9405 | ||
|
|
110d58bbc3 | ||
|
|
eda17defb2 | ||
|
|
f563fb124e | ||
|
|
14d0a96999 | ||
|
|
f0474ffccc | ||
|
|
11ce6845f2 | ||
|
|
70d610b5e4 | ||
|
|
f5ca649977 | ||
|
|
8954d33019 | ||
|
|
2e6205bc05 | ||
|
|
e0dea63079 | ||
|
|
7c244b01c6 | ||
|
|
3f5edf7c3e | ||
|
|
92d8d65543 | ||
|
|
cebd8e14e9 | ||
|
|
16e92a7ca3 | ||
|
|
59e2710137 | ||
|
|
f1ca96bbf0 | ||
|
|
ec01f5d5ee | ||
|
|
2a800e4ce0 | ||
|
|
ca2e09fe8b | ||
|
|
7e343f11f2 | ||
|
|
db20a54861 | ||
|
|
ec4f6b7f91 | ||
|
|
08a69cdcbd | ||
|
|
aa9c095c8e | ||
|
|
b257029d3e | ||
|
|
cb9062f818 | ||
|
|
3a1f623ea3 | ||
|
|
47d46e367e | ||
|
|
e5534e86ab | ||
|
|
e0ca572572 | ||
|
|
ca4b86e7ca | ||
|
|
f177bd0b51 | ||
|
|
11086e8ef8 | ||
|
|
1237aef727 | ||
|
|
79bfea5970 | ||
|
|
50f8ae6fc7 | ||
|
|
73ec86797b | ||
|
|
703417a760 | ||
|
|
3013a87bd2 | ||
|
|
833cb2556b | ||
|
|
8f4f8fccdb | ||
|
|
38e4ab1cea | ||
|
|
366a3e2c35 | ||
|
|
fcb175ebb3 | ||
|
|
a76cc79f88 | ||
|
|
1a6d74fcb2 | ||
|
|
eb351b1882 | ||
|
|
43caace1b6 | ||
|
|
167ed7c35b | ||
|
|
69735940ec | ||
|
|
1a7fad129d | ||
|
|
6931e6cf0f | ||
|
|
87e021cd2e | ||
|
|
d3f5d94afe | ||
|
|
a3d8b5e526 | ||
|
|
5e46abfa03 | ||
|
|
f4740bac65 | ||
|
|
dc10e61a20 | ||
|
|
82c8aad157 | ||
|
|
4ba1f26e4d | ||
|
|
f8805e8311 | ||
|
|
c815979f2a | ||
|
|
54e5ffcac1 | ||
|
|
3fd0502cb9 | ||
|
|
8aed51180f | ||
|
|
e616877fd2 | ||
|
|
df15ee4074 | ||
|
|
4cf3acd0ec | ||
|
|
77ea16e18f | ||
|
|
85d993386a | ||
|
|
14a7da767b | ||
|
|
2f3df71cc1 | ||
|
|
dc13e72b89 | ||
|
|
2beff9896a | ||
|
|
43af6f4792 | ||
|
|
04d1a35cb5 | ||
|
|
f075b36d4f | ||
|
|
c21b1e5fe0 | ||
|
|
042c1fd54b | ||
|
|
ee6086373b | ||
|
|
382310fe51 | ||
|
|
d52cb510fc | ||
|
|
c1de2788b1 | ||
|
|
41dc9e0894 | ||
|
|
d3b0d23d8f | ||
|
|
f96dcaccbe | ||
|
|
2672f205fd | ||
|
|
1ba21ed367 | ||
|
|
79408d359c | ||
|
|
12c76e53cb | ||
|
|
ac44426557 | ||
|
|
684e5bec15 | ||
|
|
70d19530c4 | ||
|
|
e34ab6c5ae | ||
|
|
b3cb9d8459 | ||
|
|
df3fa973ad | ||
|
|
1f4895428d | ||
|
|
417941a1bf | ||
|
|
973a6b21a2 | ||
|
|
b50604d070 | ||
|
|
a1ecf459b3 | ||
|
|
6ea80eadd6 | ||
|
|
9dafaa2c0c | ||
|
|
50e5736c03 | ||
|
|
46fcfb7629 | ||
|
|
8a86540090 | ||
|
|
785ab8192b | ||
|
|
3c386e0c50 | ||
|
|
bec48492ab | ||
|
|
13a10f8afd | ||
|
|
00fe97a55a | ||
|
|
9e665e4903 | ||
|
|
efc128e681 | ||
|
|
6851c5443a | ||
|
|
baf08dd688 | ||
|
|
67115b3e9b | ||
|
|
4ca2697271 | ||
|
|
4696bfbb80 | ||
|
|
18c62a1987 | ||
|
|
d60a4e97d6 | ||
|
|
43883a6945 | ||
|
|
58ff5c6cc6 | ||
|
|
3902e8bff0 | ||
|
|
5d6f37017b | ||
|
|
ecbf2f1429 | ||
|
|
56dc2eb96e | ||
|
|
2154a22c90 | ||
|
|
3fafe0da07 | ||
|
|
983535224e | ||
|
|
88effdd9c3 | ||
|
|
e9a4843eb0 | ||
|
|
c50132b29f | ||
|
|
e92a6b3c6c | ||
|
|
66a36bf591 | ||
|
|
39559f0a09 | ||
|
|
712623946f | ||
|
|
47ce72e011 | ||
|
|
7f8c5c4f64 | ||
|
|
64fdff6ace |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -16,6 +16,7 @@ config.log
|
|||||||
config.status
|
config.status
|
||||||
config
|
config
|
||||||
configure
|
configure
|
||||||
|
data/50-gnome-shell-*.xml
|
||||||
data/gnome-shell.desktop
|
data/gnome-shell.desktop
|
||||||
data/gnome-shell.desktop.in
|
data/gnome-shell.desktop.in
|
||||||
data/gnome-shell-extension-prefs.desktop
|
data/gnome-shell-extension-prefs.desktop
|
||||||
@@ -44,6 +45,7 @@ intltool-merge.in
|
|||||||
intltool-update.in
|
intltool-update.in
|
||||||
libtool
|
libtool
|
||||||
m4/
|
m4/
|
||||||
|
man/gnome-shell.1
|
||||||
omf.make
|
omf.make
|
||||||
po/*.gmo
|
po/*.gmo
|
||||||
po/gnome-shell.pot
|
po/gnome-shell.pot
|
||||||
|
|||||||
331
HACKING
Normal file
331
HACKING
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
Coding guide
|
||||||
|
============
|
||||||
|
|
||||||
|
Our goal is to have all JavaScript code in GNOME follow a consistent style. In
|
||||||
|
a dynamic language like JavaScript, it is essential to be rigorous about style
|
||||||
|
(and unit tests), or you rapidly end up with a spaghetti-code mess.
|
||||||
|
|
||||||
|
A quick note
|
||||||
|
------------
|
||||||
|
|
||||||
|
Life isn't fun if you can't break the rules. If a rule seems unnecessarily
|
||||||
|
restrictive while you're coding, ignore it, and let the patch reviewer decide
|
||||||
|
what to do.
|
||||||
|
|
||||||
|
Indentation and whitespace
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
Use four-space indents. Braces are on the same line as their associated
|
||||||
|
statements. You should only omit braces if *both* sides of the statement are
|
||||||
|
on one line.
|
||||||
|
|
||||||
|
* One space after the `function` keyword. No space between the function name
|
||||||
|
* in a declaration or a call. One space before the parens in the `if`
|
||||||
|
* statements, or `while`, or `for` loops.
|
||||||
|
|
||||||
|
function foo(a, b) {
|
||||||
|
let bar;
|
||||||
|
|
||||||
|
if (a > b)
|
||||||
|
bar = do_thing(a);
|
||||||
|
else
|
||||||
|
bar = do_thing(b);
|
||||||
|
|
||||||
|
if (var == 5) {
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
print(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print(20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Semicolons
|
||||||
|
----------
|
||||||
|
|
||||||
|
JavaScript allows omitting semicolons at the end of lines, but don't. Always
|
||||||
|
end statements with a semicolon.
|
||||||
|
|
||||||
|
js2-mode
|
||||||
|
--------
|
||||||
|
|
||||||
|
If using Emacs, do not use js2-mode. It is outdated and hasn't worked for a
|
||||||
|
while. emacs now has a built-in JavaScript mode, js-mode, based on
|
||||||
|
espresso-mode. It is the de facto emacs mode for JavaScript.
|
||||||
|
|
||||||
|
File naming and creation
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
For JavaScript files, use lowerCamelCase-style names, with a `.js` extension.
|
||||||
|
|
||||||
|
We only use C where gjs/gobject-introspection is not available for the task, or
|
||||||
|
where C would be cleaner. To work around limitations in
|
||||||
|
gjs/gobject-introspection itself, add a new method in `shell-util.[ch]`.
|
||||||
|
|
||||||
|
Like many other GNOME projects, we prefix our C source filenames with the
|
||||||
|
library name followed by a dash, e.g. `shell-app-system.c`. Create a
|
||||||
|
`-private.h` header when you want to share code internally in the
|
||||||
|
library. These headers are not installed, distributed or introspected.
|
||||||
|
|
||||||
|
Imports
|
||||||
|
-------
|
||||||
|
|
||||||
|
Use UpperCamelCase when importing modules to distinguish them from ordinary
|
||||||
|
variables, e.g.
|
||||||
|
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
|
||||||
|
Imports should be categorized into one of two places. The top-most import block
|
||||||
|
should contain only "environment imports". These are either modules from
|
||||||
|
gobject-introspection or modules added by gjs itself.
|
||||||
|
|
||||||
|
The second block of imports should contain only "application imports". These
|
||||||
|
are the JS code that is in the gnome-shell codebase,
|
||||||
|
e.g. `imports.ui.popupMenu`.
|
||||||
|
|
||||||
|
Each import block should be sorted alphabetically. Don't import modules you
|
||||||
|
don't use.
|
||||||
|
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
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
|
||||||
|
location. Never reference `imports` in actual code.
|
||||||
|
|
||||||
|
Constants
|
||||||
|
---------
|
||||||
|
|
||||||
|
We use CONSTANTS_CASE to define constants. All constants should be directly
|
||||||
|
under the imports:
|
||||||
|
|
||||||
|
const MY_DBUS_INTERFACE = 'org.my.Interface';
|
||||||
|
|
||||||
|
Variable declaration
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Always use either `const` or `let` when defining a variable.
|
||||||
|
|
||||||
|
// Iterating over an array
|
||||||
|
for (let i = 0; i < arr.length; ++i) {
|
||||||
|
let item = arr[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterating over an object's properties
|
||||||
|
for (let prop in someobj) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
If you use "var" then the variable is added to function scope, not block scope.
|
||||||
|
See [What's new in JavaScript 1.7](https://developer.mozilla.org/en/JavaScript/New_in_JavaScript/1.7#Block_scope_with_let_%28Merge_into_let_Statement%29)
|
||||||
|
|
||||||
|
Classes
|
||||||
|
-------
|
||||||
|
|
||||||
|
There are many approaches to classes in JavaScript. We use our own class framework
|
||||||
|
(sigh), which is built in gjs. The advantage is that it supports inheriting from
|
||||||
|
GObjects, although this feature isn't used very often in the Shell itself.
|
||||||
|
|
||||||
|
const IconLabelMenuItem = new Lang.Class({
|
||||||
|
Name: 'IconLabelMenuItem',
|
||||||
|
Extends: PopupMenu.PopupMenuBaseItem,
|
||||||
|
|
||||||
|
_init: function(icon, label) {
|
||||||
|
this.parent({ reactive: false });
|
||||||
|
this.addActor(icon);
|
||||||
|
this.addActor(label);
|
||||||
|
},
|
||||||
|
|
||||||
|
open: function() {
|
||||||
|
log("menu opened!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
* 'Name' is required. 'Extends' is optional. If you leave it out, you will
|
||||||
|
automatically inherit from Object.
|
||||||
|
|
||||||
|
* Leave a blank line between the "class header" (Name, Extends, and other
|
||||||
|
things) and the "class body" (methods). Leave a blank line between each
|
||||||
|
method.
|
||||||
|
|
||||||
|
* No space before the colon, one space after.
|
||||||
|
|
||||||
|
* No trailing comma after the last item.
|
||||||
|
|
||||||
|
* Make sure to use a semicolon after the closing paren to the class. It's
|
||||||
|
still a giant function call, even though it may resemble a more
|
||||||
|
conventional syntax.
|
||||||
|
|
||||||
|
GObject Introspection
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
GObject Introspection is a powerful feature that allows us to have native
|
||||||
|
bindings for almost any library built around GObject. If a library requires
|
||||||
|
you to inherit from a type to use it, you can do so:
|
||||||
|
|
||||||
|
const MyClutterActor = new Lang.Class({
|
||||||
|
Name: 'MyClutterActor',
|
||||||
|
Extends: Clutter.Actor,
|
||||||
|
|
||||||
|
vfunc_get_preferred_width: function(actor, forHeight) {
|
||||||
|
return [100, 100];
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_get_preferred_height: function(actor, forWidth) {
|
||||||
|
return [100, 100];
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_paint: function(actor) {
|
||||||
|
let alloc = this.get_allocation_box();
|
||||||
|
Cogl.set_source_color4ub(255, 0, 0, 255);
|
||||||
|
Cogl.rectangle(alloc.x1, alloc.y1,
|
||||||
|
alloc.x2, alloc.y2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Translatable strings, `environment.js`
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
We use gettext to translate the GNOME Shell into all the languages that GNOME
|
||||||
|
supports. The `gettext` function is aliased globally as `_`, you do not need to
|
||||||
|
explicitly import it. This is done through some magic in the
|
||||||
|
[environment.js](http://git.gnome.org/browse/gnome-shell/tree/js/ui/environment.js)
|
||||||
|
file. If you can't find a method that's used, it's probably either in gjs itself
|
||||||
|
or installed on the global object from the Environment.
|
||||||
|
|
||||||
|
Use 'single quotes' for programming strings that should not be translated
|
||||||
|
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`
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
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".
|
||||||
|
|
||||||
|
We sometimes use expando properties to set a property called `_delegate` on
|
||||||
|
the actor itself:
|
||||||
|
|
||||||
|
const MyClass = new Lang.Class({
|
||||||
|
Name: 'MyClass',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.actor = new St.Button({ text: "This is a button" });
|
||||||
|
this.actor._delegate = this;
|
||||||
|
|
||||||
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onClicked: function(actor) {
|
||||||
|
actor.set_label("You clicked the button!");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
The 'delegate' property is important for anything which trying to get the
|
||||||
|
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.
|
||||||
|
|
||||||
|
Functional style
|
||||||
|
----------------
|
||||||
|
|
||||||
|
JavaScript Array objects offer a lot of common functional programming
|
||||||
|
capabilities such as forEach, map, filter and so on. You can use these when
|
||||||
|
they make sense, but please don't have a spaghetti mess of function programming
|
||||||
|
messed in a procedural style. Use your best judgment.
|
||||||
|
|
||||||
|
Closures
|
||||||
|
--------
|
||||||
|
|
||||||
|
`this` will not be captured in a closure, it is relative to how the closure is
|
||||||
|
invoked, not to the value of this where the closure is created, because "this"
|
||||||
|
is a keyword with a value passed in at function invocation time, it is not a
|
||||||
|
variable that can be captured in closures.
|
||||||
|
|
||||||
|
All closures should be wrapped with a Lang.bind.
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
|
||||||
|
let closure = Lang.bind(this, function() { this._fnorbate(); });
|
||||||
|
|
||||||
|
A more realistic example would be connecting to a signal on a method of a
|
||||||
|
prototype:
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const FnorbLib = imports.fborbLib;
|
||||||
|
|
||||||
|
const MyClass = new Lang.Class({
|
||||||
|
_init: function() {
|
||||||
|
let fnorb = new FnorbLib.Fnorb();
|
||||||
|
fnorb.connect('frobate', Lang.bind(this, this._onFnorbFrobate));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onFnorbFrobate: function(fnorb) {
|
||||||
|
this._updateFnorb();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object literal syntax
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
In JavaScript, these are equivalent:
|
||||||
|
|
||||||
|
foo = { 'bar': 42 };
|
||||||
|
foo = { bar: 42 };
|
||||||
|
|
||||||
|
and so are these:
|
||||||
|
|
||||||
|
var b = foo['bar'];
|
||||||
|
var b = foo.bar;
|
||||||
|
|
||||||
|
If your usage of an object is like an object, then you're defining "member
|
||||||
|
variables." For member variables, use the no-quotes no-brackets syntax: `{ bar:
|
||||||
|
42 }` `foo.bar`.
|
||||||
|
|
||||||
|
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
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
const ANIMATION_TIME = 2000;
|
||||||
|
|
||||||
|
const MyClass = new Lang.Class({
|
||||||
|
Name: 'MyClass',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
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' });
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
# Point to our macro directory and pick up user flags from the environment
|
# Point to our macro directory and pick up user flags from the environment
|
||||||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||||
|
|
||||||
SUBDIRS = data js src browser-plugin tests po man docs
|
SUBDIRS = data js src browser-plugin tests po docs
|
||||||
|
|
||||||
|
if ENABLE_MAN
|
||||||
|
SUBDIRS += man
|
||||||
|
endif
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
.project \
|
.project \
|
||||||
@@ -13,6 +17,7 @@ EXTRA_DIST = \
|
|||||||
DIST_EXCLUDE = \
|
DIST_EXCLUDE = \
|
||||||
.gitignore \
|
.gitignore \
|
||||||
gnome-shell.doap \
|
gnome-shell.doap \
|
||||||
|
HACKING \
|
||||||
MAINTAINERS \
|
MAINTAINERS \
|
||||||
tools/build/*
|
tools/build/*
|
||||||
|
|
||||||
@@ -20,4 +25,4 @@ distcheck-hook:
|
|||||||
@echo "Checking disted files against files in git"
|
@echo "Checking disted files against files in git"
|
||||||
@$(srcdir)/tools/check-for-missing.py $(srcdir) $(distdir) $(DIST_EXCLUDE)
|
@$(srcdir)/tools/check-for-missing.py $(srcdir) $(distdir) $(DIST_EXCLUDE)
|
||||||
|
|
||||||
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc
|
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-man
|
||||||
|
|||||||
306
NEWS
306
NEWS
@@ -1,3 +1,309 @@
|
|||||||
|
3.7.2.1
|
||||||
|
=======
|
||||||
|
* Revert 490206b to not depend on NMGTK-0.9.7, which hasn't been released yet
|
||||||
|
|
||||||
|
3.7.2
|
||||||
|
=====
|
||||||
|
* Enforce RTL in he for messages that might end up as LTR [Florian; #686630]
|
||||||
|
* gdm: Move logo into the panel [Florian; #685852]
|
||||||
|
* Hide notifications when closed button is clicked [Jasper, Florian; #682237]
|
||||||
|
* Tweak screenShield animations [Rui; #686745]
|
||||||
|
* Restore Fittsability of summary items in message tray [Florian; #686474]
|
||||||
|
* Save screencasts as recent item [Ray; #680647]
|
||||||
|
* overview: Resize window captions on content change [Giovanni, Alex; #620874]
|
||||||
|
* App search: Match GenericName too [Matthias; #687121]
|
||||||
|
* runDialog: Better match style of other modal dialogs [Florian, Allan; #687127]
|
||||||
|
* Improve the button insensitive style [Stéphane; #687110]
|
||||||
|
* network: Don't use a global switch for all VPN connections [Giovanni; #682929]
|
||||||
|
* appMenu: Update on icon theme changes [Florian; #687224]
|
||||||
|
* Show 'Log out' in more situations [Matthias; #686736]
|
||||||
|
* Add a setting to force the 'Log out' menuitem [Matthias; #686057]
|
||||||
|
* overview: Improve styling of search box [Stéphane; #686479]
|
||||||
|
* Implement 'disable-user-list' in login screen [Ray; #660660]
|
||||||
|
* Fix auto-scroll to bottom in chat notifications [Sjoerd; #686571]
|
||||||
|
* Show feedback notifications when user is busy [Stéphane; #662900]
|
||||||
|
* Disable login button when there is no input [Stéphane; #687112]
|
||||||
|
* Use non-linear overview shade for background [Giovanni, Pierre-Eric; #669798]
|
||||||
|
* Reduce blocking in compositor thread [Simon, Jasper; #687465]
|
||||||
|
* network: new country-specific type to gather providers [Aleksander; #687356]
|
||||||
|
* Update man page [Matthias; #680601]
|
||||||
|
* st-entry: Change the pointer cursor on enter/leave events [Thomas; #687130]
|
||||||
|
* screenShield: Blur and desaturate the background [Giovanni, Cosimo; #682536]
|
||||||
|
* Change height of chat notifications to have more context [Carlos; #665255]
|
||||||
|
* screenShield: Account for motion velocity when hiding [Giovanni; #682537]
|
||||||
|
* screenShield: hide the cursor while the lock screen is on [Giovanni; #682535]
|
||||||
|
* Support remote search provider settings [Cosimo; #687491]
|
||||||
|
* unlockDialog: Improve label of confirmation button [Stéphane; #687656]
|
||||||
|
* userMenu: Rename "System Settings" item to "Settings" [Elad; #687738]
|
||||||
|
* messageTray: Add keybinding to focus current notification [Stéphane; #652082]
|
||||||
|
* Remove shell-screen-grabber [Neil; #685915]
|
||||||
|
* main: Stop using Metacity's keybinding files [Florian; #687672]
|
||||||
|
* Bluetooth: Remove ObexFTP functionality [Bastien; #688160]
|
||||||
|
* a11y: Also set WM theme when HighContrast is switched on [Cosimo; #688256]
|
||||||
|
* network: Rework multiple NIC support [Giovanni; #677142]
|
||||||
|
* Rework keybindings to allow selective blocking/processing [Florian; #688202]
|
||||||
|
* recorder: Show indicator on primary monitor [Adel; #688470]
|
||||||
|
* recorder: Set frame duration to fix broken video headers [Adel; #688487]
|
||||||
|
* Misc. bugfixes and cleanups [Florian, Jasper, Giovanni, Matthew, Stéphane,
|
||||||
|
Allan, Daiki, Owen, Alejandro, Jean-François, Cosimo, Sebastian, Adel, Alban;
|
||||||
|
#686484, #686728, #686805, #686574, #686763, #682428, #687132, #685239,
|
||||||
|
#687189, #687226, #658091, #670687, #687457, #687242, #687287, #687020,
|
||||||
|
#686583, #661194, #687491, #657315, #687958, #683986, #688089, #687708,
|
||||||
|
#686530, #684810, #688181, #688475, #688557, #688507, #638351]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Elad Alfassa, Matthew Barnes, Alban Browaeys, Giovanni Campagna,
|
||||||
|
Cosimo Cecchi, Matthias Clasen, Allan Day, Stéphane Démurget,
|
||||||
|
Jean-François Fortin Tam, Adel Gadllah, Alex Hultman, Sebastian Keller,
|
||||||
|
Rui Matos, Simon McVittie, Aleksander Morgado, Florian Müllner,
|
||||||
|
Bastien Nocera, Pierre-Eric Pelloux-Prayer, Alejandro Piñeiro, Neil Roberts,
|
||||||
|
Sjoerd Simons, Carlos Soriano Sánchez, Jasper St. Pierre, Ray Strode,
|
||||||
|
Owen Taylor, Daiki Ueno, Thomas Wood
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Dušan Kazik [sk], Pavol Klačanský [sk], Piotr Drąg [pl], Yuri Myasoedov [ru],
|
||||||
|
Marek Černocký [cs], Kjartan Maraas [nb], Wolfgang Stöggl [de],
|
||||||
|
Yaron Shahrabani [he], Fran Diéguez [gl], Mattias Põldaru [et]
|
||||||
|
|
||||||
|
3.7.1
|
||||||
|
=====
|
||||||
|
* Add shortcut to open application view directly [Jeremy; #685738]
|
||||||
|
* Expose '<Super>F10' shortcut in System Settings [Florian; #672909]
|
||||||
|
* Clean up timestamp format in chat notifications [Carlos; #680989]
|
||||||
|
* loginScreen: Add support for 'disable-restart-buttons' [Florian; #686247]
|
||||||
|
* Update textures automatically on file changes [Florian; #679268]
|
||||||
|
* Implement org.gnome.ScreenSaver.GetActiveTime [Giovanni; #686064]
|
||||||
|
* Add missing translations for GSetting schema [Giovanni; #686413]
|
||||||
|
* Hide workspace switcher completely when it's not necessary [Seif; #686483]
|
||||||
|
* Explicitly load gnome-screensaver when not running GDM [Tim; #683060]
|
||||||
|
* Port to GnomeIdleMonitor [Jasper; #682224]
|
||||||
|
* Set Empathy as preferred handler when delegating channels [Xavier; #686296]
|
||||||
|
* Allow testing GDM login dialog from the session [Giovanni; #683725]
|
||||||
|
* Use all available space for windows in window picker [Jasper, Pierre-Eric;
|
||||||
|
#582650]
|
||||||
|
* Use logind for suspend if available [Florian; #686482]
|
||||||
|
* Misc. fixes and cleanups [Jasper, Florian, Adel, Rui; #677426, #680426,
|
||||||
|
#686233, #686241, #686318, #686240, #686484, #686002, #684650, #686487]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jeremy Bicha, Giovanni Campagna, Xavier Claessens, Adel Gadllah, Seif Lotfy,
|
||||||
|
Tim Lunn, Rui Matos, Florian Müllner, Pierre-Eric Pelloux-Prayer,
|
||||||
|
Carlos Soriano, Jasper St. Pierre
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Andika Triwidada [id], Matej Urbančič [sl], Ihar Hrachyshka [be],
|
||||||
|
Daniel Mustieles [es], Fran Diéguez [gl], Takayuki KUSANO [ja],
|
||||||
|
Мирослав Николић [sr, sr@latin], Dušan Kazik [sk], Tom Tryfonidis [el]
|
||||||
|
|
||||||
|
3.6.1
|
||||||
|
=====
|
||||||
|
* dash: Make padding even on the top/bottom of the dash [Jasper; #684619]
|
||||||
|
* Fix a crash when dragging search results [Jasper; #684888]
|
||||||
|
* workspaceThumbnail: Fix dragging with static workspaces [Jasper; #684641]
|
||||||
|
* Really hide 'Show Keyboard Layout' on the lock screen [Matthias]
|
||||||
|
* Misc. improvements to jhbuild setup [Owen; #685352, #685353, #685354, #685355]
|
||||||
|
* Show message tray in Ctrl+Alt+Tab outside of the overview [Jasper, Florian;
|
||||||
|
#684633, #685914]
|
||||||
|
* Disable hotplug sniffer on remote filesystems [Jasper; #684093]
|
||||||
|
* userMenu: Remove 'Switch Session' item [Florian; #685062]
|
||||||
|
* unlockDialog: Make prompt entry insensitive while logging in [Jasper; #685444]
|
||||||
|
* messageTray: Don't animate desktop clone for failed grabs [Jasper; #685342]
|
||||||
|
* Fix crash on dragging windows between workspaces [Ryan; #681399]
|
||||||
|
* userMenu: Ignore 'lock-enabled' setting for user switching [Florian; #685536]
|
||||||
|
* gdm: Fix key-focus on first user [Adel; #684650]
|
||||||
|
* Make grid button insensitive when dragging non-favorites [Jasper; #685313]
|
||||||
|
* Calendar: hide all actions when on the login screen [Matthias; #685142]
|
||||||
|
* Adapt unlock dialog layout for the login screen [Florian; #685201]
|
||||||
|
* Make focus-follows-mouse work better with Shell UI [Florian; #678169]
|
||||||
|
* Improve look of screen shield [Jasper; #685919]
|
||||||
|
* Fix keynav in the login screen [Florian; #684730]
|
||||||
|
* dateMenu: Hide "Open Calendar" item if calendar unavailable [Florian; #686050]
|
||||||
|
* unlockDialog: Reset UI on verification failure [Giovanni; #685441]
|
||||||
|
* Show unlock dialog on primary monitor when using keynav [Giovanni; #685855]
|
||||||
|
* Fix height changes of entries when entering text [Florian; #685534]
|
||||||
|
* Fix show-apps label after successful drags [Florian; #684627]
|
||||||
|
* Misc. bugfixes and cleanups [Jasper, Olivier, Florian, Owen, Adel, Tanner, Tim, Matthias; #685434, #685511, #685466, #685341, #685156, #681159, #673189, #686016, 684869, #686079, #686063
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jasper St. Pierre
|
||||||
|
Matthias Clasen
|
||||||
|
Owen Taylor
|
||||||
|
Olivier Blin
|
||||||
|
Florian Müllner
|
||||||
|
Ryan Lortie
|
||||||
|
Adel Gadllah
|
||||||
|
Tanner Doshier
|
||||||
|
Tim Lunn
|
||||||
|
Giovanni Campagna
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Tobias Endrigkeit [de], Rudolfs Mazurs [lv], Ask H. Larsen [da],
|
||||||
|
Shankar Prasad [kn], Changwoo Ryu [ko], Chris Leonard [en_GB],
|
||||||
|
Arash Mousavi [fa], Theppitak Karoonboonyanan [th], Seán de Búrca [ga],
|
||||||
|
Yaron Shahrabani [he], Alexander Shopov [bg], Žygimantas Beručka [lt],
|
||||||
|
Milo Casagrande [it], Kjartan Maraas [nb], Kris Thomsen [da],
|
||||||
|
Aurimas Černius [lt], Yuri Myasoedov [ru], Мирослав Николић [sr],
|
||||||
|
Marek Černocký [cs], Gabor Kelemen [hu], Ihar Hrachyshka [be],
|
||||||
|
Chao-Hsiung Liao [zh_HK, zh_TW], Eleanor Chen [zh_CN],
|
||||||
|
Carles Ferrando [ca@valencia], Vicent Cubells [ca], Daniel Korostil [uk],
|
||||||
|
Alexandre Franke [fr], Piotr Drąg [pl]
|
||||||
|
|
||||||
|
3.6.0
|
||||||
|
=====
|
||||||
|
* keyboard: Make input source items accessible [Florian; #684462]
|
||||||
|
* Don't show network dialogs in the lock screen [Giovanni; #684384]
|
||||||
|
* popupMenu: Fix initial visibility of settings items [Florian; #684473]
|
||||||
|
* userMenu: Close menu immediately on user/session switch [Florian; #684459]
|
||||||
|
* Fix alignment of search section headers in RTL locales [Florian; #684379]
|
||||||
|
* screenShield: Fix unlock animation [Florian; #684591]
|
||||||
|
* Don't open the tray from a dwell while in a modal grab [Jasper; #684458]
|
||||||
|
* userMenu: Fix texture updates on icon changes [Florian; #679268]
|
||||||
|
* Fix a11y support in the login screen [Florian, Ray; #684727, #684728, #684748]
|
||||||
|
* Make On-Screen-Keyboard usable with new message tray [Giovanni, Florian;
|
||||||
|
#683546]
|
||||||
|
* Fix initial visibility of input volume in lock-screen [Florian; #684611]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Giovanni Campagna, Florian Müllner, Jasper St. Pierre, Ray Strode
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Matej Urbančič [sl], Dr.T.Vasudevan [ta], Piotr Drąg [pl], A S Alam [pa],
|
||||||
|
Alexander Shopov [bg], Nilamdyuti Goswami [as], Chandan Kumar [hi],
|
||||||
|
Khaled Hosny [ar], Ibrahim Saed [ar], Sandeep Sheshrao Shedmake [mr],
|
||||||
|
Tom Tryfonidis [el], Theppitak Karoonboonyanan [th], Alexandre Franke [fr],
|
||||||
|
Fran Diéguez [gl], Gabor Kelemen [hu], Ani Peter [ml], Daniel Mustieles [es],
|
||||||
|
Мирослав Николић [sr, sr@latin], Duarte Loreto [pt], ManojKumar Giri [or],
|
||||||
|
Ihar Hrachyshka [be], Aurimas Černius [lt], Djavan Fagundes [pt_BR],
|
||||||
|
Changwoo Ryu [ko], Bruce Cowan [en_GB], Kris Thomsen [da], Gil Forcada [ca],
|
||||||
|
Yaron Shahrabani [he], Milo Casagrande [it], Ville-Pekka Vainio [fi],
|
||||||
|
YunQiang Su [zh_CN], Carles Ferrando [ca@valencia], Mario Blättermann [de],
|
||||||
|
Rajesh Ranjan [hi], Yuri Myasoedov [ru], Rūdolfs Mazurs [lv],
|
||||||
|
Jiro Matsuzawa [ja], Mattias Põldaru [et], Timur Zhamakeev [ky],
|
||||||
|
Petr Kovar [cs], Chao-Hsiung Liao [zh_HK,zh_TW], Andika Triwidada [id]
|
||||||
|
|
||||||
|
3.5.92
|
||||||
|
======
|
||||||
|
* Login/UnlockDialog: Don't reset immediately if auth fails [Giovanni; #682544]
|
||||||
|
* Allow changing session mode at runtime [Jasper, Giovanni; #683156]
|
||||||
|
* Add zoom out animation on login [Jasper; #683170]
|
||||||
|
* Bluetooth: don't restrict the length of non numeric PINs [Giovanni; #683356]
|
||||||
|
* Force chat notification to stay open when focusing entry [Debarshi; #682236]
|
||||||
|
* Make sure the screen is fully locked before suspending [Giovanni; #683448]
|
||||||
|
* st-texture-cache: Fix a case of distorted textures [Florian; #683483]
|
||||||
|
* popupSubMenu: Fix padding for non-scrolled submenus [Florian; #683009]
|
||||||
|
* popupMenu: Fix width changes on submenu open/close [Florian; #683485]
|
||||||
|
* boxpointer: Avoid malformed boxpointer arrow [Debarshi; #680077]
|
||||||
|
* Change stage background color to grey [Adel; #683514]
|
||||||
|
* messageTray: Update style of summary counters [Debarshi; #682891]
|
||||||
|
* Don't fail if a legacy tray icon has no WM_CLASS [Giovanni; #683724]
|
||||||
|
* PolkitAgent: Fix a crash if there is no avatar [Giovanni; #683707]
|
||||||
|
* Hide the a11y menu in the lock screen, but show it in the login screen
|
||||||
|
[Giovanni; #682542]
|
||||||
|
* Fix show-apps button dropping off the dash [Florian; #683340]
|
||||||
|
* Fix committing strings to shell entries from input method [Florian; #658325]
|
||||||
|
* Make IBus display strings consistent with control-center [Rui; #683124]
|
||||||
|
* Fix missing short codes for some input sources [Rui; #683613]
|
||||||
|
* Remove support for long-press from entry context menus [Jasper; #683509]
|
||||||
|
* screenShield: Add box-shadow to the shield [Florian]
|
||||||
|
* Don't show a right-click menu for the hotplug source [Jasper; #683438]
|
||||||
|
* Fix extension styling [Giovanni; #682128]
|
||||||
|
* Fix on-screen keyboard not working with system-modal dialogs
|
||||||
|
[Giovanni; #664309]
|
||||||
|
* Fix insensitive styling for popup menu items [Giovanni; #683988]
|
||||||
|
* Disable the message tray dwell when the user is interacting [Owen; #683811]
|
||||||
|
* Animate going from the unlock dialog to the lock screen [Giovanni; #681143]
|
||||||
|
* Autostart fprintd when necessary [Ray; #683131]
|
||||||
|
* UnlockDialog: Allow typing before the first PAM question [Giovanni; #681576]
|
||||||
|
* Make Return key dismiss screenshield [Ray; #683889]
|
||||||
|
* Fix keyboard navigation in the message tray [Florian; #682243]
|
||||||
|
* Remove the places & devices search provider [Giovanni; #683506]
|
||||||
|
* Enable hot corner while the message tray is up [Florian; #682255]
|
||||||
|
* Port screen recorder to new GStreamer vp8enc API [Adel; #684206]
|
||||||
|
* Fix fish flickering [Giovanni; #684154]
|
||||||
|
* Fix extension ordering with !important [Jasper; #684163]
|
||||||
|
* Allow the shell to run without the screenshield [Giovanni; #683060]
|
||||||
|
* Add menu items for IBus Anthy's InputMode, TypingMode [Rui; #682314]
|
||||||
|
* Improve transition to the login dialog [Jasper; #682428]
|
||||||
|
* Keep unlock dialog around until shield animation ends [Florian; #684342]
|
||||||
|
* Expose shell keybindings in System Settings [Florian; #671010]
|
||||||
|
* Misc. bugfixes and cleanups [Debarshi, Florian, Giovanni, Jasper, Rico, Rui;
|
||||||
|
#672790, #677434, #683305, #683357, #683369, #683377, #683378, #683400,
|
||||||
|
#683449, #683472, #683482, #683487, #683488, #683526, #683529, #683546,
|
||||||
|
#683583, #683628, #683705, #683982, #683989, #684035, #684036, #684040,
|
||||||
|
#684162, #684214, #684343]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Giovanni Campagna, Adel Gadllah, Rui Matos, Florian Müllner, Debarshi Ray,
|
||||||
|
Jasper St. Pierre, Ray Strode, Owen Taylor, Rico Tzschichholz
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Gabor Kelemen [hu], Piotr Drąg [pl], Khaled Hosny [ar],
|
||||||
|
Мирослав Николић [sr, sr@latin], Chao-Hsiung Liao [zh_HK, zh_TW],
|
||||||
|
Bruce Cowan [en_GB], Dirgita [id], Tom Tryfonidis [el], Timo Jyrinki [fi],
|
||||||
|
Adorilson Bezerra [pt_BR], Arash Mousavi [fa], Matej Urbančič [sl],
|
||||||
|
Christian Kirbach [de], Yaron Shahrabani [he], Ihar Hrachyshka [be],
|
||||||
|
Changwoo Ryu [ko], Duarte Loreto [pt], Theppitak Karoonboonyanan [th],
|
||||||
|
Nilamdyuti Goswami [as], Sandeep Sheshrao Shedmake [mr],
|
||||||
|
Alexandre Franke [fr], Ivaylo Valkov [bg], tuhaihe [zh_CN],
|
||||||
|
Yuri Myasoedov [ru], Aurimas Černius [lt], Andika Triwidada [id],
|
||||||
|
Rajesh Ranjan [hi], Sweta Kothari [gu], Daniel Mustieles [es],
|
||||||
|
Fran Diéguez [gl], Praveen Illa [te]
|
||||||
|
|
||||||
|
3.5.91
|
||||||
|
======
|
||||||
|
* Improve modal dialog styling of network secret prompts [Jasper; #682412]
|
||||||
|
* Fix visibility of non-active workspaces during overview transition
|
||||||
|
[Florian; #682002]
|
||||||
|
* Improve scrollbar theming [Cosimo; #682476]
|
||||||
|
* Make sure the app menu remains hidden in locked state [Florian; #682475]
|
||||||
|
* Add tooltip to show-applications icon [Jasper; #682445]
|
||||||
|
* Do not add duplicate remote search providers [Florian; #682470]
|
||||||
|
* Handle 'popup-menu' signal on summary items [Florian; #682486]
|
||||||
|
* Fix dwelling during mouse-down [Owen; #682385]
|
||||||
|
* Set label actor for endSessionDialog.ListItem [Alejandro; #677503]
|
||||||
|
* Don't match on comments when searching applications [Florian; #682529]
|
||||||
|
* Make workspace selector more similar to the mockup [Stefano; #662087]
|
||||||
|
* Fix extension installation and reloading [Jasper; #682578]
|
||||||
|
* Hide removable devices in the lock screen [Giovanni; #681143]
|
||||||
|
* Reset cancellable after hitting Escape on login screen [Alban; #681537]
|
||||||
|
* Fix suspend from the user menu [Giovanni; #682746]
|
||||||
|
* Set label actor for summary items in message tray [Alejandro; #677229]
|
||||||
|
* Set label for the "Show applications" dash button [Alejandro; #682366]
|
||||||
|
* Load extensions as late as possible [Jasper; #682822]
|
||||||
|
* Improve mount operation dialogs [Jon; #682645]
|
||||||
|
* Remove "Connect to ..." item from places search [Florian; #682817]
|
||||||
|
* Don't auto-expand notifications with actions [Giovanni; #682738]
|
||||||
|
* Add a new lock screen menu to combine volume network and power
|
||||||
|
[Giovanni; #682540]
|
||||||
|
* Add support for pre-edit to StIMText [Daiki; #664041]
|
||||||
|
* Remove StIconType [Jasper, Florian, Rui, Giovanni, Debarshi; #682540]
|
||||||
|
* Use monitor geometry for dwelling [Florian; #683044]
|
||||||
|
* Add support for surrounding-text to StIMText [Daiki; #683015]
|
||||||
|
* Improve the placement and style of the "No results" text [Jasper; #683135]
|
||||||
|
* Remove broken network device activation policy [Giovanni; #683136]
|
||||||
|
* Hide power status icon when no battery is present [Tim; #683080]
|
||||||
|
* Ensure summary items are square and have spacing [Debarshi; #682248]
|
||||||
|
* Fix close buttons overlapping screen edge [Debarshi; #682343]
|
||||||
|
* Escape the tray when a legacy icon is clicked [Giovanni; #682244]
|
||||||
|
* Update arrow in the screen shield to match latest mockups [Giovanni; #682285]
|
||||||
|
* Allow lifting the screen shield with the mouse wheel [Giovanni; #683164]
|
||||||
|
* Make sure to show the app menu after unlocking the screen [Jasper; #683154]
|
||||||
|
* Misc bug fixes and cleanups [Debarshi, Florian, Giovanni, Jasper, Rui;
|
||||||
|
#582650, #667439, #682238, #682268, #682429, #682455, #682544, #682546,
|
||||||
|
#682683, #682710, #682998, #683073, #683137, #683156]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Alban Browaeys, Giovanni Campagna, Cosimo Cecchi, Stefano Facchini,
|
||||||
|
Adel Gadllah, Tim Lunn, Rui Matos, William Jon McCann, Florian Müllner,
|
||||||
|
Alejandro Piñeiro, Debarshi Ray, Jasper St. Pierre, Owen Taylor, Daiki Ueno
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Piotr Drąg [pl], Takayuki KUSANO [ja], Kjartan Maraas [nb],
|
||||||
|
Aurimas Černius [lt], Daniel Mustieles [es], Yuri Myasoedov [ru],
|
||||||
|
Khaled Hosny [ar], Yaron Shahrabani [he], Tom Tryfonidis [el],
|
||||||
|
Nilamdyuti Goswami [as], Fran Diéguez [gl], Nguyễn Thái Ngọc Duy [vi],
|
||||||
|
A S Alam [pa], Dr.T.Vasudevan [ta], Luca Ferretti [it]
|
||||||
|
|
||||||
3.5.90
|
3.5.90
|
||||||
======
|
======
|
||||||
* Use symbolic icons for workspace switch OSD [Jon; #680738]
|
* Use symbolic icons for workspace switch OSD [Jon; #680738]
|
||||||
|
|||||||
@@ -153,8 +153,6 @@ NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
|
|||||||
/* global initialization routine, called once when plugin
|
/* global initialization routine, called once when plugin
|
||||||
is loaded */
|
is loaded */
|
||||||
|
|
||||||
g_type_init ();
|
|
||||||
|
|
||||||
g_debug ("plugin loaded");
|
g_debug ("plugin loaded");
|
||||||
|
|
||||||
memcpy (&funcs, pfuncs, sizeof (funcs));
|
memcpy (&funcs, pfuncs, sizeof (funcs));
|
||||||
|
|||||||
36
configure.ac
36
configure.ac
@@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.63)
|
AC_PREREQ(2.63)
|
||||||
AC_INIT([gnome-shell],[3.5.90],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
AC_INIT([gnome-shell],[3.7.2.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||||
@@ -36,6 +36,8 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
|
|||||||
|
|
||||||
PKG_PROG_PKG_CONFIG([0.22])
|
PKG_PROG_PKG_CONFIG([0.22])
|
||||||
|
|
||||||
|
AC_PATH_PROG([XSLTPROC], [xsltproc])
|
||||||
|
|
||||||
GLIB_GSETTINGS
|
GLIB_GSETTINGS
|
||||||
|
|
||||||
# Get a value to substitute into gnome-shell.in
|
# Get a value to substitute into gnome-shell.in
|
||||||
@@ -52,7 +54,7 @@ AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
|
|||||||
if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
|
if $PKG_CONFIG --exists gstreamer-1.0 '>=' $GSTREAMER_MIN_VERSION ; then
|
||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
build_recorder=true
|
build_recorder=true
|
||||||
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11"
|
recorder_modules="gstreamer-1.0 gstreamer-base-1.0 x11 gtk+-3.0"
|
||||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
|
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
@@ -63,9 +65,9 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
|||||||
CLUTTER_MIN_VERSION=1.11.11
|
CLUTTER_MIN_VERSION=1.11.11
|
||||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||||
GJS_MIN_VERSION=1.33.2
|
GJS_MIN_VERSION=1.33.2
|
||||||
MUTTER_MIN_VERSION=3.5.90
|
MUTTER_MIN_VERSION=3.7.2
|
||||||
GTK_MIN_VERSION=3.3.9
|
GTK_MIN_VERSION=3.3.9
|
||||||
GIO_MIN_VERSION=2.31.6
|
GIO_MIN_VERSION=2.35.0
|
||||||
LIBECAL_MIN_VERSION=3.5.3
|
LIBECAL_MIN_VERSION=3.5.3
|
||||||
LIBEDATASERVER_MIN_VERSION=3.5.3
|
LIBEDATASERVER_MIN_VERSION=3.5.3
|
||||||
LIBEDATASERVERUI_MIN_VERSION=3.5.3
|
LIBEDATASERVERUI_MIN_VERSION=3.5.3
|
||||||
@@ -74,7 +76,7 @@ TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
|||||||
POLKIT_MIN_VERSION=0.100
|
POLKIT_MIN_VERSION=0.100
|
||||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||||
GCR_MIN_VERSION=3.3.90
|
GCR_MIN_VERSION=3.3.90
|
||||||
GNOME_DESKTOP_REQUIRED_VERSION=3.5.1
|
GNOME_DESKTOP_REQUIRED_VERSION=3.7.1
|
||||||
GNOME_MENUS_REQUIRED_VERSION=3.5.3
|
GNOME_MENUS_REQUIRED_VERSION=3.5.3
|
||||||
|
|
||||||
# Collect more than 20 libraries for a prize!
|
# Collect more than 20 libraries for a prize!
|
||||||
@@ -97,8 +99,7 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
|||||||
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
||||||
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
||||||
libnm-glib libnm-util gnome-keyring-1
|
libnm-glib libnm-util gnome-keyring-1
|
||||||
gcr-3 >= $GCR_MIN_VERSION
|
gcr-3 >= $GCR_MIN_VERSION)
|
||||||
gnome-desktop-3.0 >= $GNOME_DESKTOP_REQUIRED_VERSION)
|
|
||||||
|
|
||||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||||
|
|
||||||
@@ -106,6 +107,9 @@ PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
|
|||||||
|
|
||||||
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
|
PKG_CHECK_MODULES(BROWSER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION json-glib-1.0 >= 0.13.2)
|
||||||
|
|
||||||
|
GNOME_KEYBINDINGS_KEYSDIR=`$PKG_CONFIG --variable keysdir gnome-keybindings`
|
||||||
|
AC_SUBST([GNOME_KEYBINDINGS_KEYSDIR])
|
||||||
|
|
||||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||||
|
|
||||||
saved_CFLAGS=$CFLAGS
|
saved_CFLAGS=$CFLAGS
|
||||||
@@ -117,10 +121,10 @@ CFLAGS=$saved_CFLAGS
|
|||||||
LIBS=$saved_LIBS
|
LIBS=$saved_LIBS
|
||||||
|
|
||||||
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
|
PKG_CHECK_MODULES(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
|
||||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 x11)
|
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.8 x11)
|
||||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
||||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.5.4)
|
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 3.7.2)
|
||||||
|
|
||||||
AC_MSG_CHECKING([for bluetooth support])
|
AC_MSG_CHECKING([for bluetooth support])
|
||||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
||||||
@@ -136,7 +140,7 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
|||||||
AC_SUBST([HAVE_BLUETOOTH],[0])
|
AC_SUBST([HAVE_BLUETOOTH],[0])
|
||||||
AC_MSG_RESULT([no])])
|
AC_MSG_RESULT([no])])
|
||||||
|
|
||||||
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-3.0 >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
|
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION gio-2.0)
|
||||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||||
AC_SUBST(CALENDAR_SERVER_LIBS)
|
AC_SUBST(CALENDAR_SERVER_LIBS)
|
||||||
|
|
||||||
@@ -205,6 +209,18 @@ AC_SUBST(TYPELIBDIR)
|
|||||||
|
|
||||||
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
|
GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
|
||||||
|
|
||||||
|
AC_ARG_ENABLE(man,
|
||||||
|
[AS_HELP_STRING([--enable-man],
|
||||||
|
[generate man pages [default=yes]])],,
|
||||||
|
enable_man=yes)
|
||||||
|
if test "$enable_man" != no; then
|
||||||
|
AC_PATH_PROG([XSLTPROC], [xsltproc])
|
||||||
|
if test -z "$XSLTPROC"; then
|
||||||
|
AC_MSG_ERROR([xsltproc is required for --enable-man])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(ENABLE_MAN, test "$enable_man" != no)
|
||||||
|
|
||||||
# Stay command-line compatible with the gnome-common configure option. Here
|
# Stay command-line compatible with the gnome-common configure option. Here
|
||||||
# minimum/yes/maximum are the same, however.
|
# minimum/yes/maximum are the same, however.
|
||||||
AC_ARG_ENABLE(compile_warnings,
|
AC_ARG_ENABLE(compile_warnings,
|
||||||
|
|||||||
12
data/50-gnome-shell-screenshot.xml.in
Normal file
12
data/50-gnome-shell-screenshot.xml.in
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<KeyListEntries schema="org.gnome.shell.keybindings"
|
||||||
|
group="system"
|
||||||
|
_name="Screenshots"
|
||||||
|
wm_name="GNOME Shell"
|
||||||
|
package="gnome-shell">
|
||||||
|
|
||||||
|
<KeyListEntry name="toggle-recording"
|
||||||
|
_description="Record a screencast"/>
|
||||||
|
|
||||||
|
</KeyListEntries>
|
||||||
|
|
||||||
21
data/50-gnome-shell-system.xml.in
Normal file
21
data/50-gnome-shell-system.xml.in
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<KeyListEntries schema="org.gnome.shell.keybindings"
|
||||||
|
group="system"
|
||||||
|
_name="System"
|
||||||
|
wm_name="GNOME Shell"
|
||||||
|
package="gnome-shell">
|
||||||
|
|
||||||
|
<KeyListEntry name="toggle-message-tray"
|
||||||
|
_description="Show the message tray"/>
|
||||||
|
|
||||||
|
<KeyListEntry name="focus-active-notification"
|
||||||
|
_description="Focus the active notification"/>
|
||||||
|
|
||||||
|
<KeyListEntry name="toggle-application-view"
|
||||||
|
_description="Show all applications"/>
|
||||||
|
|
||||||
|
<KeyListEntry name="open-application-menu"
|
||||||
|
_description="Open the application menu"/>
|
||||||
|
|
||||||
|
</KeyListEntries>
|
||||||
|
|
||||||
@@ -39,6 +39,7 @@ dist_theme_DATA = \
|
|||||||
theme/process-working.svg \
|
theme/process-working.svg \
|
||||||
theme/running-indicator.svg \
|
theme/running-indicator.svg \
|
||||||
theme/source-button-border.svg \
|
theme/source-button-border.svg \
|
||||||
|
theme/summary-counter.svg \
|
||||||
theme/toggle-off-us.svg \
|
theme/toggle-off-us.svg \
|
||||||
theme/toggle-off-intl.svg \
|
theme/toggle-off-intl.svg \
|
||||||
theme/toggle-on-us.svg \
|
theme/toggle-on-us.svg \
|
||||||
@@ -46,6 +47,13 @@ dist_theme_DATA = \
|
|||||||
theme/ws-switch-arrow-up.png \
|
theme/ws-switch-arrow-up.png \
|
||||||
theme/ws-switch-arrow-down.png
|
theme/ws-switch-arrow-down.png
|
||||||
|
|
||||||
|
keysdir = @GNOME_KEYBINDINGS_KEYSDIR@
|
||||||
|
keys_in_files = \
|
||||||
|
50-gnome-shell-screenshot.xml.in \
|
||||||
|
50-gnome-shell-system.xml.in \
|
||||||
|
$(NULL)
|
||||||
|
keys_DATA = $(keys_in_files:.xml.in=.xml)
|
||||||
|
|
||||||
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
|
gsettings_SCHEMAS = org.gnome.shell.gschema.xml
|
||||||
|
|
||||||
@INTLTOOL_XML_NOMERGE_RULE@
|
@INTLTOOL_XML_NOMERGE_RULE@
|
||||||
@@ -72,12 +80,14 @@ EXTRA_DIST = \
|
|||||||
$(introspection_DATA) \
|
$(introspection_DATA) \
|
||||||
$(menu_DATA) \
|
$(menu_DATA) \
|
||||||
$(convert_DATA) \
|
$(convert_DATA) \
|
||||||
|
$(keys_in_files) \
|
||||||
org.gnome.shell.gschema.xml.in.in
|
org.gnome.shell.gschema.xml.in.in
|
||||||
|
|
||||||
CLEANFILES = \
|
CLEANFILES = \
|
||||||
gnome-shell.desktop.in \
|
gnome-shell.desktop.in \
|
||||||
gnome-shell-extension-prefs.in \
|
gnome-shell-extension-prefs.in \
|
||||||
$(desktop_DATA) \
|
$(desktop_DATA) \
|
||||||
|
$(keys_DATA) \
|
||||||
$(gsettings_SCHEMAS) \
|
$(gsettings_SCHEMAS) \
|
||||||
gschemas.compiled \
|
gschemas.compiled \
|
||||||
org.gnome.shell.gschema.valid \
|
org.gnome.shell.gschema.valid \
|
||||||
|
|||||||
@@ -108,7 +108,7 @@
|
|||||||
</doc:summary>
|
</doc:summary>
|
||||||
</doc:doc>
|
</doc:doc>
|
||||||
</arg>
|
</arg>
|
||||||
<arg type="a{sv}" direction="out">
|
<arg type="aa{sv}" direction="out">
|
||||||
<doc:doc>
|
<doc:doc>
|
||||||
<doc:summary>
|
<doc:summary>
|
||||||
<doc:para>
|
<doc:para>
|
||||||
|
|||||||
@@ -39,10 +39,6 @@
|
|||||||
will be displayed in the favorites area.
|
will be displayed in the favorites area.
|
||||||
</_description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
<key name="disabled-open-search-providers" type="as">
|
|
||||||
<default>[]</default>
|
|
||||||
<_summary>disabled OpenSearch providers</_summary>
|
|
||||||
</key>
|
|
||||||
<key name="command-history" type="as">
|
<key name="command-history" type="as">
|
||||||
<default>[]</default>
|
<default>[]</default>
|
||||||
<_summary>History for command (Alt-F2) dialog</_summary>
|
<_summary>History for command (Alt-F2) dialog</_summary>
|
||||||
@@ -61,6 +57,14 @@ value here is from the TpConnectionPresenceType enumeration.</_summary>
|
|||||||
<_summary>Internally used to store the last session presence status for the user. The
|
<_summary>Internally used to store the last session presence status for the user. The
|
||||||
value here is from the GsmPresenceStatus enumeration.</_summary>
|
value here is from the GsmPresenceStatus enumeration.</_summary>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="always-show-log-out" type="b">
|
||||||
|
<default>false</default>
|
||||||
|
<_summary>Always show the 'Log out' menuitem in the user menu.</_summary>
|
||||||
|
<_description>
|
||||||
|
This key overrides the automatic hiding of the 'Log out'
|
||||||
|
menuitem in single-user, single-session situations.
|
||||||
|
</_description>
|
||||||
|
</key>
|
||||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||||
@@ -87,6 +91,14 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
Keybinding to open the application menu.
|
Keybinding to open the application menu.
|
||||||
</_description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="toggle-application-view" type="as">
|
||||||
|
<default>["<Super>a"]</default>
|
||||||
|
<_summary>Keybinding to open the "Show Applications" view</_summary>
|
||||||
|
<_description>
|
||||||
|
Keybinding to open the "Show Applications" view of the Activities
|
||||||
|
Overview.
|
||||||
|
</_description>
|
||||||
|
</key>
|
||||||
<key name="toggle-message-tray" type="as">
|
<key name="toggle-message-tray" type="as">
|
||||||
<default>["<Super>m"]</default>
|
<default>["<Super>m"]</default>
|
||||||
<_summary>Keybinding to toggle the visibility of the message tray</_summary>
|
<_summary>Keybinding to toggle the visibility of the message tray</_summary>
|
||||||
@@ -94,6 +106,13 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
Keybinding to toggle the visibility of the message tray.
|
Keybinding to toggle the visibility of the message tray.
|
||||||
</_description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="focus-active-notification" type="as">
|
||||||
|
<default>["<Super>n"]</default>
|
||||||
|
<_summary>Keybinding to focus the active notification</_summary>
|
||||||
|
<_description>
|
||||||
|
Keybinding to focus the active notification.
|
||||||
|
</_description>
|
||||||
|
</key>
|
||||||
<key name="toggle-recording" type="as">
|
<key name="toggle-recording" type="as">
|
||||||
<default><![CDATA[['<Control><Shift><Alt>r']]]></default>
|
<default><![CDATA[['<Control><Shift><Alt>r']]]></default>
|
||||||
<_summary>Keybinding to toggle the screen recorder</_summary>
|
<_summary>Keybinding to toggle the screen recorder</_summary>
|
||||||
@@ -136,7 +155,7 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
take care of its own output - this might be used to send the output
|
take care of its own output - this might be used to send the output
|
||||||
to an icecast server via shout2send or similar. When unset or set
|
to an icecast server via shout2send or similar. When unset or set
|
||||||
to an empty value, the default pipeline will be used. This is currently
|
to an empty value, the default pipeline will be used. This is currently
|
||||||
'vp8enc quality=8 speed=6 threads=%T ! queue ! webmmux'
|
'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux'
|
||||||
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
||||||
for a guess at the optimal thread count on the system.
|
for a guess at the optimal thread count on the system.
|
||||||
</_description>
|
</_description>
|
||||||
@@ -152,44 +171,53 @@ value here is from the GsmPresenceStatus enumeration.</_summary>
|
|||||||
</key>
|
</key>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/">
|
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/"
|
||||||
|
gettext-domain="@GETTEXT_PACKAGE@">
|
||||||
<key name="attach-modal-dialogs" type="b">
|
<key name="attach-modal-dialogs" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Attach modal dialog to the parent window</summary>
|
<_summary>Attach modal dialog to the parent window</_summary>
|
||||||
<description>
|
<_description>
|
||||||
This key overrides the key in org.gnome.mutter when running
|
This key overrides the key in org.gnome.mutter when running
|
||||||
GNOME Shell.
|
GNOME Shell.
|
||||||
</description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="button-layout" type="s">
|
<key name="button-layout" type="s">
|
||||||
<default>":close"</default>
|
<default>":close"</default>
|
||||||
<summary>Arrangement of buttons on the titlebar</summary>
|
<_summary>Arrangement of buttons on the titlebar</_summary>
|
||||||
<description>
|
<_description>
|
||||||
This key overrides the key in org.gnome.desktop.wm.preferences when
|
This key overrides the key in org.gnome.desktop.wm.preferences when
|
||||||
running GNOME Shell.
|
running GNOME Shell.
|
||||||
</description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="edge-tiling" type="b">
|
<key name="edge-tiling" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Enable edge tiling when dropping windows on screen edges</summary>
|
<_summary>Enable edge tiling when dropping windows on screen edges</_summary>
|
||||||
<description>
|
<_description>
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
</description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="dynamic-workspaces" type="b">
|
<key name="dynamic-workspaces" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Workspaces are managed dynamically</summary>
|
<_summary>Workspaces are managed dynamically</_summary>
|
||||||
<description>
|
<_description>
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
</description>
|
</_description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
<key name="workspaces-only-on-primary" type="b">
|
<key name="workspaces-only-on-primary" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Workspaces only on primary monitor</summary>
|
<_summary>Workspaces only on primary monitor</_summary>
|
||||||
|
<_description>
|
||||||
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
|
</_description>
|
||||||
|
</key>
|
||||||
|
|
||||||
|
<key name="focus-change-on-pointer-rest" type="b">
|
||||||
|
<default>true</default>
|
||||||
|
<summary>Delay focus changes in mouse mode until the pointer stops moving</summary>
|
||||||
<description>
|
<description>
|
||||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
</description>
|
</description>
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ stage {
|
|||||||
/* small */
|
/* small */
|
||||||
.app-well-menu,
|
.app-well-menu,
|
||||||
.contact-details-status,
|
.contact-details-status,
|
||||||
.run-dialog-label,
|
|
||||||
.run-dialog-error-label {
|
.run-dialog-error-label {
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
}
|
}
|
||||||
@@ -80,25 +79,25 @@ StScrollBar StBin#trough {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#vhandle {
|
StScrollBar StButton#vhandle {
|
||||||
background-color: #959797;
|
background-color: #5d6464;
|
||||||
border: 2px solid #242424;
|
border: 2px solid #242424;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#hhandle {
|
StScrollBar StButton#hhandle {
|
||||||
background-color: #959797;
|
background-color: #5d6464;
|
||||||
border: 2px solid #242424;
|
border: 2px solid #242424;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#hhandle:hover,
|
StScrollBar StButton#hhandle:hover,
|
||||||
StScrollBar StButton#vhandle:hover {
|
StScrollBar StButton#vhandle:hover {
|
||||||
background-color: #c2c3c3;
|
background-color: #777d7c;
|
||||||
}
|
}
|
||||||
|
|
||||||
StScrollBar StButton#hhandle:active,
|
StScrollBar StButton#hhandle:active,
|
||||||
StScrollBar StButton#vhandle:active {
|
StScrollBar StButton#vhandle:active {
|
||||||
background-color: #729fcf;
|
background-color: #3465a4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check Boxes */
|
/* Check Boxes */
|
||||||
@@ -151,11 +150,11 @@ StScrollBar StButton#vhandle:active {
|
|||||||
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
|
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.9);
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-sub-menu .popup-menu-item:ltr {
|
.popup-sub-menu:scrolled .popup-menu-item:ltr {
|
||||||
padding-right: 0em;
|
padding-right: 0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-sub-menu .popup-menu-item:rtl {
|
.popup-sub-menu:scrolled .popup-menu-item:rtl {
|
||||||
padding-left: 0em;
|
padding-left: 0em;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +194,7 @@ StScrollBar StButton#vhandle:active {
|
|||||||
background-color: #4c4c4c;
|
background-color: #4c4c4c;
|
||||||
}
|
}
|
||||||
|
|
||||||
StButton.popup-menu-item:insensitive {
|
.popup-menu-item:insensitive {
|
||||||
color: #9f9f9f;
|
color: #9f9f9f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,13 +233,18 @@ StButton.popup-menu-item:insensitive {
|
|||||||
spacing: .5em;
|
spacing: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-inactive-menu-item {
|
.popup-status-menu-item {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-subtitle-menu-item {
|
.popup-inactive-menu-item, .popup-inactive-menu-item:insensitive {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-subtitle-menu-item, .popup-subtitle-menu-item:insensitive {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-menu-icon {
|
.popup-menu-icon {
|
||||||
@@ -306,7 +310,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
.notification-icon-button:focus,
|
.notification-icon-button:focus,
|
||||||
.hotplug-notification-item:focus,
|
.hotplug-notification-item:focus,
|
||||||
.modal-dialog-button:focus {
|
.modal-dialog-button:focus {
|
||||||
border: 2px solid #8b8b8b;
|
border-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-search-button:active,
|
.dash-search-button:active,
|
||||||
@@ -321,26 +325,30 @@ StButton.popup-menu-item:insensitive {
|
|||||||
background-gradient-end: rgba(255, 255, 255, 0.2);
|
background-gradient-end: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification-button:insensitive,
|
||||||
.notification-icon-button:insensitive,
|
.notification-icon-button:insensitive,
|
||||||
.notification-button:insensitive {
|
.modal-dialog-button:insensitive {
|
||||||
|
border-color: #666666;
|
||||||
color: #9f9f9f;
|
color: #9f9f9f;
|
||||||
|
background-gradient-direction: none;
|
||||||
|
background-color: rgba(102, 102, 102, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Entries */
|
/* Entries */
|
||||||
|
|
||||||
#searchEntry,
|
#searchEntry,
|
||||||
.notification StEntry,
|
.notification StEntry,
|
||||||
.login-dialog-prompt-entry,
|
.modal-dialog StEntry {
|
||||||
.prompt-dialog-password-entry {
|
|
||||||
color: rgb(64, 64, 64);
|
color: rgb(64, 64, 64);
|
||||||
caret-color: rgb(64, 64, 64);
|
caret-color: rgb(64, 64, 64);
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
caret-size: 1px;
|
caret-size: 1px;
|
||||||
selected-color: black;
|
selected-color: white;
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchEntry,
|
#searchEntry,
|
||||||
|
.run-dialog-entry,
|
||||||
.notification StEntry {
|
.notification StEntry {
|
||||||
border: 2px solid rgba(245,245,245,0.2);
|
border: 2px solid rgba(245,245,245,0.2);
|
||||||
background-gradient-start: rgba(5,5,6,0.1);
|
background-gradient-start: rgba(5,5,6,0.1);
|
||||||
@@ -353,8 +361,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
#searchEntry:focus,
|
#searchEntry:focus,
|
||||||
#searchEntry:hover,
|
#searchEntry:hover,
|
||||||
.notification StEntry:focus,
|
.notification StEntry:focus,
|
||||||
.login-dialog-prompt-entry,
|
.modal-dialog StEntry {
|
||||||
.prompt-dialog-password-entry {
|
|
||||||
border: 2px solid rgb(136,138,133);
|
border: 2px solid rgb(136,138,133);
|
||||||
background-gradient-start: rgb(200,200,200);
|
background-gradient-start: rgb(200,200,200);
|
||||||
background-gradient-end: white;
|
background-gradient-end: white;
|
||||||
@@ -363,12 +370,17 @@ StButton.popup-menu-item:insensitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notification StEntry:focus,
|
.notification StEntry:focus,
|
||||||
.prompt-dialog-password-entry:focus,
|
.modal-dialog StEntry:focus {
|
||||||
.login-dialog-prompt-entry:focus {
|
|
||||||
border: 2px solid #3465a4;
|
border: 2px solid #3465a4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#searchEntry {
|
#searchEntry {
|
||||||
|
border-color: rgba(245,245,245,0.3);
|
||||||
|
color: rgb(192, 192, 192);
|
||||||
|
caret-color: rgb(192, 192, 192);
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchEntry:hover {
|
||||||
color: rgb(128, 128, 128);
|
color: rgb(128, 128, 128);
|
||||||
caret-color: rgb(128, 128, 128);
|
caret-color: rgb(128, 128, 128);
|
||||||
}
|
}
|
||||||
@@ -381,8 +393,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.notification StEntry,
|
.notification StEntry,
|
||||||
.prompt-dialog-password-entry,
|
.modal-dialog StEntry {
|
||||||
.login-dialog-prompt-entry {
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 4px 4px;
|
padding: 4px 4px;
|
||||||
}
|
}
|
||||||
@@ -397,6 +408,8 @@ StButton.popup-menu-item:insensitive {
|
|||||||
.login-dialog-prompt-entry:insensitive {
|
.login-dialog-prompt-entry:insensitive {
|
||||||
color: rgba(0,0,0,0.7);
|
color: rgba(0,0,0,0.7);
|
||||||
border: 2px solid #565656;
|
border: 2px solid #565656;
|
||||||
|
background-gradient-start: rgb(200,200,200);
|
||||||
|
background-gradient-end: rgb(210,210,210);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Panel */
|
/* Panel */
|
||||||
@@ -502,7 +515,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
-boxpointer-gap: 4px
|
-boxpointer-gap: 4px
|
||||||
}
|
}
|
||||||
|
|
||||||
#networkMenu {
|
.panel-status-button-box {
|
||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,7 +557,6 @@ StButton.popup-menu-item:insensitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.status-chooser-combo.popup-combo-menu {
|
.status-chooser-combo.popup-combo-menu {
|
||||||
background-color: rgba(0,0,0,0.7);
|
|
||||||
padding: .4em 0em;
|
padding: .4em 0em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #5f5f5f;
|
border: 1px solid #5f5f5f;
|
||||||
@@ -562,7 +574,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
/* Overview */
|
/* Overview */
|
||||||
|
|
||||||
#overview {
|
#overview {
|
||||||
spacing: 12px;
|
spacing: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-caption {
|
.window-caption {
|
||||||
@@ -578,22 +590,24 @@ StButton.popup-menu-item:insensitive {
|
|||||||
border-right: 0px;
|
border-right: 0px;
|
||||||
border-radius: 9px 0px 0px 9px;
|
border-radius: 9px 0px 0px 9px;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
padding: 8px;
|
padding: 11px 7px 11px 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-thumbnails-background:rtl {
|
.workspace-thumbnails-background:rtl {
|
||||||
border-right: 1px;
|
border-right: 1px;
|
||||||
border-left: 0px;
|
border-left: 0px;
|
||||||
border-radius: 0px 9px 9px 0px;
|
border-radius: 0px 9px 9px 0px;
|
||||||
|
padding: 11px 11px 11px 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-thumbnails {
|
.workspace-thumbnails {
|
||||||
spacing: 7px;
|
spacing: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.workspace-thumbnail-indicator {
|
.workspace-thumbnail-indicator {
|
||||||
outline: 2px solid white;
|
border: 4px solid rgba(255,255,255,0.7);
|
||||||
border: 1px solid #888;
|
border-radius: 4px;
|
||||||
|
padding: 1px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-caption {
|
.window-caption {
|
||||||
@@ -605,9 +619,9 @@ StButton.popup-menu-item:insensitive {
|
|||||||
|
|
||||||
.window-close, .notification-close {
|
.window-close, .notification-close {
|
||||||
background-image: url("close-window.svg");
|
background-image: url("close-window.svg");
|
||||||
background-size: 34px;
|
background-size: 32px;
|
||||||
height: 34px;
|
height: 32px;
|
||||||
width: 34px;
|
width: 32px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-close {
|
.window-close {
|
||||||
@@ -618,19 +632,31 @@ StButton.popup-menu-item:insensitive {
|
|||||||
/* we start out in the top right of the
|
/* we start out in the top right of the
|
||||||
* notification, inset.
|
* notification, inset.
|
||||||
*
|
*
|
||||||
* center is 32px/2 = 17px
|
* center is 32px/2 = 16px
|
||||||
*
|
*
|
||||||
* adjust left 2px
|
* adjust left 2px
|
||||||
* adjust down 8px */
|
* adjust down 8px */
|
||||||
|
|
||||||
-shell-close-overlap-x: 15px;
|
-shell-close-overlap-x: 14px;
|
||||||
-shell-close-overlap-y: 12px;
|
-shell-close-overlap-y: -12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-close:rtl {
|
||||||
|
/* as above, but starting out in the top left of the
|
||||||
|
* notification. */
|
||||||
|
|
||||||
|
-shell-close-overlap-x: -14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-close:rtl {
|
.window-close:rtl {
|
||||||
-st-background-image-shadow: 2px 2px 6px rgba(0,0,0,0.5);
|
-st-background-image-shadow: 2px 2px 6px rgba(0,0,0,0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.window-picker {
|
||||||
|
-horizontal-spacing: 40px;
|
||||||
|
-vertical-spacing: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dash */
|
/* Dash */
|
||||||
|
|
||||||
#dash {
|
#dash {
|
||||||
@@ -649,11 +675,6 @@ StButton.popup-menu-item:insensitive {
|
|||||||
border-radius: 9px 0px 0px 9px;
|
border-radius: 9px 0px 0px 9px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dash:empty {
|
|
||||||
height: 100px;
|
|
||||||
width: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder {
|
.placeholder {
|
||||||
background-image: url("dash-placeholder.svg");
|
background-image: url("dash-placeholder.svg");
|
||||||
background-size: contain;
|
background-size: contain;
|
||||||
@@ -673,6 +694,11 @@ StButton.popup-menu-item:insensitive {
|
|||||||
|
|
||||||
.search-entry-icon {
|
.search-entry-icon {
|
||||||
icon-size: 1em;
|
icon-size: 1em;
|
||||||
|
color: #c0c0c0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchEntry:hover .search-entry-icon,
|
||||||
|
#searchEntry:focus .search-entry-icon {
|
||||||
color: #8d8f8a;
|
color: #8d8f8a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,7 +719,6 @@ StButton.popup-menu-item:insensitive {
|
|||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-statustext,
|
|
||||||
.search-section-header {
|
.search-section-header {
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
@@ -701,6 +726,12 @@ StButton.popup-menu-item:insensitive {
|
|||||||
font-size: .8em;
|
font-size: .8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-statustext {
|
||||||
|
color: #efefef;
|
||||||
|
font-size: 2em;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.search-section-results {
|
.search-section-results {
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
@@ -713,10 +744,6 @@ StButton.popup-menu-item:insensitive {
|
|||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-providers-box {
|
|
||||||
spacing: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Text labels are an odd number of pixels tall. The uneven top and bottom
|
/* Text labels are an odd number of pixels tall. The uneven top and bottom
|
||||||
* padding compensates for this and ensures that the label is vertically
|
* padding compensates for this and ensures that the label is vertically
|
||||||
* centered */
|
* centered */
|
||||||
@@ -1183,12 +1210,16 @@ StButton.popup-menu-item:insensitive {
|
|||||||
background: #2e3436 url(message-tray-background.png);
|
background: #2e3436 url(message-tray-background.png);
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
transition-duration: 250;
|
transition-duration: 250;
|
||||||
height: 72px;
|
}
|
||||||
|
|
||||||
|
#message-tray:keyboard {
|
||||||
|
/* Same as the OSK */
|
||||||
|
background: rgba(0, 0, 0, 0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#message-tray:overview {
|
#message-tray:overview {
|
||||||
background: rgba(0, 0, 0, 0.1);
|
background: rgba(0, 0, 0, 0.1);
|
||||||
border-top: 1px solid rgba(128, 128, 128, 0.3);
|
outline: 1px solid rgba(128, 128, 128, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.notification {
|
.notification {
|
||||||
@@ -1208,6 +1239,13 @@ StButton.popup-menu-item:insensitive {
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notification-unexpanded {
|
||||||
|
/* We want to force the actor at a specific size, irrespective
|
||||||
|
of its minimum and preferred size, so we override both */
|
||||||
|
min-height: 36px;
|
||||||
|
height: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
/* We use row-span = 2 for the image cell, which prevents its height preferences to be
|
/* We use row-span = 2 for the image cell, which prevents its height preferences to be
|
||||||
taken into account during allocation, so its height ends up being limited by the height
|
taken into account during allocation, so its height ends up being limited by the height
|
||||||
of the content in the other rows. To avoid showing a stretched image, we set the minimum
|
of the content in the other rows. To avoid showing a stretched image, we set the minimum
|
||||||
@@ -1394,6 +1432,10 @@ StButton.popup-menu-item:insensitive {
|
|||||||
padding-right: 4px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.chat-notification-scrollview{
|
||||||
|
max-height: 22em;
|
||||||
|
}
|
||||||
|
|
||||||
.subscription-message {
|
.subscription-message {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
@@ -1403,41 +1445,45 @@ StButton.popup-menu-item:insensitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#summary-mode {
|
#summary-mode {
|
||||||
padding: 2px 0px 0px 4px;
|
|
||||||
height: 72px;
|
height: 72px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#summary-mode:rtl {
|
|
||||||
padding: 2px 4px 0px 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.summary-source-button {
|
.summary-source-button {
|
||||||
border-radius: 4px;
|
padding: 6px 3px 6px 3px;
|
||||||
transition-duration: 100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-button:hover {
|
.summary-source-button:last-child:ltr {
|
||||||
|
padding-right: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-source-button:last-child:rtl {
|
||||||
|
padding-left: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.summary-source-button:hover .summary-source {
|
||||||
background-color: rgba(255,255,255,0.1);
|
background-color: rgba(255,255,255,0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-button:focus,
|
.summary-source-button:focus .summary-source,
|
||||||
.summary-source-button:selected {
|
.summary-source-button:selected .summary-source {
|
||||||
background-color: rgba(255,255,255,0.33);
|
background-color: rgba(255,255,255,0.33);
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source {
|
.summary-source {
|
||||||
padding-right: 6px;
|
border-radius: 4px;
|
||||||
padding-left: 6px;
|
padding: 0 6px 0 6px;
|
||||||
|
transition-duration: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-counter {
|
.summary-source-counter {
|
||||||
color: white;
|
background-image: url("summary-counter.svg");
|
||||||
background-color: #3465A4;
|
background-size: 2.5em;
|
||||||
text-shadow: black 1px 1px 0;
|
font-size: 10pt;
|
||||||
font-size: 9pt;
|
font-weight: bold;
|
||||||
border-radius: 1em;
|
height: 2.5em;
|
||||||
min-height: 1em;
|
width: 2.5em;
|
||||||
min-width: 1em;
|
-shell-counter-overlap-x: 4px;
|
||||||
|
-shell-counter-overlap-y: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* App Switcher */
|
/* App Switcher */
|
||||||
@@ -1604,35 +1650,26 @@ StButton.popup-menu-item:insensitive {
|
|||||||
padding: 4px 32px 5px;
|
padding: 4px 32px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-dialog-button:insensitive {
|
|
||||||
color: rgb(60, 60, 60);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-dialog-button:focus {
|
.modal-dialog-button:focus {
|
||||||
padding: 3px 31px 4px;
|
padding: 3px 31px 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Run Dialog */
|
/* Run Dialog */
|
||||||
|
|
||||||
|
.run-dialog-label {
|
||||||
|
font-size: 12pt;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #999999;
|
||||||
|
padding-bottom: .4em;
|
||||||
|
}
|
||||||
|
|
||||||
.run-dialog-error-box {
|
.run-dialog-error-box {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
spacing: 5px;
|
spacing: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.run-dialog-entry {
|
.modal-dialog .run-dialog-entry {
|
||||||
font-weight: bold;
|
width: 20em;
|
||||||
width: 23em;
|
|
||||||
selection-background-color: white;
|
|
||||||
selected-color: black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.run-dialog {
|
|
||||||
border-radius: 16px;
|
|
||||||
|
|
||||||
padding-right: 21px;
|
|
||||||
padding-left: 21px;
|
|
||||||
padding-bottom: 15px;
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.lightbox {
|
.lightbox {
|
||||||
@@ -1672,6 +1709,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
background-size: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.end-session-dialog-shutdown-icon {
|
.end-session-dialog-shutdown-icon {
|
||||||
@@ -1832,6 +1870,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
|
|
||||||
.prompt-dialog-password-box {
|
.prompt-dialog-password-box {
|
||||||
spacing: 1em;
|
spacing: 1em;
|
||||||
|
padding-bottom: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.prompt-dialog-error-label {
|
.prompt-dialog-error-label {
|
||||||
@@ -1870,10 +1909,19 @@ StButton.popup-menu-item:insensitive {
|
|||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.polkit-dialog-user-icon {
|
||||||
|
border: 2px solid #8b8b8b;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-size: contain;
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Network Agent Dialog */
|
/* Network Agent Dialog */
|
||||||
|
|
||||||
.network-dialog-secret-table {
|
.network-dialog-secret-table {
|
||||||
spacing-rows: 15px;
|
spacing-rows: 15px;
|
||||||
|
spacing-columns: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.keyring-dialog-control-table {
|
.keyring-dialog-control-table {
|
||||||
@@ -2002,7 +2050,6 @@ StButton.popup-menu-item:insensitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog-user-list-item {
|
.login-dialog-user-list-item {
|
||||||
color: #666666;
|
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
padding: .2em;
|
padding: .2em;
|
||||||
}
|
}
|
||||||
@@ -2020,6 +2067,11 @@ StButton.popup-menu-item:insensitive {
|
|||||||
padding-left: 1em;
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list:expanded .login-dialog-user-list-item {
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-user-list-item,
|
||||||
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name,
|
.login-dialog-user-list-item:hover .login-dialog-user-list-item-name,
|
||||||
.login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name,
|
.login-dialog-user-list:expanded .login-dialog-user-list-item:focus .login-dialog-user-list-item-name,
|
||||||
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
|
.login-dialog-user-list:expanded .login-dialog-user-list-item:logged-in {
|
||||||
@@ -2067,6 +2119,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
padding-top: 1em;
|
padding-top: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-dialog-not-listed-button:focus .login-dialog-not-listed-label,
|
||||||
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
|
.login-dialog-not-listed-button:hover .login-dialog-not-listed-label {
|
||||||
color: #E8E8E8;
|
color: #E8E8E8;
|
||||||
}
|
}
|
||||||
@@ -2076,7 +2129,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
text-shadow: black 4px 4px 3px 0px;
|
text-shadow: black 0px 4px 3px 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog-prompt-layout {
|
.login-dialog-prompt-layout {
|
||||||
@@ -2142,18 +2195,24 @@ StButton.popup-menu-item:insensitive {
|
|||||||
height: .75em;
|
height: .75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button {
|
.login-dialog .modal-dialog-button {
|
||||||
border: 1px solid #666666;
|
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
padding: 3px 18px;
|
padding: 3px 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-dialog .modal-dialog-button:focus {
|
||||||
|
padding: 2px 17px;
|
||||||
|
}
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:default {
|
.login-dialog .modal-dialog-button:default {
|
||||||
background-gradient-start: #6793c4;
|
background-gradient-start: #6793c4;
|
||||||
background-gradient-end: #335d8f;
|
background-gradient-end: #335d8f;
|
||||||
background-gradient-direction: vertical;
|
background-gradient-direction: vertical;
|
||||||
border: 2px solid #16335d;
|
border-color: #16335d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog .modal-dialog-button:default:focus {
|
||||||
|
border: 2px solid #377fe7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-dialog .modal-dialog-button:default:hover {
|
.login-dialog .modal-dialog-button:default:hover {
|
||||||
@@ -2167,21 +2226,47 @@ StButton.popup-menu-item:insensitive {
|
|||||||
background-gradient-end: #74a0d0;
|
background-gradient-end: #74a0d0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.login-dialog .modal-dialog-button:default:insensitive {
|
||||||
|
border-color: #666666;
|
||||||
|
color: #9f9f9f;
|
||||||
|
background-gradient-direction: none;
|
||||||
|
background-color: rgba(102, 102, 102, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-dialog-message-warning {
|
||||||
|
color: orange;
|
||||||
|
}
|
||||||
|
|
||||||
.unlock-dialog-user-name-container {
|
.unlock-dialog-user-name-container {
|
||||||
spacing: .4em;
|
spacing: .4em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Screen shield */
|
/* Screen shield */
|
||||||
|
|
||||||
|
.screen-shield-background {
|
||||||
|
background: black;
|
||||||
|
box-shadow: 0px 4px 8px rgba(0,0,0,0.9);
|
||||||
|
}
|
||||||
|
|
||||||
#lockDialogGroup {
|
#lockDialogGroup {
|
||||||
background: #2e3436 url(noise-texture.png);
|
background: #2e3436 url(noise-texture.png);
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
#lockScreenGroup .arrow {
|
.screen-shield-arrows {
|
||||||
color: #333333;
|
padding-bottom: 3em;
|
||||||
width: 100px;
|
}
|
||||||
height: 50px;
|
|
||||||
|
.screen-shield-arrows Gjs_Arrow {
|
||||||
|
color: white;
|
||||||
|
width: 80px;
|
||||||
|
height: 48px;
|
||||||
|
-arrow-thickness: 12px;
|
||||||
|
-arrow-shadow: 0 1px 1px rgba(0,0,0,0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.screen-shield-contents-box {
|
||||||
|
spacing: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-clock {
|
.screen-shield-clock {
|
||||||
@@ -2193,12 +2278,12 @@ StButton.popup-menu-item:insensitive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-clock-time {
|
.screen-shield-clock-time {
|
||||||
font-size: 86px;
|
font-size: 72pt;
|
||||||
text-shadow: 0px 2px 2px rgba(0,0,0,0.4);
|
text-shadow: 0px 2px 2px rgba(0,0,0,0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-clock-date {
|
.screen-shield-clock-date {
|
||||||
font-size: 48px;
|
font-size: 28pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
#screenShieldNotifications {
|
#screenShieldNotifications {
|
||||||
@@ -2206,11 +2291,12 @@ StButton.popup-menu-item:insensitive {
|
|||||||
background-color: rgba(0.0, 0.0, 0.0, 0.9);
|
background-color: rgba(0.0, 0.0, 0.0, 0.9);
|
||||||
border: 2px solid #868686;
|
border: 2px solid #868686;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
padding: 12px 0;
|
padding: 18px 0;
|
||||||
|
box-shadow: .5em .5em 20px rgba(0, 0, 0, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-notifications-box {
|
.screen-shield-notifications-box {
|
||||||
spacing: 12px;
|
spacing: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.screen-shield-notification-source {
|
.screen-shield-notification-source {
|
||||||
@@ -2221,6 +2307,7 @@ StButton.popup-menu-item:insensitive {
|
|||||||
.screen-shield-notification-label {
|
.screen-shield-notification-label {
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
color: #babdb6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove background from notifications, otherwise
|
/* Remove background from notifications, otherwise
|
||||||
|
|||||||
120
data/theme/summary-counter.svg
Normal file
120
data/theme/summary-counter.svg
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||||
|
|
||||||
|
<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"
|
||||||
|
version="1.0"
|
||||||
|
id="Foreground"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
viewBox="0 0 23.272727 23.272727"
|
||||||
|
enable-background="new 0 0 16 16"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:version="0.32"
|
||||||
|
inkscape:version="0.48.2 r9819"
|
||||||
|
sodipodi:docname="summary-counter.svg"
|
||||||
|
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||||
|
id="metadata2399"><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 /></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs2397"><linearGradient
|
||||||
|
id="linearGradient3173"><stop
|
||||||
|
style="stop-color:#c4c4c4;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop3175" /><stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3177" /></linearGradient><inkscape:perspective
|
||||||
|
sodipodi:type="inkscape:persp3d"
|
||||||
|
inkscape:vp_x="0 : 8 : 1"
|
||||||
|
inkscape:vp_y="0 : 1000 : 0"
|
||||||
|
inkscape:vp_z="16 : 8 : 1"
|
||||||
|
inkscape:persp3d-origin="8 : 5.3333333 : 1"
|
||||||
|
id="perspective2401" /><filter
|
||||||
|
color-interpolation-filters="sRGB"
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="filter16494-4"
|
||||||
|
x="-0.20989846"
|
||||||
|
width="1.4197969"
|
||||||
|
y="-0.20903821"
|
||||||
|
height="1.4180764"><feGaussianBlur
|
||||||
|
inkscape:collect="always"
|
||||||
|
stdDeviation="1.3282637"
|
||||||
|
id="feGaussianBlur16496-8" /></filter><radialGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient16498-6"
|
||||||
|
id="radialGradient16504-1"
|
||||||
|
cx="7.6582627"
|
||||||
|
cy="5.8191104"
|
||||||
|
fx="7.6582627"
|
||||||
|
fy="5.8191104"
|
||||||
|
r="8.6928644"
|
||||||
|
gradientTransform="matrix(1.0474339,0,0,1.0517402,-0.3632615,-0.42032492)"
|
||||||
|
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient16498-6"><stop
|
||||||
|
style="stop-color:#9FD0FF;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop16500-8" /><stop
|
||||||
|
style="stop-color:#3465A4;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop16502-0" /></linearGradient></defs><sodipodi:namedview
|
||||||
|
inkscape:window-height="709"
|
||||||
|
inkscape:window-width="1366"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
guidetolerance="10.0"
|
||||||
|
gridtolerance="10.0"
|
||||||
|
objecttolerance="10.0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#000000"
|
||||||
|
id="base"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="11.313708"
|
||||||
|
inkscape:cx="15.386407"
|
||||||
|
inkscape:cy="13.739577"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="1179"
|
||||||
|
inkscape:current-layer="g16402-8"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:guide-bbox="true"
|
||||||
|
borderlayer="true"
|
||||||
|
inkscape:showpageshadow="false"
|
||||||
|
inkscape:window-maximized="1"><inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid11246"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" /></sodipodi:namedview><g
|
||||||
|
style="display:inline"
|
||||||
|
id="g16402-8"
|
||||||
|
transform="translate(4.7533483,2.8238929)"><g
|
||||||
|
id="g3175-4"
|
||||||
|
transform="translate(-0.89995416,0.94028614)"><path
|
||||||
|
sodipodi:type="inkscape:offset"
|
||||||
|
inkscape:radius="0"
|
||||||
|
inkscape:original="M 7.65625 0.125 C 3.2589349 0.125 -0.3125 3.7070002 -0.3125 8.125 C -0.3125 12.543001 3.2589349 16.125 7.65625 16.125 C 12.053566 16.125 15.625 12.543001 15.625 8.125 C 15.625 3.7070002 12.053566 0.125 7.65625 0.125 z "
|
||||||
|
xlink:href="#path2394-32"
|
||||||
|
style="opacity:0.52994014;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.18181825;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16494-4);enable-background:accumulate"
|
||||||
|
id="path16480-5"
|
||||||
|
inkscape:href="#path2394-32"
|
||||||
|
d="m 7.65625,0.125 c -4.3973151,0 -7.96875,3.5820002 -7.96875,8 0,4.418001 3.5714349,8 7.96875,8 4.397316,0 7.96875,-3.581999 7.96875,-8 0,-4.4179998 -3.571434,-8 -7.96875,-8 z"
|
||||||
|
transform="translate(0,1.028519)" /><path
|
||||||
|
clip-rule="evenodd"
|
||||||
|
d="m -0.30428257,8.1237596 c 0,-4.4179998 3.56522987,-7.9999996 7.96254497,-7.9999996 4.3973156,0 7.9625456,3.5819998 7.9625456,7.9999996 0,4.4180014 -3.56523,8.0000004 -7.9625456,8.0000004 -4.3973151,0 -7.96254497,-3.581999 -7.96254497,-8.0000004 z"
|
||||||
|
id="path2394-32"
|
||||||
|
style="color:#000000;fill:url(#radialGradient16504-1);fill-opacity:1;fill-rule:nonzero;stroke:#eeeeec;stroke-width:1.4545455;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||||
|
sodipodi:nodetypes="csssc"
|
||||||
|
inkscape:connector-curvature="0" /><g
|
||||||
|
id="g3172-6" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 5.4 KiB |
@@ -29,8 +29,6 @@
|
|||||||
<chapter>
|
<chapter>
|
||||||
<title>Search</title>
|
<title>Search</title>
|
||||||
<xi:include href="xml/shell-app-system.xml"/>
|
<xi:include href="xml/shell-app-system.xml"/>
|
||||||
<xi:include href="xml/shell-contact-system.xml"/>
|
|
||||||
<xi:include href="xml/shell-doc-system.xml"/>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter>
|
<chapter>
|
||||||
<title>Tray Icons</title>
|
<title>Tray Icons</title>
|
||||||
@@ -42,7 +40,6 @@
|
|||||||
<chapter>
|
<chapter>
|
||||||
<title>Recorder</title>
|
<title>Recorder</title>
|
||||||
<xi:include href="xml/shell-recorder.xml"/>
|
<xi:include href="xml/shell-recorder.xml"/>
|
||||||
<xi:include href="xml/shell-recorder-src.xml"/>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter>
|
<chapter>
|
||||||
<title>Integration helpers and utilities</title>
|
<title>Integration helpers and utilities</title>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
NULL =
|
||||||
|
|
||||||
EXTRA_DIST = misc/config.js.in
|
EXTRA_DIST = misc/config.js.in
|
||||||
CLEANFILES = misc/config.js
|
CLEANFILES = misc/config.js
|
||||||
@@ -37,8 +38,6 @@ nobase_dist_js_DATA = \
|
|||||||
ui/altTab.js \
|
ui/altTab.js \
|
||||||
ui/appDisplay.js \
|
ui/appDisplay.js \
|
||||||
ui/appFavorites.js \
|
ui/appFavorites.js \
|
||||||
ui/automountManager.js \
|
|
||||||
ui/autorunManager.js \
|
|
||||||
ui/boxpointer.js \
|
ui/boxpointer.js \
|
||||||
ui/calendar.js \
|
ui/calendar.js \
|
||||||
ui/checkBox.js \
|
ui/checkBox.js \
|
||||||
@@ -47,15 +46,14 @@ nobase_dist_js_DATA = \
|
|||||||
ui/dateMenu.js \
|
ui/dateMenu.js \
|
||||||
ui/dnd.js \
|
ui/dnd.js \
|
||||||
ui/endSessionDialog.js \
|
ui/endSessionDialog.js \
|
||||||
ui/environment.js \
|
|
||||||
ui/extensionSystem.js \
|
ui/extensionSystem.js \
|
||||||
ui/extensionDownloader.js \
|
ui/extensionDownloader.js \
|
||||||
|
ui/environment.js \
|
||||||
ui/flashspot.js \
|
ui/flashspot.js \
|
||||||
ui/ibusCandidatePopup.js\
|
ui/ibusCandidatePopup.js\
|
||||||
ui/grabHelper.js \
|
ui/grabHelper.js \
|
||||||
ui/iconGrid.js \
|
ui/iconGrid.js \
|
||||||
ui/keyboard.js \
|
ui/keyboard.js \
|
||||||
ui/keyringPrompt.js \
|
|
||||||
ui/layout.js \
|
ui/layout.js \
|
||||||
ui/lightbox.js \
|
ui/lightbox.js \
|
||||||
ui/lookingGlass.js \
|
ui/lookingGlass.js \
|
||||||
@@ -64,7 +62,6 @@ nobase_dist_js_DATA = \
|
|||||||
ui/main.js \
|
ui/main.js \
|
||||||
ui/messageTray.js \
|
ui/messageTray.js \
|
||||||
ui/modalDialog.js \
|
ui/modalDialog.js \
|
||||||
ui/networkAgent.js \
|
|
||||||
ui/sessionMode.js \
|
ui/sessionMode.js \
|
||||||
ui/shellEntry.js \
|
ui/shellEntry.js \
|
||||||
ui/shellMountOperation.js \
|
ui/shellMountOperation.js \
|
||||||
@@ -72,9 +69,7 @@ nobase_dist_js_DATA = \
|
|||||||
ui/overview.js \
|
ui/overview.js \
|
||||||
ui/panel.js \
|
ui/panel.js \
|
||||||
ui/panelMenu.js \
|
ui/panelMenu.js \
|
||||||
ui/placeDisplay.js \
|
|
||||||
ui/pointerWatcher.js \
|
ui/pointerWatcher.js \
|
||||||
ui/polkitAuthenticationAgent.js \
|
|
||||||
ui/popupMenu.js \
|
ui/popupMenu.js \
|
||||||
ui/remoteSearch.js \
|
ui/remoteSearch.js \
|
||||||
ui/runDialog.js \
|
ui/runDialog.js \
|
||||||
@@ -85,11 +80,11 @@ nobase_dist_js_DATA = \
|
|||||||
ui/shellDBus.js \
|
ui/shellDBus.js \
|
||||||
ui/status/accessibility.js \
|
ui/status/accessibility.js \
|
||||||
ui/status/keyboard.js \
|
ui/status/keyboard.js \
|
||||||
|
ui/status/lockScreenMenu.js \
|
||||||
ui/status/network.js \
|
ui/status/network.js \
|
||||||
ui/status/power.js \
|
ui/status/power.js \
|
||||||
ui/status/volume.js \
|
ui/status/volume.js \
|
||||||
ui/status/bluetooth.js \
|
ui/status/bluetooth.js \
|
||||||
ui/telepathyClient.js \
|
|
||||||
ui/tweener.js \
|
ui/tweener.js \
|
||||||
ui/unlockDialog.js \
|
ui/unlockDialog.js \
|
||||||
ui/userMenu.js \
|
ui/userMenu.js \
|
||||||
@@ -101,4 +96,13 @@ nobase_dist_js_DATA = \
|
|||||||
ui/workspaceThumbnail.js \
|
ui/workspaceThumbnail.js \
|
||||||
ui/workspacesView.js \
|
ui/workspacesView.js \
|
||||||
ui/workspaceSwitcherPopup.js \
|
ui/workspaceSwitcherPopup.js \
|
||||||
ui/xdndHandler.js
|
ui/xdndHandler.js \
|
||||||
|
ui/components/__init__.js \
|
||||||
|
ui/components/autorunManager.js \
|
||||||
|
ui/components/automountManager.js \
|
||||||
|
ui/components/networkAgent.js \
|
||||||
|
ui/components/polkitAgent.js \
|
||||||
|
ui/components/recorder.js \
|
||||||
|
ui/components/telepathyClient.js \
|
||||||
|
ui/components/keyring.js \
|
||||||
|
$(NULL)
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ const Application = new Lang.Class({
|
|||||||
let renderer = new Gtk.CellRendererText();
|
let renderer = new Gtk.CellRendererText();
|
||||||
this._extensionSelector.pack_start(renderer, true);
|
this._extensionSelector.pack_start(renderer, true);
|
||||||
this._extensionSelector.add_attribute(renderer, 'text', 1);
|
this._extensionSelector.add_attribute(renderer, 'text', 1);
|
||||||
this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive), null);
|
this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive));
|
||||||
this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
|
this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
|
||||||
|
|
||||||
toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
|
toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
|
||||||
|
|||||||
@@ -19,8 +19,7 @@ function FprintManager() {
|
|||||||
g_interface_info: FprintManagerInfo,
|
g_interface_info: FprintManagerInfo,
|
||||||
g_name: 'net.reactivated.Fprint',
|
g_name: 'net.reactivated.Fprint',
|
||||||
g_object_path: '/net/reactivated/Fprint/Manager',
|
g_object_path: '/net/reactivated/Fprint/Manager',
|
||||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
|
||||||
|
|
||||||
self.init(null);
|
self.init(null);
|
||||||
return self;
|
return self;
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const Gio = imports.gi.Gio;
|
|||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
|
const Meta = imports.gi.Meta;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
@@ -38,12 +39,14 @@ const GdmUtil = imports.gdm.util;
|
|||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
const UserMenu = imports.ui.userMenu;
|
||||||
|
|
||||||
const _RESIZE_ANIMATION_TIME = 0.25;
|
const _RESIZE_ANIMATION_TIME = 0.25;
|
||||||
const _SCROLL_ANIMATION_TIME = 0.5;
|
const _SCROLL_ANIMATION_TIME = 0.5;
|
||||||
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
|
||||||
const _LOGO_ICON_NAME_SIZE = 48;
|
const _LOGO_ICON_HEIGHT = 16;
|
||||||
|
|
||||||
let _loginDialog = null;
|
let _loginDialog = null;
|
||||||
|
|
||||||
@@ -80,6 +83,36 @@ function _smoothlyResizeActor(actor, width, height) {
|
|||||||
return hold;
|
return hold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const LogoMenuButton = new Lang.Class({
|
||||||
|
Name: 'LogoMenuButton',
|
||||||
|
Extends: PanelMenu.Button,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent(0.0, null, true);
|
||||||
|
|
||||||
|
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||||
|
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
||||||
|
Lang.bind(this, this._updateLogo));
|
||||||
|
|
||||||
|
this._iconBin = new St.Bin();
|
||||||
|
this.actor.add_actor(this._iconBin);
|
||||||
|
|
||||||
|
this._updateLogo();
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateLogo: function() {
|
||||||
|
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
|
||||||
|
let icon = null;
|
||||||
|
|
||||||
|
if (path) {
|
||||||
|
let file = Gio.file_new_for_path(path);
|
||||||
|
let cache = St.TextureCache.get_default();
|
||||||
|
icon = cache.load_uri_async(file.get_uri(), -1, _LOGO_ICON_HEIGHT);
|
||||||
|
}
|
||||||
|
this._iconBin.set_child(icon);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const UserListItem = new Lang.Class({
|
const UserListItem = new Lang.Class({
|
||||||
Name: 'UserListItem',
|
Name: 'UserListItem',
|
||||||
|
|
||||||
@@ -96,14 +129,15 @@ const UserListItem = new Lang.Class({
|
|||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
|
|
||||||
this._iconBin = new St.Bin();
|
this._userAvatar = new UserMenu.UserAvatarWidget(this.user,
|
||||||
layout.add(this._iconBin);
|
{ styleClass: 'login-dialog-user-list-item-icon' });
|
||||||
|
layout.add(this._userAvatar.actor);
|
||||||
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
let textLayout = new St.BoxLayout({ style_class: 'login-dialog-user-list-item-text-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
layout.add(textLayout, { expand: true });
|
layout.add(textLayout, { expand: true });
|
||||||
|
|
||||||
this._nameLabel = new St.Label({ text: this.user.get_real_name(),
|
this._nameLabel = new St.Label({ style_class: 'login-dialog-user-list-item-name' });
|
||||||
style_class: 'login-dialog-user-list-item-name' });
|
this.actor.label_actor = this._nameLabel;
|
||||||
textLayout.add(this._nameLabel,
|
textLayout.add(this._nameLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.MIDDLE,
|
y_align: St.Align.MIDDLE,
|
||||||
@@ -117,63 +151,16 @@ const UserListItem = new Lang.Class({
|
|||||||
y_fill: false,
|
y_fill: false,
|
||||||
y_align: St.Align.END });
|
y_align: St.Align.END });
|
||||||
|
|
||||||
this._updateIcon();
|
|
||||||
this._updateLoggedIn();
|
|
||||||
|
|
||||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
|
this._onUserChanged();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUserChanged: function() {
|
_onUserChanged: function() {
|
||||||
this._nameLabel.set_text(this.user.get_real_name());
|
this._nameLabel.set_text(this.user.get_real_name());
|
||||||
this._updateIcon();
|
this._userAvatar.update();
|
||||||
this._updateLoggedIn();
|
this._updateLoggedIn();
|
||||||
},
|
},
|
||||||
|
|
||||||
_setIconFromFile: function(iconFile, styleClass) {
|
|
||||||
if (styleClass)
|
|
||||||
this._iconBin.set_style_class_name(styleClass);
|
|
||||||
this._iconBin.set_style(null);
|
|
||||||
|
|
||||||
this._iconBin.child = null;
|
|
||||||
if (iconFile) {
|
|
||||||
this._iconBin.show();
|
|
||||||
// We use background-image instead of, say, St.TextureCache
|
|
||||||
// so the theme writers can add a rounded frame around the image
|
|
||||||
// and so theme writers can pick the icon size.
|
|
||||||
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
|
||||||
'background-size: contain;');
|
|
||||||
} else {
|
|
||||||
this._iconBin.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_setIconFromName: function(iconName, styleClass) {
|
|
||||||
if (styleClass)
|
|
||||||
this._iconBin.set_style_class_name(styleClass);
|
|
||||||
this._iconBin.set_style(null);
|
|
||||||
|
|
||||||
if (iconName != null) {
|
|
||||||
let icon = new St.Icon();
|
|
||||||
icon.set_icon_name(iconName)
|
|
||||||
|
|
||||||
this._iconBin.child = icon;
|
|
||||||
this._iconBin.show();
|
|
||||||
} else {
|
|
||||||
this._iconBin.child = null;
|
|
||||||
this._iconBin.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateIcon: function() {
|
|
||||||
let iconFileName = this.user.get_icon_file();
|
|
||||||
let gicon = null;
|
|
||||||
|
|
||||||
if (GLib.file_test(iconFileName, GLib.FileTest.EXISTS))
|
|
||||||
this._setIconFromFile(iconFileName, 'login-dialog-user-list-item-icon');
|
|
||||||
else
|
|
||||||
this._setIconFromName('avatar-default', 'login-dialog-user-list-item-icon');
|
|
||||||
},
|
|
||||||
|
|
||||||
syncStyleClasses: function() {
|
syncStyleClasses: function() {
|
||||||
this._updateLoggedIn();
|
this._updateLoggedIn();
|
||||||
|
|
||||||
@@ -194,14 +181,6 @@ const UserListItem = new Lang.Class({
|
|||||||
this.emit('activate');
|
this.emit('activate');
|
||||||
},
|
},
|
||||||
|
|
||||||
fadeOutName: function() {
|
|
||||||
return GdmUtil.fadeOutActor(this._nameLabel);
|
|
||||||
},
|
|
||||||
|
|
||||||
fadeInName: function() {
|
|
||||||
return GdmUtil.fadeInActor(this._nameLabel);
|
|
||||||
},
|
|
||||||
|
|
||||||
showTimedLoginIndicator: function(time) {
|
showTimedLoginIndicator: function(time) {
|
||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
@@ -252,16 +231,18 @@ const UserList = new Lang.Class({
|
|||||||
if (global.stage.get_key_focus() != this.actor)
|
if (global.stage.get_key_focus() != this.actor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
let focusSet = this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
|
if (!focusSet) {
|
||||||
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||||
|
this._moveFocusToItems();
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_showItem: function(item) {
|
_showItem: function(item) {
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return GdmUtil.fadeInActor(item.actor);
|
return GdmUtil.fadeInActor(item.actor);
|
||||||
},
|
|
||||||
|
|
||||||
function() {
|
|
||||||
return item.fadeInName();
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
@@ -325,13 +306,16 @@ const UserList = new Lang.Class({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._box.remove_style_pseudo_class('expanded');
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this,
|
let batch = new Batch.ConsecutiveBatch(this,
|
||||||
[function() {
|
[function() {
|
||||||
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
return GdmUtil.fadeOutActor(this.actor.vscroll);
|
||||||
},
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, tasks)
|
new Batch.ConcurrentBatch(this, tasks),
|
||||||
|
|
||||||
|
function() {
|
||||||
|
this._box.remove_style_pseudo_class('expanded');
|
||||||
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return batch.run();
|
return batch.run();
|
||||||
@@ -381,7 +365,6 @@ const UserList = new Lang.Class({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this._box.add_style_pseudo_class('expanded');
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this,
|
let batch = new Batch.ConsecutiveBatch(this,
|
||||||
[function() {
|
[function() {
|
||||||
this.takeOverWhitespace();
|
this.takeOverWhitespace();
|
||||||
@@ -392,6 +375,10 @@ const UserList = new Lang.Class({
|
|||||||
return _smoothlyResizeActor(this._box, -1, fullHeight);
|
return _smoothlyResizeActor(this._box, -1, fullHeight);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
function() {
|
||||||
|
this._box.add_style_pseudo_class('expanded');
|
||||||
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, tasks),
|
new Batch.ConcurrentBatch(this, tasks),
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
@@ -517,6 +504,7 @@ const SessionListItem = new Lang.Class({
|
|||||||
|
|
||||||
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
|
let label = new St.Label({ style_class: 'login-dialog-session-list-item-label',
|
||||||
text: name });
|
text: name });
|
||||||
|
this.actor.label_actor = label;
|
||||||
|
|
||||||
this._box.add_actor(label);
|
this._box.add_actor(label);
|
||||||
},
|
},
|
||||||
@@ -671,8 +659,9 @@ const LoginDialog = new Lang.Class({
|
|||||||
_init: function(parentActor) {
|
_init: function(parentActor) {
|
||||||
this.parent({ shellReactive: true,
|
this.parent({ shellReactive: true,
|
||||||
styleClass: 'login-dialog',
|
styleClass: 'login-dialog',
|
||||||
parentActor: parentActor
|
parentActor: parentActor,
|
||||||
});
|
keybindingMode: Main.KeybindingMode.LOGIN_SCREEN,
|
||||||
|
shouldFadeIn: false });
|
||||||
this.connect('destroy',
|
this.connect('destroy',
|
||||||
Lang.bind(this, this._onDestroy));
|
Lang.bind(this, this._onDestroy));
|
||||||
this.connect('opened',
|
this.connect('opened',
|
||||||
@@ -681,6 +670,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._userManager = AccountsService.UserManager.get_default()
|
this._userManager = AccountsService.UserManager.get_default()
|
||||||
this._greeterClient = new Gdm.Client();
|
this._greeterClient = new Gdm.Client();
|
||||||
|
|
||||||
|
if (GLib.getenv('GDM_GREETER_TEST') != '1') {
|
||||||
this._greeter = this._greeterClient.get_greeter_sync(null);
|
this._greeter = this._greeterClient.get_greeter_sync(null);
|
||||||
|
|
||||||
this._greeter.connect('default-session-name-changed',
|
this._greeter.connect('default-session-name-changed',
|
||||||
@@ -690,27 +680,24 @@ const LoginDialog = new Lang.Class({
|
|||||||
Lang.bind(this, this._onSessionOpened));
|
Lang.bind(this, this._onSessionOpened));
|
||||||
this._greeter.connect('timed-login-requested',
|
this._greeter.connect('timed-login-requested',
|
||||||
Lang.bind(this, this._onTimedLoginRequested));
|
Lang.bind(this, this._onTimedLoginRequested));
|
||||||
|
}
|
||||||
|
|
||||||
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
|
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient);
|
||||||
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
|
this._userVerifier.connect('ask-question', Lang.bind(this, this._askQuestion));
|
||||||
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
|
||||||
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
this._userVerifier.connect('reset', Lang.bind(this, this._reset));
|
||||||
|
|
||||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
||||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
||||||
|
this._verifyingUser = false;
|
||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||||
|
|
||||||
this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
|
|
||||||
Lang.bind(this, this._updateLogo));
|
|
||||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
|
||||||
Lang.bind(this, this._updateBanner));
|
Lang.bind(this, this._updateBanner));
|
||||||
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
|
||||||
Lang.bind(this, this._updateBanner));
|
Lang.bind(this, this._updateBanner));
|
||||||
|
this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
|
||||||
this._logoBox = new St.Bin({ style_class: 'login-dialog-logo-box' });
|
Lang.bind(this, this._updateDisableUserList));
|
||||||
this.contentLayout.add(this._logoBox);
|
|
||||||
this._updateLogo();
|
|
||||||
|
|
||||||
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
|
this._bannerLabel = new St.Label({ style_class: 'login-dialog-banner',
|
||||||
text: '' });
|
text: '' });
|
||||||
@@ -718,20 +705,15 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._updateBanner();
|
this._updateBanner();
|
||||||
|
|
||||||
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
this._titleLabel = new St.Label({ style_class: 'login-dialog-title',
|
||||||
text: C_("title", "Sign In") });
|
text: C_("title", "Sign In"),
|
||||||
|
visible: false });
|
||||||
|
|
||||||
this.contentLayout.add(this._titleLabel,
|
this.contentLayout.add(this._titleLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
let mainContentBox = new St.BoxLayout({ vertical: false });
|
|
||||||
this.contentLayout.add(mainContentBox,
|
|
||||||
{ expand: true,
|
|
||||||
x_fill: true,
|
|
||||||
y_fill: false });
|
|
||||||
|
|
||||||
this._userList = new UserList();
|
this._userList = new UserList();
|
||||||
mainContentBox.add(this._userList.actor,
|
this.contentLayout.add(this._userList.actor,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: true });
|
y_fill: true });
|
||||||
@@ -740,15 +722,13 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
this._promptBox = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
mainContentBox.add(this._promptBox,
|
this.contentLayout.add(this._promptBox,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: true,
|
y_fill: true,
|
||||||
x_align: St.Align.START });
|
x_align: St.Align.START });
|
||||||
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
this._promptLabel = new St.Label({ style_class: 'login-dialog-prompt-label' });
|
||||||
|
|
||||||
this._mainContentBox = mainContentBox;
|
|
||||||
|
|
||||||
this._promptBox.add(this._promptLabel,
|
this._promptBox.add(this._promptLabel,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
@@ -756,11 +736,16 @@ const LoginDialog = new Lang.Class({
|
|||||||
x_align: St.Align.START });
|
x_align: St.Align.START });
|
||||||
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
||||||
can_focus: true });
|
can_focus: true });
|
||||||
|
this._promptEntryTextChangedId = 0;
|
||||||
this._promptBox.add(this._promptEntry,
|
this._promptBox.add(this._promptEntry,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
x_align: St.Align.START });
|
x_align: St.Align.START });
|
||||||
|
|
||||||
|
this._promptMessage = new St.Label({ visible: false });
|
||||||
|
this._promptBox.add(this._promptMessage, { x_fill: true });
|
||||||
|
|
||||||
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
|
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint-message' });
|
||||||
this._promptLoginHint.hide();
|
this._promptLoginHint.hide();
|
||||||
this._promptBox.add(this._promptLoginHint);
|
this._promptBox.add(this._promptLoginHint);
|
||||||
@@ -790,7 +775,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
|
|
||||||
this._notListedButton.connect('clicked', Lang.bind(this, this._onNotListedClicked));
|
this._notListedButton.connect('clicked', Lang.bind(this, this._hideUserListAndLogIn));
|
||||||
|
|
||||||
this.contentLayout.add(this._notListedButton,
|
this.contentLayout.add(this._notListedButton,
|
||||||
{ expand: false,
|
{ expand: false,
|
||||||
@@ -816,18 +801,19 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateLogo: function() {
|
_updateDisableUserList: function() {
|
||||||
this._logoBox.child = null;
|
let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY);
|
||||||
let path = this._settings.get_string(GdmUtil.LOGO_KEY);
|
|
||||||
|
|
||||||
if (path) {
|
// If this is the first time around, set initial focus
|
||||||
let file = Gio.file_new_for_path(path);
|
if (this._disableUserList == undefined && disableUserList)
|
||||||
let uri = file.get_uri();
|
this.setInitialKeyFocus(this._promptEntry);
|
||||||
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
if (disableUserList != this._disableUserList) {
|
||||||
this._logoBox.child = textureCache.load_uri_async(uri, -1, _LOGO_ICON_NAME_SIZE);
|
this._disableUserList = disableUserList;
|
||||||
|
|
||||||
|
if (!this._verifyingUser)
|
||||||
|
this._reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateBanner: function() {
|
_updateBanner: function() {
|
||||||
@@ -842,36 +828,31 @@ const LoginDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function(client, serviceName) {
|
_reset: function() {
|
||||||
let tasks = [this._hidePrompt,
|
this._promptMessage.hide();
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
|
||||||
this._fadeInNotListedButton,
|
|
||||||
this._fadeInLogo]),
|
|
||||||
|
|
||||||
function() {
|
|
||||||
this._sessionList.close();
|
|
||||||
this._promptLoginHint.hide();
|
|
||||||
this._userList.actor.show();
|
|
||||||
this._userList.actor.opacity = 255;
|
|
||||||
return this._userList.showItems();
|
|
||||||
},
|
|
||||||
|
|
||||||
function() {
|
|
||||||
this._userList.actor.reactive = true;
|
|
||||||
this._userList.actor.grab_key_focus();
|
|
||||||
}];
|
|
||||||
|
|
||||||
this._user = null;
|
this._user = null;
|
||||||
|
this._verifyingUser = false;
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
if (this._disableUserList)
|
||||||
batch.run();
|
this._hideUserListAndLogIn();
|
||||||
|
else
|
||||||
|
this._showUserList();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDefaultSessionChanged: function(client, sessionId) {
|
_onDefaultSessionChanged: function(client, sessionId) {
|
||||||
this._sessionList.setActiveSession(sessionId);
|
this._sessionList.setActiveSession(sessionId);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showMessage: function(userVerifier, message, styleClass) {
|
||||||
|
if (message) {
|
||||||
|
this._promptMessage.text = message;
|
||||||
|
this._promptMessage.styleClass = styleClass;
|
||||||
|
GdmUtil.fadeInActor(this._promptMessage);
|
||||||
|
} else {
|
||||||
|
GdmUtil.fadeOutActor(this._promptMessage);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_showLoginHint: function(verifier, message) {
|
_showLoginHint: function(verifier, message) {
|
||||||
this._promptLoginHint.set_text(message)
|
this._promptLoginHint.set_text(message)
|
||||||
GdmUtil.fadeInActor(this._promptLoginHint);
|
GdmUtil.fadeInActor(this._promptLoginHint);
|
||||||
@@ -910,6 +891,9 @@ const LoginDialog = new Lang.Class({
|
|||||||
if (this._user && this._user.is_logged_in())
|
if (this._user && this._user.is_logged_in())
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if (!this._verifyingUser)
|
||||||
|
return null;
|
||||||
|
|
||||||
return GdmUtil.fadeInActor(this._sessionList.actor);
|
return GdmUtil.fadeInActor(this._sessionList.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -922,26 +906,21 @@ const LoginDialog = new Lang.Class({
|
|||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
|
|
||||||
_showPrompt: function() {
|
_showPrompt: function(forSecret) {
|
||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
let buttons = [{ action: Lang.bind(this, this.cancel),
|
let cancelButtonInfo = { action: Lang.bind(this, this.cancel),
|
||||||
label: _("Cancel"),
|
label: _("Cancel"),
|
||||||
key: Clutter.Escape },
|
key: Clutter.Escape };
|
||||||
{ action: Lang.bind(this, function() {
|
let okButtonInfo = { action: Lang.bind(this, function() {
|
||||||
hold.release();
|
hold.release();
|
||||||
}),
|
}),
|
||||||
label: C_("button", "Sign In"),
|
label: forSecret ? C_("button", "Sign In") : _("Next"),
|
||||||
default: true }];
|
default: true };
|
||||||
|
let buttons = [];
|
||||||
this._promptEntryActivateCallbackId = this._promptEntry.clutter_text.connect('activate',
|
if (!this._disableUserList || this._verifyingUser)
|
||||||
Lang.bind(this, function() {
|
buttons.push(cancelButtonInfo);
|
||||||
hold.release();
|
buttons.push(okButtonInfo);
|
||||||
}));
|
|
||||||
hold.connect('release', Lang.bind(this, function() {
|
|
||||||
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
|
|
||||||
this._promptEntryActivateCallbackId = null;
|
|
||||||
}));
|
|
||||||
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return this._fadeInPrompt();
|
return this._fadeInPrompt();
|
||||||
@@ -949,6 +928,16 @@ const LoginDialog = new Lang.Class({
|
|||||||
|
|
||||||
function() {
|
function() {
|
||||||
this.setButtons(buttons);
|
this.setButtons(buttons);
|
||||||
|
|
||||||
|
let updateOkButtonEnabled = Lang.bind(this, function() {
|
||||||
|
let sensitive = this._promptEntry.text.length > 0;
|
||||||
|
okButtonInfo.button.reactive = sensitive;
|
||||||
|
okButtonInfo.button.can_focus = sensitive;
|
||||||
|
});
|
||||||
|
|
||||||
|
updateOkButtonEnabled();
|
||||||
|
|
||||||
|
this._promptEntryTextChangedId = this._promptEntry.clutter_text.connect('text-changed', updateOkButtonEnabled);
|
||||||
},
|
},
|
||||||
|
|
||||||
hold];
|
hold];
|
||||||
@@ -959,13 +948,13 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_hidePrompt: function() {
|
_hidePrompt: function() {
|
||||||
if (this._promptEntryActivateCallbackId) {
|
|
||||||
this._promptEntry.clutter_text.disconnect(this._promptEntryActivateCallbackId);
|
|
||||||
this._promptEntryActivateCallbackId = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setButtons([]);
|
this.setButtons([]);
|
||||||
|
|
||||||
|
if (this._promptEntryTextChangedId > 0) {
|
||||||
|
this._promptEntry.clutter_text.disconnect(this._promptEntryTextChangedId);
|
||||||
|
this._promptEntryTextChangedId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return GdmUtil.fadeOutActor(this._promptBox);
|
return GdmUtil.fadeOutActor(this._promptBox);
|
||||||
},
|
},
|
||||||
@@ -987,7 +976,9 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._promptEntry.set_text('');
|
this._promptEntry.set_text('');
|
||||||
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
||||||
|
|
||||||
let tasks = [this._showPrompt,
|
let tasks = [function() {
|
||||||
|
return this._showPrompt(!!passwordChar);
|
||||||
|
},
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
let _text = this._promptEntry.get_text();
|
let _text = this._promptEntry.get_text();
|
||||||
@@ -999,6 +990,23 @@ const LoginDialog = new Lang.Class({
|
|||||||
return batch.run();
|
return batch.run();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_askForUsernameAndLogIn: function() {
|
||||||
|
this._promptLabel.set_text(_("Username: "));
|
||||||
|
this._promptEntry.set_text('');
|
||||||
|
this._promptEntry.clutter_text.set_password_char('');
|
||||||
|
|
||||||
|
let tasks = [this._showPrompt,
|
||||||
|
|
||||||
|
function() {
|
||||||
|
let userName = this._promptEntry.get_text();
|
||||||
|
this._promptEntry.reactive = false;
|
||||||
|
return this._beginVerificationForUser(userName);
|
||||||
|
}];
|
||||||
|
|
||||||
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
|
return batch.run();
|
||||||
|
},
|
||||||
|
|
||||||
_onSessionOpened: function(client, serviceName) {
|
_onSessionOpened: function(client, serviceName) {
|
||||||
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
|
||||||
},
|
},
|
||||||
@@ -1127,11 +1135,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onVerificationFailed: function() {
|
_hideUserListAndLogIn: function() {
|
||||||
this._userVerifier.cancel();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onNotListedClicked: function(user) {
|
|
||||||
let tasks = [function() {
|
let tasks = [function() {
|
||||||
return this._userList.hideItems();
|
return this._userList.hideItems();
|
||||||
},
|
},
|
||||||
@@ -1145,26 +1149,37 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||||
this._fadeOutNotListedButton,
|
this._fadeOutNotListedButton]),
|
||||||
this._fadeOutLogo]),
|
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
let hold = new Batch.Hold();
|
return this._askForUsernameAndLogIn();
|
||||||
|
|
||||||
this._userVerifier.begin(null, hold);
|
|
||||||
return hold;
|
|
||||||
}];
|
}];
|
||||||
|
|
||||||
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
batch.run();
|
batch.run();
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInLogo: function() {
|
_showUserList: function() {
|
||||||
return GdmUtil.fadeInActor(this._logoBox);
|
let tasks = [this._hidePrompt,
|
||||||
|
|
||||||
|
new Batch.ConcurrentBatch(this, [this._fadeInTitleLabel,
|
||||||
|
this._fadeInNotListedButton]),
|
||||||
|
|
||||||
|
function() {
|
||||||
|
this._sessionList.close();
|
||||||
|
this._promptLoginHint.hide();
|
||||||
|
this._userList.actor.show();
|
||||||
|
this._userList.actor.opacity = 255;
|
||||||
|
return this._userList.showItems();
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOutLogo: function() {
|
function() {
|
||||||
return GdmUtil.fadeOutActor(this._logoBox);
|
this._userList.actor.reactive = true;
|
||||||
|
this._userList.actor.grab_key_focus();
|
||||||
|
}];
|
||||||
|
|
||||||
|
let batch = new Batch.ConsecutiveBatch(this, tasks);
|
||||||
|
batch.run();
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeInBanner: function() {
|
_fadeInBanner: function() {
|
||||||
@@ -1195,6 +1210,7 @@ const LoginDialog = new Lang.Class({
|
|||||||
let hold = new Batch.Hold();
|
let hold = new Batch.Hold();
|
||||||
|
|
||||||
this._userVerifier.begin(userName, hold);
|
this._userVerifier.begin(userName, hold);
|
||||||
|
this._verifyingUser = true;
|
||||||
return hold;
|
return hold;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1214,13 +1230,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
return this._userList.giveUpWhitespace();
|
return this._userList.giveUpWhitespace();
|
||||||
},
|
},
|
||||||
|
|
||||||
function() {
|
|
||||||
return activatedItem.fadeOutName();
|
|
||||||
},
|
|
||||||
|
|
||||||
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
new Batch.ConcurrentBatch(this, [this._fadeOutTitleLabel,
|
||||||
this._fadeOutNotListedButton,
|
this._fadeOutNotListedButton]),
|
||||||
this._fadeOutLogo]),
|
|
||||||
|
|
||||||
function() {
|
function() {
|
||||||
return this._userList.shrinkToNaturalHeight();
|
return this._userList.shrinkToNaturalHeight();
|
||||||
@@ -1252,6 +1263,8 @@ const LoginDialog = new Lang.Class({
|
|||||||
this._userList.addUser(users[i]);
|
this._userList.addUser(users[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._updateDisableUserList();
|
||||||
|
|
||||||
this._userManager.connect('user-added',
|
this._userManager.connect('user-added',
|
||||||
Lang.bind(this, function(userManager, user) {
|
Lang.bind(this, function(userManager, user) {
|
||||||
this._userList.addUser(user);
|
this._userList.addUser(user);
|
||||||
@@ -1273,9 +1286,9 @@ const LoginDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onOpened: function() {
|
_onOpened: function() {
|
||||||
Main.ctrlAltTabManager.addGroup(this._mainContentBox,
|
Main.ctrlAltTabManager.addGroup(this.dialogLayout,
|
||||||
_("Login Window"),
|
_("Login Window"),
|
||||||
'dialog-password',
|
'dialog-password-symbolic',
|
||||||
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
|
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -1283,6 +1296,6 @@ const LoginDialog = new Lang.Class({
|
|||||||
close: function() {
|
close: function() {
|
||||||
this.parent();
|
this.parent();
|
||||||
|
|
||||||
Main.ctrlAltTabManager.removeGroup(this._group);
|
Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,11 +18,12 @@
|
|||||||
* 02111-1307, USA.
|
* 02111-1307, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const UPowerGlib = imports.gi.UPowerGlib;
|
|
||||||
|
|
||||||
const LoginManager = imports.misc.loginManager;
|
const LoginManager = imports.misc.loginManager;
|
||||||
|
|
||||||
|
const GdmUtil = imports.gdm.util;
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
|
||||||
@@ -31,16 +32,16 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('system-shutdown', null);
|
/* Translators: accessible name of the power menu in the login screen */
|
||||||
this._upClient = new UPowerGlib.Client();
|
this.parent('system-shutdown-symbolic', _("Power"));
|
||||||
|
|
||||||
this._loginManager = LoginManager.getLoginManager();
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
|
|
||||||
this._createSubMenu();
|
this._settings = new Gio.Settings({ schema: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||||
|
this._settings.connect('changed::disable-restart-buttons',
|
||||||
|
Lang.bind(this, this._updateVisibility));
|
||||||
|
|
||||||
this._upClient.connect('notify::can-suspend',
|
this._createSubMenu();
|
||||||
Lang.bind(this, this._updateHaveSuspend));
|
|
||||||
this._updateHaveSuspend();
|
|
||||||
|
|
||||||
// ConsoleKit doesn't send notifications when shutdown/reboot
|
// ConsoleKit doesn't send notifications when shutdown/reboot
|
||||||
// are disabled, so we update the menu item each time the menu opens
|
// are disabled, so we update the menu item each time the menu opens
|
||||||
@@ -49,15 +50,17 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
if (open) {
|
if (open) {
|
||||||
this._updateHaveShutdown();
|
this._updateHaveShutdown();
|
||||||
this._updateHaveRestart();
|
this._updateHaveRestart();
|
||||||
|
this._updateHaveSuspend();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
this._updateHaveShutdown();
|
this._updateHaveShutdown();
|
||||||
this._updateHaveRestart();
|
this._updateHaveRestart();
|
||||||
|
this._updateHaveSuspend();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
let shouldBeVisible = (this._haveSuspend || this._haveShutdown || this._haveRestart);
|
let shouldBeVisible = (this._haveSuspend || this._haveShutdown || this._haveRestart);
|
||||||
this.actor.visible = shouldBeVisible;
|
this.actor.visible = shouldBeVisible && !this._settings.get_boolean('disable-restart-buttons');
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveShutdown: function() {
|
_updateHaveShutdown: function() {
|
||||||
@@ -77,9 +80,11 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveSuspend: function() {
|
_updateHaveSuspend: function() {
|
||||||
this._haveSuspend = this._upClient.get_can_suspend();
|
this._loginManager.canSuspend(Lang.bind(this, function(result) {
|
||||||
|
this._haveSuspend = result;
|
||||||
this._suspendItem.actor.visible = this._haveSuspend;
|
this._suspendItem.actor.visible = this._haveSuspend;
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_createSubMenu: function() {
|
_createSubMenu: function() {
|
||||||
@@ -102,8 +107,10 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onActivateSuspend: function() {
|
_onActivateSuspend: function() {
|
||||||
if (this._haveSuspend)
|
if (!this._haveSuspend)
|
||||||
this._upClient.suspend_sync(null);
|
return;
|
||||||
|
|
||||||
|
this._loginManager.suspend();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivateRestart: function() {
|
_onActivateRestart: function() {
|
||||||
|
|||||||
124
js/gdm/util.js
124
js/gdm/util.js
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Batch = imports.gdm.batch;
|
const Batch = imports.gdm.batch;
|
||||||
@@ -19,8 +20,10 @@ const LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
|
|||||||
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
const FINGERPRINT_AUTHENTICATION_KEY = 'enable-fingerprint-authentication';
|
||||||
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
const BANNER_MESSAGE_KEY = 'banner-message-enable';
|
||||||
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
const BANNER_MESSAGE_TEXT_KEY = 'banner-message-text';
|
||||||
|
const ALLOWED_FAILURES_KEY = 'allowed-failures';
|
||||||
|
|
||||||
const LOGO_KEY = 'logo';
|
const LOGO_KEY = 'logo';
|
||||||
|
const DISABLE_USER_LIST_KEY = 'disable-user-list';
|
||||||
|
|
||||||
function fadeInActor(actor) {
|
function fadeInActor(actor) {
|
||||||
if (actor.opacity == 255 && actor.visible)
|
if (actor.opacity == 255 && actor.visible)
|
||||||
@@ -79,18 +82,19 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
|
|
||||||
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
this._settings = new Gio.Settings({ schema: LOGIN_SCREEN_SCHEMA });
|
||||||
|
|
||||||
this._cancellable = new Gio.Cancellable();
|
|
||||||
|
|
||||||
this._fprintManager = new Fprint.FprintManager();
|
this._fprintManager = new Fprint.FprintManager();
|
||||||
this._checkForFingerprintReader();
|
|
||||||
|
|
||||||
this._realmManager = new Realmd.Manager();
|
this._realmManager = new Realmd.Manager();
|
||||||
|
|
||||||
|
this._failCounter = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
begin: function(userName, hold) {
|
begin: function(userName, hold) {
|
||||||
|
this._cancellable = new Gio.Cancellable();
|
||||||
this._hold = hold;
|
this._hold = hold;
|
||||||
this._userName = userName;
|
this._userName = userName;
|
||||||
|
|
||||||
|
this._checkForFingerprintReader();
|
||||||
|
|
||||||
if (userName) {
|
if (userName) {
|
||||||
// If possible, reauthenticate an already running session,
|
// If possible, reauthenticate an already running session,
|
||||||
// so any session specific credentials get updated appropriately
|
// so any session specific credentials get updated appropriately
|
||||||
@@ -102,6 +106,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
|
if (this._cancellable)
|
||||||
this._cancellable.cancel();
|
this._cancellable.cancel();
|
||||||
|
|
||||||
if (this._userVerifier)
|
if (this._userVerifier)
|
||||||
@@ -109,7 +114,10 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
clear: function() {
|
clear: function() {
|
||||||
|
if (this._cancellable) {
|
||||||
this._cancellable.cancel();
|
this._cancellable.cancel();
|
||||||
|
this._cancellable = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (this._userVerifier) {
|
if (this._userVerifier) {
|
||||||
this._userVerifier.run_dispose();
|
this._userVerifier.run_dispose();
|
||||||
@@ -118,6 +126,9 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
answerQuery: function(serviceName, answer) {
|
answerQuery: function(serviceName, answer) {
|
||||||
|
// Clear any previous message
|
||||||
|
this.emit('show-message', null, null);
|
||||||
|
|
||||||
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -134,34 +145,48 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_reportInitError: function(where, error) {
|
||||||
|
logError(error, where);
|
||||||
|
this._hold.release();
|
||||||
|
|
||||||
|
this.emit('show-message', _("Authentication error"), 'login-dialog-message-warning');
|
||||||
|
this._verificationFailed(false);
|
||||||
|
},
|
||||||
|
|
||||||
_reauthenticationChannelOpened: function(client, result) {
|
_reauthenticationChannelOpened: function(client, result) {
|
||||||
try {
|
try {
|
||||||
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
||||||
this._connectSignals();
|
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||||
this._beginVerification();
|
return;
|
||||||
|
} catch(e if e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
|
||||||
this._hold.release();
|
!this._reauthOnly) {
|
||||||
|
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there is
|
||||||
|
// no session to reauthenticate. Fall back to performing verification
|
||||||
|
// from this login session
|
||||||
|
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
||||||
|
return;
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
if (this._reauthOnly) {
|
this._reportInitError('Failed to open reauthentication channel', e);
|
||||||
logError(e, 'Failed to open reauthentication channel');
|
|
||||||
|
|
||||||
this._hold.release();
|
|
||||||
this.emit('verification-failed');
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no session running, or it otherwise fails, then fall back
|
this._connectSignals();
|
||||||
// to performing verification from this login session
|
this._beginVerification();
|
||||||
client.get_user_verifier(this._cancellable, Lang.bind(this, this._userVerifierGot));
|
this._hold.release();
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_userVerifierGot: function(client, result) {
|
_userVerifierGot: function(client, result) {
|
||||||
|
try {
|
||||||
this._userVerifier = client.get_user_verifier_finish(result);
|
this._userVerifier = client.get_user_verifier_finish(result);
|
||||||
|
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||||
|
return;
|
||||||
|
} catch(e) {
|
||||||
|
this._reportInitError('Failed to obtain user verifier', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._connectSignals();
|
this._connectSignals();
|
||||||
this._beginVerification();
|
this._beginVerification();
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -183,7 +208,15 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userName,
|
this._userName,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
|
try {
|
||||||
obj.call_begin_verification_for_user_finish(result);
|
obj.call_begin_verification_for_user_finish(result);
|
||||||
|
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||||
|
return;
|
||||||
|
} catch(e) {
|
||||||
|
this._reportInitError('Failed to start verification for user', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -194,7 +227,15 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userName,
|
this._userName,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
|
try {
|
||||||
obj.call_begin_verification_for_user_finish(result);
|
obj.call_begin_verification_for_user_finish(result);
|
||||||
|
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||||
|
return;
|
||||||
|
} catch(e) {
|
||||||
|
this._reportInitError('Failed to start fingerprint verification for user', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -202,7 +243,15 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
this._userVerifier.call_begin_verification(PASSWORD_SERVICE_NAME,
|
||||||
this._cancellable,
|
this._cancellable,
|
||||||
Lang.bind(this, function(obj, result) {
|
Lang.bind(this, function(obj, result) {
|
||||||
|
try {
|
||||||
obj.call_begin_verification_finish(result);
|
obj.call_begin_verification_finish(result);
|
||||||
|
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||||
|
return;
|
||||||
|
} catch(e) {
|
||||||
|
this._reportInitError('Failed to start verification', e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._hold.release();
|
this._hold.release();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@@ -219,7 +268,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
// to indicate the user can swipe their finger instead
|
// to indicate the user can swipe their finger instead
|
||||||
this.emit('show-login-hint', _("(or swipe finger)"));
|
this.emit('show-login-hint', _("(or swipe finger)"));
|
||||||
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
} else if (serviceName == PASSWORD_SERVICE_NAME) {
|
||||||
Main.notifyError(info);
|
this.emit('show-message', info, 'login-dialog-message-info');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -228,7 +277,7 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
// users who haven't enrolled their fingerprint.
|
// users who haven't enrolled their fingerprint.
|
||||||
if (serviceName != PASSWORD_SERVICE_NAME)
|
if (serviceName != PASSWORD_SERVICE_NAME)
|
||||||
return;
|
return;
|
||||||
Main.notifyError(problem);
|
this.emit('show-message', problem, 'login-dialog-message-warning');
|
||||||
},
|
},
|
||||||
|
|
||||||
_showRealmLoginHint: function() {
|
_showRealmLoginHint: function() {
|
||||||
@@ -267,10 +316,10 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onReset: function() {
|
_onReset: function() {
|
||||||
this._userVerifier.run_dispose();
|
this.clear();
|
||||||
this._userVerifier = null;
|
|
||||||
|
|
||||||
this._checkForFingerprintReader();
|
// Clear previous attempts to authenticate
|
||||||
|
this._failCounter = 0;
|
||||||
|
|
||||||
this.emit('reset');
|
this.emit('reset');
|
||||||
},
|
},
|
||||||
@@ -279,12 +328,37 @@ const ShellUserVerifier = new Lang.Class({
|
|||||||
this.emit('verification-complete');
|
this.emit('verification-complete');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_verificationFailed: function(retry) {
|
||||||
|
// For Not Listed / enterprise logins, immediately reset
|
||||||
|
// the dialog
|
||||||
|
// Otherwise, we allow ALLOWED_FAILURES attempts. After that, we
|
||||||
|
// go back to the welcome screen.
|
||||||
|
|
||||||
|
this._failCounter++;
|
||||||
|
let canRetry = retry && this._userName &&
|
||||||
|
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY);
|
||||||
|
|
||||||
|
if (canRetry) {
|
||||||
|
this.clear();
|
||||||
|
this.begin(this._userName, new Batch.Hold());
|
||||||
|
} else {
|
||||||
|
// Allow some time to see the message, then reset everything
|
||||||
|
Mainloop.timeout_add(3000, Lang.bind(this, function() {
|
||||||
|
this.cancel();
|
||||||
|
|
||||||
|
this._onReset();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.emit('verification-failed');
|
||||||
|
},
|
||||||
|
|
||||||
_onConversationStopped: function(client, serviceName) {
|
_onConversationStopped: function(client, serviceName) {
|
||||||
// if the password service fails, then cancel everything.
|
// if the password service fails, then cancel everything.
|
||||||
// But if, e.g., fingerprint fails, still give
|
// But if, e.g., fingerprint fails, still give
|
||||||
// password authentication a chance to succeed
|
// password authentication a chance to succeed
|
||||||
if (serviceName == PASSWORD_SERVICE_NAME) {
|
if (serviceName == PASSWORD_SERVICE_NAME) {
|
||||||
this.emit('verification-failed');
|
this._verificationFailed(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.emit('hide-login-hint');
|
this.emit('hide-login-hint');
|
||||||
|
|||||||
@@ -120,11 +120,6 @@ function createExtensionObject(uuid, dir, type) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encourage people to add this
|
|
||||||
if (!meta.url) {
|
|
||||||
log('Warning: Missing "url" property in %s/metadata.json'.format(uuid));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uuid != meta.uuid) {
|
if (uuid != meta.uuid) {
|
||||||
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
||||||
}
|
}
|
||||||
@@ -161,6 +156,7 @@ const ExtensionFinder = new Lang.Class({
|
|||||||
try {
|
try {
|
||||||
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
|
if (e.domain != Gio.io_error_quark() || e.code != Gio.IOErrorEnum.NOT_FOUND)
|
||||||
logError(e, 'Could not enumerate extensions directory');
|
logError(e, 'Could not enumerate extensions directory');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,24 +41,26 @@ const HistoryManager = new Lang.Class({
|
|||||||
this._historyIndex = this._history.length;
|
this._historyIndex = this._history.length;
|
||||||
},
|
},
|
||||||
|
|
||||||
prevItem: function(text) {
|
_setPrevItem: function(text) {
|
||||||
if (this._historyIndex <= 0)
|
if (this._historyIndex <= 0)
|
||||||
return text;
|
return false;
|
||||||
|
|
||||||
if (text)
|
if (text)
|
||||||
this._history[this._historyIndex] = text;
|
this._history[this._historyIndex] = text;
|
||||||
this._historyIndex--;
|
this._historyIndex--;
|
||||||
return this._indexChanged();
|
this._indexChanged();
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
nextItem: function(text) {
|
_setNextItem: function(text) {
|
||||||
if (this._historyIndex >= this._history.length)
|
if (this._historyIndex >= this._history.length)
|
||||||
return text;
|
return false;
|
||||||
|
|
||||||
if (text)
|
if (text)
|
||||||
this._history[this._historyIndex] = text;
|
this._history[this._historyIndex] = text;
|
||||||
this._historyIndex++;
|
this._historyIndex++;
|
||||||
return this._indexChanged();
|
this._indexChanged();
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
lastItem: function() {
|
lastItem: function() {
|
||||||
@@ -83,11 +85,9 @@ const HistoryManager = new Lang.Class({
|
|||||||
_onEntryKeyPress: function(entry, event) {
|
_onEntryKeyPress: function(entry, event) {
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
if (symbol == Clutter.KEY_Up) {
|
if (symbol == Clutter.KEY_Up) {
|
||||||
this.prevItem(entry.get_text());
|
return this._setPrevItem(entry.get_text());
|
||||||
return true;
|
|
||||||
} else if (symbol == Clutter.KEY_Down) {
|
} else if (symbol == Clutter.KEY_Down) {
|
||||||
this.nextItem(entry.get_text());
|
return this._setNextItem(entry.get_text());
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
@@ -98,8 +98,6 @@ const HistoryManager = new Lang.Class({
|
|||||||
|
|
||||||
if (this._entry)
|
if (this._entry)
|
||||||
this._entry.set_text(current);
|
this._entry.set_text(current);
|
||||||
|
|
||||||
return current;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_save: function() {
|
_save: function() {
|
||||||
|
|||||||
@@ -3,7 +3,9 @@
|
|||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
|
const UPowerGlib = imports.gi.UPowerGlib;
|
||||||
|
|
||||||
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
||||||
<method name='PowerOff'>
|
<method name='PowerOff'>
|
||||||
@@ -12,12 +14,18 @@ const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager
|
|||||||
<method name='Reboot'>
|
<method name='Reboot'>
|
||||||
<arg type='b' direction='in'/>
|
<arg type='b' direction='in'/>
|
||||||
</method>
|
</method>
|
||||||
|
<method name='Suspend'>
|
||||||
|
<arg type='b' direction='in'/>
|
||||||
|
</method>
|
||||||
<method name='CanPowerOff'>
|
<method name='CanPowerOff'>
|
||||||
<arg type='s' direction='out'/>
|
<arg type='s' direction='out'/>
|
||||||
</method>
|
</method>
|
||||||
<method name='CanReboot'>
|
<method name='CanReboot'>
|
||||||
<arg type='s' direction='out'/>
|
<arg type='s' direction='out'/>
|
||||||
</method>
|
</method>
|
||||||
|
<method name='CanSuspend'>
|
||||||
|
<arg type='s' direction='out'/>
|
||||||
|
</method>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
|
const SystemdLoginSessionIface = <interface name='org.freedesktop.login1.Session'>
|
||||||
@@ -123,12 +131,25 @@ const LoginManagerSystemd = new Lang.Class({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
canSuspend: function(asyncCallback) {
|
||||||
|
this._proxy.CanSuspendRemote(function(result, error) {
|
||||||
|
if (error)
|
||||||
|
asyncCallback(false);
|
||||||
|
else
|
||||||
|
asyncCallback(result[0] != 'no');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
powerOff: function() {
|
powerOff: function() {
|
||||||
this._proxy.PowerOffRemote(true);
|
this._proxy.PowerOffRemote(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
reboot: function() {
|
reboot: function() {
|
||||||
this._proxy.RebootRemote(true);
|
this._proxy.RebootRemote(true);
|
||||||
|
},
|
||||||
|
|
||||||
|
suspend: function() {
|
||||||
|
this._proxy.SuspendRemote(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -139,6 +160,7 @@ const LoginManagerConsoleKit = new Lang.Class({
|
|||||||
this._proxy = new ConsoleKitManager(Gio.DBus.system,
|
this._proxy = new ConsoleKitManager(Gio.DBus.system,
|
||||||
'org.freedesktop.ConsoleKit',
|
'org.freedesktop.ConsoleKit',
|
||||||
'/org/freedesktop/ConsoleKit/Manager');
|
'/org/freedesktop/ConsoleKit/Manager');
|
||||||
|
this._upClient = new UPowerGlib.Client();
|
||||||
},
|
},
|
||||||
|
|
||||||
// Having this function is a bit of a hack since the Systemd and ConsoleKit
|
// Having this function is a bit of a hack since the Systemd and ConsoleKit
|
||||||
@@ -186,12 +208,22 @@ const LoginManagerConsoleKit = new Lang.Class({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
canSuspend: function(asyncCallback) {
|
||||||
|
Mainloop.idle_add(Lang.bind(this, function() {
|
||||||
|
asyncCallback(this._upClient.get_can_suspend());
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
powerOff: function() {
|
powerOff: function() {
|
||||||
this._proxy.StopRemote();
|
this._proxy.StopRemote();
|
||||||
},
|
},
|
||||||
|
|
||||||
reboot: function() {
|
reboot: function() {
|
||||||
this._proxy.RestartRemote();
|
this._proxy.RestartRemote();
|
||||||
}
|
},
|
||||||
|
|
||||||
|
suspend: function() {
|
||||||
|
this._upClient.suspend_sync(null);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -46,8 +46,70 @@ let _providersTable;
|
|||||||
function _getProvidersTable() {
|
function _getProvidersTable() {
|
||||||
if (_providersTable)
|
if (_providersTable)
|
||||||
return _providersTable;
|
return _providersTable;
|
||||||
let [providers, countryCodes] = Shell.mobile_providers_parse();
|
return _providersTable = Shell.mobile_providers_parse(null,null);
|
||||||
return _providersTable = providers;
|
}
|
||||||
|
|
||||||
|
function findProviderForMCCMNC(table, needle) {
|
||||||
|
let needlemcc = needle.substring(0, 3);
|
||||||
|
let needlemnc = needle.substring(3, needle.length);
|
||||||
|
|
||||||
|
let name2, name3;
|
||||||
|
for (let iter in table) {
|
||||||
|
let country = table[iter];
|
||||||
|
let providers = country.get_providers();
|
||||||
|
|
||||||
|
// Search through each country's providers
|
||||||
|
for (let i = 0; i < providers.length; i++) {
|
||||||
|
let provider = providers[i];
|
||||||
|
|
||||||
|
// Search through MCC/MNC list
|
||||||
|
let list = provider.get_gsm_mcc_mnc();
|
||||||
|
for (let j = 0; j < list.length; j++) {
|
||||||
|
let mccmnc = list[j];
|
||||||
|
|
||||||
|
// Match both 2-digit and 3-digit MNC; prefer a
|
||||||
|
// 3-digit match if found, otherwise a 2-digit one.
|
||||||
|
if (mccmnc.mcc != needlemcc)
|
||||||
|
continue; // MCC was wrong
|
||||||
|
|
||||||
|
if (!name3 && needle.length == 6 && needlemnc == mccmnc.mnc)
|
||||||
|
name3 = provider.name;
|
||||||
|
|
||||||
|
if (!name2 && needlemnc.substring(0, 2) == mccmnc.mnc.substring(0, 2))
|
||||||
|
name2 = provider.name;
|
||||||
|
|
||||||
|
if (name2 && name3)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return name3 || name2 || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findProviderForSid(table, sid) {
|
||||||
|
if (sid == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Search through each country
|
||||||
|
for (let iter in table) {
|
||||||
|
let country = table[iter];
|
||||||
|
let providers = country.get_providers();
|
||||||
|
|
||||||
|
// Search through each country's providers
|
||||||
|
for (let i = 0; i < providers.length; i++) {
|
||||||
|
let provider = providers[i];
|
||||||
|
let cdma_sid = provider.get_cdma_sid();
|
||||||
|
|
||||||
|
// Search through CDMA SID list
|
||||||
|
for (let j = 0; j < cdma_sid.length; j++) {
|
||||||
|
if (cdma_sid[j] == sid)
|
||||||
|
return provider.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ModemGsm = new Lang.Class({
|
const ModemGsm = new Lang.Class({
|
||||||
@@ -91,7 +153,8 @@ const ModemGsm = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_findOperatorName: function(name, opCode) {
|
_findOperatorName: function(name, opCode) {
|
||||||
if (name.length != 0 && (name.length > 6 || name.length < 5)) {
|
if (name) {
|
||||||
|
if (name && name.length != 0 && (name.length > 6 || name.length < 5)) {
|
||||||
// this looks like a valid name, i.e. not an MCCMNC (that some
|
// this looks like a valid name, i.e. not an MCCMNC (that some
|
||||||
// devices return when not yet connected
|
// devices return when not yet connected
|
||||||
return name;
|
return name;
|
||||||
@@ -101,54 +164,18 @@ const ModemGsm = new Lang.Class({
|
|||||||
// after all; return that
|
// after all; return that
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let needle;
|
let needle;
|
||||||
if (name.length == 0 && opCode)
|
if ((name == null || name.length == 0) && opCode)
|
||||||
needle = opCode;
|
needle = opCode;
|
||||||
else if (name.length == 6 || name.length == 5)
|
else if (name.length == 6 || name.length == 5)
|
||||||
needle = name;
|
needle = name;
|
||||||
else // nothing to search
|
else // nothing to search
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return this._findProviderForMCCMNC(needle);
|
|
||||||
},
|
|
||||||
|
|
||||||
_findProviderForMCCMNC: function(needle) {
|
|
||||||
let table = _getProvidersTable();
|
let table = _getProvidersTable();
|
||||||
let needlemcc = needle.substring(0, 3);
|
return findProviderForMCCMNC(table, needle);
|
||||||
let needlemnc = needle.substring(3, needle.length);
|
|
||||||
|
|
||||||
let name2, name3;
|
|
||||||
for (let iter in table) {
|
|
||||||
let providers = table[iter];
|
|
||||||
|
|
||||||
// Search through each country's providers
|
|
||||||
for (let i = 0; i < providers.length; i++) {
|
|
||||||
let provider = providers[i];
|
|
||||||
|
|
||||||
// Search through MCC/MNC list
|
|
||||||
let list = provider.get_gsm_mcc_mnc();
|
|
||||||
for (let j = 0; j < list.length; j++) {
|
|
||||||
let mccmnc = list[j];
|
|
||||||
|
|
||||||
// Match both 2-digit and 3-digit MNC; prefer a
|
|
||||||
// 3-digit match if found, otherwise a 2-digit one.
|
|
||||||
if (mccmnc.mcc != needlemcc)
|
|
||||||
continue; // MCC was wrong
|
|
||||||
|
|
||||||
if (!name3 && needle.length == 6 && needlemnc == mccmnc.mnc)
|
|
||||||
name3 = provider.name;
|
|
||||||
|
|
||||||
if (!name2 && needlemnc.substring(0, 2) == mccmnc.mnc.substring(0, 2))
|
|
||||||
name2 = provider.name;
|
|
||||||
|
|
||||||
if (name2 && name3)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return name3 || name2 || null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ModemGsm.prototype);
|
Signals.addSignalMethods(ModemGsm.prototype);
|
||||||
@@ -189,39 +216,14 @@ const ModemCdma = new Lang.Class({
|
|||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
} else {
|
} else {
|
||||||
let [bandClass, band, id] = result;
|
let [bandClass, band, id] = result;
|
||||||
if (name.length > 0)
|
if (name.length > 0) {
|
||||||
this.operator_name = this._findProviderForSid(id);
|
let table = _getProvidersTable();
|
||||||
else
|
this.operator_name = findProviderForSid(table, id);
|
||||||
|
} else
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
}
|
}
|
||||||
this.emit('notify::operator-name');
|
this.emit('notify::operator-name');
|
||||||
}));
|
}));
|
||||||
},
|
|
||||||
|
|
||||||
_findProviderForSid: function(sid) {
|
|
||||||
if (sid == 0)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
let table = _getProvidersTable();
|
|
||||||
|
|
||||||
// Search through each country
|
|
||||||
for (let iter in table) {
|
|
||||||
let providers = table[iter];
|
|
||||||
|
|
||||||
// Search through each country's providers
|
|
||||||
for (let i = 0; i < providers.length; i++) {
|
|
||||||
let provider = providers[i];
|
|
||||||
let cdma_sid = provider.get_cdma_sid();
|
|
||||||
|
|
||||||
// Search through CDMA SID list
|
|
||||||
for (let j = 0; j < cdma_sid.length; j++) {
|
|
||||||
if (cdma_sid[j] == sid)
|
|
||||||
return provider.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ModemCdma.prototype);
|
Signals.addSignalMethods(ModemCdma.prototype);
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
|
|
||||||
if (!Main.pushModal(this.actor)) {
|
if (!Main.pushModal(this.actor)) {
|
||||||
// Probably someone else has a pointer grab, try again with keyboard only
|
// Probably someone else has a pointer grab, try again with keyboard only
|
||||||
if (!Main.pushModal(this.actor, global.get_current_time(), Meta.ModalOptions.POINTER_ALREADY_GRABBED)) {
|
if (!Main.pushModal(this.actor, { options: Meta.ModalOptions.POINTER_ALREADY_GRABBED })) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -479,7 +479,6 @@ const AppWellIcon = new Lang.Class({
|
|||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
this._onStateChanged));
|
this._onStateChanged));
|
||||||
this._onStateChanged();
|
this._onStateChanged();
|
||||||
this.isMenuUp = false;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
@@ -561,7 +560,8 @@ const AppWellIcon = new Lang.Class({
|
|||||||
this._menuManager.addMenu(this._menu);
|
this._menuManager.addMenu(this._menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isMenuUp = true;
|
this.emit('menu-state-changed', true);
|
||||||
|
|
||||||
this.actor.set_hover(true);
|
this.actor.set_hover(true);
|
||||||
this._menu.popup();
|
this._menu.popup();
|
||||||
|
|
||||||
@@ -578,7 +578,7 @@ const AppWellIcon = new Lang.Class({
|
|||||||
|
|
||||||
_onMenuPoppedDown: function() {
|
_onMenuPoppedDown: function() {
|
||||||
this.actor.sync_hover();
|
this.actor.sync_hover();
|
||||||
this.isMenuUp = false;
|
this.emit('menu-state-changed', false);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivate: function (event) {
|
_onActivate: function (event) {
|
||||||
|
|||||||
@@ -84,9 +84,12 @@ const AppFavorites = new Lang.Class({
|
|||||||
|
|
||||||
let app = Shell.AppSystem.get_default().lookup_app(appId);
|
let app = Shell.AppSystem.get_default().lookup_app(appId);
|
||||||
|
|
||||||
Main.overview.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () {
|
Main.overview.setMessage(_("%s has been added to your favorites.").format(app.get_name()),
|
||||||
|
{ forFeedback: true,
|
||||||
|
undoCallback: Lang.bind(this, function () {
|
||||||
this._removeFavorite(appId);
|
this._removeFavorite(appId);
|
||||||
}));
|
})
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
addFavorite: function(appId) {
|
addFavorite: function(appId) {
|
||||||
@@ -116,9 +119,11 @@ const AppFavorites = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
Main.overview.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
|
Main.overview.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
|
||||||
Lang.bind(this, function () {
|
{ forFeedback: true,
|
||||||
|
undoCallback: Lang.bind(this, function () {
|
||||||
this._addFavorite(appId, pos);
|
this._addFavorite(appId, pos);
|
||||||
}));
|
})
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(AppFavorites.prototype);
|
Signals.addSignalMethods(AppFavorites.prototype);
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ const BoxPointer = new Lang.Class({
|
|||||||
|
|
||||||
this._muteInput();
|
this._muteInput();
|
||||||
|
|
||||||
|
Tweener.removeTweens(this);
|
||||||
Tweener.addTween(this, { opacity: fade ? 0 : 255,
|
Tweener.addTween(this, { opacity: fade ? 0 : 255,
|
||||||
xOffset: xOffset,
|
xOffset: xOffset,
|
||||||
yOffset: yOffset,
|
yOffset: yOffset,
|
||||||
@@ -274,14 +275,51 @@ const BoxPointer = new Lang.Class({
|
|||||||
let [x1, y1] = [halfBorder, halfBorder];
|
let [x1, y1] = [halfBorder, halfBorder];
|
||||||
let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder];
|
let [x2, y2] = [boxWidth - halfBorder, boxHeight - halfBorder];
|
||||||
|
|
||||||
|
let skipTopLeft = false;
|
||||||
|
let skipTopRight = false;
|
||||||
|
let skipBottomLeft = false;
|
||||||
|
let skipBottomRight = false;
|
||||||
|
|
||||||
|
switch (this._arrowSide) {
|
||||||
|
case St.Side.TOP:
|
||||||
|
if (this._arrowOrigin == x1)
|
||||||
|
skipTopLeft = true;
|
||||||
|
else if (this._arrowOrigin == x2)
|
||||||
|
skipTopRight = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case St.Side.RIGHT:
|
||||||
|
if (this._arrowOrigin == y1)
|
||||||
|
skipTopRight = true;
|
||||||
|
else if (this._arrowOrigin == y2)
|
||||||
|
skipBottomRight = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case St.Side.BOTTOM:
|
||||||
|
if (this._arrowOrigin == x1)
|
||||||
|
skipBottomLeft = true;
|
||||||
|
else if (this._arrowOrigin == x2)
|
||||||
|
skipBottomRight = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case St.Side.LEFT:
|
||||||
|
if (this._arrowOrigin == y1)
|
||||||
|
skipTopLeft = true;
|
||||||
|
else if (this._arrowOrigin == y2)
|
||||||
|
skipBottomLeft = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
cr.moveTo(x1 + borderRadius, y1);
|
cr.moveTo(x1 + borderRadius, y1);
|
||||||
if (this._arrowSide == St.Side.TOP) {
|
if (this._arrowSide == St.Side.TOP) {
|
||||||
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
|
if (skipTopLeft) {
|
||||||
cr.lineTo(this._arrowOrigin, y1 - rise);
|
cr.moveTo(x1, y2 - borderRadius);
|
||||||
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y1);
|
cr.lineTo(x1, y1 - rise);
|
||||||
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
|
cr.lineTo(x1 + halfBase, y1);
|
||||||
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y1);
|
} else if (skipTopRight) {
|
||||||
cr.lineTo(this._arrowOrigin, y1 - rise);
|
cr.lineTo(x2 - halfBase, y1);
|
||||||
|
cr.lineTo(x2, y1 - rise);
|
||||||
|
cr.lineTo(x2, y1 + borderRadius);
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(this._arrowOrigin - halfBase, y1);
|
cr.lineTo(this._arrowOrigin - halfBase, y1);
|
||||||
cr.lineTo(this._arrowOrigin, y1 - rise);
|
cr.lineTo(this._arrowOrigin, y1 - rise);
|
||||||
@@ -289,19 +327,20 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skipTopRight) {
|
||||||
cr.lineTo(x2 - borderRadius, y1);
|
cr.lineTo(x2 - borderRadius, y1);
|
||||||
|
|
||||||
// top-right corner
|
|
||||||
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
|
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) {
|
if (this._arrowSide == St.Side.RIGHT) {
|
||||||
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
|
if (skipTopRight) {
|
||||||
cr.lineTo(x2 + rise, this._arrowOrigin);
|
cr.lineTo(x2 + rise, y1);
|
||||||
cr.lineTo(x2, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
|
cr.lineTo(x2 + rise, y1 + halfBase);
|
||||||
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
|
} else if (skipBottomRight) {
|
||||||
cr.lineTo(x2, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
|
cr.lineTo(x2, y2 - halfBase);
|
||||||
cr.lineTo(x2 + rise, this._arrowOrigin);
|
cr.lineTo(x2 + rise, y2);
|
||||||
|
cr.lineTo(x2 - borderRadius, y2);
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(x2, this._arrowOrigin - halfBase);
|
cr.lineTo(x2, this._arrowOrigin - halfBase);
|
||||||
cr.lineTo(x2 + rise, this._arrowOrigin);
|
cr.lineTo(x2 + rise, this._arrowOrigin);
|
||||||
@@ -309,19 +348,20 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skipBottomRight) {
|
||||||
cr.lineTo(x2, y2 - borderRadius);
|
cr.lineTo(x2, y2 - borderRadius);
|
||||||
|
|
||||||
// bottom-right corner
|
|
||||||
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
|
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
|
||||||
0, Math.PI/2);
|
0, Math.PI/2);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._arrowSide == St.Side.BOTTOM) {
|
if (this._arrowSide == St.Side.BOTTOM) {
|
||||||
if (this._arrowOrigin < (x1 + (borderRadius + halfBase))) {
|
if (skipBottomLeft) {
|
||||||
cr.lineTo(Math.max(x1 + borderRadius, this._arrowOrigin) + halfBase, y2);
|
cr.lineTo(x1 + halfBase, y2);
|
||||||
cr.lineTo(this._arrowOrigin, y2 + rise);
|
cr.lineTo(x1, y2 + rise);
|
||||||
} else if (this._arrowOrigin > (x2 - (borderRadius + halfBase))) {
|
cr.lineTo(x1, y2 - borderRadius);
|
||||||
cr.lineTo(this._arrowOrigin, y2 + rise);
|
} else if (skipBottomRight) {
|
||||||
cr.lineTo(Math.min(x2 - borderRadius, this._arrowOrigin) - halfBase, y2);
|
cr.lineTo(x2, y2 + rise);
|
||||||
|
cr.lineTo(x2 - halfBase, y2);
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(this._arrowOrigin + halfBase, y2);
|
cr.lineTo(this._arrowOrigin + halfBase, y2);
|
||||||
cr.lineTo(this._arrowOrigin, y2 + rise);
|
cr.lineTo(this._arrowOrigin, y2 + rise);
|
||||||
@@ -329,19 +369,20 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skipBottomLeft) {
|
||||||
cr.lineTo(x1 + borderRadius, y2);
|
cr.lineTo(x1 + borderRadius, y2);
|
||||||
|
|
||||||
// bottom-left corner
|
|
||||||
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
|
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
|
||||||
Math.PI/2, Math.PI);
|
Math.PI/2, Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
if (this._arrowSide == St.Side.LEFT) {
|
if (this._arrowSide == St.Side.LEFT) {
|
||||||
if (this._arrowOrigin < (y1 + (borderRadius + halfBase))) {
|
if (skipTopLeft) {
|
||||||
cr.lineTo(x1, Math.max(y1 + borderRadius, this._arrowOrigin) + halfBase);
|
cr.lineTo(x1, y1 + halfBase);
|
||||||
cr.lineTo(x1 - rise, this._arrowOrigin);
|
cr.lineTo(x1 - rise, y1);
|
||||||
} else if (this._arrowOrigin > (y2 - (borderRadius + halfBase))) {
|
cr.lineTo(x1 + borderRadius, y1);
|
||||||
cr.lineTo(x1 - rise, this._arrowOrigin);
|
} else if (skipBottomLeft) {
|
||||||
cr.lineTo(x1, Math.min(y2 - borderRadius, this._arrowOrigin) - halfBase);
|
cr.lineTo(x1 - rise, y2)
|
||||||
|
cr.lineTo(x1 - rise, y2 - halfBase);
|
||||||
} else {
|
} else {
|
||||||
cr.lineTo(x1, this._arrowOrigin + halfBase);
|
cr.lineTo(x1, this._arrowOrigin + halfBase);
|
||||||
cr.lineTo(x1 - rise, this._arrowOrigin);
|
cr.lineTo(x1 - rise, this._arrowOrigin);
|
||||||
@@ -349,11 +390,11 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skipTopLeft) {
|
||||||
cr.lineTo(x1, y1 + borderRadius);
|
cr.lineTo(x1, y1 + borderRadius);
|
||||||
|
|
||||||
// top-left corner
|
|
||||||
cr.arc(x1 + borderRadius, y1 + borderRadius, 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);
|
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||||
cr.fillPreserve();
|
cr.fillPreserve();
|
||||||
@@ -406,10 +447,9 @@ const BoxPointer = new Lang.Class({
|
|||||||
let arrowBase = themeNode.get_length('-arrow-base');
|
let arrowBase = themeNode.get_length('-arrow-base');
|
||||||
let borderRadius = themeNode.get_length('-arrow-border-radius');
|
let borderRadius = themeNode.get_length('-arrow-border-radius');
|
||||||
let margin = (4 * borderRadius + borderWidth + arrowBase);
|
let margin = (4 * borderRadius + borderWidth + arrowBase);
|
||||||
let halfMargin = margin / 2;
|
|
||||||
|
|
||||||
let themeNode = this.actor.get_theme_node();
|
|
||||||
let gap = themeNode.get_length('-boxpointer-gap');
|
let gap = themeNode.get_length('-boxpointer-gap');
|
||||||
|
let padding = themeNode.get_length('-arrow-rise');
|
||||||
|
|
||||||
let resX, resY;
|
let resX, resY;
|
||||||
|
|
||||||
@@ -428,29 +468,66 @@ const BoxPointer = new Lang.Class({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now align and position the pointing axis, making sure
|
// Now align and position the pointing axis, making sure it fits on
|
||||||
// it fits on screen
|
// screen. If the arrowOrigin is so close to the edge that the arrow
|
||||||
|
// will not be isosceles, we try to compensate as follows:
|
||||||
|
// - We skip the rounded corner and settle for a right angled arrow
|
||||||
|
// as shown below. See _drawBorder for further details.
|
||||||
|
// |\_____
|
||||||
|
// |
|
||||||
|
// |
|
||||||
|
// - If the arrow was going to be acute angled, we move the position
|
||||||
|
// of the box to maintain the arrow's accuracy.
|
||||||
|
|
||||||
|
let arrowOrigin;
|
||||||
|
let halfBase = Math.floor(arrowBase/2);
|
||||||
|
let halfBorder = borderWidth / 2;
|
||||||
|
let halfMargin = margin / 2;
|
||||||
|
let [x1, y1] = [halfBorder, halfBorder];
|
||||||
|
let [x2, y2] = [natWidth - halfBorder, natHeight - halfBorder];
|
||||||
|
|
||||||
switch (this._arrowSide) {
|
switch (this._arrowSide) {
|
||||||
case St.Side.TOP:
|
case St.Side.TOP:
|
||||||
case St.Side.BOTTOM:
|
case St.Side.BOTTOM:
|
||||||
resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
|
resX = sourceCenterX - (halfMargin + (natWidth - margin) * alignment);
|
||||||
|
|
||||||
resX = Math.max(resX, monitor.x + 10);
|
resX = Math.max(resX, monitor.x + padding);
|
||||||
resX = Math.min(resX, monitor.x + monitor.width - (10 + natWidth));
|
resX = Math.min(resX, monitor.x + monitor.width - (padding + natWidth));
|
||||||
this.setArrowOrigin(sourceCenterX - resX);
|
|
||||||
|
arrowOrigin = sourceCenterX - resX;
|
||||||
|
if (arrowOrigin <= (x1 + (borderRadius + halfBase))) {
|
||||||
|
if (arrowOrigin > x1)
|
||||||
|
resX += (arrowOrigin - x1);
|
||||||
|
arrowOrigin = x1;
|
||||||
|
} else if (arrowOrigin >= (x2 - (borderRadius + halfBase))) {
|
||||||
|
if (arrowOrigin < x2)
|
||||||
|
resX -= (x2 - arrowOrigin);
|
||||||
|
arrowOrigin = x2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case St.Side.LEFT:
|
case St.Side.LEFT:
|
||||||
case St.Side.RIGHT:
|
case St.Side.RIGHT:
|
||||||
resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment);
|
resY = sourceCenterY - (halfMargin + (natHeight - margin) * alignment);
|
||||||
|
|
||||||
resY = Math.max(resY, monitor.y + 10);
|
resY = Math.max(resY, monitor.y + padding);
|
||||||
resY = Math.min(resY, monitor.y + monitor.height - (10 + natHeight));
|
resY = Math.min(resY, monitor.y + monitor.height - (padding + natHeight));
|
||||||
|
|
||||||
this.setArrowOrigin(sourceCenterY - resY);
|
arrowOrigin = sourceCenterY - resY;
|
||||||
|
if (arrowOrigin <= (y1 + (borderRadius + halfBase))) {
|
||||||
|
if (arrowOrigin > y1)
|
||||||
|
resY += (arrowOrigin - y1);
|
||||||
|
arrowOrigin = y1;
|
||||||
|
} else if (arrowOrigin >= (y2 - (borderRadius + halfBase))) {
|
||||||
|
if (arrowOrigin < y2)
|
||||||
|
resX -= (y2 - arrowOrigin);
|
||||||
|
arrowOrigin = y2;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.setArrowOrigin(arrowOrigin);
|
||||||
|
|
||||||
let parent = this.actor.get_parent();
|
let parent = this.actor.get_parent();
|
||||||
let success, x, y;
|
let success, x, y;
|
||||||
while (!success) {
|
while (!success) {
|
||||||
|
|||||||
@@ -208,8 +208,7 @@ function CalendarServer() {
|
|||||||
g_interface_info: CalendarServerInfo,
|
g_interface_info: CalendarServerInfo,
|
||||||
g_name: 'org.gnome.Shell.CalendarServer',
|
g_name: 'org.gnome.Shell.CalendarServer',
|
||||||
g_object_path: '/org/gnome/Shell/CalendarServer',
|
g_object_path: '/org/gnome/Shell/CalendarServer',
|
||||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
|
||||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
|
||||||
|
|
||||||
self.init(null);
|
self.init(null);
|
||||||
return self;
|
return self;
|
||||||
@@ -271,8 +270,9 @@ const DBusEventSource = new Lang.Class({
|
|||||||
this._loadEvents(false);
|
this._loadEvents(false);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onEventsReceived: function([appointments]) {
|
_onEventsReceived: function(results, error) {
|
||||||
let newEvents = [];
|
let newEvents = [];
|
||||||
|
let appointments = results ? results[0] : null;
|
||||||
if (appointments != null) {
|
if (appointments != null) {
|
||||||
for (let n = 0; n < appointments.length; n++) {
|
for (let n = 0; n < appointments.length; n++) {
|
||||||
let a = appointments[n];
|
let a = appointments[n];
|
||||||
@@ -340,22 +340,10 @@ const DBusEventSource = new Lang.Class({
|
|||||||
});
|
});
|
||||||
Signals.addSignalMethods(DBusEventSource.prototype);
|
Signals.addSignalMethods(DBusEventSource.prototype);
|
||||||
|
|
||||||
// Calendar:
|
|
||||||
// @eventSource: is an object implementing the EventSource API, e.g. the
|
|
||||||
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
|
||||||
const Calendar = new Lang.Class({
|
const Calendar = new Lang.Class({
|
||||||
Name: 'Calendar',
|
Name: 'Calendar',
|
||||||
|
|
||||||
_init: function(eventSource) {
|
_init: function() {
|
||||||
if (eventSource) {
|
|
||||||
this._eventSource = eventSource;
|
|
||||||
|
|
||||||
this._eventSource.connect('changed', Lang.bind(this,
|
|
||||||
function() {
|
|
||||||
this._update(false);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
this._weekStart = Shell.util_get_week_start();
|
this._weekStart = Shell.util_get_week_start();
|
||||||
this._weekdate = NaN;
|
this._weekdate = NaN;
|
||||||
this._digitWidth = NaN;
|
this._digitWidth = NaN;
|
||||||
@@ -392,6 +380,24 @@ const Calendar = new Lang.Class({
|
|||||||
this._buildHeader ();
|
this._buildHeader ();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// @eventSource: is an object implementing the EventSource API, e.g. the
|
||||||
|
// requestRange(), getEvents(), hasEvents() methods and the ::changed signal.
|
||||||
|
setEventSource: function(eventSource) {
|
||||||
|
if (this._eventSource) {
|
||||||
|
this._eventSource.disconnect(this._eventSourceChangedId);
|
||||||
|
this._eventSource = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._eventSource = eventSource;
|
||||||
|
|
||||||
|
if (this._eventSource) {
|
||||||
|
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, function() {
|
||||||
|
this._update(false);
|
||||||
|
}));
|
||||||
|
this._update(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Sets the calendar to show a specific date
|
// Sets the calendar to show a specific date
|
||||||
setDate: function(date, forceReload) {
|
setDate: function(date, forceReload) {
|
||||||
if (!_sameDay(date, this._selectedDate)) {
|
if (!_sameDay(date, this._selectedDate)) {
|
||||||
@@ -622,16 +628,25 @@ Signals.addSignalMethods(Calendar.prototype);
|
|||||||
const EventsList = new Lang.Class({
|
const EventsList = new Lang.Class({
|
||||||
Name: 'EventsList',
|
Name: 'EventsList',
|
||||||
|
|
||||||
_init: function(eventSource) {
|
_init: function() {
|
||||||
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
this.actor = new St.BoxLayout({ vertical: true, style_class: 'events-header-vbox'});
|
||||||
this._date = new Date();
|
this._date = new Date();
|
||||||
this._eventSource = eventSource;
|
|
||||||
this._eventSource.connect('changed', Lang.bind(this, this._update));
|
|
||||||
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
this._desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||||
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
|
this._desktopSettings.connect('changed', Lang.bind(this, this._update));
|
||||||
this._weekStart = Shell.util_get_week_start();
|
this._weekStart = Shell.util_get_week_start();
|
||||||
|
},
|
||||||
|
|
||||||
this._update();
|
setEventSource: function(eventSource) {
|
||||||
|
if (this._eventSource) {
|
||||||
|
this._eventSource.disconnect(this._eventSourceChangedId);
|
||||||
|
this._eventSource = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._eventSource = eventSource;
|
||||||
|
|
||||||
|
if (this._eventSource) {
|
||||||
|
this._eventSourceChangedId = this._eventSource.connect('changed', Lang.bind(this, this._update));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
|
_addEvent: function(dayNameBox, timeBox, eventTitleBox, includeDayName, day, time, desc) {
|
||||||
|
|||||||
65
js/ui/components/__init__.js
Normal file
65
js/ui/components/__init__.js
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
const ComponentManager = new Lang.Class({
|
||||||
|
Name: 'ComponentManager',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this._allComponents = {};
|
||||||
|
this._enabledComponents = [];
|
||||||
|
|
||||||
|
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||||
|
this._sessionUpdated();
|
||||||
|
},
|
||||||
|
|
||||||
|
_sessionUpdated: function() {
|
||||||
|
let newEnabledComponents = Main.sessionMode.components;
|
||||||
|
|
||||||
|
newEnabledComponents.filter(Lang.bind(this, function(name) {
|
||||||
|
return this._enabledComponents.indexOf(name) == -1;
|
||||||
|
})).forEach(Lang.bind(this, function(name) {
|
||||||
|
this._enableComponent(name);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._enabledComponents.filter(Lang.bind(this, function(name) {
|
||||||
|
return newEnabledComponents.indexOf(name) == -1;
|
||||||
|
})).forEach(Lang.bind(this, function(name) {
|
||||||
|
this._disableComponent(name);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._enabledComponents = newEnabledComponents;
|
||||||
|
},
|
||||||
|
|
||||||
|
_importComponent: function(name) {
|
||||||
|
let module = imports.ui.components[name];
|
||||||
|
return module.Component;
|
||||||
|
},
|
||||||
|
|
||||||
|
_ensureComponent: function(name) {
|
||||||
|
let component = this._allComponents[name];
|
||||||
|
if (component)
|
||||||
|
return component;
|
||||||
|
|
||||||
|
if (Main.sessionMode.isLocked)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let constructor = this._importComponent(name);
|
||||||
|
component = new constructor();
|
||||||
|
this._allComponents[name] = component;
|
||||||
|
return component;
|
||||||
|
},
|
||||||
|
|
||||||
|
_enableComponent: function(name) {
|
||||||
|
let component = this._ensureComponent(name);
|
||||||
|
if (component)
|
||||||
|
component.enable();
|
||||||
|
},
|
||||||
|
|
||||||
|
_disableComponent: function(name) {
|
||||||
|
let component = this._allComponents[name];
|
||||||
|
if (component == null)
|
||||||
|
return;
|
||||||
|
component.disable();
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -34,28 +34,30 @@ const AutomountManager = new Lang.Class({
|
|||||||
this._inhibited = false;
|
this._inhibited = false;
|
||||||
|
|
||||||
this._loginManager = LoginManager.getLoginManager();
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
|
|
||||||
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._lockStatusChanged));
|
|
||||||
|
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
|
},
|
||||||
|
|
||||||
this._volumeMonitor.connect('volume-added',
|
enable: function() {
|
||||||
Lang.bind(this,
|
this._volumeAddedId = this._volumeMonitor.connect('volume-added', Lang.bind(this, this._onVolumeAdded));
|
||||||
this._onVolumeAdded));
|
this._volumeRemovedId = this._volumeMonitor.connect('volume-removed', Lang.bind(this, this._onVolumeRemoved));
|
||||||
this._volumeMonitor.connect('volume-removed',
|
this._driveConnectedId = this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._onDriveConnected));
|
||||||
Lang.bind(this,
|
this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._onDriveDisconnected));
|
||||||
this._onVolumeRemoved));
|
this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', Lang.bind(this, this._onDriveEjectButton));
|
||||||
this._volumeMonitor.connect('drive-connected',
|
|
||||||
Lang.bind(this,
|
|
||||||
this._onDriveConnected));
|
|
||||||
this._volumeMonitor.connect('drive-disconnected',
|
|
||||||
Lang.bind(this,
|
|
||||||
this._onDriveDisconnected));
|
|
||||||
this._volumeMonitor.connect('drive-eject-button',
|
|
||||||
Lang.bind(this,
|
|
||||||
this._onDriveEjectButton));
|
|
||||||
|
|
||||||
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
this._mountAllId = Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
this._volumeMonitor.disconnect(this._volumeAddedId);
|
||||||
|
this._volumeMonitor.disconnect(this._volumeRemovedId);
|
||||||
|
this._volumeMonitor.disconnect(this._driveConnectedId);
|
||||||
|
this._volumeMonitor.disconnect(this._driveDisconnectedId);
|
||||||
|
this._volumeMonitor.disconnect(this._driveEjectButtonId);
|
||||||
|
|
||||||
|
if (this._mountAllId > 0) {
|
||||||
|
Mainloop.source_remove(this._mountAllId);
|
||||||
|
this._mountAllId = 0;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_InhibitorsChanged: function(object, senderName, [inhibtor]) {
|
_InhibitorsChanged: function(object, senderName, [inhibtor]) {
|
||||||
@@ -68,17 +70,6 @@ const AutomountManager = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_lockStatusChanged: function(shield, locked) {
|
|
||||||
if (!locked) {
|
|
||||||
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
|
|
||||||
this._checkAndMountVolume(volume);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// clear the queue anyway
|
|
||||||
this._volumeQueue = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
_startupMountAll: function() {
|
_startupMountAll: function() {
|
||||||
let volumes = this._volumeMonitor.get_volumes();
|
let volumes = this._volumeMonitor.get_volumes();
|
||||||
volumes.forEach(Lang.bind(this, function(volume) {
|
volumes.forEach(Lang.bind(this, function(volume) {
|
||||||
@@ -87,6 +78,7 @@ const AutomountManager = new Lang.Class({
|
|||||||
allowAutorun: false });
|
allowAutorun: false });
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._mountAllId = 0;
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -96,9 +88,6 @@ const AutomountManager = new Lang.Class({
|
|||||||
if (!this._loginManager.sessionActive)
|
if (!this._loginManager.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Main.screenShield.locked)
|
|
||||||
return;
|
|
||||||
|
|
||||||
global.play_theme_sound(0, 'device-added-media');
|
global.play_theme_sound(0, 'device-added-media');
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -108,9 +97,6 @@ const AutomountManager = new Lang.Class({
|
|||||||
if (!this._loginManager.sessionActive)
|
if (!this._loginManager.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Main.screenShield.locked)
|
|
||||||
return;
|
|
||||||
|
|
||||||
global.play_theme_sound(0, 'device-removed-media');
|
global.play_theme_sound(0, 'device-removed-media');
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -159,13 +145,6 @@ const AutomountManager = new Lang.Class({
|
|||||||
// don't attempt automount
|
// don't attempt automount
|
||||||
if (!this._loginManager.sessionActive)
|
if (!this._loginManager.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Main.screenShield.locked) {
|
|
||||||
if (this._volumeQueue.indexOf(volume) == -1)
|
|
||||||
this._volumeQueue.push(volume);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._inhibited)
|
if (this._inhibited)
|
||||||
@@ -259,3 +238,4 @@ const AutomountManager = new Lang.Class({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const Component = AutomountManager;
|
||||||
@@ -4,6 +4,7 @@ const Lang = imports.lang;
|
|||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const LoginManager = imports.misc.loginManager;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
@@ -43,6 +44,17 @@ function isMountRootHidden(root) {
|
|||||||
return (path.indexOf('/.') != -1);
|
return (path.indexOf('/.') != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isMountNonLocal(mount) {
|
||||||
|
// If the mount doesn't have an associated volume, that means it's
|
||||||
|
// an uninteresting filesystem. Most devices that we care about will
|
||||||
|
// have a mount, like media players and USB sticks.
|
||||||
|
let volume = mount.get_volume();
|
||||||
|
if (volume == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return (volume.get_identifier("class") == "network");
|
||||||
|
}
|
||||||
|
|
||||||
function startAppForMount(app, mount) {
|
function startAppForMount(app, mount) {
|
||||||
let files = [];
|
let files = [];
|
||||||
let root = mount.get_root();
|
let root = mount.get_root();
|
||||||
@@ -82,13 +94,21 @@ const ContentTypeDiscoverer = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(callback) {
|
_init: function(callback) {
|
||||||
this._callback = callback;
|
this._callback = callback;
|
||||||
|
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||||
},
|
},
|
||||||
|
|
||||||
guessContentTypes: function(mount) {
|
guessContentTypes: function(mount) {
|
||||||
|
let autorunEnabled = !this._settings.get_boolean(SETTING_DISABLE_AUTORUN);
|
||||||
|
let shouldScan = autorunEnabled && !isMountNonLocal(mount);
|
||||||
|
|
||||||
|
if (shouldScan) {
|
||||||
// guess mount's content types using GIO
|
// guess mount's content types using GIO
|
||||||
mount.guess_content_type(false, null,
|
mount.guess_content_type(false, null,
|
||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
this._onContentTypeGuessed));
|
this._onContentTypeGuessed));
|
||||||
|
} else {
|
||||||
|
this._emitCallback(mount, []);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onContentTypeGuessed: function(mount, res) {
|
_onContentTypeGuessed: function(mount, res) {
|
||||||
@@ -142,54 +162,68 @@ const AutorunManager = new Lang.Class({
|
|||||||
Name: 'AutorunManager',
|
Name: 'AutorunManager',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
|
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||||
|
|
||||||
this._volumeMonitor.connect('mount-added',
|
this._transDispatcher = new AutorunTransientDispatcher(this);
|
||||||
Lang.bind(this,
|
},
|
||||||
this._onMountAdded));
|
|
||||||
this._volumeMonitor.connect('mount-removed',
|
|
||||||
Lang.bind(this,
|
|
||||||
this._onMountRemoved));
|
|
||||||
|
|
||||||
this._transDispatcher = new AutorunTransientDispatcher();
|
_ensureResidentSource: function() {
|
||||||
this._createResidentSource();
|
if (this._residentSource)
|
||||||
|
return;
|
||||||
|
|
||||||
let mounts = this._volumeMonitor.get_mounts();
|
this._residentSource = new AutorunResidentSource(this);
|
||||||
|
let destroyId = this._residentSource.connect('destroy', Lang.bind(this, function() {
|
||||||
mounts.forEach(Lang.bind(this, function (mount) {
|
this._residentSource.disconnect(destroyId);
|
||||||
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
this._residentSource = null;
|
||||||
function (mount, apps) {
|
|
||||||
this._residentSource.addMount(mount, apps);
|
|
||||||
}));
|
|
||||||
|
|
||||||
discoverer.guessContentTypes(mount);
|
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_createResidentSource: function() {
|
enable: function() {
|
||||||
this._residentSource = new AutorunResidentSource();
|
this._scanMounts();
|
||||||
this._residentSource.connect('destroy',
|
|
||||||
Lang.bind(this,
|
this._mountAddedId = this._volumeMonitor.connect('mount-added', Lang.bind(this, this._onMountAdded));
|
||||||
this._createResidentSource));
|
this._mountRemovedId = this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._onMountRemoved));
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
if (this._residentSource)
|
||||||
|
this._residentSource.destroy();
|
||||||
|
this._volumeMonitor.disconnect(this._mountAddedId);
|
||||||
|
this._volumeMonitor.disconnect(this._mountRemovedId);
|
||||||
|
},
|
||||||
|
|
||||||
|
_processMount: function(mount, hotplug) {
|
||||||
|
let discoverer = new ContentTypeDiscoverer(Lang.bind(this, function(mount, apps, contentTypes) {
|
||||||
|
this._ensureResidentSource();
|
||||||
|
this._residentSource.addMount(mount, apps);
|
||||||
|
|
||||||
|
if (hotplug)
|
||||||
|
this._transDispatcher.addMount(mount, apps, contentTypes);
|
||||||
|
}));
|
||||||
|
discoverer.guessContentTypes(mount);
|
||||||
|
},
|
||||||
|
|
||||||
|
_scanMounts: function() {
|
||||||
|
let mounts = this._volumeMonitor.get_mounts();
|
||||||
|
mounts.forEach(Lang.bind(this, function(mount) {
|
||||||
|
this._processMount(mount, false);
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMountAdded: function(monitor, mount) {
|
_onMountAdded: function(monitor, mount) {
|
||||||
// don't do anything if our session is not the currently
|
// don't do anything if our session is not the currently
|
||||||
// active one
|
// active one
|
||||||
if (!Main.automountManager.isSessionActive())
|
if (!this._loginManager.sessionActive)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
this._processMount(mount, true);
|
||||||
function (mount, apps, contentTypes) {
|
|
||||||
this._transDispatcher.addMount(mount, apps, contentTypes);
|
|
||||||
this._residentSource.addMount(mount, apps);
|
|
||||||
}));
|
|
||||||
|
|
||||||
discoverer.guessContentTypes(mount);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMountRemoved: function(monitor, mount) {
|
_onMountRemoved: function(monitor, mount) {
|
||||||
this._transDispatcher.removeMount(mount);
|
this._transDispatcher.removeMount(mount);
|
||||||
|
if (this._residentSource)
|
||||||
this._residentSource.removeMount(mount);
|
this._residentSource.removeMount(mount);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -257,12 +291,18 @@ const AutorunResidentSource = new Lang.Class({
|
|||||||
Name: 'AutorunResidentSource',
|
Name: 'AutorunResidentSource',
|
||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function() {
|
_init: function(manager) {
|
||||||
this.parent(_("Removable Devices"), 'media-removable', St.IconType.FULLCOLOR);
|
this.parent(_("Removable Devices"), 'media-removable');
|
||||||
|
this.showInLockScreen = false;
|
||||||
|
|
||||||
this._mounts = [];
|
this._mounts = [];
|
||||||
|
|
||||||
this._notification = new AutorunResidentNotification(this);
|
this._manager = manager;
|
||||||
|
this._notification = new AutorunResidentNotification(this._manager, this);
|
||||||
|
},
|
||||||
|
|
||||||
|
buildRightClickMenu: function() {
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
addMount: function(mount, apps) {
|
addMount: function(mount, apps) {
|
||||||
@@ -312,7 +352,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
Name: 'AutorunResidentNotification',
|
Name: 'AutorunResidentNotification',
|
||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(source) {
|
_init: function(manager, source) {
|
||||||
this.parent(source, source.title, null, { customContent: true });
|
this.parent(source, source.title, null, { customContent: true });
|
||||||
|
|
||||||
// set the notification as resident
|
// set the notification as resident
|
||||||
@@ -320,6 +360,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
|
|
||||||
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
|
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
|
this._manager = manager;
|
||||||
|
|
||||||
this.addActor(this._layout,
|
this.addActor(this._layout,
|
||||||
{ x_expand: true,
|
{ x_expand: true,
|
||||||
@@ -367,7 +408,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
expand: true });
|
expand: true });
|
||||||
|
|
||||||
let ejectIcon =
|
let ejectIcon =
|
||||||
new St.Icon({ icon_name: 'media-eject',
|
new St.Icon({ icon_name: 'media-eject-symbolic',
|
||||||
style_class: 'hotplug-resident-eject-icon' });
|
style_class: 'hotplug-resident-eject-icon' });
|
||||||
|
|
||||||
let ejectButton =
|
let ejectButton =
|
||||||
@@ -382,7 +423,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
ejectButton.connect('clicked', Lang.bind(this, function() {
|
ejectButton.connect('clicked', Lang.bind(this, function() {
|
||||||
Main.autorunManager.ejectMount(mount);
|
this._manager.ejectMount(mount);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
@@ -392,7 +433,8 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
const AutorunTransientDispatcher = new Lang.Class({
|
const AutorunTransientDispatcher = new Lang.Class({
|
||||||
Name: 'AutorunTransientDispatcher',
|
Name: 'AutorunTransientDispatcher',
|
||||||
|
|
||||||
_init: function() {
|
_init: function(manager) {
|
||||||
|
this._manager = manager;
|
||||||
this._sources = [];
|
this._sources = [];
|
||||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||||
},
|
},
|
||||||
@@ -435,7 +477,7 @@ const AutorunTransientDispatcher = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// add a new source
|
// add a new source
|
||||||
this._sources.push(new AutorunTransientSource(mount, apps));
|
this._sources.push(new AutorunTransientSource(this._manager, mount, apps));
|
||||||
},
|
},
|
||||||
|
|
||||||
addMount: function(mount, apps, contentTypes) {
|
addMount: function(mount, apps, contentTypes) {
|
||||||
@@ -488,22 +530,22 @@ const AutorunTransientSource = new Lang.Class({
|
|||||||
Name: 'AutorunTransientSource',
|
Name: 'AutorunTransientSource',
|
||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function(mount, apps) {
|
_init: function(manager, mount, apps) {
|
||||||
|
this._manager = manager;
|
||||||
this.mount = mount;
|
this.mount = mount;
|
||||||
this.apps = apps;
|
this.apps = apps;
|
||||||
|
|
||||||
this.parent(mount.get_name());
|
this.parent(mount.get_name());
|
||||||
|
|
||||||
this._notification = new AutorunTransientNotification(this);
|
this._notification = new AutorunTransientNotification(this._manager, this);
|
||||||
|
|
||||||
// add ourselves as a source, and popup the notification
|
// add ourselves as a source, and popup the notification
|
||||||
Main.messageTray.add(this);
|
Main.messageTray.add(this);
|
||||||
this.notify(this._notification);
|
this.notify(this._notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(size) {
|
getIcon: function() {
|
||||||
return new St.Icon({ gicon: this.mount.get_icon(),
|
return this.mount.get_icon();
|
||||||
icon_size: size });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -511,9 +553,10 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
Name: 'AutorunTransientNotification',
|
Name: 'AutorunTransientNotification',
|
||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(source) {
|
_init: function(manager, source) {
|
||||||
this.parent(source, source.title, null, { customContent: true });
|
this.parent(source, source.title, null, { customContent: true });
|
||||||
|
|
||||||
|
this._manager = manager;
|
||||||
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
this.addActor(this._box);
|
this.addActor(this._box);
|
||||||
@@ -565,7 +608,7 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
|
|
||||||
_buttonForEject: function() {
|
_buttonForEject: function() {
|
||||||
let box = new St.BoxLayout();
|
let box = new St.BoxLayout();
|
||||||
let icon = new St.Icon({ icon_name: 'media-eject',
|
let icon = new St.Icon({ icon_name: 'media-eject-symbolic',
|
||||||
style_class: 'hotplug-notification-item-icon' });
|
style_class: 'hotplug-notification-item-icon' });
|
||||||
box.add(icon);
|
box.add(icon);
|
||||||
|
|
||||||
@@ -582,10 +625,11 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
style_class: 'hotplug-notification-item' });
|
style_class: 'hotplug-notification-item' });
|
||||||
|
|
||||||
button.connect('clicked', Lang.bind(this, function() {
|
button.connect('clicked', Lang.bind(this, function() {
|
||||||
Main.autorunManager.ejectMount(this._mount);
|
this._manager.ejectMount(this._mount);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Component = AutorunManager;
|
||||||
@@ -192,23 +192,36 @@ const KeyringDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onContinueButton: function() {
|
_onContinueButton: function() {
|
||||||
this.prompt.complete()
|
this.prompt.complete();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCancelButton: function() {
|
_onCancelButton: function() {
|
||||||
this.prompt.cancel()
|
this.prompt.cancel();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function init() {
|
const KeyringPrompter = new Lang.Class({
|
||||||
prompter = new Gcr.SystemPrompter();
|
Name: 'KeyringPrompter',
|
||||||
prompter.connect('new-prompt', function(prompter) {
|
|
||||||
|
_init: function() {
|
||||||
|
this._prompter = new Gcr.SystemPrompter();
|
||||||
|
this._prompter.connect('new-prompt', function(prompter) {
|
||||||
let dialog = new KeyringDialog();
|
let dialog = new KeyringDialog();
|
||||||
return dialog.prompt;
|
return dialog.prompt;
|
||||||
});
|
});
|
||||||
|
this._dbusId = null;
|
||||||
|
},
|
||||||
|
|
||||||
let connection = Gio.DBus.session;
|
enable: function() {
|
||||||
prompter.register(connection);
|
this._prompter.register(Gio.DBus.session);
|
||||||
Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
|
this._dbusId = Gio.DBus.session.own_name('org.gnome.keyring.SystemPrompter',
|
||||||
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
this._prompter.unregister(false);
|
||||||
|
Gio.DBus.session.unown_name(this._dbusId);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Component = KeyringPrompter;
|
||||||
@@ -1,23 +1,4 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/*
|
|
||||||
* Copyright 2011 Giovanni Campagna <scampa.giovanni@gmail.com>
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
||||||
* 02111-1307, USA.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
@@ -135,7 +116,10 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
} else
|
} else
|
||||||
secret.valid = true;
|
secret.valid = true;
|
||||||
|
|
||||||
secretTable.add(label, { row: pos, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START, y_align: St.Align.START });
|
secretTable.add(label, { row: pos, col: 0,
|
||||||
|
x_expand: false, x_fill: true,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_fill: false, y_align: St.Align.MIDDLE });
|
||||||
secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
|
secretTable.add(secret.entry, { row: pos, col: 1, x_expand: true, x_fill: true, y_align: St.Align.END });
|
||||||
pos++;
|
pos++;
|
||||||
|
|
||||||
@@ -165,6 +149,7 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._okButton.button.reactive = valid;
|
this._okButton.button.reactive = valid;
|
||||||
|
this._okButton.button.can_focus = valid;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onOk: function() {
|
_onOk: function() {
|
||||||
@@ -423,7 +408,10 @@ const VPNRequestHandler = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function(respond) {
|
||||||
|
if (respond)
|
||||||
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
||||||
|
|
||||||
if (this._newStylePlugin && this._shellDialog) {
|
if (this._newStylePlugin && this._shellDialog) {
|
||||||
this._shellDialog.close(global.get_current_time());
|
this._shellDialog.close(global.get_current_time());
|
||||||
this._shellDialog.destroy();
|
this._shellDialog.destroy();
|
||||||
@@ -599,7 +587,7 @@ const NetworkAgent = new Lang.Class({
|
|||||||
Name: 'NetworkAgent',
|
Name: 'NetworkAgent',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._native = new Shell.NetworkAgent({ auto_register: true,
|
this._native = new Shell.NetworkAgent({ auto_register: false,
|
||||||
identifier: 'org.gnome.Shell.NetworkAgent' });
|
identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||||
|
|
||||||
this._dialogs = { };
|
this._dialogs = { };
|
||||||
@@ -609,6 +597,24 @@ const NetworkAgent = new Lang.Class({
|
|||||||
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
enable: function() {
|
||||||
|
this._native.register();
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
let requestId;
|
||||||
|
|
||||||
|
for (requestId in this._dialogs)
|
||||||
|
this._dialogs[requestId].cancel();
|
||||||
|
this._dialogs = { };
|
||||||
|
|
||||||
|
for (requestId in this._vpnRequests)
|
||||||
|
this._vpnRequests[requestId].cancel(true);
|
||||||
|
this._vpnRequests = { };
|
||||||
|
|
||||||
|
this._native.unregister();
|
||||||
|
},
|
||||||
|
|
||||||
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
|
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
|
||||||
if (settingName == 'vpn') {
|
if (settingName == 'vpn') {
|
||||||
this._vpnRequest(requestId, connection, hints, flags);
|
this._vpnRequest(requestId, connection, hints, flags);
|
||||||
@@ -629,7 +635,7 @@ const NetworkAgent = new Lang.Class({
|
|||||||
this._dialogs[requestId].destroy();
|
this._dialogs[requestId].destroy();
|
||||||
delete this._dialogs[requestId];
|
delete this._dialogs[requestId];
|
||||||
} else if (this._vpnRequests[requestId]) {
|
} else if (this._vpnRequests[requestId]) {
|
||||||
this._vpnRequests[requestId].cancel();
|
this._vpnRequests[requestId].cancel(false);
|
||||||
delete this._vpnRequests[requestId];
|
delete this._vpnRequests[requestId];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -698,3 +704,4 @@ const NetworkAgent = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const Component = NetworkAgent;
|
||||||
@@ -1,24 +1,4 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/*
|
|
||||||
* Copyright 2010 Red Hat, Inc
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2, or (at your option)
|
|
||||||
* any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
||||||
* 02111-1307, USA.
|
|
||||||
*
|
|
||||||
* Author: David Zeuthen <davidz@redhat.com>
|
|
||||||
*/
|
|
||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
@@ -33,8 +13,12 @@ const Mainloop = imports.mainloop;
|
|||||||
const Polkit = imports.gi.Polkit;
|
const Polkit = imports.gi.Polkit;
|
||||||
const PolkitAgent = imports.gi.PolkitAgent;
|
const PolkitAgent = imports.gi.PolkitAgent;
|
||||||
|
|
||||||
|
const Components = imports.ui.components;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
const UserMenu = imports.ui.userMenu;
|
||||||
|
|
||||||
|
const DIALOG_ICON_SIZE = 48;
|
||||||
|
|
||||||
const AuthenticationDialog = new Lang.Class({
|
const AuthenticationDialog = new Lang.Class({
|
||||||
Name: 'AuthenticationDialog',
|
Name: 'AuthenticationDialog',
|
||||||
@@ -65,7 +49,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
mainContentBox.add(messageBox,
|
mainContentBox.add(messageBox,
|
||||||
{ y_align: St.Align.START });
|
{ expand: true, y_align: St.Align.START });
|
||||||
|
|
||||||
this._subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
|
this._subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
|
||||||
text: _("Authentication Required") });
|
text: _("Authentication Required") });
|
||||||
@@ -117,9 +101,11 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
|
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
messageBox.add(userBox);
|
messageBox.add(userBox);
|
||||||
this._userIcon = new St.Icon();
|
this._userAvatar = new UserMenu.UserAvatarWidget(this._user,
|
||||||
this._userIcon.hide();
|
{ iconSize: DIALOG_ICON_SIZE,
|
||||||
userBox.add(this._userIcon,
|
styleClass: 'polkit-dialog-user-icon' });
|
||||||
|
this._userAvatar.actor.hide();
|
||||||
|
userBox.add(this._userAvatar.actor,
|
||||||
{ x_fill: true,
|
{ x_fill: true,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
x_align: St.Align.END,
|
x_align: St.Align.END,
|
||||||
@@ -313,19 +299,9 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onUserChanged: function() {
|
_onUserChanged: function() {
|
||||||
if (this._user.is_loaded) {
|
if (this._user.is_loaded && this._userAvatar) {
|
||||||
if (this._userIcon) {
|
this._userAvatar.update();
|
||||||
let iconFileName = this._user.get_icon_file();
|
this._userAvatar.actor.show();
|
||||||
let iconFile = Gio.file_new_for_path(iconFileName);
|
|
||||||
let icon;
|
|
||||||
if (iconFile.query_exists(null)) {
|
|
||||||
icon = new Gio.FileIcon({file: iconFile});
|
|
||||||
} else {
|
|
||||||
icon = new Gio.ThemedIcon({name: 'avatar-default'});
|
|
||||||
}
|
|
||||||
this._userIcon.set_gicon (icon);
|
|
||||||
this._userIcon.show();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -341,11 +317,20 @@ const AuthenticationAgent = new Lang.Class({
|
|||||||
Name: 'AuthenticationAgent',
|
Name: 'AuthenticationAgent',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
|
this._currentDialog = null;
|
||||||
|
this._isCompleting = false;
|
||||||
|
this._handle = null;
|
||||||
this._native = new Shell.PolkitAuthenticationAgent();
|
this._native = new Shell.PolkitAuthenticationAgent();
|
||||||
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
|
this._native.connect('initiate', Lang.bind(this, this._onInitiate));
|
||||||
this._native.connect('cancel', Lang.bind(this, this._onCancel));
|
this._native.connect('cancel', Lang.bind(this, this._onCancel));
|
||||||
this._currentDialog = null;
|
},
|
||||||
this._isCompleting = false;
|
|
||||||
|
enable: function() {
|
||||||
|
this._native.register();
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
this._native.unregister();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
|
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
|
||||||
@@ -403,6 +388,4 @@ const AuthenticationAgent = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function init() {
|
const Component = AuthenticationAgent;
|
||||||
let agent = new AuthenticationAgent();
|
|
||||||
}
|
|
||||||
62
js/ui/components/recorder.js
Normal file
62
js/ui/components/recorder.js
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Meta = imports.gi.Meta;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
|
const Recorder = new Lang.Class({
|
||||||
|
Name: 'Recorder',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this._recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
||||||
|
this._desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
|
||||||
|
this._bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
|
||||||
|
this._recorder = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
enable: function() {
|
||||||
|
Main.wm.addKeybinding('toggle-recording',
|
||||||
|
this._bindingSettings,
|
||||||
|
Meta.KeyBindingFlags.NONE,
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
|
Lang.bind(this, this._toggleRecorder));
|
||||||
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
Main.wm.removeKeybinding('toggle-recording');
|
||||||
|
},
|
||||||
|
|
||||||
|
_ensureRecorder: function() {
|
||||||
|
if (this._recorder == null)
|
||||||
|
this._recorder = new Shell.Recorder({ stage: global.stage });
|
||||||
|
return this._recorder;
|
||||||
|
},
|
||||||
|
|
||||||
|
_toggleRecorder: function() {
|
||||||
|
let recorder = this._ensureRecorder();
|
||||||
|
if (recorder.is_recording()) {
|
||||||
|
recorder.close();
|
||||||
|
Meta.enable_unredirect_for_screen(global.screen);
|
||||||
|
} else if (!this._desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
|
||||||
|
// read the parameters from GSettings always in case they have changed
|
||||||
|
recorder.set_framerate(this._recorderSettings.get_int('framerate'));
|
||||||
|
/* Translators: this is a filename used for screencast recording */
|
||||||
|
// xgettext:no-c-format
|
||||||
|
recorder.set_file_template(_("Screencast from %d %t") + '.' + this._recorderSettings.get_string('file-extension'));
|
||||||
|
let pipeline = this._recorderSettings.get_string('pipeline');
|
||||||
|
|
||||||
|
if (!pipeline.match(/^\s*$/))
|
||||||
|
recorder.set_pipeline(pipeline);
|
||||||
|
else
|
||||||
|
recorder.set_pipeline(null);
|
||||||
|
|
||||||
|
Meta.disable_unredirect_for_screen(global.screen);
|
||||||
|
recorder.record();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Component = Recorder;
|
||||||
@@ -11,10 +11,10 @@ const Tpl = imports.gi.TelepathyLogger;
|
|||||||
const Tp = imports.gi.TelepathyGLib;
|
const Tp = imports.gi.TelepathyGLib;
|
||||||
|
|
||||||
const History = imports.misc.history;
|
const History = imports.misc.history;
|
||||||
const Params = imports.misc.params;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
|
const Params = imports.misc.params;
|
||||||
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
|
||||||
// See Notification.appendMessage
|
// See Notification.appendMessage
|
||||||
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
|
const SCROLLBACK_IMMEDIATE_TIME = 60; // 1 minute
|
||||||
@@ -63,8 +63,8 @@ function makeMessageFromTplEvent(event) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const Client = new Lang.Class({
|
const TelepathyClient = new Lang.Class({
|
||||||
Name: 'Client',
|
Name: 'TelepathyClient',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
// channel path -> ChatSource
|
// channel path -> ChatSource
|
||||||
@@ -89,9 +89,9 @@ const Client = new Lang.Class({
|
|||||||
// channel matching its filters is detected.
|
// channel matching its filters is detected.
|
||||||
// The second argument, recover, means _observeChannels will be run
|
// The second argument, recover, means _observeChannels will be run
|
||||||
// for any existing channel as well.
|
// for any existing channel as well.
|
||||||
this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
|
this._tpClient = new Shell.TpClient({ name: 'GnomeShell',
|
||||||
'name': 'GnomeShell',
|
account_manager: this._accountManager,
|
||||||
'uniquify-name': true })
|
uniquify_name: true });
|
||||||
this._tpClient.set_observe_channels_func(
|
this._tpClient.set_observe_channels_func(
|
||||||
Lang.bind(this, this._observeChannels));
|
Lang.bind(this, this._observeChannels));
|
||||||
this._tpClient.set_approve_channels_func(
|
this._tpClient.set_approve_channels_func(
|
||||||
@@ -99,6 +99,10 @@ const Client = new Lang.Class({
|
|||||||
this._tpClient.set_handle_channels_func(
|
this._tpClient.set_handle_channels_func(
|
||||||
Lang.bind(this, this._handleChannels));
|
Lang.bind(this, this._handleChannels));
|
||||||
|
|
||||||
|
// Watch subscription requests and connection errors
|
||||||
|
this._subscriptionSource = null;
|
||||||
|
this._accountSource = null;
|
||||||
|
|
||||||
// Workaround for gjs not supporting GPtrArray in signals.
|
// Workaround for gjs not supporting GPtrArray in signals.
|
||||||
// See BGO bug #653941 for context.
|
// See BGO bug #653941 for context.
|
||||||
this._tpClient.set_contact_list_changed_func(
|
this._tpClient.set_contact_list_changed_func(
|
||||||
@@ -108,23 +112,28 @@ const Client = new Lang.Class({
|
|||||||
// needed
|
// needed
|
||||||
this._tpClient.set_delegated_channels_callback(
|
this._tpClient.set_delegated_channels_callback(
|
||||||
Lang.bind(this, this._delegatedChannelsCb));
|
Lang.bind(this, this._delegatedChannelsCb));
|
||||||
|
},
|
||||||
|
|
||||||
|
enable: function() {
|
||||||
try {
|
try {
|
||||||
this._tpClient.register();
|
this._tpClient.register();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Watch subscription requests and connection errors
|
this._accountManagerValidityChangedId = this._accountManager.connect('account-validity-changed',
|
||||||
this._subscriptionSource = null;
|
|
||||||
this._accountSource = null;
|
|
||||||
|
|
||||||
this._accountManager.connect('account-validity-changed',
|
|
||||||
Lang.bind(this, this._accountValidityChanged));
|
Lang.bind(this, this._accountValidityChanged));
|
||||||
|
|
||||||
|
if (!this._accountManager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
|
||||||
this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
|
this._accountManager.prepare_async(null, Lang.bind(this, this._accountManagerPrepared));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
disable: function() {
|
||||||
|
this._tpClient.unregister();
|
||||||
|
this._accountManager.disconnect(this._accountManagerValidityChangedId);
|
||||||
|
this._accountManagerValidityChangedId = 0;
|
||||||
|
},
|
||||||
|
|
||||||
_observeChannels: function(observer, account, conn, channels,
|
_observeChannels: function(observer, account, conn, channels,
|
||||||
dispatchOp, requests, context) {
|
dispatchOp, requests, context) {
|
||||||
let len = channels.length;
|
let len = channels.length;
|
||||||
@@ -383,8 +392,7 @@ const Client = new Lang.Class({
|
|||||||
_ensureSubscriptionSource: function() {
|
_ensureSubscriptionSource: function() {
|
||||||
if (this._subscriptionSource == null) {
|
if (this._subscriptionSource == null) {
|
||||||
this._subscriptionSource = new MessageTray.Source(_("Subscription request"),
|
this._subscriptionSource = new MessageTray.Source(_("Subscription request"),
|
||||||
'gtk-dialog-question',
|
'gtk-dialog-question');
|
||||||
St.IconType.FULLCOLOR);
|
|
||||||
Main.messageTray.add(this._subscriptionSource);
|
Main.messageTray.add(this._subscriptionSource);
|
||||||
this._subscriptionSource.connect('destroy', Lang.bind(this, function () {
|
this._subscriptionSource.connect('destroy', Lang.bind(this, function () {
|
||||||
this._subscriptionSource = null;
|
this._subscriptionSource = null;
|
||||||
@@ -420,8 +428,7 @@ const Client = new Lang.Class({
|
|||||||
_ensureAccountSource: function() {
|
_ensureAccountSource: function() {
|
||||||
if (this._accountSource == null) {
|
if (this._accountSource == null) {
|
||||||
this._accountSource = new MessageTray.Source(_("Connection error"),
|
this._accountSource = new MessageTray.Source(_("Connection error"),
|
||||||
'gtk-dialog-error',
|
'gtk-dialog-error');
|
||||||
St.IconType.FULLCOLOR);
|
|
||||||
Main.messageTray.add(this._accountSource);
|
Main.messageTray.add(this._accountSource);
|
||||||
this._accountSource.connect('destroy', Lang.bind(this, function () {
|
this._accountSource.connect('destroy', Lang.bind(this, function () {
|
||||||
this._accountSource = null;
|
this._accountSource = null;
|
||||||
@@ -475,6 +482,22 @@ const ChatSource = new Lang.Class({
|
|||||||
this._getLogMessages();
|
this._getLogMessages();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
buildRightClickMenu: function() {
|
||||||
|
let item;
|
||||||
|
|
||||||
|
let rightClickMenu = this.parent();
|
||||||
|
item = new PopupMenu.PopupMenuItem('');
|
||||||
|
item.actor.connect('notify::mapped', Lang.bind(this, function() {
|
||||||
|
item.label.set_text(this.isMuted ? _("Unmute") : _("Mute"));
|
||||||
|
}));
|
||||||
|
item.connect('activate', Lang.bind(this, function() {
|
||||||
|
this.setMuted(!this.isMuted);
|
||||||
|
this.emit('done-displaying-content');
|
||||||
|
}));
|
||||||
|
rightClickMenu.add(item.actor);
|
||||||
|
return rightClickMenu;
|
||||||
|
},
|
||||||
|
|
||||||
_updateAlias: function() {
|
_updateAlias: function() {
|
||||||
let oldAlias = this.title;
|
let oldAlias = this.title;
|
||||||
let newAlias = this._contact.get_alias();
|
let newAlias = this._contact.get_alias();
|
||||||
@@ -486,53 +509,42 @@ const ChatSource = new Lang.Class({
|
|||||||
this._notification.appendAliasChange(oldAlias, newAlias);
|
this._notification.appendAliasChange(oldAlias, newAlias);
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(size) {
|
getIcon: function() {
|
||||||
this._iconBox = new St.Bin({ style_class: 'avatar-box' });
|
|
||||||
this._iconBox._size = size;
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
|
||||||
let file = this._contact.get_avatar_file();
|
let file = this._contact.get_avatar_file();
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
let uri = file.get_uri();
|
return new Gio.FileIcon({ file: file });
|
||||||
this._iconBox.child = textureCache.load_uri_async(uri, this._iconBox._size, this._iconBox._size);
|
|
||||||
} else {
|
} else {
|
||||||
this._iconBox.child = new St.Icon({ icon_name: 'avatar-default',
|
return new Gio.ThemedIcon({ name: 'avatar-default' });
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
|
||||||
icon_size: this._iconBox._size });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._iconBox;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
createSecondaryIcon: function() {
|
getSecondaryIcon: function() {
|
||||||
let iconBox = new St.Bin();
|
let iconName;
|
||||||
iconBox.child = new St.Icon({ style_class: 'secondary-icon',
|
|
||||||
icon_type: St.IconType.FULLCOLOR });
|
|
||||||
let presenceType = this._contact.get_presence_type();
|
let presenceType = this._contact.get_presence_type();
|
||||||
|
|
||||||
switch (presenceType) {
|
switch (presenceType) {
|
||||||
case Tp.ConnectionPresenceType.AVAILABLE:
|
case Tp.ConnectionPresenceType.AVAILABLE:
|
||||||
iconBox.child.icon_name = 'user-available';
|
iconName = 'user-available';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.BUSY:
|
case Tp.ConnectionPresenceType.BUSY:
|
||||||
iconBox.child.icon_name = 'user-busy';
|
iconName = 'user-busy';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.OFFLINE:
|
case Tp.ConnectionPresenceType.OFFLINE:
|
||||||
iconBox.child.icon_name = 'user-offline';
|
iconName = 'user-offline';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.HIDDEN:
|
case Tp.ConnectionPresenceType.HIDDEN:
|
||||||
iconBox.child.icon_name = 'user-invisible';
|
iconName = 'user-invisible';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.AWAY:
|
case Tp.ConnectionPresenceType.AWAY:
|
||||||
iconBox.child.icon_name = 'user-away';
|
iconName = 'user-away';
|
||||||
break;
|
break;
|
||||||
case Tp.ConnectionPresenceType.EXTENDED_AWAY:
|
case Tp.ConnectionPresenceType.EXTENDED_AWAY:
|
||||||
iconBox.child.icon_name = 'user-idle';
|
iconName = 'user-idle';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
iconBox.child.icon_name = 'user-offline';
|
iconName = 'user-offline';
|
||||||
}
|
}
|
||||||
return iconBox;
|
return new Gio.ThemedIcon({ name: iconName });
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateAvatarIcon: function() {
|
_updateAvatarIcon: function() {
|
||||||
@@ -543,7 +555,9 @@ const ChatSource = new Lang.Class({
|
|||||||
open: function(notification) {
|
open: function(notification) {
|
||||||
if (this._client.is_handling_channel(this._channel)) {
|
if (this._client.is_handling_channel(this._channel)) {
|
||||||
// We are handling the channel, try to pass it to Empathy
|
// We are handling the channel, try to pass it to Empathy
|
||||||
this._client.delegate_channels_async([this._channel], global.get_current_time(), '', null);
|
this._client.delegate_channels_async([this._channel],
|
||||||
|
global.get_current_time(),
|
||||||
|
'org.freedesktop.Telepathy.Client.Empathy.Chat', null);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// We are not the handler, just ask to present the channel
|
// We are not the handler, just ask to present the channel
|
||||||
@@ -712,7 +726,7 @@ const ChatSource = new Lang.Class({
|
|||||||
|
|
||||||
title = GLib.markup_escape_text(this.title, -1);
|
title = GLib.markup_escape_text(this.title, -1);
|
||||||
|
|
||||||
this._notification.update(this._notification.title, null, { customContent: true, secondaryIcon: this.createSecondaryIcon() });
|
this._notification.update(this._notification.title, null, { customContent: true, secondaryGIcon: this.getSecondaryIcon() });
|
||||||
|
|
||||||
if (message)
|
if (message)
|
||||||
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
|
msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
|
||||||
@@ -725,8 +739,6 @@ const ChatSource = new Lang.Class({
|
|||||||
this._pendingMessages.splice(idx, 1);
|
this._pendingMessages.splice(idx, 1);
|
||||||
this.countUpdated();
|
this.countUpdated();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
throw new Error('Message not in our pending list: ' + message);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_ackMessages: function() {
|
_ackMessages: function() {
|
||||||
@@ -742,7 +754,7 @@ const ChatNotification = new Lang.Class({
|
|||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(source) {
|
_init: function(source) {
|
||||||
this.parent(source, source.title, null, { customContent: true, secondaryIcon: source.createSecondaryIcon() });
|
this.parent(source, source.title, null, { customContent: true, secondaryGIcon: source.getSecondaryIcon() });
|
||||||
this.setResident(true);
|
this.setResident(true);
|
||||||
|
|
||||||
this._responseEntry = new St.Entry({ style_class: 'chat-response',
|
this._responseEntry = new St.Entry({ style_class: 'chat-response',
|
||||||
@@ -751,16 +763,27 @@ const ChatNotification = new Lang.Class({
|
|||||||
this._responseEntry.clutter_text.connect('text-changed', Lang.bind(this, this._onEntryChanged));
|
this._responseEntry.clutter_text.connect('text-changed', Lang.bind(this, this._onEntryChanged));
|
||||||
this.setActionArea(this._responseEntry);
|
this.setActionArea(this._responseEntry);
|
||||||
|
|
||||||
this._oldMaxScrollAdjustment = 0;
|
this._responseEntry.clutter_text.connect('key-focus-in', Lang.bind(this, function() {
|
||||||
|
this.focused = true;
|
||||||
|
}));
|
||||||
|
this._responseEntry.clutter_text.connect('key-focus-out', Lang.bind(this, function() {
|
||||||
|
this.focused = false;
|
||||||
|
this.emit('unfocused');
|
||||||
|
}));
|
||||||
|
|
||||||
this._createScrollArea();
|
this._createScrollArea();
|
||||||
this._lastGroup = null;
|
this._lastGroup = null;
|
||||||
this._lastGroupActor = null;
|
this._lastGroupActor = null;
|
||||||
|
|
||||||
|
// Keep track of the bottom position for the current adjustment and
|
||||||
|
// force a scroll to the bottom if things change while we were at the
|
||||||
|
// bottom
|
||||||
|
this._oldMaxScrollValue = this._scrollArea.vscroll.adjustment.value;
|
||||||
|
this._scrollArea.add_style_class_name('chat-notification-scrollview');
|
||||||
this._scrollArea.vscroll.adjustment.connect('changed', Lang.bind(this, function(adjustment) {
|
this._scrollArea.vscroll.adjustment.connect('changed', Lang.bind(this, function(adjustment) {
|
||||||
let currentValue = adjustment.value + adjustment.page_size;
|
if (adjustment.value == this._oldMaxScrollValue)
|
||||||
if (currentValue == this._oldMaxScrollAdjustment)
|
|
||||||
this.scrollTo(St.Side.BOTTOM);
|
this.scrollTo(St.Side.BOTTOM);
|
||||||
this._oldMaxScrollAdjustment = adjustment.upper;
|
this._oldMaxScrollValue = Math.max(adjustment.lower, adjustment.upper - adjustment.page_size);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._inputHistory = new History.HistoryManager({ entry: this._responseEntry.clutter_text });
|
this._inputHistory = new History.HistoryManager({ entry: this._responseEntry.clutter_text });
|
||||||
@@ -912,24 +935,32 @@ const ChatNotification = new Lang.Class({
|
|||||||
|
|
||||||
let format;
|
let format;
|
||||||
|
|
||||||
// Show a week day and time if date is in the last week
|
// Show only the hour if date is on today
|
||||||
if (daysAgo < 1 || (daysAgo < 7 && now.getDay() != date.getDay())) {
|
if(daysAgo < 1){
|
||||||
/* Translators: this is a time format string followed by a date.
|
format = "<b>%H:%M</b>";
|
||||||
If applicable, replace %X with a strftime format valid for your
|
}
|
||||||
locale, without seconds. */
|
// Show the word "Yesterday" and time if date is on yesterday
|
||||||
|
else if(daysAgo <2){
|
||||||
|
/* Translators: this is a time format string followed by the word "Yesterday". i.e. "14:30 on Yesterday"*/
|
||||||
// xgettext:no-c-format
|
// xgettext:no-c-format
|
||||||
format = _("Sent at <b>%X</b> on <b>%A</b>");
|
format = _("<b>%H:%M</b> on Yesterday");
|
||||||
|
}
|
||||||
|
// Show a week day and time if date is in the last week
|
||||||
|
else if (daysAgo < 7) {
|
||||||
|
/* Translators: this is a time format string followed by a week day name. i.e. "14:30 on Monday*/
|
||||||
|
// xgettext:no-c-format
|
||||||
|
format = _("<b>%H:%M</b> on <b>%A</b>");
|
||||||
|
|
||||||
} else if (date.getYear() == now.getYear()) {
|
} else if (date.getYear() == now.getYear()) {
|
||||||
/* Translators: this is a time format in the style of "Wednesday, May 25",
|
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25",
|
||||||
shown when you get a chat message in the same year. */
|
shown when you get a chat message in the same year */
|
||||||
// xgettext:no-c-format
|
// xgettext:no-c-format
|
||||||
format = _("Sent on <b>%A</b>, <b>%B %d</b>");
|
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>");
|
||||||
} else {
|
} else {
|
||||||
/* Translators: this is a time format in the style of "Wednesday, May 25, 2012",
|
/* Translators: this is a time format in the style of "14:30 on Wednesday, May 25, 2012",
|
||||||
shown when you get a chat message in a different year. */
|
shown when you get a chat message in a different year */
|
||||||
// xgettext:no-c-format
|
// xgettext:no-c-format
|
||||||
format = _("Sent on <b>%A</b>, <b>%B %d</b>, %Y");
|
format = _("<b>%H:%M</b> on <b>%A</b>, <b>%B</b> <b>%d</b>, %Y");
|
||||||
}
|
}
|
||||||
|
|
||||||
return date.toLocaleFormat(format);
|
return date.toLocaleFormat(format);
|
||||||
@@ -942,8 +973,7 @@ const ChatNotification = new Lang.Class({
|
|||||||
let timeLabel = this._append({ body: this._formatTimestamp(lastMessageDate),
|
let timeLabel = this._append({ body: this._formatTimestamp(lastMessageDate),
|
||||||
group: 'meta',
|
group: 'meta',
|
||||||
styles: ['chat-meta-message'],
|
styles: ['chat-meta-message'],
|
||||||
childProps: { expand: true, x_fill: false,
|
childProps: { expand: true, x_fill: false },
|
||||||
x_align: St.Align.END },
|
|
||||||
noTimestamp: true,
|
noTimestamp: true,
|
||||||
timestamp: lastMessageTime });
|
timestamp: lastMessageTime });
|
||||||
|
|
||||||
@@ -1044,9 +1074,8 @@ const ApproverSource = new Lang.Class({
|
|||||||
this.parent();
|
this.parent();
|
||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(size) {
|
getIcon: function() {
|
||||||
return new St.Icon({ gicon: this._gicon,
|
return this._gicon;
|
||||||
icon_size: size });
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1107,7 +1136,7 @@ const AudioVideoNotification = new Lang.Class({
|
|||||||
this.parent(source, title, null, { customContent: true });
|
this.parent(source, title, null, { customContent: true });
|
||||||
this.setResident(true);
|
this.setResident(true);
|
||||||
|
|
||||||
this.addButton('reject', _("Reject"));
|
this.addButton('reject', _("Decline"));
|
||||||
/* translators: this is a button label (verb), not a noun */
|
/* translators: this is a button label (verb), not a noun */
|
||||||
this.addButton('answer', _("Answer"));
|
this.addButton('answer', _("Answer"));
|
||||||
|
|
||||||
@@ -1197,7 +1226,6 @@ const SubscriptionRequestNotification = new Lang.Class({
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iconBox.child = new St.Icon({ icon_name: 'avatar-default',
|
iconBox.child = new St.Icon({ icon_name: 'avatar-default',
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
|
||||||
icon_size: iconBox._size });
|
icon_size: iconBox._size });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1404,3 +1432,4 @@ const AccountNotification = new Lang.Class({
|
|||||||
this.parent();
|
this.parent();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
const Component = TelepathyClient;
|
||||||
@@ -54,16 +54,17 @@ const CtrlAltTabManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
focusGroup: function(item) {
|
focusGroup: function(item) {
|
||||||
|
if (item.window) {
|
||||||
|
Main.activateWindow(item.window);
|
||||||
|
} else if (item.focusCallback) {
|
||||||
|
item.focusCallback();
|
||||||
|
} else {
|
||||||
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
|
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
|
||||||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
|
global.stage_input_mode == Shell.StageInputMode.NORMAL)
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
||||||
|
|
||||||
if (item.window)
|
|
||||||
Main.activateWindow(item.window);
|
|
||||||
else if (item.focusCallback)
|
|
||||||
item.focusCallback();
|
|
||||||
else
|
|
||||||
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sort the items into a consistent order; panel first, tray last,
|
// Sort the items into a consistent order; panel first, tray last,
|
||||||
@@ -318,7 +319,6 @@ const CtrlAltTabSwitcher = new Lang.Class({
|
|||||||
let icon = item.iconActor;
|
let icon = item.iconActor;
|
||||||
if (!icon) {
|
if (!icon) {
|
||||||
icon = new St.Icon({ icon_name: item.iconName,
|
icon = new St.Icon({ icon_name: item.iconName,
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
|
||||||
icon_size: POPUP_APPICON_SIZE });
|
icon_size: POPUP_APPICON_SIZE });
|
||||||
}
|
}
|
||||||
box.add(icon, { x_fill: false, y_fill: false } );
|
box.add(icon, { x_fill: false, y_fill: false } );
|
||||||
|
|||||||
249
js/ui/dash.js
249
js/ui/dash.js
@@ -21,6 +21,17 @@ const DASH_ITEM_LABEL_SHOW_TIME = 0.15;
|
|||||||
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
||||||
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
||||||
|
|
||||||
|
function getAppFromSource(source) {
|
||||||
|
if (source instanceof AppDisplay.AppWellIcon) {
|
||||||
|
return source.app;
|
||||||
|
} else if (source.metaWindow) {
|
||||||
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
|
return tracker.get_window_app(source.metaWindow);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A container like StBin, but taking the child's scale into account
|
// A container like StBin, but taking the child's scale into account
|
||||||
// when requesting a size
|
// when requesting a size
|
||||||
const DashItemContainer = new Lang.Class({
|
const DashItemContainer = new Lang.Class({
|
||||||
@@ -36,7 +47,11 @@ const DashItemContainer = new Lang.Class({
|
|||||||
Lang.bind(this, this._allocate));
|
Lang.bind(this, this._allocate));
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this.label = null;
|
this._labelText = "";
|
||||||
|
this.label = new St.Label({ style_class: 'dash-label'});
|
||||||
|
this.label.hide();
|
||||||
|
Main.layoutManager.addChrome(this.label);
|
||||||
|
this.actor.label_actor = this.label;
|
||||||
|
|
||||||
this.child = null;
|
this.child = null;
|
||||||
this._childScale = 1;
|
this._childScale = 1;
|
||||||
@@ -91,9 +106,10 @@ const DashItemContainer = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
showLabel: function() {
|
showLabel: function() {
|
||||||
if (this.label == null)
|
if (!this._labelText)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this.label.set_text(this._labelText);
|
||||||
this.label.opacity = 0;
|
this.label.opacity = 0;
|
||||||
this.label.show();
|
this.label.show();
|
||||||
|
|
||||||
@@ -124,12 +140,8 @@ const DashItemContainer = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setLabelText: function(text) {
|
setLabelText: function(text) {
|
||||||
if (this.label == null)
|
this._labelText = text;
|
||||||
this.label = new St.Label({ style_class: 'dash-label'});
|
this.child.accessible_name = text;
|
||||||
|
|
||||||
this.label.set_text(text);
|
|
||||||
Main.layoutManager.addChrome(this.label);
|
|
||||||
this.label.hide();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
hideLabel: function () {
|
hideLabel: function () {
|
||||||
@@ -246,37 +258,56 @@ const ShowAppsIcon = new Lang.Class({
|
|||||||
this.toggleButton._delegate = this;
|
this.toggleButton._delegate = this;
|
||||||
|
|
||||||
this.setChild(this.toggleButton);
|
this.setChild(this.toggleButton);
|
||||||
|
this.setDragApp(null);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createIcon: function(size) {
|
_createIcon: function(size) {
|
||||||
this._iconActor = new St.Icon({ icon_name: 'view-grid-symbolic',
|
this._iconActor = new St.Icon({ icon_name: 'view-grid-symbolic',
|
||||||
|
icon_size: size,
|
||||||
style_class: 'show-apps-icon',
|
style_class: 'show-apps-icon',
|
||||||
track_hover: true,
|
track_hover: true });
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
|
||||||
icon_size: size });
|
|
||||||
return this._iconActor;
|
return this._iconActor;
|
||||||
},
|
},
|
||||||
|
|
||||||
setHover: function(hovered) {
|
_canRemoveApp: function(app) {
|
||||||
this.toggleButton.set_hover(hovered);
|
if (app == null)
|
||||||
if (this._iconActor)
|
return false;
|
||||||
this._iconActor.set_hover(hovered);
|
|
||||||
|
let id = app.get_id();
|
||||||
|
let isFavorite = AppFavorites.getAppFavorites().isFavorite(id);
|
||||||
|
return isFavorite;
|
||||||
|
},
|
||||||
|
|
||||||
|
setDragApp: function(app) {
|
||||||
|
let canRemove = this._canRemoveApp(app);
|
||||||
|
|
||||||
|
this.toggleButton.set_hover(canRemove);
|
||||||
|
if (this._iconActor)
|
||||||
|
this._iconActor.set_hover(canRemove);
|
||||||
|
|
||||||
|
if (canRemove)
|
||||||
|
this.setLabelText(_("Remove from Favorites"));
|
||||||
|
else
|
||||||
|
this.setLabelText(_("Show Applications"));
|
||||||
},
|
},
|
||||||
|
|
||||||
// Rely on the dragged item being a favorite
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
|
let app = getAppFromSource(source);
|
||||||
|
if (app == null)
|
||||||
|
return DND.DragMotionResult.NO_DROP;
|
||||||
|
|
||||||
|
let id = app.get_id();
|
||||||
|
let isFavorite = AppFavorites.getAppFavorites().isFavorite(id);
|
||||||
|
if (!isFavorite)
|
||||||
|
return DND.DragMotionResult.NO_DROP;
|
||||||
|
|
||||||
return DND.DragMotionResult.MOVE_DROP;
|
return DND.DragMotionResult.MOVE_DROP;
|
||||||
},
|
},
|
||||||
|
|
||||||
acceptDrop: function(source, actor, x, y, time) {
|
acceptDrop: function(source, actor, x, y, time) {
|
||||||
let app = null;
|
let app = getAppFromSource(source);
|
||||||
if (source instanceof AppDisplay.AppWellIcon) {
|
if (app == null)
|
||||||
let appSystem = Shell.AppSystem.get_default();
|
return false;
|
||||||
app = appSystem.lookup_app(source.getId());
|
|
||||||
} else if (source.metaWindow) {
|
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
|
||||||
app = tracker.get_window_app(source.metaWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
let id = app.get_id();
|
let id = app.get_id();
|
||||||
|
|
||||||
@@ -300,6 +331,39 @@ const DragPlaceholderItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const DashActor = new Lang.Class({
|
||||||
|
Name: 'DashActor',
|
||||||
|
Extends: St.Widget,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
let layout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.VERTICAL });
|
||||||
|
this.parent({ name: 'dash',
|
||||||
|
layout_manager: layout,
|
||||||
|
clip_to_allocation: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_allocate: function(box, flags) {
|
||||||
|
let contentBox = this.get_theme_node().get_content_box(box);
|
||||||
|
let availWidth = contentBox.x2 - contentBox.x1;
|
||||||
|
|
||||||
|
this.set_allocation(box, flags);
|
||||||
|
|
||||||
|
let [appIcons, showAppsButton] = this.get_children();
|
||||||
|
let [showAppsMinHeight, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
|
||||||
|
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
childBox.x1 = contentBox.x1;
|
||||||
|
childBox.y1 = contentBox.y1;
|
||||||
|
childBox.x2 = contentBox.x2;
|
||||||
|
childBox.y2 = contentBox.y2 - showAppsNatHeight;
|
||||||
|
appIcons.allocate(childBox, flags);
|
||||||
|
|
||||||
|
childBox.y1 = contentBox.y2 - showAppsNatHeight;
|
||||||
|
childBox.y2 = contentBox.y2;
|
||||||
|
showAppsButton.allocate(childBox, flags);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const Dash = new Lang.Class({
|
const Dash = new Lang.Class({
|
||||||
Name: 'Dash',
|
Name: 'Dash',
|
||||||
|
|
||||||
@@ -315,21 +379,19 @@ const Dash = new Lang.Class({
|
|||||||
this._resetHoverTimeoutId = 0;
|
this._resetHoverTimeoutId = 0;
|
||||||
this._labelShowing = false;
|
this._labelShowing = false;
|
||||||
|
|
||||||
this._container = new St.BoxLayout({ name: 'dash',
|
this._container = new DashActor();
|
||||||
vertical: true,
|
|
||||||
clip_to_allocation: true });
|
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ vertical: true,
|
this._box = new St.BoxLayout({ vertical: true,
|
||||||
clip_to_allocation: true });
|
clip_to_allocation: true });
|
||||||
this._box._delegate = this;
|
this._box._delegate = this;
|
||||||
this._container.add(this._box);
|
this._container.add_actor(this._box);
|
||||||
|
|
||||||
this._showAppsIcon = new ShowAppsIcon();
|
this._showAppsIcon = new ShowAppsIcon();
|
||||||
this._showAppsIcon.icon.setIconSize(this.iconSize);
|
this._showAppsIcon.icon.setIconSize(this.iconSize);
|
||||||
|
this._hookUpLabel(this._showAppsIcon);
|
||||||
|
|
||||||
this.showAppsButton = this._showAppsIcon.toggleButton;
|
this.showAppsButton = this._showAppsIcon.toggleButton;
|
||||||
|
|
||||||
this._container.add(this._showAppsIcon.actor);
|
this._container.add_actor(this._showAppsIcon.actor);
|
||||||
|
|
||||||
this.actor = new St.Bin({ child: this._container });
|
this.actor = new St.Bin({ child: this._container });
|
||||||
this.actor.connect('notify::height', Lang.bind(this,
|
this.actor.connect('notify::height', Lang.bind(this,
|
||||||
@@ -341,7 +403,6 @@ const Dash = new Lang.Class({
|
|||||||
|
|
||||||
this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay));
|
this._workId = Main.initializeDeferredWork(this._box, Lang.bind(this, this._redisplay));
|
||||||
|
|
||||||
this._tracker = Shell.WindowTracker.get_default();
|
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
this._appSystem = Shell.AppSystem.get_default();
|
||||||
|
|
||||||
this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
|
this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
|
||||||
@@ -384,31 +445,25 @@ const Dash = new Lang.Class({
|
|||||||
|
|
||||||
_endDrag: function() {
|
_endDrag: function() {
|
||||||
this._clearDragPlaceholder();
|
this._clearDragPlaceholder();
|
||||||
|
this._showAppsIcon.setDragApp(null);
|
||||||
DND.removeDragMonitor(this._dragMonitor);
|
DND.removeDragMonitor(this._dragMonitor);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragMotion: function(dragEvent) {
|
_onDragMotion: function(dragEvent) {
|
||||||
let app = null;
|
let app = getAppFromSource(dragEvent.source);
|
||||||
if (dragEvent.source instanceof AppDisplay.AppWellIcon)
|
if (app == null)
|
||||||
app = this._appSystem.lookup_app(dragEvent.source.getId());
|
|
||||||
else if (dragEvent.source.metaWindow)
|
|
||||||
app = this._tracker.get_window_app(dragEvent.source.metaWindow);
|
|
||||||
else
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
let id = app.get_id();
|
|
||||||
|
|
||||||
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
|
|
||||||
|
|
||||||
let srcIsFavorite = (id in favorites);
|
|
||||||
|
|
||||||
let showAppsHovered =
|
let showAppsHovered =
|
||||||
this._showAppsIcon.actor.contains(dragEvent.targetActor);
|
this._showAppsIcon.actor.contains(dragEvent.targetActor);
|
||||||
|
|
||||||
if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
|
if (!this._box.contains(dragEvent.targetActor) || showAppsHovered)
|
||||||
this._clearDragPlaceholder();
|
this._clearDragPlaceholder();
|
||||||
|
|
||||||
this._showAppsIcon.setHover(showAppsHovered);
|
if (showAppsHovered)
|
||||||
|
this._showAppsIcon.setDragApp(app);
|
||||||
|
else
|
||||||
|
this._showAppsIcon.setDragApp(null);
|
||||||
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
},
|
},
|
||||||
@@ -424,44 +479,63 @@ const Dash = new Lang.Class({
|
|||||||
Main.queueDeferredWork(this._workId);
|
Main.queueDeferredWork(this._workId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createAppItem: function(app) {
|
_hookUpLabel: function(item) {
|
||||||
let display = new AppDisplay.AppWellIcon(app,
|
item.child.connect('notify::hover', Lang.bind(this, function() {
|
||||||
{ setSizeManually: true,
|
this._onHover(item);
|
||||||
showLabel: false });
|
|
||||||
display._draggable.connect('drag-begin',
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
display.actor.opacity = 50;
|
|
||||||
}));
|
|
||||||
display._draggable.connect('drag-end',
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
display.actor.opacity = 255;
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let item = new DashItemContainer();
|
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||||
item.setChild(display.actor);
|
|
||||||
|
|
||||||
item.setLabelText(app.get_name());
|
|
||||||
// Override default AppWellIcon label_actor
|
|
||||||
display.actor.label_actor = item.label;
|
|
||||||
|
|
||||||
|
|
||||||
display.icon.setIconSize(this.iconSize);
|
|
||||||
display.actor.connect('notify::hover',
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
this._onHover(item, display)
|
|
||||||
}));
|
|
||||||
|
|
||||||
Main.overview.connect('hiding',
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
this._labelShowing = false;
|
this._labelShowing = false;
|
||||||
item.hideLabel();
|
item.hideLabel();
|
||||||
}));
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_createAppItem: function(app) {
|
||||||
|
let appIcon = new AppDisplay.AppWellIcon(app,
|
||||||
|
{ setSizeManually: true,
|
||||||
|
showLabel: false });
|
||||||
|
appIcon._draggable.connect('drag-begin',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
appIcon.actor.opacity = 50;
|
||||||
|
}));
|
||||||
|
appIcon._draggable.connect('drag-end',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
appIcon.actor.opacity = 255;
|
||||||
|
}));
|
||||||
|
appIcon.connect('menu-state-changed',
|
||||||
|
Lang.bind(this, function(appIcon, opened) {
|
||||||
|
this._itemMenuStateChanged(item, opened);
|
||||||
|
}));
|
||||||
|
|
||||||
|
let item = new DashItemContainer();
|
||||||
|
item.setChild(appIcon.actor);
|
||||||
|
|
||||||
|
// Override default AppWellIcon label_actor, now the
|
||||||
|
// accessible_name is set at DashItemContainer.setLabelText
|
||||||
|
appIcon.actor.label_actor = null;
|
||||||
|
item.setLabelText(app.get_name());
|
||||||
|
|
||||||
|
appIcon.icon.setIconSize(this.iconSize);
|
||||||
|
this._hookUpLabel(item);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onHover: function (item, display) {
|
_itemMenuStateChanged: function(item, opened) {
|
||||||
if (display.actor.get_hover() && !display.isMenuUp) {
|
// When the menu closes, it calls sync_hover, which means
|
||||||
|
// that the notify::hover handler does everything we need to.
|
||||||
|
if (opened) {
|
||||||
|
if (this._showLabelTimeoutId > 0) {
|
||||||
|
Mainloop.source_remove(this._showLabelTimeoutId);
|
||||||
|
this._showLabelTimeoutId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.hideLabel();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onHover: function (item) {
|
||||||
|
if (item.child.get_hover()) {
|
||||||
if (this._showLabelTimeoutId == 0) {
|
if (this._showLabelTimeoutId == 0) {
|
||||||
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
||||||
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
|
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
|
||||||
@@ -563,8 +637,10 @@ const Dash = new Lang.Class({
|
|||||||
icon.setIconSize(this.iconSize);
|
icon.setIconSize(this.iconSize);
|
||||||
|
|
||||||
// Don't animate the icon size change when the overview
|
// Don't animate the icon size change when the overview
|
||||||
// is not visible or when initially filling the dash
|
// is transitioning, not visible or when initially filling
|
||||||
if (!Main.overview.visible || !this._shownInitially)
|
// the dash
|
||||||
|
if (!Main.overview.visible || Main.overview.animationInProgress ||
|
||||||
|
!this._shownInitially)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let [targetWidth, targetHeight] = icon.icon.get_size();
|
let [targetWidth, targetHeight] = icon.icon.get_size();
|
||||||
@@ -688,8 +764,9 @@ const Dash = new Lang.Class({
|
|||||||
for (let i = 0; i < removedActors.length; i++) {
|
for (let i = 0; i < removedActors.length; i++) {
|
||||||
let item = removedActors[i]._delegate;
|
let item = removedActors[i]._delegate;
|
||||||
|
|
||||||
// Don't animate item removal when the overview is hidden
|
// Don't animate item removal when the overview is transitioning
|
||||||
if (Main.overview.visible)
|
// or hidden
|
||||||
|
if (Main.overview.visible && !Main.overview.animationInProgress)
|
||||||
item.animateOutAndDestroy();
|
item.animateOutAndDestroy();
|
||||||
else
|
else
|
||||||
item.destroy();
|
item.destroy();
|
||||||
@@ -704,8 +781,9 @@ const Dash = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't animate item addition when the overview is hidden
|
// Don't animate item addition when the overview is transitioning
|
||||||
if (!Main.overview.visible)
|
// or hidden
|
||||||
|
if (!Main.overview.visible || Main.overview.animationInProgress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (let i = 0; i < addedItems.length; i++)
|
for (let i = 0; i < addedItems.length; i++)
|
||||||
@@ -721,11 +799,7 @@ const Dash = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleDragOver : function(source, actor, x, y, time) {
|
handleDragOver : function(source, actor, x, y, time) {
|
||||||
let app = null;
|
let app = getAppFromSource(source);
|
||||||
if (source instanceof AppDisplay.AppWellIcon)
|
|
||||||
app = this._appSystem.lookup_app(source.getId());
|
|
||||||
else if (source.metaWindow)
|
|
||||||
app = this._tracker.get_window_app(source.metaWindow);
|
|
||||||
|
|
||||||
// Don't allow favoriting of transient apps
|
// Don't allow favoriting of transient apps
|
||||||
if (app == null || app.is_window_backed())
|
if (app == null || app.is_window_backed())
|
||||||
@@ -806,12 +880,7 @@ const Dash = new Lang.Class({
|
|||||||
|
|
||||||
// Draggable target interface
|
// Draggable target interface
|
||||||
acceptDrop : function(source, actor, x, y, time) {
|
acceptDrop : function(source, actor, x, y, time) {
|
||||||
let app = null;
|
let app = getAppFromSource(source);
|
||||||
if (source instanceof AppDisplay.AppWellIcon) {
|
|
||||||
app = this._appSystem.lookup_app(source.getId());
|
|
||||||
} else if (source.metaWindow) {
|
|
||||||
app = this._tracker.get_window_app(source.metaWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't allow favoriting of transient apps
|
// Don't allow favoriting of transient apps
|
||||||
if (app == null || app.is_window_backed()) {
|
if (app == null || app.is_window_backed()) {
|
||||||
|
|||||||
@@ -70,16 +70,8 @@ const DateMenuButton = new Lang.Class({
|
|||||||
this._date.style_class = 'datemenu-date-label';
|
this._date.style_class = 'datemenu-date-label';
|
||||||
vbox.add(this._date);
|
vbox.add(this._date);
|
||||||
|
|
||||||
if (Main.sessionMode.showCalendarEvents) {
|
this._eventList = new Calendar.EventsList();
|
||||||
this._eventSource = new Calendar.DBusEventSource();
|
this._calendar = new Calendar.Calendar();
|
||||||
this._eventList = new Calendar.EventsList(this._eventSource);
|
|
||||||
} else {
|
|
||||||
this._eventSource = null;
|
|
||||||
this._eventList = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calendar
|
|
||||||
this._calendar = new Calendar.Calendar(this._eventSource);
|
|
||||||
|
|
||||||
this._calendar.connect('selected-date-changed',
|
this._calendar.connect('selected-date-changed',
|
||||||
Lang.bind(this, function(calendar, date) {
|
Lang.bind(this, function(calendar, date) {
|
||||||
@@ -97,17 +89,16 @@ const DateMenuButton = new Lang.Class({
|
|||||||
separator.setColumnWidths(1);
|
separator.setColumnWidths(1);
|
||||||
vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
vbox.add(separator.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||||
|
|
||||||
|
item.actor.show_on_set_parent = false;
|
||||||
item.actor.can_focus = false;
|
item.actor.can_focus = false;
|
||||||
item.actor.reparent(vbox);
|
item.actor.reparent(vbox);
|
||||||
|
this._dateAndTimeSeparator = separator;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Main.sessionMode.showCalendarEvents) {
|
this._separator = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
||||||
// Add vertical separator
|
|
||||||
|
|
||||||
item = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
|
||||||
pseudo_class: 'highlighted' });
|
pseudo_class: 'highlighted' });
|
||||||
item.connect('repaint', Lang.bind(this, _onVertSepRepaint));
|
this._separator.connect('repaint', Lang.bind(this, _onVertSepRepaint));
|
||||||
hbox.add(item);
|
hbox.add(this._separator);
|
||||||
|
|
||||||
// Fill up the second column
|
// Fill up the second column
|
||||||
vbox = new St.BoxLayout({ name: 'calendarEventsArea',
|
vbox = new St.BoxLayout({ name: 'calendarEventsArea',
|
||||||
@@ -117,11 +108,15 @@ const DateMenuButton = new Lang.Class({
|
|||||||
// Event list
|
// Event list
|
||||||
vbox.add(this._eventList.actor, { expand: true });
|
vbox.add(this._eventList.actor, { expand: true });
|
||||||
|
|
||||||
item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
this._openCalendarItem = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
||||||
item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
this._openCalendarItem.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
||||||
item.actor.can_focus = false;
|
this._openCalendarItem.actor.can_focus = false;
|
||||||
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
vbox.add(this._openCalendarItem.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||||
}
|
|
||||||
|
this._calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
|
||||||
|
this._calendarSettings.connect('changed::exec',
|
||||||
|
Lang.bind(this, this._calendarSettingsChanged));
|
||||||
|
this._calendarSettingsChanged();
|
||||||
|
|
||||||
// Whenever the menu is opened, select today
|
// Whenever the menu is opened, select today
|
||||||
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
||||||
@@ -151,6 +146,51 @@ const DateMenuButton = new Lang.Class({
|
|||||||
this._clock = new GnomeDesktop.WallClock();
|
this._clock = new GnomeDesktop.WallClock();
|
||||||
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
|
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
|
||||||
this._updateClockAndDate();
|
this._updateClockAndDate();
|
||||||
|
|
||||||
|
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||||
|
this._sessionUpdated();
|
||||||
|
},
|
||||||
|
|
||||||
|
_calendarSettingsChanged: function() {
|
||||||
|
let exec = this._calendarSettings.get_string('exec');
|
||||||
|
let fullExec = GLib.find_program_in_path(exec);
|
||||||
|
this._openCalendarItem.actor.visible = fullExec != null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_setEventsVisibility: function(visible) {
|
||||||
|
this._openCalendarItem.actor.visible = visible;
|
||||||
|
this._separator.visible = visible;
|
||||||
|
if (visible) {
|
||||||
|
let alignment = 0.25;
|
||||||
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
|
alignment = 1.0 - alignment;
|
||||||
|
this.menu._arrowAlignment = alignment;
|
||||||
|
this._eventList.actor.get_parent().show();
|
||||||
|
} else {
|
||||||
|
this.menu._arrowAlignment = 0.5;
|
||||||
|
this._eventList.actor.get_parent().hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_setEventSource: function(eventSource) {
|
||||||
|
this._calendar.setEventSource(eventSource);
|
||||||
|
this._eventList.setEventSource(eventSource);
|
||||||
|
},
|
||||||
|
|
||||||
|
_sessionUpdated: function() {
|
||||||
|
let eventSource;
|
||||||
|
let showEvents = Main.sessionMode.showCalendarEvents;
|
||||||
|
if (showEvents) {
|
||||||
|
eventSource = new Calendar.DBusEventSource();
|
||||||
|
} else {
|
||||||
|
eventSource = null;
|
||||||
|
}
|
||||||
|
this._setEventSource(eventSource);
|
||||||
|
this._setEventsVisibility(showEvents);
|
||||||
|
|
||||||
|
// This needs to be handled manually, as the code to
|
||||||
|
// autohide separators doesn't work across the vbox
|
||||||
|
this._dateAndTimeSeparator.actor.visible = Main.sessionMode.allowSettings;
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateClockAndDate: function() {
|
_updateClockAndDate: function() {
|
||||||
@@ -165,14 +205,13 @@ const DateMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
_onOpenCalendarActivate: function() {
|
_onOpenCalendarActivate: function() {
|
||||||
this.menu.close();
|
this.menu.close();
|
||||||
let calendarSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.office.calendar' });
|
let tool = this._calendarSettings.get_string('exec');
|
||||||
let tool = calendarSettings.get_string('exec');
|
|
||||||
if (tool.length == 0 || tool.substr(0, 9) == 'evolution') {
|
if (tool.length == 0 || tool.substr(0, 9) == 'evolution') {
|
||||||
// TODO: pass the selected day
|
// TODO: pass the selected day
|
||||||
let app = Shell.AppSystem.get_default().lookup_app('evolution-calendar.desktop');
|
let app = Shell.AppSystem.get_default().lookup_app('evolution-calendar.desktop');
|
||||||
app.activate();
|
app.activate();
|
||||||
} else {
|
} else {
|
||||||
let needTerm = calendarSettings.get_boolean('needs-term');
|
let needTerm = this._calendarSettings.get_boolean('needs-term');
|
||||||
if (needTerm) {
|
if (needTerm) {
|
||||||
let terminalSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.terminal' });
|
let terminalSettings = new Gio.Settings({ schema: 'org.gnome.desktop.default-applications.terminal' });
|
||||||
let term = terminalSettings.get_string('exec');
|
let term = terminalSettings.get_string('exec');
|
||||||
|
|||||||
13
js/ui/dnd.js
13
js/ui/dnd.js
@@ -235,6 +235,10 @@ const _Draggable = new Lang.Class({
|
|||||||
|
|
||||||
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
||||||
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
||||||
|
this._dragActor.reparent(Main.uiGroup);
|
||||||
|
this._dragActor.raise_top();
|
||||||
|
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
||||||
|
|
||||||
// Drag actor does not always have to be the same as actor. For example drag actor
|
// Drag actor does not always have to be the same as actor. For example drag actor
|
||||||
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
||||||
// to know what was the drag actor source.
|
// to know what was the drag actor source.
|
||||||
@@ -263,12 +267,17 @@ const _Draggable = new Lang.Class({
|
|||||||
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
||||||
} else {
|
} else {
|
||||||
this._dragActor = this.actor;
|
this._dragActor = this.actor;
|
||||||
|
|
||||||
this._dragActorSource = undefined;
|
this._dragActorSource = undefined;
|
||||||
this._dragOrigParent = this.actor.get_parent();
|
this._dragOrigParent = this.actor.get_parent();
|
||||||
this._dragOrigX = this._dragActor.x;
|
this._dragOrigX = this._dragActor.x;
|
||||||
this._dragOrigY = this._dragActor.y;
|
this._dragOrigY = this._dragActor.y;
|
||||||
this._dragOrigScale = this._dragActor.scale_x;
|
this._dragOrigScale = this._dragActor.scale_x;
|
||||||
|
|
||||||
|
this._dragActor.reparent(Main.uiGroup);
|
||||||
|
this._dragActor.raise_top();
|
||||||
|
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
||||||
|
|
||||||
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
|
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
|
||||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||||
@@ -280,10 +289,6 @@ const _Draggable = new Lang.Class({
|
|||||||
scaledHeight / this.actor.height);
|
scaledHeight / this.actor.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dragActor.reparent(Main.uiGroup);
|
|
||||||
this._dragActor.raise_top();
|
|
||||||
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
|
||||||
|
|
||||||
this._dragOrigOpacity = this._dragActor.opacity;
|
this._dragOrigOpacity = this._dragActor.opacity;
|
||||||
if (this._dragActorOpacity != undefined)
|
if (this._dragActorOpacity != undefined)
|
||||||
this._dragActor.opacity = this._dragActorOpacity;
|
this._dragActor.opacity = this._dragActorOpacity;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ const GnomeSession = imports.misc.gnomeSession;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
const UserMenu = imports.ui.userMenu;
|
||||||
|
|
||||||
let _endSessionDialog = null;
|
let _endSessionDialog = null;
|
||||||
|
|
||||||
@@ -89,7 +90,7 @@ const shutdownDialogContent = {
|
|||||||
label: C_("button", "Restart") },
|
label: C_("button", "Restart") },
|
||||||
{ signal: 'ConfirmedShutdown',
|
{ signal: 'ConfirmedShutdown',
|
||||||
label: C_("button", "Power Off") }],
|
label: C_("button", "Power Off") }],
|
||||||
iconName: 'system-shutdown',
|
iconName: 'system-shutdown-symbolic',
|
||||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ const restartDialogContent = {
|
|||||||
endDescription: _("Restarting the system."),
|
endDescription: _("Restarting the system."),
|
||||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||||
label: C_("button", "Restart") }],
|
label: C_("button", "Restart") }],
|
||||||
iconName: 'system-shutdown',
|
iconName: 'view-refresh-symbolic',
|
||||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,6 +161,7 @@ const ListItem = new Lang.Class({
|
|||||||
|
|
||||||
this._descriptionLabel = new St.Label({ text: this._reason,
|
this._descriptionLabel = new St.Label({ text: this._reason,
|
||||||
style_class: 'end-session-dialog-app-list-item-description' });
|
style_class: 'end-session-dialog-app-list-item-description' });
|
||||||
|
this.actor.label_actor = this._nameLabel;
|
||||||
textLayout.add(this._descriptionLabel,
|
textLayout.add(this._descriptionLabel,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true });
|
x_fill: true });
|
||||||
@@ -302,41 +304,6 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this._user.disconnect(this._userChangedId);
|
this._user.disconnect(this._userChangedId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_setIconFromFile: function(iconFile, styleClass) {
|
|
||||||
if (styleClass)
|
|
||||||
this._iconBin.set_style_class_name(styleClass);
|
|
||||||
this._iconBin.set_style(null);
|
|
||||||
|
|
||||||
this._iconBin.child = null;
|
|
||||||
if (iconFile) {
|
|
||||||
this._iconBin.show();
|
|
||||||
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
|
||||||
'background-size: contain;');
|
|
||||||
} else {
|
|
||||||
this._iconBin.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_setIconFromName: function(iconName, styleClass) {
|
|
||||||
if (styleClass)
|
|
||||||
this._iconBin.set_style_class_name(styleClass);
|
|
||||||
this._iconBin.set_style(null);
|
|
||||||
|
|
||||||
if (iconName != null) {
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
|
||||||
let icon = textureCache.load_icon_name(this._iconBin.get_theme_node(),
|
|
||||||
iconName,
|
|
||||||
St.IconType.SYMBOLIC,
|
|
||||||
_DIALOG_ICON_SIZE);
|
|
||||||
|
|
||||||
this._iconBin.child = icon;
|
|
||||||
this._iconBin.show();
|
|
||||||
} else {
|
|
||||||
this._iconBin.child = null;
|
|
||||||
this._iconBin.hide();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateDescription: function() {
|
_updateDescription: function() {
|
||||||
if (this.state != ModalDialog.State.OPENING &&
|
if (this.state != ModalDialog.State.OPENING &&
|
||||||
this.state != ModalDialog.State.OPENED)
|
this.state != ModalDialog.State.OPENED)
|
||||||
@@ -385,16 +352,16 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
let dialogContent = DialogContent[this._type];
|
let dialogContent = DialogContent[this._type];
|
||||||
|
if (dialogContent.iconName) {
|
||||||
if (this._user.is_loaded && !dialogContent.iconName) {
|
this._iconBin.child = new St.Icon({ icon_name: dialogContent.iconName,
|
||||||
let iconFile = this._user.get_icon_file();
|
icon_size: _DIALOG_ICON_SIZE,
|
||||||
if (GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
style_class: dialogContent.iconStyleClass });
|
||||||
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
|
} else {
|
||||||
else
|
let avatarWidget = new UserMenu.UserAvatarWidget(this._user,
|
||||||
this._setIconFromName('avatar-default', dialogContent.iconStyleClass);
|
{ iconSize: _DIALOG_ICON_SIZE,
|
||||||
} else if (dialogContent.iconName) {
|
styleClass: dialogContent.iconStyleClass });
|
||||||
this._setIconFromName(dialogContent.iconName,
|
this._iconBin.child = avatarWidget.actor;
|
||||||
dialogContent.iconStyleClass);
|
avatarWidget.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateDescription();
|
this._updateDescription();
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ function uninstallExtension(uuid) {
|
|||||||
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (!ExtensionSystem.unloadExtension(uuid))
|
if (!ExtensionSystem.unloadExtension(extension))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
FileUtils.recursivelyDeleteDir(extension.dir, true);
|
FileUtils.recursivelyDeleteDir(extension.dir, true);
|
||||||
@@ -82,7 +82,7 @@ function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
let [file, stream] = Gio.File.new_tmp('XXXXXX.shell-extension.zip');
|
||||||
let contents = message.response_body.flatten().as_bytes();
|
let contents = message.response_body.flatten().get_as_bytes();
|
||||||
stream.output_stream.write_bytes(contents, null);
|
stream.output_stream.write_bytes(contents, null);
|
||||||
stream.close(null);
|
stream.close(null);
|
||||||
let [success, pid] = GLib.spawn_async(null,
|
let [success, pid] = GLib.spawn_async(null,
|
||||||
@@ -124,7 +124,7 @@ function updateExtension(uuid) {
|
|||||||
let oldExtension = ExtensionUtils.extensions[uuid];
|
let oldExtension = ExtensionUtils.extensions[uuid];
|
||||||
let extensionDir = oldExtension.dir;
|
let extensionDir = oldExtension.dir;
|
||||||
|
|
||||||
if (!ExtensionSystem.unloadExtension(uuid))
|
if (!ExtensionSystem.unloadExtension(oldExtension))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
|
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
|
||||||
@@ -135,7 +135,7 @@ function updateExtension(uuid) {
|
|||||||
try {
|
try {
|
||||||
ExtensionSystem.loadExtension(extension);
|
ExtensionSystem.loadExtension(extension);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
ExtensionSystem.unloadExtension(uuid);
|
ExtensionSystem.unloadExtension(extension);
|
||||||
|
|
||||||
logError(e, 'Error loading extension %s'.format(uuid));
|
logError(e, 'Error loading extension %s'.format(uuid));
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ const Gio = imports.gi.Gio;
|
|||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const ExtensionUtils = imports.misc.extensionUtils;
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
const ExtensionState = {
|
const ExtensionState = {
|
||||||
ENABLED: 1,
|
ENABLED: 1,
|
||||||
@@ -38,6 +39,9 @@ const disconnect = Lang.bind(_signals, _signals.disconnect);
|
|||||||
|
|
||||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||||
|
|
||||||
|
var initted = false;
|
||||||
|
var enabled;
|
||||||
|
|
||||||
function disableExtension(uuid) {
|
function disableExtension(uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
if (!extension)
|
if (!extension)
|
||||||
@@ -102,8 +106,6 @@ function enableExtension(uuid) {
|
|||||||
|
|
||||||
extensionOrder.push(uuid);
|
extensionOrder.push(uuid);
|
||||||
|
|
||||||
extension.stateObj.enable();
|
|
||||||
|
|
||||||
let stylesheetFile = extension.dir.get_child('stylesheet.css');
|
let stylesheetFile = extension.dir.get_child('stylesheet.css');
|
||||||
if (stylesheetFile.query_exists(null)) {
|
if (stylesheetFile.query_exists(null)) {
|
||||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||||
@@ -111,6 +113,8 @@ function enableExtension(uuid) {
|
|||||||
extension.stylesheet = stylesheetFile;
|
extension.stylesheet = stylesheetFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension.stateObj.enable();
|
||||||
|
|
||||||
extension.state = ExtensionState.ENABLED;
|
extension.state = ExtensionState.ENABLED;
|
||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', extension);
|
||||||
}
|
}
|
||||||
@@ -158,23 +162,32 @@ function loadExtension(extension) {
|
|||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unloadExtension(uuid) {
|
function unloadExtension(extension) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
|
||||||
if (!extension)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
// 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
|
// but it will be removed on next reboot, and hopefully nothing
|
||||||
// broke too much.
|
// broke too much.
|
||||||
disableExtension(uuid);
|
disableExtension(extension.uuid);
|
||||||
|
|
||||||
extension.state = ExtensionState.UNINSTALLED;
|
extension.state = ExtensionState.UNINSTALLED;
|
||||||
_signals.emit('extension-state-changed', extension);
|
_signals.emit('extension-state-changed', extension);
|
||||||
|
|
||||||
delete ExtensionUtils.extensions[uuid];
|
delete ExtensionUtils.extensions[extension.uuid];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reloadExtension(oldExtension) {
|
||||||
|
// Grab the things we'll need to pass to createExtensionObject
|
||||||
|
// to reload it.
|
||||||
|
let { uuid: uuid, dir: dir, type: type } = oldExtension;
|
||||||
|
|
||||||
|
// Then unload the old extension.
|
||||||
|
unloadExtension(oldExtension);
|
||||||
|
|
||||||
|
// Now, recreate the extension and load it.
|
||||||
|
let newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||||
|
loadExtension(newExtension);
|
||||||
|
}
|
||||||
|
|
||||||
function initExtension(uuid) {
|
function initExtension(uuid) {
|
||||||
let extension = ExtensionUtils.extensions[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
let dir = extension.dir;
|
let dir = extension.dir;
|
||||||
@@ -207,6 +220,9 @@ function initExtension(uuid) {
|
|||||||
function onEnabledExtensionsChanged() {
|
function onEnabledExtensionsChanged() {
|
||||||
let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
let newEnabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||||
|
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||||
// new setting, but not in the old one.
|
// new setting, but not in the old one.
|
||||||
newEnabledExtensions.filter(function(uuid) {
|
newEnabledExtensions.filter(function(uuid) {
|
||||||
@@ -234,7 +250,7 @@ function onEnabledExtensionsChanged() {
|
|||||||
enabledExtensions = newEnabledExtensions;
|
enabledExtensions = newEnabledExtensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadExtensions() {
|
function _loadExtensions() {
|
||||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||||
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||||
|
|
||||||
@@ -248,3 +264,43 @@ function loadExtensions() {
|
|||||||
});
|
});
|
||||||
finder.scanExtensions();
|
finder.scanExtensions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function enableAllExtensions() {
|
||||||
|
if (enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!initted) {
|
||||||
|
_loadExtensions();
|
||||||
|
initted = true;
|
||||||
|
} else {
|
||||||
|
enabledExtensions.forEach(function(uuid) {
|
||||||
|
enableExtension(uuid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function disableAllExtensions() {
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (initted) {
|
||||||
|
enabledExtensions.forEach(function(uuid) {
|
||||||
|
disableExtension(uuid);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _sessionUpdated() {
|
||||||
|
if (Main.sessionMode.allowExtensions)
|
||||||
|
enableAllExtensions();
|
||||||
|
else
|
||||||
|
disableAllExtensions();
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
Main.sessionMode.connect('updated', _sessionUpdated);
|
||||||
|
_sessionUpdated();
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ const St = imports.gi.St;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
function _navigateActor(actor, needsGrab) {
|
function _navigateActor(actor) {
|
||||||
if (!actor)
|
if (!actor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (needsGrab && actor instanceof St.Widget)
|
let needsGrab = true;
|
||||||
|
if (actor instanceof St.Widget)
|
||||||
needsGrab = !actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
needsGrab = !actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
if (needsGrab)
|
if (needsGrab)
|
||||||
actor.grab_key_focus();
|
actor.grab_key_focus();
|
||||||
@@ -22,6 +23,7 @@ function _navigateActor(actor, needsGrab) {
|
|||||||
|
|
||||||
// GrabHelper:
|
// GrabHelper:
|
||||||
// @owner: the actor that owns the GrabHelper
|
// @owner: the actor that owns the GrabHelper
|
||||||
|
// @params: optional parameters to pass to Main.pushModal()
|
||||||
//
|
//
|
||||||
// Creates a new GrabHelper object, for dealing with keyboard and pointer grabs
|
// Creates a new GrabHelper object, for dealing with keyboard and pointer grabs
|
||||||
// associated with a set of actors.
|
// associated with a set of actors.
|
||||||
@@ -33,8 +35,9 @@ function _navigateActor(actor, needsGrab) {
|
|||||||
const GrabHelper = new Lang.Class({
|
const GrabHelper = new Lang.Class({
|
||||||
Name: 'GrabHelper',
|
Name: 'GrabHelper',
|
||||||
|
|
||||||
_init: function(owner) {
|
_init: function(owner, params) {
|
||||||
this._owner = owner;
|
this._owner = owner;
|
||||||
|
this._modalParams = params;
|
||||||
|
|
||||||
this._grabStack = [];
|
this._grabStack = [];
|
||||||
|
|
||||||
@@ -84,11 +87,7 @@ const GrabHelper = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
get currentGrab() {
|
get currentGrab() {
|
||||||
let idx = this._grabStack.length - 1;
|
return this._grabStack[this._grabStack.length - 1] || {};
|
||||||
while (idx >= 0 && this._grabStack[idx].untracked)
|
|
||||||
idx--;
|
|
||||||
|
|
||||||
return this._grabStack[idx] || {};
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_findStackIndex: function(actor) {
|
_findStackIndex: function(actor) {
|
||||||
@@ -128,21 +127,18 @@ const GrabHelper = new Lang.Class({
|
|||||||
// on the owner of the GrabHelper. As long as there is at least one
|
// on the owner of the GrabHelper. As long as there is at least one
|
||||||
// { modal: true } actor on the grab stack, the grab will be kept.
|
// { modal: true } actor on the grab stack, the grab will be kept.
|
||||||
// When the last { modal: true } actor is ungrabbed, then the modal
|
// When the last { modal: true } actor is ungrabbed, then the modal
|
||||||
// will be dropped.
|
// will be dropped. A modal grab can fail if there is already a grab
|
||||||
|
// in effect from aother application; in this case the function returns
|
||||||
|
// false and nothing happens. Non-modal grabs can never fail.
|
||||||
//
|
//
|
||||||
// If @params contains { grabFocus: true }, then if you call grab()
|
// If @params contains { grabFocus: true }, then if you call grab()
|
||||||
// while the shell is outside the overview, it will set the stage
|
// while the shell is outside the overview, it will set the stage
|
||||||
// input mode to %Shell.StageInputMode.FOCUSED, and ungrab() will
|
// input mode to %Shell.StageInputMode.FOCUSED, and ungrab() will
|
||||||
// revert it back, and re-focus the previously-focused window (if
|
// revert it back, and re-focus the previously-focused window (if
|
||||||
// another window hasn't been explicitly focused before then).
|
// another window hasn't been explicitly focused before then).
|
||||||
//
|
|
||||||
// If @params contains { untracked: true }, then it will be skipped
|
|
||||||
// when the grab helper ungrabs for you, or when calculating
|
|
||||||
// currentGrab.
|
|
||||||
grab: function(params) {
|
grab: function(params) {
|
||||||
params = Params.parse(params, { actor: null,
|
params = Params.parse(params, { actor: null,
|
||||||
modal: false,
|
modal: false,
|
||||||
untracked: false,
|
|
||||||
grabFocus: false,
|
grabFocus: false,
|
||||||
onUngrab: null });
|
onUngrab: null });
|
||||||
|
|
||||||
@@ -151,48 +147,109 @@ const GrabHelper = new Lang.Class({
|
|||||||
let newFocus = params.actor;
|
let newFocus = params.actor;
|
||||||
|
|
||||||
if (this.isActorGrabbed(params.actor))
|
if (this.isActorGrabbed(params.actor))
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
if (this._grabFocusCount == 0 && this._modalCount == 0)
|
|
||||||
this._fullGrab(hadFocus, params.modal, params.grabFocus);
|
|
||||||
|
|
||||||
params.savedFocus = focus;
|
params.savedFocus = focus;
|
||||||
|
|
||||||
|
if (params.modal && !this._takeModalGrab())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (params.grabFocus && !this._takeFocusGrab(hadFocus))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (hadFocus || params.grabFocus)
|
||||||
|
_navigateActor(newFocus);
|
||||||
|
|
||||||
this._grabStack.push(params);
|
this._grabStack.push(params);
|
||||||
|
return true;
|
||||||
if (params.modal)
|
|
||||||
this._modalCount++;
|
|
||||||
|
|
||||||
if (params.grabFocus)
|
|
||||||
this._grabFocusCount++;
|
|
||||||
|
|
||||||
_navigateActor(newFocus, hadFocus);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_fullGrab: function(hadFocus, modal, grabFocus) {
|
_takeModalGrab: function() {
|
||||||
|
let firstGrab = (this._modalCount == 0);
|
||||||
|
if (firstGrab) {
|
||||||
|
if (!Main.pushModal(this._owner, this._modalParams))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||||
|
this._eventId = global.stage.connect('event', Lang.bind(this, this._onEvent));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._modalCount++;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_releaseModalGrab: function() {
|
||||||
|
this._modalCount--;
|
||||||
|
if (this._modalCount > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this._capturedEventId > 0) {
|
||||||
|
global.stage.disconnect(this._capturedEventId);
|
||||||
|
this._capturedEventId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._eventId > 0) {
|
||||||
|
global.stage.disconnect(this._eventId);
|
||||||
|
this._eventId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Main.popModal(this._owner);
|
||||||
|
global.sync_pointer();
|
||||||
|
},
|
||||||
|
|
||||||
|
_takeFocusGrab: function(hadFocus) {
|
||||||
|
let firstGrab = (this._grabFocusCount == 0);
|
||||||
|
if (firstGrab) {
|
||||||
let metaDisplay = global.screen.get_display();
|
let metaDisplay = global.screen.get_display();
|
||||||
|
|
||||||
this._grabbedFromKeynav = hadFocus;
|
this._grabbedFromKeynav = hadFocus;
|
||||||
this._preGrabInputMode = global.stage_input_mode;
|
this._preGrabInputMode = global.stage_input_mode;
|
||||||
this._prevFocusedWindow = null;
|
|
||||||
|
|
||||||
if (modal) {
|
|
||||||
Main.pushModal(this._owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (grabFocus) {
|
|
||||||
this._prevFocusedWindow = metaDisplay.focus_window;
|
this._prevFocusedWindow = metaDisplay.focus_window;
|
||||||
|
|
||||||
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
|
if (this._preGrabInputMode == Shell.StageInputMode.NONREACTIVE ||
|
||||||
this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
|
this._preGrabInputMode == Shell.StageInputMode.NORMAL) {
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (modal || grabFocus) {
|
|
||||||
this._capturedEventId = global.stage.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
|
||||||
this._eventId = global.stage.connect('event', Lang.bind(this, this._onEvent));
|
|
||||||
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
||||||
this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));
|
this._focusWindowChangedId = metaDisplay.connect('notify::focus-window', Lang.bind(this, this._focusWindowChanged));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._grabFocusCount++;
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_releaseFocusGrab: function() {
|
||||||
|
this._grabFocusCount--;
|
||||||
|
if (this._grabFocusCount > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this._keyFocusNotifyId > 0) {
|
||||||
|
global.stage.disconnect(this._keyFocusNotifyId);
|
||||||
|
this._keyFocusNotifyId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._focusWindowChanged > 0) {
|
||||||
|
let metaDisplay = global.screen.get_display();
|
||||||
|
metaDisplay.disconnect(this._focusWindowChangedId);
|
||||||
|
this._focusWindowChangedId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prePopInputMode = global.stage_input_mode;
|
||||||
|
|
||||||
|
if (this._grabbedFromKeynav) {
|
||||||
|
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED &&
|
||||||
|
prePopInputMode != Shell.StageInputMode.FULLSCREEN)
|
||||||
|
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._prevFocusedWindow) {
|
||||||
|
let metaDisplay = global.screen.get_display();
|
||||||
|
if (!metaDisplay.focus_window) {
|
||||||
|
metaDisplay.set_input_focus_window(this._prevFocusedWindow,
|
||||||
|
false, global.get_current_time());
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// ignoreRelease:
|
// ignoreRelease:
|
||||||
@@ -219,12 +276,14 @@ const GrabHelper = new Lang.Class({
|
|||||||
if (grabStackIndex < 0)
|
if (grabStackIndex < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let focus = global.stage.key_focus;
|
||||||
|
let hadFocus = focus && this._isWithinGrabbedActor(focus);
|
||||||
|
|
||||||
let poppedGrabs = this._grabStack.slice(grabStackIndex);
|
let poppedGrabs = this._grabStack.slice(grabStackIndex);
|
||||||
// "Pop" all newly ungrabbed actors off the grab stack
|
// "Pop" all newly ungrabbed actors off the grab stack
|
||||||
// by truncating the array.
|
// by truncating the array.
|
||||||
this._grabStack.length = grabStackIndex;
|
this._grabStack.length = grabStackIndex;
|
||||||
|
|
||||||
let wasModal = this._modalCount > 0;
|
|
||||||
for (let i = poppedGrabs.length - 1; i >= 0; i--) {
|
for (let i = poppedGrabs.length - 1; i >= 0; i--) {
|
||||||
let poppedGrab = poppedGrabs[i];
|
let poppedGrab = poppedGrabs[i];
|
||||||
|
|
||||||
@@ -232,63 +291,15 @@ const GrabHelper = new Lang.Class({
|
|||||||
poppedGrab.onUngrab();
|
poppedGrab.onUngrab();
|
||||||
|
|
||||||
if (poppedGrab.modal)
|
if (poppedGrab.modal)
|
||||||
this._modalCount--;
|
this._releaseModalGrab();
|
||||||
|
|
||||||
if (poppedGrab.grabFocus)
|
if (poppedGrab.grabFocus)
|
||||||
this._grabFocusCount--;
|
this._releaseFocusGrab();
|
||||||
}
|
}
|
||||||
|
|
||||||
let focus = global.stage.key_focus;
|
if (hadFocus) {
|
||||||
let hadFocus = focus && this._isWithinGrabbedActor(focus);
|
|
||||||
|
|
||||||
if (this._grabFocusCount == 0 && this._modalCount == 0)
|
|
||||||
this._fullUngrab(wasModal);
|
|
||||||
|
|
||||||
let poppedGrab = poppedGrabs[0];
|
let poppedGrab = poppedGrabs[0];
|
||||||
_navigateActor(poppedGrab.savedFocus, hadFocus);
|
_navigateActor(poppedGrab.savedFocus);
|
||||||
},
|
|
||||||
|
|
||||||
_fullUngrab: function(wasModal) {
|
|
||||||
if (this._capturedEventId > 0) {
|
|
||||||
global.stage.disconnect(this._capturedEventId);
|
|
||||||
this._capturedEventId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._eventId > 0) {
|
|
||||||
global.stage.disconnect(this._eventId);
|
|
||||||
this._eventId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._keyFocusNotifyId > 0) {
|
|
||||||
global.stage.disconnect(this._keyFocusNotifyId);
|
|
||||||
this._keyFocusNotifyId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this._focusWindowChanged > 0) {
|
|
||||||
let metaDisplay = global.screen.get_display();
|
|
||||||
metaDisplay.disconnect(this._focusWindowChangedId);
|
|
||||||
this._focusWindowChangedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let prePopInputMode = global.stage_input_mode;
|
|
||||||
|
|
||||||
if (wasModal) {
|
|
||||||
Main.popModal(this._owner);
|
|
||||||
global.sync_pointer();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._grabbedFromKeynav) {
|
|
||||||
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED &&
|
|
||||||
prePopInputMode != Shell.StageInputMode.FULLSCREEN)
|
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._prevFocusedWindow) {
|
|
||||||
let metaDisplay = global.screen.get_display();
|
|
||||||
if (!metaDisplay.focus_window) {
|
|
||||||
metaDisplay.set_input_focus_window(this._prevFocusedWindow,
|
|
||||||
false, global.get_current_time());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -309,12 +320,15 @@ const GrabHelper = new Lang.Class({
|
|||||||
if (this._isWithinGrabbedActor(event.get_source()))
|
if (this._isWithinGrabbedActor(event.get_source()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (Main.keyboard.shouldTakeEvent(event))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (button) {
|
if (button) {
|
||||||
// If we have a press event, ignore the next event,
|
// If we have a press event, ignore the next event,
|
||||||
// which should be a release event.
|
// which should be a release event.
|
||||||
if (press)
|
if (press)
|
||||||
this._ignoreRelease = true;
|
this._ignoreRelease = true;
|
||||||
this.ungrab();
|
this.ungrab({ actor: this._grabStack[0].actor });
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._modalCount > 0;
|
return this._modalCount > 0;
|
||||||
|
|||||||
@@ -20,25 +20,6 @@ const KEYBOARD_TYPE = 'keyboard-type';
|
|||||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
||||||
|
|
||||||
// Key constants taken from Antler
|
|
||||||
// FIXME: ought to be moved into libcaribou
|
|
||||||
const PRETTY_KEYS = {
|
|
||||||
'BackSpace': '\u232b',
|
|
||||||
'space': ' ',
|
|
||||||
'Return': '\u23ce',
|
|
||||||
'Caribou_Prefs': '\u2328',
|
|
||||||
'Caribou_ShiftUp': '\u2b06',
|
|
||||||
'Caribou_ShiftDown': '\u2b07',
|
|
||||||
'Caribou_Emoticons': '\u263a',
|
|
||||||
'Caribou_Symbols': '123',
|
|
||||||
'Caribou_Symbols_More': '{#*',
|
|
||||||
'Caribou_Alpha': 'Abc',
|
|
||||||
'Tab': 'Tab',
|
|
||||||
'Escape': 'Esc',
|
|
||||||
'Control_L': 'Ctrl',
|
|
||||||
'Alt_L': 'Alt'
|
|
||||||
};
|
|
||||||
|
|
||||||
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
|
const CaribouKeyboardIface = <interface name='org.gnome.Caribou.Keyboard'>
|
||||||
<method name='Show'>
|
<method name='Show'>
|
||||||
<arg type='u' direction='in' />
|
<arg type='u' direction='in' />
|
||||||
@@ -98,17 +79,7 @@ const Key = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_makeKey: function () {
|
_makeKey: function () {
|
||||||
let label = this._key.name;
|
let label = GLib.markup_escape_text(this._key.label, -1);
|
||||||
|
|
||||||
if (label.length > 1) {
|
|
||||||
let pretty = PRETTY_KEYS[label];
|
|
||||||
if (pretty)
|
|
||||||
label = pretty;
|
|
||||||
else
|
|
||||||
label = this._getUnichar(this._key);
|
|
||||||
}
|
|
||||||
|
|
||||||
label = GLib.markup_escape_text(label, -1);
|
|
||||||
let button = new St.Button ({ label: label,
|
let button = new St.Button ({ label: label,
|
||||||
style_class: 'keyboard-key' });
|
style_class: 'keyboard-key' });
|
||||||
|
|
||||||
@@ -200,8 +171,10 @@ const Keyboard = new Lang.Class({
|
|||||||
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
|
this._impl.export(Gio.DBus.session, '/org/gnome/Caribou/Keyboard');
|
||||||
|
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
|
this._focusInTray = false;
|
||||||
|
this._focusInExtendedKeys = false;
|
||||||
|
|
||||||
this._timestamp = global.get_current_time();
|
this._timestamp = global.display.get_current_time_roundtrip();
|
||||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
|
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
|
||||||
|
|
||||||
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
|
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
|
||||||
@@ -288,7 +261,15 @@ const Keyboard = new Lang.Class({
|
|||||||
|
|
||||||
// Showing an extended key popup and clicking a key from the extended keys
|
// Showing an extended key popup and clicking a key from the extended keys
|
||||||
// will grab focus, but ignore that
|
// will grab focus, but ignore that
|
||||||
if (focus && (focus._extended_keys || (focus._key && focus._key.extended_key)))
|
let extendedKeysWereFocused = this._focusInExtendedKeys;
|
||||||
|
this._focusInExtendedKeys = focus && (focus._extended_keys || focus.extended_key);
|
||||||
|
if (this._focusInExtendedKeys || extendedKeysWereFocused)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Ignore focus changes caused by message tray showing/hiding
|
||||||
|
let trayWasFocused = this._focusInTray;
|
||||||
|
this._focusInTray = (focus && Main.messageTray.actor.contains(focus));
|
||||||
|
if (this._focusInTray || trayWasFocused)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let time = global.get_current_time();
|
let time = global.get_current_time();
|
||||||
@@ -339,6 +320,13 @@ const Keyboard = new Lang.Class({
|
|||||||
trayButton.reactive = true;
|
trayButton.reactive = true;
|
||||||
trayButton.remove_style_pseudo_class('grayed');
|
trayButton.remove_style_pseudo_class('grayed');
|
||||||
}));
|
}));
|
||||||
|
Main.sessionMode.connect('updated', Lang.bind(this, function() {
|
||||||
|
trayButton.reactive = !Main.sessionMode.isLocked;
|
||||||
|
if (Main.sessionMode.isLocked)
|
||||||
|
trayButton.add_style_pseudo_class('grayed');
|
||||||
|
else
|
||||||
|
trayButton.remove_style_pseudo_class('grayed');
|
||||||
|
}));
|
||||||
|
|
||||||
return trayButton;
|
return trayButton;
|
||||||
},
|
},
|
||||||
@@ -468,6 +456,12 @@ const Keyboard = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
shouldTakeEvent: function(event) {
|
||||||
|
let actor = event.get_source();
|
||||||
|
return Main.layoutManager.keyboardBox.contains(actor) ||
|
||||||
|
actor._extended_keys || actor.extended_key;
|
||||||
|
},
|
||||||
|
|
||||||
show: function () {
|
show: function () {
|
||||||
this._redraw();
|
this._redraw();
|
||||||
|
|
||||||
@@ -494,14 +488,29 @@ const Keyboard = new Lang.Class({
|
|||||||
this._moveTemporarily();
|
this._moveTemporarily();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// _compareTimestamp:
|
||||||
|
//
|
||||||
|
// Compare two timestamps taking into account
|
||||||
|
// CURRENT_TIME (0)
|
||||||
|
_compareTimestamp: function(one, two) {
|
||||||
|
if (one == two)
|
||||||
|
return 0;
|
||||||
|
if (one == Clutter.CURRENT_TIME)
|
||||||
|
return 1;
|
||||||
|
if (two == Clutter.CURRENT_TIME)
|
||||||
|
return -1;
|
||||||
|
return one - two;
|
||||||
|
},
|
||||||
|
|
||||||
// D-Bus methods
|
// D-Bus methods
|
||||||
Show: function(timestamp) {
|
Show: function(timestamp) {
|
||||||
if (!this._enableKeyboard)
|
if (!this._enableKeyboard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (timestamp - this._timestamp < 0)
|
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (timestamp != Clutter.CURRENT_TIME)
|
||||||
this._timestamp = timestamp;
|
this._timestamp = timestamp;
|
||||||
this.show();
|
this.show();
|
||||||
},
|
},
|
||||||
@@ -510,9 +519,10 @@ const Keyboard = new Lang.Class({
|
|||||||
if (!this._enableKeyboard)
|
if (!this._enableKeyboard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (timestamp - this._timestamp < 0)
|
if (this._compareTimestamp(timestamp, this._timestamp) < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (timestamp != Clutter.CURRENT_TIME)
|
||||||
this._timestamp = timestamp;
|
this._timestamp = timestamp;
|
||||||
this.hide();
|
this.hide();
|
||||||
},
|
},
|
||||||
@@ -542,7 +552,8 @@ const KeyboardSource = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(keyboard) {
|
_init: function(keyboard) {
|
||||||
this._keyboard = keyboard;
|
this._keyboard = keyboard;
|
||||||
this.parent(_("Keyboard"), 'input-keyboard', St.IconType.SYMBOLIC);
|
this.parent(_("Keyboard"), 'input-keyboard-symbolic');
|
||||||
|
this.keepTrayOnSummaryClick = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSummaryClick: function() {
|
handleSummaryClick: function() {
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const Tweener = imports.ui.tweener;
|
|||||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||||
const STARTUP_ANIMATION_TIME = 0.2;
|
const STARTUP_ANIMATION_TIME = 0.2;
|
||||||
const KEYBOARD_ANIMATION_TIME = 0.5;
|
const KEYBOARD_ANIMATION_TIME = 0.5;
|
||||||
|
const PLYMOUTH_TRANSITION_TIME = 1;
|
||||||
|
|
||||||
const MonitorConstraint = new Lang.Class({
|
const MonitorConstraint = new Lang.Class({
|
||||||
Name: 'MonitorConstraint',
|
Name: 'MonitorConstraint',
|
||||||
@@ -42,6 +43,8 @@ const MonitorConstraint = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
set primary(v) {
|
set primary(v) {
|
||||||
|
if (v)
|
||||||
|
this._index = -1;
|
||||||
this._primary = v;
|
this._primary = v;
|
||||||
if (this.actor)
|
if (this.actor)
|
||||||
this.actor.queue_relayout();
|
this.actor.queue_relayout();
|
||||||
@@ -53,6 +56,7 @@ const MonitorConstraint = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
set index(v) {
|
set index(v) {
|
||||||
|
this._primary = false;
|
||||||
this._index = v;
|
this._index = v;
|
||||||
if (this.actor)
|
if (this.actor)
|
||||||
this.actor.queue_relayout();
|
this.actor.queue_relayout();
|
||||||
@@ -100,6 +104,7 @@ const LayoutManager = new Lang.Class({
|
|||||||
this.primaryMonitor = null;
|
this.primaryMonitor = null;
|
||||||
this.primaryIndex = -1;
|
this.primaryIndex = -1;
|
||||||
this._hotCorners = [];
|
this._hotCorners = [];
|
||||||
|
this._background = null;
|
||||||
this._leftPanelBarrier = 0;
|
this._leftPanelBarrier = 0;
|
||||||
this._rightPanelBarrier = 0;
|
this._rightPanelBarrier = 0;
|
||||||
this._trayBarrier = 0;
|
this._trayBarrier = 0;
|
||||||
@@ -120,10 +125,9 @@ const LayoutManager = new Lang.Class({
|
|||||||
this.panelBox.connect('allocation-changed',
|
this.panelBox.connect('allocation-changed',
|
||||||
Lang.bind(this, this._updatePanelBarriers));
|
Lang.bind(this, this._updatePanelBarriers));
|
||||||
|
|
||||||
this.trayBox = new St.BoxLayout({ name: 'trayBox' });
|
this.trayBox = new St.Widget({ name: 'trayBox',
|
||||||
|
layout_manager: new Clutter.BinLayout() });
|
||||||
this.addChrome(this.trayBox);
|
this.addChrome(this.trayBox);
|
||||||
this.trayBox.connect('allocation-changed',
|
|
||||||
Lang.bind(this, this._updateTrayBarrier));
|
|
||||||
|
|
||||||
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
|
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
@@ -274,22 +278,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateTrayBarrier: function() {
|
|
||||||
let monitor = this.bottomMonitor;
|
|
||||||
|
|
||||||
if (this._trayBarrier)
|
|
||||||
global.destroy_pointer_barrier(this._trayBarrier);
|
|
||||||
|
|
||||||
if (Main.messageTray) {
|
|
||||||
this._trayBarrier =
|
|
||||||
global.create_pointer_barrier(monitor.x + monitor.width, monitor.y + monitor.height - Main.messageTray.actor.height,
|
|
||||||
monitor.x + monitor.width, monitor.y + monitor.height,
|
|
||||||
4 /* BarrierNegativeX */);
|
|
||||||
} else {
|
|
||||||
this._trayBarrier = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_monitorsChanged: function() {
|
_monitorsChanged: function() {
|
||||||
this._updateMonitors();
|
this._updateMonitors();
|
||||||
this._updateBoxes();
|
this._updateBoxes();
|
||||||
@@ -314,14 +302,45 @@ const LayoutManager = new Lang.Class({
|
|||||||
|
|
||||||
get currentMonitor() {
|
get currentMonitor() {
|
||||||
let index = global.screen.get_current_monitor();
|
let index = global.screen.get_current_monitor();
|
||||||
return Main.layoutManager.monitors[index];
|
return this.monitors[index];
|
||||||
},
|
},
|
||||||
|
|
||||||
_startupAnimation: function() {
|
_startupAnimation: function() {
|
||||||
|
this.panelBox.anchor_y = this.panelBox.height;
|
||||||
|
|
||||||
|
let plymouthTransitionRunning = false;
|
||||||
|
|
||||||
|
// If we're the greeter, put up the xrootpmap actor
|
||||||
|
// and fade it out to have a nice transition from plymouth
|
||||||
|
// to the greeter. Otherwise, we'll just animate the panel,
|
||||||
|
// as usual.
|
||||||
|
if (Main.sessionMode.isGreeter) {
|
||||||
|
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||||
|
if (this._background != null) {
|
||||||
|
Main.uiGroup.add_actor(this._background);
|
||||||
|
Tweener.addTween(this._background,
|
||||||
|
{ opacity: 0,
|
||||||
|
time: PLYMOUTH_TRANSITION_TIME,
|
||||||
|
transition: 'linear',
|
||||||
|
onComplete: this._fadeBackgroundComplete,
|
||||||
|
onCompleteScope: this });
|
||||||
|
plymouthTransitionRunning = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!plymouthTransitionRunning)
|
||||||
|
this._fadeBackgroundComplete();
|
||||||
|
},
|
||||||
|
|
||||||
|
_fadeBackgroundComplete: function() {
|
||||||
// Don't animate the strut
|
// Don't animate the strut
|
||||||
this._chrome.freezeUpdateRegions();
|
this._chrome.freezeUpdateRegions();
|
||||||
|
|
||||||
this.panelBox.anchor_y = this.panelBox.height;
|
if (this._background != null) {
|
||||||
|
this._background.destroy();
|
||||||
|
this._background = null;
|
||||||
|
}
|
||||||
|
|
||||||
Tweener.addTween(this.panelBox,
|
Tweener.addTween(this.panelBox,
|
||||||
{ anchor_y: 0,
|
{ anchor_y: 0,
|
||||||
time: STARTUP_ANIMATION_TIME,
|
time: STARTUP_ANIMATION_TIME,
|
||||||
@@ -336,7 +355,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
showKeyboard: function () {
|
showKeyboard: function () {
|
||||||
Main.messageTray.hide();
|
|
||||||
this.keyboardBox.raise_top();
|
this.keyboardBox.raise_top();
|
||||||
Tweener.addTween(this.keyboardBox,
|
Tweener.addTween(this.keyboardBox,
|
||||||
{ anchor_y: this.keyboardBox.height,
|
{ anchor_y: this.keyboardBox.height,
|
||||||
@@ -350,6 +368,8 @@ const LayoutManager = new Lang.Class({
|
|||||||
time: KEYBOARD_ANIMATION_TIME,
|
time: KEYBOARD_ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.emit('keyboard-visible-changed', true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_showKeyboardComplete: function() {
|
_showKeyboardComplete: function() {
|
||||||
@@ -364,7 +384,6 @@ const LayoutManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
hideKeyboard: function (immediate) {
|
hideKeyboard: function (immediate) {
|
||||||
Main.messageTray.hide();
|
|
||||||
if (this._keyboardHeightNotifyId) {
|
if (this._keyboardHeightNotifyId) {
|
||||||
this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
|
this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
|
||||||
this._keyboardHeightNotifyId = 0;
|
this._keyboardHeightNotifyId = 0;
|
||||||
@@ -381,6 +400,8 @@ const LayoutManager = new Lang.Class({
|
|||||||
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
|
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.emit('keyboard-visible-changed', false);
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideKeyboardComplete: function() {
|
_hideKeyboardComplete: function() {
|
||||||
@@ -639,7 +660,6 @@ const Chrome = new Lang.Class({
|
|||||||
|
|
||||||
this._monitors = [];
|
this._monitors = [];
|
||||||
this._inOverview = false;
|
this._inOverview = false;
|
||||||
this._isLocked = false;
|
|
||||||
this._updateRegionIdle = 0;
|
this._updateRegionIdle = 0;
|
||||||
this._freezeUpdateCount = 0;
|
this._freezeUpdateCount = 0;
|
||||||
|
|
||||||
@@ -658,12 +678,9 @@ const Chrome = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
init: function() {
|
init: function() {
|
||||||
Main.overview.connect('showing',
|
Main.overview.connect('showing', Lang.bind(this, this._overviewShowing));
|
||||||
Lang.bind(this, this._overviewShowing));
|
Main.overview.connect('hidden', Lang.bind(this, this._overviewHidden));
|
||||||
Main.overview.connect('hidden',
|
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||||
Lang.bind(this, this._overviewHidden));
|
|
||||||
Main.screenShield.connect('lock-status-changed',
|
|
||||||
Lang.bind(this, this._lockStatusChanged));
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addActor: function(actor, params) {
|
addActor: function(actor, params) {
|
||||||
@@ -749,10 +766,13 @@ const Chrome = new Lang.Class({
|
|||||||
|
|
||||||
_actorReparented: function(actor, oldParent) {
|
_actorReparented: function(actor, oldParent) {
|
||||||
let newParent = actor.get_parent();
|
let newParent = actor.get_parent();
|
||||||
if (!newParent)
|
if (!newParent) {
|
||||||
this._untrackActor(actor);
|
this._untrackActor(actor);
|
||||||
else
|
} else {
|
||||||
|
let i = this._findActor(actor);
|
||||||
|
let actorData = this._trackedActors[i];
|
||||||
actorData.isToplevel = (newParent == Main.uiGroup);
|
actorData.isToplevel = (newParent == Main.uiGroup);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
@@ -763,7 +783,7 @@ const Chrome = new Lang.Class({
|
|||||||
if (!actorData.isToplevel)
|
if (!actorData.isToplevel)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (this._inOverview || this._isLocked)
|
if (this._inOverview || !Main.sessionMode.hasWindows)
|
||||||
visible = true;
|
visible = true;
|
||||||
else if (this.findMonitorForActor(actorData.actor).inFullscreen)
|
else if (this.findMonitorForActor(actorData.actor).inFullscreen)
|
||||||
visible = false;
|
visible = false;
|
||||||
@@ -785,8 +805,7 @@ const Chrome = new Lang.Class({
|
|||||||
this._queueUpdateRegions();
|
this._queueUpdateRegions();
|
||||||
},
|
},
|
||||||
|
|
||||||
_lockStatusChanged: function(shield, locked) {
|
_sessionUpdated: function() {
|
||||||
this._isLocked = locked;
|
|
||||||
this._updateVisibility();
|
this._updateVisibility();
|
||||||
this._queueUpdateRegions();
|
this._queueUpdateRegions();
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
|||||||
/* Utility functions...we should probably be able to use these
|
/* Utility functions...we should probably be able to use these
|
||||||
* in the shell core code too. */
|
* in the shell core code too. */
|
||||||
'const stage = global.stage; ' +
|
'const stage = global.stage; ' +
|
||||||
'const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; ' +
|
|
||||||
/* Special lookingGlass functions */
|
/* Special lookingGlass functions */
|
||||||
'const it = Main.lookingGlass.getIt(); ' +
|
'const it = Main.lookingGlass.getIt(); ' +
|
||||||
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
|
'const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ';
|
||||||
@@ -372,7 +371,8 @@ const ObjInspector = new Lang.Class({
|
|||||||
|
|
||||||
this._parentList = [];
|
this._parentList = [];
|
||||||
|
|
||||||
this.actor = new St.ScrollView({ x_fill: true, y_fill: true });
|
this.actor = new St.ScrollView({ pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
|
||||||
|
x_fill: true, y_fill: true });
|
||||||
this.actor.get_hscroll_bar().hide();
|
this.actor.get_hscroll_bar().hide();
|
||||||
this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector',
|
this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector',
|
||||||
style_class: 'lg-dialog',
|
style_class: 'lg-dialog',
|
||||||
@@ -444,10 +444,6 @@ const ObjInspector = new Lang.Class({
|
|||||||
this.actor.show();
|
this.actor.show();
|
||||||
if (sourceActor) {
|
if (sourceActor) {
|
||||||
this.actor.set_scale(0, 0);
|
this.actor.set_scale(0, 0);
|
||||||
let [sourceX, sourceY] = sourceActor.get_transformed_position();
|
|
||||||
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
|
|
||||||
this.actor.move_anchor_point(Math.floor(sourceX + sourceWidth / 2),
|
|
||||||
Math.floor(sourceY + sourceHeight / 2));
|
|
||||||
Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
|
Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
time: 0.2 });
|
time: 0.2 });
|
||||||
@@ -869,7 +865,6 @@ const LookingGlass = new Lang.Class({
|
|||||||
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
|
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
|
||||||
this.actor.add_actor(toolbar);
|
this.actor.add_actor(toolbar);
|
||||||
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
|
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
|
||||||
icon_size: 24 });
|
icon_size: 24 });
|
||||||
toolbar.add_actor(inspectIcon);
|
toolbar.add_actor(inspectIcon);
|
||||||
inspectIcon.reactive = true;
|
inspectIcon.reactive = true;
|
||||||
@@ -1094,8 +1089,8 @@ const LookingGlass = new Lang.Class({
|
|||||||
this.actor.width = myWidth;
|
this.actor.width = myWidth;
|
||||||
this.actor.height = myHeight;
|
this.actor.height = myHeight;
|
||||||
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
|
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
|
||||||
this._objInspector.actor.set_position(this.actor.x + Math.floor(myWidth * 0.1),
|
this._objInspector.actor.set_position(primary.x + this.actor.x + Math.floor(myWidth * 0.1),
|
||||||
this._targetY + Math.floor(myHeight * 0.1));
|
primary.y + this._targetY + Math.floor(myHeight * 0.1));
|
||||||
},
|
},
|
||||||
|
|
||||||
insertObject: function(obj) {
|
insertObject: function(obj) {
|
||||||
@@ -1134,7 +1129,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
if (this._open)
|
if (this._open)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!Main.pushModal(this._entry))
|
if (!Main.pushModal(this._entry, { keybindingMode: Main.KeybindingMode.LOOKING_GLASS }))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._notebook.selectIndex(0);
|
this._notebook.selectIndex(0);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const Signals = imports.signals;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MagnifierDBus = imports.ui.magnifierDBus;
|
const MagnifierDBus = imports.ui.magnifierDBus;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
const PointerWatcher = imports.ui.pointerWatcher;
|
||||||
|
|
||||||
const MOUSE_POLL_FREQUENCY = 50;
|
const MOUSE_POLL_FREQUENCY = 50;
|
||||||
const CROSSHAIRS_CLIP_SIZE = [100, 100];
|
const CROSSHAIRS_CLIP_SIZE = [100, 100];
|
||||||
@@ -56,7 +56,7 @@ const Magnifier = new Lang.Class({
|
|||||||
let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
|
let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
|
||||||
this._mouseSprite = new Clutter.Texture();
|
this._mouseSprite = new Clutter.Texture();
|
||||||
xfixesCursor.update_texture_image(this._mouseSprite);
|
xfixesCursor.update_texture_image(this._mouseSprite);
|
||||||
this._cursorRoot = new Clutter.Group();
|
this._cursorRoot = new Clutter.Actor();
|
||||||
this._cursorRoot.add_actor(this._mouseSprite);
|
this._cursorRoot.add_actor(this._mouseSprite);
|
||||||
|
|
||||||
// Create the first ZoomRegion and initialize it according to the
|
// Create the first ZoomRegion and initialize it according to the
|
||||||
@@ -136,11 +136,8 @@ const Magnifier = new Lang.Class({
|
|||||||
* Turn on mouse tracking, if not already doing so.
|
* Turn on mouse tracking, if not already doing so.
|
||||||
*/
|
*/
|
||||||
startTrackingMouse: function() {
|
startTrackingMouse: function() {
|
||||||
if (!this._mouseTrackingId)
|
if (!this._pointerWatch)
|
||||||
this._mouseTrackingId = Mainloop.timeout_add(
|
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(MOUSE_POLL_FREQUENCY, Lang.bind(this, this.scrollToMousePos));
|
||||||
MOUSE_POLL_FREQUENCY,
|
|
||||||
Lang.bind(this, this.scrollToMousePos)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -148,10 +145,10 @@ const Magnifier = new Lang.Class({
|
|||||||
* Turn off mouse tracking, if not already doing so.
|
* Turn off mouse tracking, if not already doing so.
|
||||||
*/
|
*/
|
||||||
stopTrackingMouse: function() {
|
stopTrackingMouse: function() {
|
||||||
if (this._mouseTrackingId)
|
if (this._pointerWatch)
|
||||||
Mainloop.source_remove(this._mouseTrackingId);
|
this._pointerWatch.remove();
|
||||||
|
|
||||||
this._mouseTrackingId = null;
|
this._pointerWatch = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -303,8 +300,7 @@ const Magnifier = new Lang.Class({
|
|||||||
*/
|
*/
|
||||||
setCrosshairsColor: function(color) {
|
setCrosshairsColor: function(color) {
|
||||||
if (this._crossHairs) {
|
if (this._crossHairs) {
|
||||||
let clutterColor = new Clutter.Color();
|
let [res, clutterColor] = Clutter.Color.from_string(color);
|
||||||
clutterColor.from_string(color);
|
|
||||||
this._crossHairs.setColor(clutterColor);
|
this._crossHairs.setColor(clutterColor);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1081,21 +1077,21 @@ const ZoomRegion = new Lang.Class({
|
|||||||
// hide the magnified region from CLUTTER_PICK_ALL
|
// hide the magnified region from CLUTTER_PICK_ALL
|
||||||
Shell.util_set_hidden_from_pick (this._magView, true);
|
Shell.util_set_hidden_from_pick (this._magView, true);
|
||||||
|
|
||||||
// Append a Clutter.Group to clip the contents of the magnified view.
|
// Add a group to clip the contents of the magnified view.
|
||||||
let mainGroup = new Clutter.Group({ clip_to_allocation: true });
|
let mainGroup = new Clutter.Actor({ clip_to_allocation: true });
|
||||||
this._magView.set_child(mainGroup);
|
this._magView.set_child(mainGroup);
|
||||||
|
|
||||||
// Add a background for when the magnified uiGroup is scrolled
|
// Add a background for when the magnified uiGroup is scrolled
|
||||||
// out of view (don't want to see desktop showing through).
|
// out of view (don't want to see desktop showing through).
|
||||||
this._background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
|
this._background = new Clutter.Actor({ background_color: Main.DEFAULT_BACKGROUND_COLOR,
|
||||||
|
width: global.screen_width,
|
||||||
|
height: global.screen_height });
|
||||||
mainGroup.add_actor(this._background);
|
mainGroup.add_actor(this._background);
|
||||||
|
|
||||||
// Clone the group that contains all of UI on the screen. This is the
|
// Clone the group that contains all of UI on the screen. This is the
|
||||||
// chrome, the windows, etc.
|
// chrome, the windows, etc.
|
||||||
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
||||||
mainGroup.add_actor(this._uiGroupClone);
|
mainGroup.add_actor(this._uiGroupClone);
|
||||||
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
|
||||||
this._background.set_size(global.screen_width, global.screen_height);
|
|
||||||
|
|
||||||
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
||||||
// it.
|
// it.
|
||||||
@@ -1329,7 +1325,7 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._mouseActor.set_scale(this._xMagFactor, this._yMagFactor);
|
this._mouseActor.set_scale(this._xMagFactor, this._yMagFactor);
|
||||||
|
|
||||||
let [x, y] = this._screenToViewPort(0, 0);
|
let [x, y] = this._screenToViewPort(0, 0);
|
||||||
this._uiGroupClone.set_position(x, y);
|
this._uiGroupClone.set_position(Math.round(x), Math.round(y));
|
||||||
|
|
||||||
this._updateMousePosition();
|
this._updateMousePosition();
|
||||||
},
|
},
|
||||||
@@ -1357,7 +1353,6 @@ const ZoomRegion = new Lang.Class({
|
|||||||
if (!this.isActive())
|
if (!this.isActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
|
||||||
this._background.set_size(global.screen_width, global.screen_height);
|
this._background.set_size(global.screen_width, global.screen_height);
|
||||||
|
|
||||||
if (this._screenPosition == GDesktopEnums.MagnifierScreenPosition.NONE)
|
if (this._screenPosition == GDesktopEnums.MagnifierScreenPosition.NONE)
|
||||||
@@ -1381,15 +1376,15 @@ const Crosshairs = new Lang.Class({
|
|||||||
let groupWidth = global.screen_width * 3;
|
let groupWidth = global.screen_width * 3;
|
||||||
let groupHeight = global.screen_height * 3;
|
let groupHeight = global.screen_height * 3;
|
||||||
|
|
||||||
this._actor = new Clutter.Group({
|
this._actor = new Clutter.Actor({
|
||||||
clip_to_allocation: false,
|
clip_to_allocation: false,
|
||||||
width: groupWidth,
|
width: groupWidth,
|
||||||
height: groupHeight
|
height: groupHeight
|
||||||
});
|
});
|
||||||
this._horizLeftHair = new Clutter.Rectangle();
|
this._horizLeftHair = new Clutter.Actor();
|
||||||
this._horizRightHair = new Clutter.Rectangle();
|
this._horizRightHair = new Clutter.Actor();
|
||||||
this._vertTopHair = new Clutter.Rectangle();
|
this._vertTopHair = new Clutter.Actor();
|
||||||
this._vertBottomHair = new Clutter.Rectangle();
|
this._vertBottomHair = new Clutter.Actor();
|
||||||
this._actor.add_actor(this._horizLeftHair);
|
this._actor.add_actor(this._horizLeftHair);
|
||||||
this._actor.add_actor(this._horizRightHair);
|
this._actor.add_actor(this._horizRightHair);
|
||||||
this._actor.add_actor(this._vertTopHair);
|
this._actor.add_actor(this._vertTopHair);
|
||||||
@@ -1460,10 +1455,10 @@ const Crosshairs = new Lang.Class({
|
|||||||
* @clutterColor: The color as a Clutter.Color.
|
* @clutterColor: The color as a Clutter.Color.
|
||||||
*/
|
*/
|
||||||
setColor: function(clutterColor) {
|
setColor: function(clutterColor) {
|
||||||
this._horizLeftHair.set_color(clutterColor);
|
this._horizLeftHair.background_color = clutterColor;
|
||||||
this._horizRightHair.set_color(clutterColor);
|
this._horizRightHair.background_color = clutterColor;
|
||||||
this._vertTopHair.set_color(clutterColor);
|
this._vertTopHair.background_color = clutterColor;
|
||||||
this._vertBottomHair.set_color(clutterColor);
|
this._vertBottomHair.background_color = clutterColor;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1472,9 +1467,7 @@ const Crosshairs = new Lang.Class({
|
|||||||
* @color: The color as a Clutter.Color.
|
* @color: The color as a Clutter.Color.
|
||||||
*/
|
*/
|
||||||
getColor: function() {
|
getColor: function() {
|
||||||
let clutterColor = new Clutter.Color();
|
return this._horizLeftHair.get_color();
|
||||||
this._horizLeftHair.get_color(clutterColor);
|
|
||||||
return clutterColor;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
267
js/ui/main.js
267
js/ui/main.js
@@ -10,12 +10,9 @@ const Meta = imports.gi.Meta;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const AutomountManager = imports.ui.automountManager;
|
const Components = imports.ui.components;
|
||||||
const AutorunManager = imports.ui.autorunManager;
|
|
||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const EndSessionDialog = imports.ui.endSessionDialog;
|
const EndSessionDialog = imports.ui.endSessionDialog;
|
||||||
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
|
||||||
const KeyringPrompt = imports.ui.keyringPrompt;
|
|
||||||
const Environment = imports.ui.environment;
|
const Environment = imports.ui.environment;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||||
@@ -23,11 +20,10 @@ const Keyboard = imports.ui.keyboard;
|
|||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
const PlaceDisplay = imports.ui.placeDisplay;
|
const Params = imports.misc.params;
|
||||||
const RunDialog = imports.ui.runDialog;
|
const RunDialog = imports.ui.runDialog;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const LookingGlass = imports.ui.lookingGlass;
|
const LookingGlass = imports.ui.lookingGlass;
|
||||||
const NetworkAgent = imports.ui.networkAgent;
|
|
||||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||||
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
||||||
const ScreenShield = imports.ui.screenShield;
|
const ScreenShield = imports.ui.screenShield;
|
||||||
@@ -35,7 +31,6 @@ const Scripting = imports.ui.scripting;
|
|||||||
const SessionMode = imports.ui.sessionMode;
|
const SessionMode = imports.ui.sessionMode;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
const TelepathyClient = imports.ui.telepathyClient;
|
|
||||||
const UnlockDialog = imports.ui.unlockDialog;
|
const UnlockDialog = imports.ui.unlockDialog;
|
||||||
const WindowManager = imports.ui.windowManager;
|
const WindowManager = imports.ui.windowManager;
|
||||||
const Magnifier = imports.ui.magnifier;
|
const Magnifier = imports.ui.magnifier;
|
||||||
@@ -43,13 +38,22 @@ const XdndHandler = imports.ui.xdndHandler;
|
|||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
||||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
||||||
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
|
||||||
|
|
||||||
let automountManager = null;
|
const KeybindingMode = {
|
||||||
let autorunManager = null;
|
NONE: 0, // block all keybindings
|
||||||
|
NORMAL: 1 << 0, // window mode
|
||||||
|
OVERVIEW: 1 << 1,
|
||||||
|
LOCK_SCREEN: 1 << 2,
|
||||||
|
UNLOCK_SCREEN: 1 << 3,
|
||||||
|
LOGIN_SCREEN: 1 << 4,
|
||||||
|
MESSAGE_TRAY: 1 << 5,
|
||||||
|
SYSTEM_MODAL: 1 << 6,
|
||||||
|
LOOKING_GLASS: 1 << 7
|
||||||
|
};
|
||||||
|
|
||||||
|
let componentManager = null;
|
||||||
let panel = null;
|
let panel = null;
|
||||||
let hotCorners = [];
|
|
||||||
let overview = null;
|
let overview = null;
|
||||||
let runDialog = null;
|
let runDialog = null;
|
||||||
let lookingGlass = null;
|
let lookingGlass = null;
|
||||||
@@ -58,21 +62,19 @@ let messageTray = null;
|
|||||||
let screenShield = null;
|
let screenShield = null;
|
||||||
let notificationDaemon = null;
|
let notificationDaemon = null;
|
||||||
let windowAttentionHandler = null;
|
let windowAttentionHandler = null;
|
||||||
let telepathyClient = null;
|
|
||||||
let ctrlAltTabManager = null;
|
let ctrlAltTabManager = null;
|
||||||
let recorder = null;
|
|
||||||
let sessionMode = null;
|
let sessionMode = null;
|
||||||
let shellDBusService = null;
|
let shellDBusService = null;
|
||||||
let shellMountOpDBusService = null;
|
let shellMountOpDBusService = null;
|
||||||
let screenSaverDBus = null;
|
let screenSaverDBus = null;
|
||||||
let modalCount = 0;
|
let modalCount = 0;
|
||||||
|
let keybindingMode = KeybindingMode.NORMAL;
|
||||||
let modalActorFocusStack = [];
|
let modalActorFocusStack = [];
|
||||||
let uiGroup = null;
|
let uiGroup = null;
|
||||||
let magnifier = null;
|
let magnifier = null;
|
||||||
let xdndHandler = null;
|
let xdndHandler = null;
|
||||||
let keyboard = null;
|
let keyboard = null;
|
||||||
let layoutManager = null;
|
let layoutManager = null;
|
||||||
let networkAgent = null;
|
|
||||||
let _startDate;
|
let _startDate;
|
||||||
let _defaultCssStylesheet = null;
|
let _defaultCssStylesheet = null;
|
||||||
let _cssStylesheet = null;
|
let _cssStylesheet = null;
|
||||||
@@ -80,75 +82,22 @@ let _overridesSettings = null;
|
|||||||
|
|
||||||
let background = null;
|
let background = null;
|
||||||
|
|
||||||
function createUserSession() {
|
function _sessionUpdated() {
|
||||||
// Load the calendar server. Note that we are careful about
|
wm.setCustomKeybindingHandler('panel-main-menu',
|
||||||
// not loading any events until the user presses the clock
|
KeybindingMode.NORMAL |
|
||||||
global.launch_calendar_server();
|
KeybindingMode.OVERVIEW,
|
||||||
|
sessionMode.hasOverview ? Lang.bind(overview, overview.toggle) : null);
|
||||||
|
wm.allowKeybinding('overlay-key', KeybindingMode.NORMAL |
|
||||||
|
KeybindingMode.OVERVIEW);
|
||||||
|
|
||||||
telepathyClient = new TelepathyClient.Client();
|
wm.setCustomKeybindingHandler('panel-run-dialog',
|
||||||
automountManager = new AutomountManager.AutomountManager();
|
KeybindingMode.NORMAL |
|
||||||
autorunManager = new AutorunManager.AutorunManager();
|
KeybindingMode.OVERVIEW,
|
||||||
networkAgent = new NetworkAgent.NetworkAgent();
|
sessionMode.hasRunDialog ? openRunDialog : null);
|
||||||
|
if (sessionMode.isGreeter)
|
||||||
_initRecorder();
|
|
||||||
}
|
|
||||||
|
|
||||||
function createGDMSession() {
|
|
||||||
screenShield.showDialog();
|
screenShield.showDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGDMLoginDialog(parentActor) {
|
|
||||||
// We do this this here instead of at the top to prevent GDM
|
|
||||||
// related code from getting loaded in normal user sessions
|
|
||||||
const LoginDialog = imports.gdm.loginDialog;
|
|
||||||
|
|
||||||
let loginDialog = new LoginDialog.LoginDialog(parentActor);
|
|
||||||
return [loginDialog, true];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createSessionUnlockDialog(parentActor) {
|
|
||||||
let dialog = new UnlockDialog.UnlockDialog(parentActor);
|
|
||||||
return [dialog, false];
|
|
||||||
}
|
|
||||||
|
|
||||||
function createInitialSetupSession() {
|
|
||||||
networkAgent = new NetworkAgent.NetworkAgent();
|
|
||||||
}
|
|
||||||
|
|
||||||
function _initRecorder() {
|
|
||||||
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
|
||||||
let desktopLockdownSettings = new Gio.Settings({ schema: 'org.gnome.desktop.lockdown' });
|
|
||||||
let bindingSettings = new Gio.Settings({ schema: 'org.gnome.shell.keybindings' });
|
|
||||||
|
|
||||||
global.display.add_keybinding('toggle-recording',
|
|
||||||
bindingSettings,
|
|
||||||
Meta.KeyBindingFlags.NONE, function() {
|
|
||||||
if (recorder == null) {
|
|
||||||
recorder = new Shell.Recorder({ stage: global.stage });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recorder.is_recording()) {
|
|
||||||
recorder.close();
|
|
||||||
Meta.enable_unredirect_for_screen(global.screen);
|
|
||||||
} else if (!desktopLockdownSettings.get_boolean('disable-save-to-disk')) {
|
|
||||||
// read the parameters from GSettings always in case they have changed
|
|
||||||
recorder.set_framerate(recorderSettings.get_int('framerate'));
|
|
||||||
/* Translators: this is a filename used for screencast recording */
|
|
||||||
// xgettext:no-c-format
|
|
||||||
recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
|
|
||||||
let pipeline = recorderSettings.get_string('pipeline');
|
|
||||||
|
|
||||||
if (!pipeline.match(/^\s*$/))
|
|
||||||
recorder.set_pipeline(pipeline);
|
|
||||||
else
|
|
||||||
recorder.set_pipeline(null);
|
|
||||||
|
|
||||||
Meta.disable_unredirect_for_screen(global.screen);
|
|
||||||
recorder.record();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function start() {
|
function start() {
|
||||||
// These are here so we don't break compatibility.
|
// These are here so we don't break compatibility.
|
||||||
global.logError = window.log;
|
global.logError = window.log;
|
||||||
@@ -212,61 +161,34 @@ function start() {
|
|||||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||||
overview = new Overview.Overview();
|
overview = new Overview.Overview();
|
||||||
magnifier = new Magnifier.Magnifier();
|
magnifier = new Magnifier.Magnifier();
|
||||||
|
if (UnlockDialog.isSupported())
|
||||||
screenShield = new ScreenShield.ScreenShield();
|
screenShield = new ScreenShield.ScreenShield();
|
||||||
screenSaverDBus = new ShellDBus.ScreenSaverDBus();
|
else
|
||||||
|
screenShield = new ScreenShield.ScreenShieldFallback();
|
||||||
panel = new Panel.Panel();
|
panel = new Panel.Panel();
|
||||||
wm = new WindowManager.WindowManager();
|
wm = new WindowManager.WindowManager();
|
||||||
messageTray = new MessageTray.MessageTray();
|
messageTray = new MessageTray.MessageTray();
|
||||||
keyboard = new Keyboard.Keyboard();
|
keyboard = new Keyboard.Keyboard();
|
||||||
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||||
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
||||||
|
componentManager = new Components.ComponentManager();
|
||||||
sessionMode.createSession();
|
|
||||||
|
|
||||||
panel.startStatusArea();
|
|
||||||
|
|
||||||
layoutManager.init();
|
layoutManager.init();
|
||||||
keyboard.init();
|
keyboard.init();
|
||||||
overview.init();
|
overview.init();
|
||||||
|
|
||||||
if (sessionMode.hasWorkspaces)
|
|
||||||
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
|
global.screen.override_workspace_layout(Meta.ScreenCorner.TOPLEFT,
|
||||||
false, -1, 1);
|
false, -1, 1);
|
||||||
|
global.display.connect('overlay-key', Lang.bind(overview, overview.toggle));
|
||||||
if (sessionMode.allowExtensions) {
|
sessionMode.connect('update', _sessionUpdated);
|
||||||
ExtensionDownloader.init();
|
_sessionUpdated();
|
||||||
ExtensionSystem.loadExtensions();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionMode.hasRunDialog) {
|
|
||||||
Meta.keybindings_set_custom_handler('panel-run-dialog', function() {
|
|
||||||
getRunDialog().open();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sessionMode.hasOverview) {
|
|
||||||
Meta.keybindings_set_custom_handler('panel-main-menu', function () {
|
|
||||||
overview.toggle();
|
|
||||||
});
|
|
||||||
|
|
||||||
global.display.connect('overlay-key',
|
|
||||||
Lang.bind(overview, overview.toggle));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Provide the bus object for gnome-session to
|
// Provide the bus object for gnome-session to
|
||||||
// initiate logouts.
|
// initiate logouts.
|
||||||
EndSessionDialog.init();
|
EndSessionDialog.init();
|
||||||
|
|
||||||
// Attempt to become a PolicyKit authentication agent
|
|
||||||
PolkitAuthenticationAgent.init()
|
|
||||||
|
|
||||||
// Become a prompter for gnome keyring
|
|
||||||
KeyringPrompt.init();
|
|
||||||
|
|
||||||
_startDate = new Date();
|
_startDate = new Date();
|
||||||
|
|
||||||
global.stage.connect('captured-event', _globalKeyPressHandler);
|
|
||||||
|
|
||||||
log('GNOME Shell started at ' + _startDate);
|
log('GNOME Shell started at ' + _startDate);
|
||||||
|
|
||||||
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
|
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
|
||||||
@@ -286,6 +208,9 @@ function start() {
|
|||||||
global.screen.connect('restacked', _windowsRestacked);
|
global.screen.connect('restacked', _windowsRestacked);
|
||||||
|
|
||||||
_nWorkspacesChanged();
|
_nWorkspacesChanged();
|
||||||
|
|
||||||
|
ExtensionDownloader.init();
|
||||||
|
ExtensionSystem.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
let _workspaces = [];
|
let _workspaces = [];
|
||||||
@@ -509,9 +434,6 @@ function loadTheme() {
|
|||||||
|
|
||||||
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
||||||
|
|
||||||
if (sessionMode.extraStylesheet)
|
|
||||||
theme.load_stylesheet(sessionMode.extraStylesheet);
|
|
||||||
|
|
||||||
if (previousTheme) {
|
if (previousTheme) {
|
||||||
let customStylesheets = previousTheme.get_custom_stylesheets();
|
let customStylesheets = previousTheme.get_custom_stylesheets();
|
||||||
|
|
||||||
@@ -532,7 +454,6 @@ function notify(msg, details) {
|
|||||||
messageTray.add(source);
|
messageTray.add(source);
|
||||||
let notification = new MessageTray.Notification(source, msg, details);
|
let notification = new MessageTray.Notification(source, msg, details);
|
||||||
notification.setTransient(true);
|
notification.setTransient(true);
|
||||||
notification.setShowWhenLocked(true);
|
|
||||||
source.notify(notification);
|
source.notify(notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -564,80 +485,6 @@ function getWindowActorsForWorkspace(workspaceIndex) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function encapsulates hacks to make certain global keybindings
|
|
||||||
// work even when we are in one of our modes where global keybindings
|
|
||||||
// are disabled with a global grab. (When there is a global grab, then
|
|
||||||
// all key events will be delivered to the stage, so ::captured-event
|
|
||||||
// on the stage can be used for global keybindings.)
|
|
||||||
function _globalKeyPressHandler(actor, event) {
|
|
||||||
if (modalCount == 0)
|
|
||||||
return false;
|
|
||||||
if (event.type() != Clutter.EventType.KEY_PRESS)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!sessionMode.allowKeybindingsWhenModal) {
|
|
||||||
if (modalCount > (overview.visible ? 1 : 0))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
let symbol = event.get_key_symbol();
|
|
||||||
let keyCode = event.get_key_code();
|
|
||||||
let ignoredModifiers = global.display.get_ignored_modifier_mask();
|
|
||||||
let modifierState = event.get_state() & ~ignoredModifiers;
|
|
||||||
|
|
||||||
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
|
||||||
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
|
||||||
|
|
||||||
if (action == Meta.KeyBindingAction.SWITCH_PANELS) {
|
|
||||||
ctrlAltTabManager.popup(modifierState & Clutter.ModifierType.SHIFT_MASK,
|
|
||||||
modifierState);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (action) {
|
|
||||||
// left/right would effectively act as synonyms for up/down if we enabled them;
|
|
||||||
// but that could be considered confusing; we also disable them in the main view.
|
|
||||||
//
|
|
||||||
// case Meta.KeyBindingAction.WORKSPACE_LEFT:
|
|
||||||
// if (!sessionMode.hasWorkspaces)
|
|
||||||
// return false;
|
|
||||||
//
|
|
||||||
// wm.actionMoveWorkspaceLeft();
|
|
||||||
// return true;
|
|
||||||
// case Meta.KeyBindingAction.WORKSPACE_RIGHT:
|
|
||||||
// if (!sessionMode.hasWorkspaces)
|
|
||||||
// return false;
|
|
||||||
//
|
|
||||||
// wm.actionMoveWorkspaceRight();
|
|
||||||
// return true;
|
|
||||||
case Meta.KeyBindingAction.WORKSPACE_UP:
|
|
||||||
if (!sessionMode.hasWorkspaces)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
wm.actionMoveWorkspace(Meta.MotionDirection.UP);
|
|
||||||
return true;
|
|
||||||
case Meta.KeyBindingAction.WORKSPACE_DOWN:
|
|
||||||
if (!sessionMode.hasWorkspaces)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
wm.actionMoveWorkspace(Meta.MotionDirection.DOWN);
|
|
||||||
return true;
|
|
||||||
case Meta.KeyBindingAction.PANEL_RUN_DIALOG:
|
|
||||||
case Meta.KeyBindingAction.COMMAND_2:
|
|
||||||
if (!sessionMode.hasRunDialog)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
getRunDialog().open();
|
|
||||||
return true;
|
|
||||||
case Meta.KeyBindingAction.PANEL_MAIN_MENU:
|
|
||||||
case Meta.KeyBindingAction.OVERLAY_KEY:
|
|
||||||
overview.hide();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _findModal(actor) {
|
function _findModal(actor) {
|
||||||
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
||||||
if (modalActorFocusStack[i].actor == actor)
|
if (modalActorFocusStack[i].actor == actor)
|
||||||
@@ -653,7 +500,7 @@ function isInModalStack(actor) {
|
|||||||
/**
|
/**
|
||||||
* pushModal:
|
* pushModal:
|
||||||
* @actor: #ClutterActor which will be given keyboard focus
|
* @actor: #ClutterActor which will be given keyboard focus
|
||||||
* @timestamp: optional timestamp
|
* @params: optional parameters
|
||||||
*
|
*
|
||||||
* Ensure we are in a mode where all keyboard and mouse input goes to
|
* Ensure we are in a mode where all keyboard and mouse input goes to
|
||||||
* the stage, and focus @actor. Multiple calls to this function act in
|
* the stage, and focus @actor. Multiple calls to this function act in
|
||||||
@@ -664,21 +511,27 @@ function isInModalStack(actor) {
|
|||||||
* modal stack returns to this actor, reset the focus to the actor
|
* modal stack returns to this actor, reset the focus to the actor
|
||||||
* which was focused at the time pushModal() was invoked.
|
* which was focused at the time pushModal() was invoked.
|
||||||
*
|
*
|
||||||
* @timestamp is optionally used to associate the call with a specific user
|
* @params may be used to provide the following parameters:
|
||||||
* initiated event. If not provided then the value of
|
* - timestamp: used to associate the call with a specific user initiated
|
||||||
|
* event. If not provided then the value of
|
||||||
* global.get_current_time() is assumed.
|
* global.get_current_time() is assumed.
|
||||||
*
|
*
|
||||||
* @options: optional Meta.ModalOptions flags to indicate that the
|
* - options: Meta.ModalOptions flags to indicate that the pointer is
|
||||||
* pointer is alrady grabbed
|
* already grabbed
|
||||||
|
*
|
||||||
|
* - keybindingMode: used to set the current Main.KeybindingMode to filter
|
||||||
|
* global keybindings; the default of NONE will filter
|
||||||
|
* out all keybindings
|
||||||
*
|
*
|
||||||
* Returns: true iff we successfully acquired a grab or already had one
|
* Returns: true iff we successfully acquired a grab or already had one
|
||||||
*/
|
*/
|
||||||
function pushModal(actor, timestamp, options) {
|
function pushModal(actor, params) {
|
||||||
if (timestamp == undefined)
|
params = Params.parse(params, { timestamp: global.get_current_time(),
|
||||||
timestamp = global.get_current_time();
|
options: 0,
|
||||||
|
keybindingMode: KeybindingMode.NONE });
|
||||||
|
|
||||||
if (modalCount == 0) {
|
if (modalCount == 0) {
|
||||||
if (!global.begin_modal(timestamp, options ? options : 0)) {
|
if (!global.begin_modal(params.timestamp, params.options)) {
|
||||||
log('pushModal: invocation of begin_modal failed');
|
log('pushModal: invocation of begin_modal failed');
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -705,8 +558,10 @@ function pushModal(actor, timestamp, options) {
|
|||||||
modalActorFocusStack.push({ actor: actor,
|
modalActorFocusStack.push({ actor: actor,
|
||||||
focus: curFocus,
|
focus: curFocus,
|
||||||
destroyId: actorDestroyId,
|
destroyId: actorDestroyId,
|
||||||
focusDestroyId: curFocusDestroyId });
|
focusDestroyId: curFocusDestroyId,
|
||||||
|
keybindingMode: keybindingMode });
|
||||||
|
|
||||||
|
keybindingMode = params.keybindingMode;
|
||||||
global.stage.set_key_focus(actor);
|
global.stage.set_key_focus(actor);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -733,6 +588,7 @@ function popModal(actor, timestamp) {
|
|||||||
global.stage.set_key_focus(null);
|
global.stage.set_key_focus(null);
|
||||||
global.end_modal(timestamp);
|
global.end_modal(timestamp);
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||||
|
keybindingMode = KeybindingMode.NORMAL;
|
||||||
|
|
||||||
throw new Error('incorrect pop');
|
throw new Error('incorrect pop');
|
||||||
}
|
}
|
||||||
@@ -745,6 +601,7 @@ function popModal(actor, timestamp) {
|
|||||||
if (focusIndex == modalActorFocusStack.length - 1) {
|
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||||
if (record.focus)
|
if (record.focus)
|
||||||
record.focus.disconnect(record.focusDestroyId);
|
record.focus.disconnect(record.focusDestroyId);
|
||||||
|
keybindingMode = record.keybindingMode;
|
||||||
global.stage.set_key_focus(record.focus);
|
global.stage.set_key_focus(record.focus);
|
||||||
} else {
|
} else {
|
||||||
let t = modalActorFocusStack[modalActorFocusStack.length - 1];
|
let t = modalActorFocusStack[modalActorFocusStack.length - 1];
|
||||||
@@ -754,6 +611,7 @@ function popModal(actor, timestamp) {
|
|||||||
for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
|
for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
|
||||||
modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
|
modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
|
||||||
modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
|
modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
|
||||||
|
modalActorFocusStack[i].keybindingMode = modalActorFocusStack[i - 1].keybindingMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
modalActorFocusStack.splice(focusIndex, 1);
|
modalActorFocusStack.splice(focusIndex, 1);
|
||||||
@@ -764,6 +622,7 @@ function popModal(actor, timestamp) {
|
|||||||
global.end_modal(timestamp);
|
global.end_modal(timestamp);
|
||||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||||
Meta.enable_unredirect_for_screen(global.screen);
|
Meta.enable_unredirect_for_screen(global.screen);
|
||||||
|
keybindingMode = KeybindingMode.NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createLookingGlass() {
|
function createLookingGlass() {
|
||||||
@@ -773,11 +632,11 @@ function createLookingGlass() {
|
|||||||
return lookingGlass;
|
return lookingGlass;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRunDialog() {
|
function openRunDialog() {
|
||||||
if (runDialog == null) {
|
if (runDialog == null) {
|
||||||
runDialog = new RunDialog.RunDialog();
|
runDialog = new RunDialog.RunDialog();
|
||||||
}
|
}
|
||||||
return runDialog;
|
runDialog.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,6 @@ const Main = imports.ui.main;
|
|||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
const OPEN_AND_CLOSE_TIME = 0.1;
|
const OPEN_AND_CLOSE_TIME = 0.1;
|
||||||
const FADE_IN_BUTTONS_TIME = 0.33;
|
|
||||||
const FADE_OUT_DIALOG_TIME = 1.0;
|
const FADE_OUT_DIALOG_TIME = 1.0;
|
||||||
|
|
||||||
const State = {
|
const State = {
|
||||||
@@ -37,12 +36,15 @@ const ModalDialog = new Lang.Class({
|
|||||||
_init: function(params) {
|
_init: function(params) {
|
||||||
params = Params.parse(params, { shellReactive: false,
|
params = Params.parse(params, { shellReactive: false,
|
||||||
styleClass: null,
|
styleClass: null,
|
||||||
parentActor: Main.uiGroup
|
parentActor: Main.uiGroup,
|
||||||
});
|
keybindingMode: Main.KeybindingMode.SYSTEM_MODAL,
|
||||||
|
shouldFadeIn: true });
|
||||||
|
|
||||||
this.state = State.CLOSED;
|
this.state = State.CLOSED;
|
||||||
this._hasModal = false;
|
this._hasModal = false;
|
||||||
|
this._keybindingMode = params.keybindingMode;
|
||||||
this._shellReactive = params.shellReactive;
|
this._shellReactive = params.shellReactive;
|
||||||
|
this._shouldFadeIn = params.shouldFadeIn;
|
||||||
|
|
||||||
this._group = new St.Widget({ visible: false,
|
this._group = new St.Widget({ visible: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
@@ -116,8 +118,6 @@ const ModalDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setButtons: function(buttons) {
|
setButtons: function(buttons) {
|
||||||
let hadChildren = this._buttonLayout.get_children() > 0;
|
|
||||||
|
|
||||||
this._buttonLayout.destroy_all_children();
|
this._buttonLayout.destroy_all_children();
|
||||||
this._actionKeys = {};
|
this._actionKeys = {};
|
||||||
|
|
||||||
@@ -130,8 +130,11 @@ const ModalDialog = new Lang.Class({
|
|||||||
let key = buttonInfo['key'];
|
let key = buttonInfo['key'];
|
||||||
let isDefault = buttonInfo['default'];
|
let isDefault = buttonInfo['default'];
|
||||||
|
|
||||||
if (isDefault && !key)
|
if (isDefault && !key) {
|
||||||
|
this._actionKeys[Clutter.KEY_KP_Enter] = action;
|
||||||
|
this._actionKeys[Clutter.KEY_ISO_Enter] = action;
|
||||||
key = Clutter.KEY_Return;
|
key = Clutter.KEY_Return;
|
||||||
|
}
|
||||||
|
|
||||||
buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
|
buttonInfo.button = new St.Button({ style_class: 'modal-dialog-button',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
@@ -165,21 +168,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._actionKeys[key] = action;
|
this._actionKeys[key] = action;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fade in buttons if there weren't any before
|
|
||||||
if (!hadChildren && buttons.length > 0) {
|
|
||||||
this._buttonLayout.opacity = 0;
|
|
||||||
Tweener.addTween(this._buttonLayout,
|
|
||||||
{ opacity: 255,
|
|
||||||
time: FADE_IN_BUTTONS_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: Lang.bind(this, function() {
|
|
||||||
this.emit('buttons-set');
|
this.emit('buttons-set');
|
||||||
})
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.emit('buttons-set');
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onKeyReleaseEvent: function(object, event) {
|
_onKeyReleaseEvent: function(object, event) {
|
||||||
@@ -198,7 +187,10 @@ const ModalDialog = new Lang.Class({
|
|||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
},
|
},
|
||||||
|
|
||||||
_fadeOpen: function() {
|
_fadeOpen: function(onPrimary) {
|
||||||
|
if (onPrimary)
|
||||||
|
this._monitorConstraint.primary = true;
|
||||||
|
else
|
||||||
this._monitorConstraint.index = global.screen.get_current_monitor();
|
this._monitorConstraint.index = global.screen.get_current_monitor();
|
||||||
|
|
||||||
this.state = State.OPENING;
|
this.state = State.OPENING;
|
||||||
@@ -210,7 +202,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._group.show();
|
this._group.show();
|
||||||
Tweener.addTween(this._group,
|
Tweener.addTween(this._group,
|
||||||
{ opacity: 255,
|
{ opacity: 255,
|
||||||
time: OPEN_AND_CLOSE_TIME,
|
time: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this,
|
onComplete: Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
@@ -232,14 +224,14 @@ const ModalDialog = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function(timestamp) {
|
open: function(timestamp, onPrimary) {
|
||||||
if (this.state == State.OPENED || this.state == State.OPENING)
|
if (this.state == State.OPENED || this.state == State.OPENING)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (!this.pushModal(timestamp))
|
if (!this.pushModal({ timestamp: timestamp }))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this._fadeOpen();
|
this._fadeOpen(onPrimary);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -286,7 +278,8 @@ const ModalDialog = new Lang.Class({
|
|||||||
pushModal: function (timestamp) {
|
pushModal: function (timestamp) {
|
||||||
if (this._hasModal)
|
if (this._hasModal)
|
||||||
return true;
|
return true;
|
||||||
if (!Main.pushModal(this._group, timestamp))
|
if (!Main.pushModal(this._group, { timestamp: timestamp,
|
||||||
|
keybindingMode: this._keybindingMode }))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
this._hasModal = true;
|
this._hasModal = true;
|
||||||
|
|||||||
@@ -116,8 +116,8 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
this._busProxy = new Bus();
|
this._busProxy = new Bus();
|
||||||
|
|
||||||
this._trayManager = new Shell.TrayManager();
|
this._trayManager = new Shell.TrayManager();
|
||||||
this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
this._trayIconAddedId = this._trayManager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||||
this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
this._trayIconRemovedId = this._trayManager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||||
|
|
||||||
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
||||||
Lang.bind(this, this._onFocusAppChanged));
|
Lang.bind(this, this._onFocusAppChanged));
|
||||||
@@ -256,6 +256,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
Mainloop.idle_add(Lang.bind(this,
|
Mainloop.idle_add(Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
|
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
|
||||||
|
return false;
|
||||||
}));
|
}));
|
||||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||||
}
|
}
|
||||||
@@ -355,13 +356,10 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
ndata.actions, ndata.hints, ndata.notification];
|
ndata.actions, ndata.hints, ndata.notification];
|
||||||
|
|
||||||
let gicon = this._iconForNotificationData(icon, hints);
|
let gicon = this._iconForNotificationData(icon, hints);
|
||||||
let iconActor = new St.Icon({ gicon: gicon,
|
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
|
||||||
icon_size: MessageTray.NOTIFICATION_ICON_SIZE });
|
|
||||||
|
|
||||||
if (notification == null) {
|
if (notification == null) {
|
||||||
notification = new MessageTray.Notification(source, summary, body,
|
notification = new MessageTray.Notification(source, summary, body,
|
||||||
{ icon: iconActor,
|
{ gicon: gicon,
|
||||||
bannerMarkup: true });
|
bannerMarkup: true });
|
||||||
ndata.notification = notification;
|
ndata.notification = notification;
|
||||||
notification.connect('destroy', Lang.bind(this,
|
notification.connect('destroy', Lang.bind(this,
|
||||||
@@ -386,7 +384,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
this._emitActionInvoked(ndata.id, actionId);
|
this._emitActionInvoked(ndata.id, actionId);
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
notification.update(summary, body, { icon: iconActor,
|
notification.update(summary, body, { gicon: gicon,
|
||||||
bannerMarkup: true,
|
bannerMarkup: true,
|
||||||
clear: true });
|
clear: true });
|
||||||
}
|
}
|
||||||
@@ -499,7 +497,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onTrayIconAdded: function(o, icon) {
|
_onTrayIconAdded: function(o, icon) {
|
||||||
let wmClass = icon.wm_class.toLowerCase();
|
let wmClass = icon.wm_class ? icon.wm_class.toLowerCase() : '';
|
||||||
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
|
if (STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass] !== undefined)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -583,18 +581,12 @@ const Source = new Lang.Class({
|
|||||||
this.notifications.length > 0)
|
this.notifications.length > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (Main.overview.visible) {
|
let id = global.connect('notify::stage-input-mode', Lang.bind(this, function () {
|
||||||
// We can't just connect to Main.overview's 'hidden' signal,
|
|
||||||
// because it's emitted *before* it calls popModal()...
|
|
||||||
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
|
|
||||||
function () {
|
|
||||||
global.disconnect(id);
|
global.disconnect(id);
|
||||||
this.trayIcon.click(event);
|
this.trayIcon.click(event);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
} else {
|
|
||||||
this.trayIcon.click(event);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,29 @@ const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
|||||||
// Time for initial animation going into Overview mode
|
// Time for initial animation going into Overview mode
|
||||||
const ANIMATION_TIME = 0.25;
|
const ANIMATION_TIME = 0.25;
|
||||||
|
|
||||||
// We split the screen vertically between the dash and the view selector.
|
// XXX -- grab this automatically. Hard to do.
|
||||||
const DASH_SPLIT_FRACTION = 0.1;
|
const DASH_MAX_WIDTH = 96;
|
||||||
|
|
||||||
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
|
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
|
||||||
|
|
||||||
|
const GLSL_DIM_EFFECT_DECLARATIONS = '';
|
||||||
|
const GLSL_DIM_EFFECT_CODE = '\
|
||||||
|
vec2 dist = cogl_tex_coord_in[0].xy - vec2(0.5, 0.5); \
|
||||||
|
float elipse_radius = 0.5; \
|
||||||
|
/* from https://bugzilla.gnome.org/show_bug.cgi?id=669798: \
|
||||||
|
the alpha on the gradient goes from 165 at its darkest to 98 at its most transparent. */ \
|
||||||
|
float y = 165.0 / 255.0; \
|
||||||
|
float x = 98.0 / 255.0; \
|
||||||
|
/* interpolate darkening value, based on distance from screen center */ \
|
||||||
|
float val = min(length(dist), elipse_radius); \
|
||||||
|
float a = mix(x, y, val / elipse_radius); \
|
||||||
|
/* dim_factor varies from [1.0 -> 0.5] when overview is showing \
|
||||||
|
We use it to smooth value, then we clamp it to valid color interval */ \
|
||||||
|
a = clamp(a - cogl_color_in.r + 0.5, 0.0, 1.0); \
|
||||||
|
/* We\'re blending between: color and black color (obviously omitted in the equation) */ \
|
||||||
|
cogl_color_out.xyz = cogl_color_out.xyz * (1.0 - a); \
|
||||||
|
cogl_color_out.a = 1.0;';
|
||||||
|
|
||||||
const SwipeScrollDirection = {
|
const SwipeScrollDirection = {
|
||||||
NONE: 0,
|
NONE: 0,
|
||||||
HORIZONTAL: 1,
|
HORIZONTAL: 1,
|
||||||
@@ -57,7 +75,14 @@ const ShellInfo = new Lang.Class({
|
|||||||
this._source.destroy();
|
this._source.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
setMessage: function(text, undoCallback, undoLabel) {
|
setMessage: function(text, options) {
|
||||||
|
options = Params.parse(options, { undoCallback: null,
|
||||||
|
forFeedback: false
|
||||||
|
});
|
||||||
|
|
||||||
|
let undoCallback = options.undoCallback;
|
||||||
|
let forFeedback = options.forFeedback;
|
||||||
|
|
||||||
if (this._source == null) {
|
if (this._source == null) {
|
||||||
this._source = new MessageTray.SystemNotificationSource();
|
this._source = new MessageTray.SystemNotificationSource();
|
||||||
this._source.connect('destroy', Lang.bind(this,
|
this._source.connect('destroy', Lang.bind(this,
|
||||||
@@ -70,20 +95,17 @@ const ShellInfo = new Lang.Class({
|
|||||||
let notification = null;
|
let notification = null;
|
||||||
if (this._source.notifications.length == 0) {
|
if (this._source.notifications.length == 0) {
|
||||||
notification = new MessageTray.Notification(this._source, text, null);
|
notification = new MessageTray.Notification(this._source, text, null);
|
||||||
notification.setShowWhenLocked(true);
|
notification.setTransient(true);
|
||||||
|
notification.setForFeedback(forFeedback);
|
||||||
} else {
|
} else {
|
||||||
notification = this._source.notifications[0];
|
notification = this._source.notifications[0];
|
||||||
notification.update(text, null, { clear: true });
|
notification.update(text, null, { clear: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
notification.setTransient(true);
|
|
||||||
|
|
||||||
this._undoCallback = undoCallback;
|
this._undoCallback = undoCallback;
|
||||||
if (undoCallback) {
|
if (undoCallback) {
|
||||||
notification.addButton('system-undo',
|
notification.addButton('system-undo', _("Undo"));
|
||||||
undoLabel ? undoLabel : _("Undo"));
|
notification.connect('action-invoked', Lang.bind(this, this._onUndoClicked));
|
||||||
notification.connect('action-invoked',
|
|
||||||
Lang.bind(this, this._onUndoClicked));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._source.notify(notification);
|
this._source.notify(notification);
|
||||||
@@ -94,15 +116,20 @@ const Overview = new Lang.Class({
|
|||||||
Name: 'Overview',
|
Name: 'Overview',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.isDummy = !Main.sessionMode.hasOverview;
|
this._overviewCreated = false;
|
||||||
|
|
||||||
// We only have an overview in user sessions, so
|
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||||
// create a dummy overview in other cases
|
this._sessionUpdated();
|
||||||
if (this.isDummy) {
|
},
|
||||||
this.animationInProgress = false;
|
|
||||||
this.visible = false;
|
_createOverview: function() {
|
||||||
|
if (this._overviewCreated)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
if (this.isDummy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._overviewCreated = true;
|
||||||
|
|
||||||
// The main BackgroundActor is inside global.window_group which is
|
// The main BackgroundActor is inside global.window_group which is
|
||||||
// hidden when displaying the overview, so we create a new
|
// hidden when displaying the overview, so we create a new
|
||||||
@@ -110,6 +137,10 @@ const Overview = new Lang.Class({
|
|||||||
// scenes which allows us to show the background with different
|
// scenes which allows us to show the background with different
|
||||||
// rendering options without duplicating the texture data.
|
// rendering options without duplicating the texture data.
|
||||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||||
|
this._background.add_glsl_snippet(Meta.SnippetHook.FRAGMENT,
|
||||||
|
GLSL_DIM_EFFECT_DECLARATIONS,
|
||||||
|
GLSL_DIM_EFFECT_CODE,
|
||||||
|
false);
|
||||||
this._background.hide();
|
this._background.hide();
|
||||||
global.overlay_group.add_actor(this._background);
|
global.overlay_group.add_actor(this._background);
|
||||||
|
|
||||||
@@ -175,6 +206,11 @@ const Overview = new Lang.Class({
|
|||||||
this._needsFakePointerEvent = false;
|
this._needsFakePointerEvent = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_sessionUpdated: function() {
|
||||||
|
this.isDummy = !Main.sessionMode.hasOverview;
|
||||||
|
this._createOverview();
|
||||||
|
},
|
||||||
|
|
||||||
// The members we construct that are implemented in JS might
|
// The members we construct that are implemented in JS might
|
||||||
// want to access the overview as Main.overview to connect
|
// want to access the overview as Main.overview to connect
|
||||||
// signal handlers and so forth. So we create them after
|
// signal handlers and so forth. So we create them after
|
||||||
@@ -211,7 +247,7 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
// Translators: this is the name of the dock/favorites area on
|
// Translators: this is the name of the dock/favorites area on
|
||||||
// the left of the overview
|
// the left of the overview
|
||||||
Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks');
|
Main.ctrlAltTabManager.addGroup(this._dash.actor, _("Dash"), 'user-bookmarks-symbolic');
|
||||||
|
|
||||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
||||||
this._relayout();
|
this._relayout();
|
||||||
@@ -225,11 +261,16 @@ const Overview = new Lang.Class({
|
|||||||
this._viewSelector.removeSearchProvider(provider);
|
this._viewSelector.removeSearchProvider(provider);
|
||||||
},
|
},
|
||||||
|
|
||||||
setMessage: function(text, undoCallback, undoLabel) {
|
//
|
||||||
|
// options:
|
||||||
|
// - undoCallback (function): the callback to be called if undo support is needed
|
||||||
|
// - forFeedback (boolean): whether the message is for direct feedback of a user action
|
||||||
|
//
|
||||||
|
setMessage: function(text, options) {
|
||||||
if (this.isDummy)
|
if (this.isDummy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._shellInfo.setMessage(text, undoCallback, undoLabel);
|
this._shellInfo.setMessage(text, options);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragBegin: function() {
|
_onDragBegin: function() {
|
||||||
@@ -462,7 +503,9 @@ const Overview = new Lang.Class({
|
|||||||
if (windows.length == 0)
|
if (windows.length == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
let clone = new Clutter.Clone({ source: windows[0].get_texture() });
|
let window = windows[0];
|
||||||
|
let clone = new Clutter.Clone({ source: window.get_texture(),
|
||||||
|
x: window.x, y: window.y });
|
||||||
clone.source.connect('destroy', Lang.bind(this, function() {
|
clone.source.connect('destroy', Lang.bind(this, function() {
|
||||||
clone.destroy();
|
clone.destroy();
|
||||||
}));
|
}));
|
||||||
@@ -492,7 +535,7 @@ const Overview = new Lang.Class({
|
|||||||
let searchX = (primary.width - searchWidth) / 2;
|
let searchX = (primary.width - searchWidth) / 2;
|
||||||
let searchY = contentY + this._spacing;
|
let searchY = contentY + this._spacing;
|
||||||
|
|
||||||
let dashWidth = Math.round(DASH_SPLIT_FRACTION * primary.width);
|
let dashWidth = DASH_MAX_WIDTH;
|
||||||
let dashY = searchY + searchHeight + this._spacing;
|
let dashY = searchY + searchHeight + this._spacing;
|
||||||
let dashX;
|
let dashX;
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
@@ -548,7 +591,7 @@ const Overview = new Lang.Class({
|
|||||||
if (this._shown)
|
if (this._shown)
|
||||||
return;
|
return;
|
||||||
// Do this manually instead of using _syncInputMode, to handle failure
|
// Do this manually instead of using _syncInputMode, to handle failure
|
||||||
if (!Main.pushModal(this._group))
|
if (!Main.pushModal(this._group, { keybindingMode: Main.KeybindingMode.OVERVIEW }))
|
||||||
return;
|
return;
|
||||||
this._modal = true;
|
this._modal = true;
|
||||||
this._animateVisible();
|
this._animateVisible();
|
||||||
@@ -612,7 +655,7 @@ const Overview = new Lang.Class({
|
|||||||
});
|
});
|
||||||
|
|
||||||
Tweener.addTween(this._background,
|
Tweener.addTween(this._background,
|
||||||
{ dim_factor: 0.4,
|
{ dim_factor: 0.8,
|
||||||
time: ANIMATION_TIME,
|
time: ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
});
|
});
|
||||||
@@ -699,7 +742,8 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
if (this._shown) {
|
if (this._shown) {
|
||||||
if (!this._modal) {
|
if (!this._modal) {
|
||||||
if (Main.pushModal(this._group))
|
if (Main.pushModal(this._group,
|
||||||
|
{ keybindingMode: Main.KeybindingMode.OVERVIEW }))
|
||||||
this._modal = true;
|
this._modal = true;
|
||||||
else
|
else
|
||||||
this.hide();
|
this.hide();
|
||||||
|
|||||||
299
js/ui/panel.js
299
js/ui/panel.js
@@ -14,13 +14,14 @@ const St = imports.gi.St;
|
|||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Atk = imports.gi.Atk;
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
|
|
||||||
|
const Config = imports.misc.config;
|
||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const DateMenu = imports.ui.dateMenu;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
@@ -81,26 +82,34 @@ const AnimatedIcon = new Lang.Class({
|
|||||||
_init: function(name, size) {
|
_init: function(name, size) {
|
||||||
this.actor = new St.Bin({ visible: false });
|
this.actor = new St.Bin({ visible: false });
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
this.actor.connect('notify::visible', Lang.bind(this, this._onVisibleNotify));
|
|
||||||
|
|
||||||
|
this._isLoaded = false;
|
||||||
|
this._isPlaying = false;
|
||||||
this._timeoutId = 0;
|
this._timeoutId = 0;
|
||||||
this._frame = 0;
|
this._frame = 0;
|
||||||
this._animations = St.TextureCache.get_default().load_sliced_image (global.datadir + '/theme/' + name, size, size);
|
this._animations = St.TextureCache.get_default().load_sliced_image (global.datadir + '/theme/' + name, size, size,
|
||||||
|
Lang.bind(this, this._animationsLoaded));
|
||||||
this.actor.set_child(this._animations);
|
this.actor.set_child(this._animations);
|
||||||
},
|
},
|
||||||
|
|
||||||
_disconnectTimeout: function() {
|
play: function() {
|
||||||
|
if (this._isLoaded && this._timeoutId == 0) {
|
||||||
|
if (this._frame == 0)
|
||||||
|
this._showFrame(0);
|
||||||
|
|
||||||
|
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._isPlaying = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
stop: function() {
|
||||||
if (this._timeoutId > 0) {
|
if (this._timeoutId > 0) {
|
||||||
Mainloop.source_remove(this._timeoutId);
|
Mainloop.source_remove(this._timeoutId);
|
||||||
this._timeoutId = 0;
|
this._timeoutId = 0;
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
_onVisibleNotify: function() {
|
this._isPlaying = false;
|
||||||
if (this.actor.visible)
|
|
||||||
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
|
||||||
else
|
|
||||||
this._disconnectTimeout();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_showFrame: function(frame) {
|
_showFrame: function(frame) {
|
||||||
@@ -120,8 +129,17 @@ const AnimatedIcon = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_animationsLoaded: function() {
|
||||||
|
this._isLoaded = true;
|
||||||
|
|
||||||
|
if (this._isPlaying) {
|
||||||
|
this._showFrame(0);
|
||||||
|
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
this._disconnectTimeout();
|
this.stop();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -221,14 +239,14 @@ const AppMenuButton = new Lang.Class({
|
|||||||
Name: 'AppMenuButton',
|
Name: 'AppMenuButton',
|
||||||
Extends: PanelMenu.Button,
|
Extends: PanelMenu.Button,
|
||||||
|
|
||||||
_init: function(menuManager) {
|
_init: function(panel) {
|
||||||
this.parent(0.0, null, true);
|
this.parent(0.0, null, true);
|
||||||
|
|
||||||
this.actor.accessible_role = Atk.Role.MENU;
|
this.actor.accessible_role = Atk.Role.MENU;
|
||||||
|
|
||||||
this._startingApps = [];
|
this._startingApps = [];
|
||||||
|
|
||||||
this._menuManager = menuManager;
|
this._menuManager = panel.menuManager;
|
||||||
this._targetApp = null;
|
this._targetApp = null;
|
||||||
this._appMenuNotifyId = 0;
|
this._appMenuNotifyId = 0;
|
||||||
this._actionGroupNotifyId = 0;
|
this._actionGroupNotifyId = 0;
|
||||||
@@ -246,6 +264,10 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._container.connect('get-preferred-height', Lang.bind(this, this._getContentPreferredHeight));
|
this._container.connect('get-preferred-height', Lang.bind(this, this._getContentPreferredHeight));
|
||||||
this._container.connect('allocate', Lang.bind(this, this._contentAllocate));
|
this._container.connect('allocate', Lang.bind(this, this._contentAllocate));
|
||||||
|
|
||||||
|
let textureCache = St.TextureCache.get_default();
|
||||||
|
textureCache.connect('icon-theme-changed',
|
||||||
|
Lang.bind(this, this._onIconThemeChanged));
|
||||||
|
|
||||||
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
||||||
this._iconBox.connect('style-changed',
|
this._iconBox.connect('style-changed',
|
||||||
Lang.bind(this, this._onIconBoxStyleChanged));
|
Lang.bind(this, this._onIconBoxStyleChanged));
|
||||||
@@ -285,7 +307,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
if (this._visible)
|
if (this._visible || Main.screenShield.locked)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._visible = true;
|
this._visible = true;
|
||||||
@@ -331,6 +353,15 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._updateIconBoxClip();
|
this._updateIconBoxClip();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onIconThemeChanged: function() {
|
||||||
|
if (this._iconBox.child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._iconBox.child.destroy();
|
||||||
|
let icon = this._targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
|
||||||
|
this._iconBox.set_child(icon);
|
||||||
|
},
|
||||||
|
|
||||||
_updateIconBoxClip: function() {
|
_updateIconBoxClip: function() {
|
||||||
let allocation = this._iconBox.allocation;
|
let allocation = this._iconBox.allocation;
|
||||||
if (this._iconBottomClip > 0)
|
if (this._iconBottomClip > 0)
|
||||||
@@ -353,6 +384,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
transition: "easeOutQuad",
|
transition: "easeOutQuad",
|
||||||
onCompleteScope: this,
|
onCompleteScope: this,
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
|
this._spinner.stop();
|
||||||
this._spinner.actor.opacity = 255;
|
this._spinner.actor.opacity = 255;
|
||||||
this._spinner.actor.hide();
|
this._spinner.actor.hide();
|
||||||
}
|
}
|
||||||
@@ -362,6 +394,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
startAnimation: function() {
|
startAnimation: function() {
|
||||||
this._stop = false;
|
this._stop = false;
|
||||||
this.actor.reactive = false;
|
this.actor.reactive = false;
|
||||||
|
this._spinner.play();
|
||||||
this._spinner.actor.show();
|
this._spinner.actor.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -467,13 +500,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._sync();
|
this._sync();
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
if (locked)
|
|
||||||
this.hide();
|
|
||||||
else
|
|
||||||
this._sync();
|
|
||||||
},
|
|
||||||
|
|
||||||
_sync: function() {
|
_sync: function() {
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
let focusedApp = tracker.focus_app;
|
let focusedApp = tracker.focus_app;
|
||||||
@@ -607,8 +633,8 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
|
|
||||||
this.actor.label_actor = this._label;
|
this.actor.label_actor = this._label;
|
||||||
|
|
||||||
this._hotCorner = new Layout.HotCorner();
|
this.hotCorner = new Layout.HotCorner();
|
||||||
container.add_actor(this._hotCorner.actor);
|
container.add_actor(this.hotCorner.actor);
|
||||||
|
|
||||||
// Hack up our menu...
|
// Hack up our menu...
|
||||||
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
|
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
|
||||||
@@ -658,10 +684,10 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
hotBox.x1 = Math.round(x);
|
hotBox.x1 = Math.round(x);
|
||||||
hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
|
hotBox.x2 = hotBox.x1 + this.hotCorner.actor.width;
|
||||||
hotBox.y1 = Math.round(y);
|
hotBox.y1 = Math.round(y);
|
||||||
hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
|
hotBox.y2 = hotBox.y1 + this.hotCorner.actor.height;
|
||||||
this._hotCorner.actor.allocate(hotBox, flags);
|
this.hotCorner.actor.allocate(hotBox, flags);
|
||||||
},
|
},
|
||||||
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
@@ -683,7 +709,7 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
|
|
||||||
_onCapturedEvent: function(actor, event) {
|
_onCapturedEvent: function(actor, event) {
|
||||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||||
if (!this._hotCorner.shouldToggleOverviewOnClick())
|
if (!this.hotCorner.shouldToggleOverviewOnClick())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -899,6 +925,30 @@ const PanelCorner = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const PANEL_ITEM_IMPLEMENTATIONS = {
|
||||||
|
'activities': ActivitiesButton,
|
||||||
|
'appMenu': AppMenuButton,
|
||||||
|
'dateMenu': imports.ui.dateMenu.DateMenuButton,
|
||||||
|
'a11y': imports.ui.status.accessibility.ATIndicator,
|
||||||
|
'volume': imports.ui.status.volume.Indicator,
|
||||||
|
'battery': imports.ui.status.power.Indicator,
|
||||||
|
'lockScreen': imports.ui.status.lockScreenMenu.Indicator,
|
||||||
|
'logo': imports.gdm.loginDialog.LogoMenuButton,
|
||||||
|
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
||||||
|
'powerMenu': imports.gdm.powerMenu.PowerMenuButton,
|
||||||
|
'userMenu': imports.ui.userMenu.UserMenuButton
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Config.HAVE_BLUETOOTH)
|
||||||
|
PANEL_ITEM_IMPLEMENTATIONS['bluetooth'] =
|
||||||
|
imports.ui.status.bluetooth.Indicator;
|
||||||
|
|
||||||
|
try {
|
||||||
|
PANEL_ITEM_IMPLEMENTATIONS['network'] =
|
||||||
|
imports.ui.status.network.NMApplet;
|
||||||
|
} catch(e) {
|
||||||
|
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
|
||||||
|
}
|
||||||
|
|
||||||
const Panel = new Lang.Class({
|
const Panel = new Lang.Class({
|
||||||
Name: 'Panel',
|
Name: 'Panel',
|
||||||
@@ -908,7 +958,7 @@ const Panel = new Lang.Class({
|
|||||||
reactive: true });
|
reactive: true });
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this._statusArea = {};
|
this.statusArea = {};
|
||||||
|
|
||||||
Main.overview.connect('shown', Lang.bind(this, function () {
|
Main.overview.connect('shown', Lang.bind(this, function () {
|
||||||
this.actor.add_style_class_name('in-overview');
|
this.actor.add_style_class_name('in-overview');
|
||||||
@@ -917,9 +967,7 @@ const Panel = new Lang.Class({
|
|||||||
this.actor.remove_style_class_name('in-overview');
|
this.actor.remove_style_class_name('in-overview');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
Main.screenShield.connect('lock-status-changed', Lang.bind(this, this._onLockStateChanged));
|
this.menuManager = new PopupMenu.PopupMenuManager(this);
|
||||||
|
|
||||||
this._menus = new PopupMenu.PopupMenuManager(this);
|
|
||||||
|
|
||||||
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
||||||
this.actor.add_actor(this._leftBox);
|
this.actor.add_actor(this._leftBox);
|
||||||
@@ -946,30 +994,12 @@ const Panel = new Lang.Class({
|
|||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||||
|
|
||||||
/* Button on the left side of the panel. */
|
|
||||||
if (Main.sessionMode.hasOverview) {
|
|
||||||
this._activitiesButton = new ActivitiesButton();
|
|
||||||
this._activities = this._activitiesButton.actor;
|
|
||||||
this._leftBox.add(this._activities);
|
|
||||||
|
|
||||||
// The activities button has a pretend menu, so as to integrate
|
|
||||||
// more cleanly with the rest of the panel
|
|
||||||
this._menus.addMenu(this._activitiesButton.menu);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Main.sessionMode.hasAppMenu) {
|
|
||||||
this._appMenu = new AppMenuButton(this._menus);
|
|
||||||
this._leftBox.add(this._appMenu.actor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* center */
|
|
||||||
this._dateMenu = new DateMenu.DateMenuButton();
|
|
||||||
this._centerBox.add(this._dateMenu.actor, { y_fill: true });
|
|
||||||
this._menus.addMenu(this._dateMenu.menu);
|
|
||||||
|
|
||||||
Main.layoutManager.panelBox.add(this.actor);
|
Main.layoutManager.panelBox.add(this.actor);
|
||||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
|
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here-symbolic',
|
||||||
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
||||||
|
|
||||||
|
Main.sessionMode.connect('updated', Lang.bind(this, this._updatePanel));
|
||||||
|
this._updatePanel();
|
||||||
},
|
},
|
||||||
|
|
||||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||||
@@ -1029,16 +1059,19 @@ const Panel = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this._rightBox.allocate(childBox, flags);
|
this._rightBox.allocate(childBox, flags);
|
||||||
|
|
||||||
let [cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
|
let cornerMinWidth, cornerMinHeight;
|
||||||
let [cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_width(-1);
|
let cornerWidth, cornerHeight;
|
||||||
|
|
||||||
|
[cornerMinWidth, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
|
||||||
|
[cornerMinHeight, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1);
|
||||||
childBox.x1 = 0;
|
childBox.x1 = 0;
|
||||||
childBox.x2 = cornerWidth;
|
childBox.x2 = cornerWidth;
|
||||||
childBox.y1 = allocHeight;
|
childBox.y1 = allocHeight;
|
||||||
childBox.y2 = allocHeight + cornerHeight;
|
childBox.y2 = allocHeight + cornerHeight;
|
||||||
this._leftCorner.actor.allocate(childBox, flags);
|
this._leftCorner.actor.allocate(childBox, flags);
|
||||||
|
|
||||||
let [cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
|
[cornerMinWidth, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
|
||||||
let [cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_width(-1);
|
[cornerMinHeight, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1);
|
||||||
childBox.x1 = allocWidth - cornerWidth;
|
childBox.x1 = allocWidth - cornerWidth;
|
||||||
childBox.x2 = allocWidth;
|
childBox.x2 = allocWidth;
|
||||||
childBox.y1 = allocHeight;
|
childBox.y1 = allocHeight;
|
||||||
@@ -1086,76 +1119,126 @@ const Panel = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
openAppMenu: function() {
|
openAppMenu: function() {
|
||||||
let menu = this._appMenu.menu;
|
let indicator = this.statusArea.appMenu;
|
||||||
if (!this._appMenu.actor.reactive || menu.isOpen)
|
if (!indicator) // appMenu not supported by current session mode
|
||||||
|
return;
|
||||||
|
|
||||||
|
let menu = indicator.menu;
|
||||||
|
if (!indicator.actor.reactive || menu.isOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
menu.open();
|
menu.open();
|
||||||
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
startStatusArea: function() {
|
set boxOpacity(value) {
|
||||||
for (let i = 0; i < Main.sessionMode.statusArea.order.length; i++) {
|
let isReactive = value > 0;
|
||||||
let role = Main.sessionMode.statusArea.order[i];
|
|
||||||
let constructor = Main.sessionMode.statusArea.implementation[role];
|
this._leftBox.opacity = value;
|
||||||
|
this._leftBox.reactive = isReactive;
|
||||||
|
this._centerBox.opacity = value;
|
||||||
|
this._centerBox.reactive = isReactive;
|
||||||
|
this._rightBox.opacity = value;
|
||||||
|
this._rightBox.reactive = isReactive;
|
||||||
|
},
|
||||||
|
|
||||||
|
get boxOpacity() {
|
||||||
|
return this._leftBox.opacity;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updatePanel: function() {
|
||||||
|
let panel = Main.sessionMode.panel;
|
||||||
|
this._hideIndicators();
|
||||||
|
this._updateBox(panel.left, this._leftBox);
|
||||||
|
this._updateBox(panel.center, this._centerBox);
|
||||||
|
this._updateBox(panel.right, this._rightBox);
|
||||||
|
},
|
||||||
|
|
||||||
|
_initBox: function(elements, box) {
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
let role = elements[i];
|
||||||
|
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
|
||||||
if (!constructor) {
|
if (!constructor) {
|
||||||
// This icon is not implemented (this is a bug)
|
// panel icon is not supported (can happen for
|
||||||
|
// bluetooth or network)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let indicator = new constructor();
|
|
||||||
this.addToStatusArea(role, indicator, i);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_insertStatusItem: function(actor, position) {
|
_hideIndicators: function() {
|
||||||
let children = this._rightBox.get_children();
|
for (let role in PANEL_ITEM_IMPLEMENTATIONS) {
|
||||||
let i;
|
let indicator = this.statusArea[role];
|
||||||
for (i = children.length - 1; i >= 0; i--) {
|
if (!indicator)
|
||||||
let rolePosition = children[i]._rolePosition;
|
continue;
|
||||||
if (position > rolePosition) {
|
if (indicator.menu)
|
||||||
this._rightBox.insert_child_at_index(actor, i + 1);
|
indicator.menu.close();
|
||||||
break;
|
indicator.container.hide();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (i == -1) {
|
|
||||||
// If we didn't find a position, we must be first
|
|
||||||
this._rightBox.insert_child_at_index(actor, 0);
|
|
||||||
}
|
|
||||||
actor._rolePosition = position;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
addToStatusArea: function(role, indicator, position) {
|
_ensureIndicator: function(role) {
|
||||||
if (this._statusArea[role])
|
let indicator = this.statusArea[role];
|
||||||
|
if (!indicator) {
|
||||||
|
let constructor = PANEL_ITEM_IMPLEMENTATIONS[role];
|
||||||
|
if (!constructor) {
|
||||||
|
// This icon is not implemented (this is a bug)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
indicator = new constructor(this);
|
||||||
|
this.statusArea[role] = indicator;
|
||||||
|
}
|
||||||
|
return indicator;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateBox: function(elements, box) {
|
||||||
|
let nChildren = box.get_n_children();
|
||||||
|
|
||||||
|
for (let i = 0; i < elements.length; i++) {
|
||||||
|
let role = elements[i];
|
||||||
|
let indicator = this._ensureIndicator(role);
|
||||||
|
if (indicator == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this._addToPanelBox(role, indicator, i + nChildren, box);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_addToPanelBox: function(role, indicator, position, box) {
|
||||||
|
let container = indicator.container;
|
||||||
|
container.show();
|
||||||
|
|
||||||
|
let parent = container.get_parent();
|
||||||
|
if (parent)
|
||||||
|
parent.remove_actor(container);
|
||||||
|
|
||||||
|
box.insert_child_at_index(container, position);
|
||||||
|
if (indicator.menu)
|
||||||
|
this.menuManager.addMenu(indicator.menu);
|
||||||
|
this.statusArea[role] = indicator;
|
||||||
|
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
||||||
|
delete this.statusArea[role];
|
||||||
|
emitter.disconnect(destroyId);
|
||||||
|
container.destroy();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
addToStatusArea: function(role, indicator, position, box) {
|
||||||
|
if (this.statusArea[role])
|
||||||
throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
|
throw new Error('Extension point conflict: there is already a status indicator for role ' + role);
|
||||||
|
|
||||||
if (!(indicator instanceof PanelMenu.Button))
|
if (!(indicator instanceof PanelMenu.Button))
|
||||||
throw new TypeError('Status indicator must be an instance of PanelMenu.Button');
|
throw new TypeError('Status indicator must be an instance of PanelMenu.Button');
|
||||||
|
|
||||||
if (!position)
|
position = position || 0;
|
||||||
position = 0;
|
let boxes = {
|
||||||
this._insertStatusItem(indicator.actor, position);
|
left: this._leftBox,
|
||||||
if (indicator.menu)
|
center: this._centerBox,
|
||||||
this._menus.addMenu(indicator.menu);
|
right: this._rightBox
|
||||||
|
};
|
||||||
this._statusArea[role] = indicator;
|
let boxContainer = boxes[box] || this._rightBox;
|
||||||
let destroyId = indicator.connect('destroy', Lang.bind(this, function(emitter) {
|
this.statusArea[role] = indicator;
|
||||||
delete this._statusArea[role];
|
this._addToPanelBox(role, indicator, position, boxContainer);
|
||||||
emitter.disconnect(destroyId);
|
|
||||||
}));
|
|
||||||
|
|
||||||
return indicator;
|
return indicator;
|
||||||
},
|
}
|
||||||
|
|
||||||
_onLockStateChanged: function(shield, locked) {
|
|
||||||
if (this._activitiesButton)
|
|
||||||
this._activitiesButton.setLockedState(locked);
|
|
||||||
if (this._appMenu)
|
|
||||||
this._appMenu.setLockedState(locked);
|
|
||||||
if (this._dateMenu)
|
|
||||||
this._dateMenu.setLockedState(locked);
|
|
||||||
|
|
||||||
for (let id in this._statusArea)
|
|
||||||
this._statusArea[id].setLockedState(locked);
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
@@ -20,6 +21,10 @@ const ButtonBox = new Lang.Class({
|
|||||||
this.actor = new Shell.GenericContainer(params);
|
this.actor = new Shell.GenericContainer(params);
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
|
this.container = new St.Bin({ y_fill: true,
|
||||||
|
x_fill: true,
|
||||||
|
child: this.actor });
|
||||||
|
|
||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
@@ -114,6 +119,12 @@ const Button = new Lang.Class({
|
|||||||
this.setName(nameText);
|
this.setName(nameText);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setSensitive: function(sensitive) {
|
||||||
|
this.actor.reactive = sensitive;
|
||||||
|
this.actor.can_focus = sensitive;
|
||||||
|
this.actor.track_hover = sensitive;
|
||||||
|
},
|
||||||
|
|
||||||
setName: function(text) {
|
setName: function(text) {
|
||||||
if (text != null) {
|
if (text != null) {
|
||||||
// This is the easiest way to provide a accessible name to
|
// This is the easiest way to provide a accessible name to
|
||||||
@@ -145,13 +156,6 @@ const Button = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
// default behaviour is to hide completely
|
|
||||||
if (locked)
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.visible = !locked;
|
|
||||||
},
|
|
||||||
|
|
||||||
_onButtonPress: function(actor, event) {
|
_onButtonPress: function(actor, event) {
|
||||||
if (!this.menu)
|
if (!this.menu)
|
||||||
return;
|
return;
|
||||||
@@ -210,6 +214,7 @@ const Button = new Lang.Class({
|
|||||||
destroy: function() {
|
destroy: function() {
|
||||||
this.actor._delegate = null;
|
this.actor._delegate = null;
|
||||||
|
|
||||||
|
if (this.menu)
|
||||||
this.menu.destroy();
|
this.menu.destroy();
|
||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
|
|
||||||
@@ -230,19 +235,36 @@ const SystemStatusButton = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(iconName, nameText) {
|
_init: function(iconName, nameText) {
|
||||||
this.parent(0.0, nameText);
|
this.parent(0.0, nameText);
|
||||||
|
|
||||||
this._iconActor = new St.Icon({ icon_name: iconName,
|
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
|
||||||
style_class: 'system-status-icon' });
|
|
||||||
this.actor.add_actor(this._iconActor);
|
|
||||||
this.actor.add_style_class_name('panel-status-button');
|
this.actor.add_style_class_name('panel-status-button');
|
||||||
|
|
||||||
|
this._box = new St.BoxLayout({ style_class: 'panel-status-button-box' });
|
||||||
|
this.actor.add_actor(this._box);
|
||||||
|
|
||||||
|
if (iconName)
|
||||||
|
this.setIcon(iconName);
|
||||||
|
},
|
||||||
|
|
||||||
|
addIcon: function(gicon) {
|
||||||
|
let icon = new St.Icon({ gicon: gicon,
|
||||||
|
style_class: 'system-status-icon' });
|
||||||
|
this._box.add_actor(icon);
|
||||||
|
|
||||||
|
return icon;
|
||||||
},
|
},
|
||||||
|
|
||||||
setIcon: function(iconName) {
|
setIcon: function(iconName) {
|
||||||
this._iconActor.icon_name = iconName;
|
// Need to first add a NULL GIcon and then set icon_name, to ensure
|
||||||
|
// compatibility with -symbolic fallbacks
|
||||||
|
|
||||||
|
if (!this.mainIcon)
|
||||||
|
this.mainIcon = this.addIcon(null);
|
||||||
|
this.mainIcon.icon_name = iconName;
|
||||||
},
|
},
|
||||||
|
|
||||||
setGIcon: function(gicon) {
|
setGIcon: function(gicon) {
|
||||||
this._iconActor.gicon = gicon;
|
if (this.mainIcon)
|
||||||
|
this.mainIcon.gicon = gicon;
|
||||||
|
else
|
||||||
|
this.mainIcon = this.addIcon(gicon);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,430 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const GLib = imports.gi.GLib;
|
|
||||||
const Gio = imports.gi.Gio;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Mainloop = imports.mainloop;
|
|
||||||
const Signals = imports.signals;
|
|
||||||
const St = imports.gi.St;
|
|
||||||
|
|
||||||
const DND = imports.ui.dnd;
|
|
||||||
const Main = imports.ui.main;
|
|
||||||
const Params = imports.misc.params;
|
|
||||||
const Search = imports.ui.search;
|
|
||||||
const Util = imports.misc.util;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a place object, which is most normally a bookmark entry,
|
|
||||||
* a mount/volume, or a special place like the Home Folder, Computer, and Network.
|
|
||||||
*
|
|
||||||
* @name: String title
|
|
||||||
* @iconFactory: A JavaScript callback which will create an icon texture given a size parameter
|
|
||||||
* @launch: A JavaScript callback to launch the entry
|
|
||||||
*/
|
|
||||||
const PlaceInfo = new Lang.Class({
|
|
||||||
Name: 'PlaceInfo',
|
|
||||||
|
|
||||||
_init: function(id, name, iconFactory, launch) {
|
|
||||||
this.id = id;
|
|
||||||
this.name = name;
|
|
||||||
this._lowerName = name.toLowerCase();
|
|
||||||
this.iconFactory = iconFactory;
|
|
||||||
this.launch = launch;
|
|
||||||
},
|
|
||||||
|
|
||||||
matchTerms: function(terms) {
|
|
||||||
let mtype = Search.MatchType.NONE;
|
|
||||||
for (let i = 0; i < terms.length; i++) {
|
|
||||||
let term = terms[i];
|
|
||||||
let idx = this._lowerName.indexOf(term);
|
|
||||||
if (idx == 0) {
|
|
||||||
mtype = Search.MatchType.PREFIX;
|
|
||||||
} else if (idx > 0) {
|
|
||||||
if (mtype == Search.MatchType.NONE)
|
|
||||||
mtype = Search.MatchType.SUBSTRING;
|
|
||||||
} else {
|
|
||||||
return Search.MatchType.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mtype;
|
|
||||||
},
|
|
||||||
|
|
||||||
isRemovable: function() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Helper function to translate launch parameters into a GAppLaunchContext
|
|
||||||
function _makeLaunchContext(params)
|
|
||||||
{
|
|
||||||
params = Params.parse(params, { workspace: -1,
|
|
||||||
timestamp: 0 });
|
|
||||||
|
|
||||||
let launchContext = global.create_app_launch_context();
|
|
||||||
if (params.workspace != -1)
|
|
||||||
launchContext.set_desktop(params.workspace);
|
|
||||||
if (params.timestamp != 0)
|
|
||||||
launchContext.set_timestamp(params.timestamp);
|
|
||||||
|
|
||||||
return launchContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PlaceDeviceInfo = new Lang.Class({
|
|
||||||
Name: 'PlaceDeviceInfo',
|
|
||||||
Extends: PlaceInfo,
|
|
||||||
|
|
||||||
_init: function(mount) {
|
|
||||||
this._mount = mount;
|
|
||||||
this.name = mount.get_name();
|
|
||||||
this._lowerName = this.name.toLowerCase();
|
|
||||||
this.id = 'mount:' + mount.get_root().get_uri();
|
|
||||||
},
|
|
||||||
|
|
||||||
iconFactory: function(size) {
|
|
||||||
let icon = this._mount.get_icon();
|
|
||||||
return St.TextureCache.get_default().load_gicon(null, icon, size);
|
|
||||||
},
|
|
||||||
|
|
||||||
launch: function(params) {
|
|
||||||
Gio.app_info_launch_default_for_uri(this._mount.get_root().get_uri(),
|
|
||||||
_makeLaunchContext(params));
|
|
||||||
},
|
|
||||||
|
|
||||||
isRemovable: function() {
|
|
||||||
return this._mount.can_unmount();
|
|
||||||
},
|
|
||||||
|
|
||||||
remove: function() {
|
|
||||||
if (!this.isRemovable())
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._mount.can_eject())
|
|
||||||
this._mount.eject(0, null, Lang.bind(this, this._removeFinish));
|
|
||||||
else
|
|
||||||
this._mount.unmount(0, null, Lang.bind(this, this._removeFinish));
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeFinish: function(o, res, data) {
|
|
||||||
try {
|
|
||||||
if (this._mount.can_eject())
|
|
||||||
this._mount.eject_finish(res);
|
|
||||||
else
|
|
||||||
this._mount.unmount_finish(res);
|
|
||||||
} catch (e) {
|
|
||||||
let message = _("Failed to unmount '%s'").format(o.get_name());
|
|
||||||
Main.overview.setMessage(message,
|
|
||||||
Lang.bind(this, this.remove),
|
|
||||||
_("Retry"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const PlacesManager = new Lang.Class({
|
|
||||||
Name: 'PlacesManager',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this._defaultPlaces = [];
|
|
||||||
this._mounts = [];
|
|
||||||
this._bookmarks = [];
|
|
||||||
|
|
||||||
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
|
|
||||||
let homeUri = homeFile.get_uri();
|
|
||||||
let homeLabel = Shell.util_get_label_for_uri (homeUri);
|
|
||||||
let homeIcon = Shell.util_get_icon_for_uri (homeUri);
|
|
||||||
this._home = new PlaceInfo('special:home', homeLabel,
|
|
||||||
function(size) {
|
|
||||||
return St.TextureCache.get_default().load_gicon(null, homeIcon, size);
|
|
||||||
},
|
|
||||||
function(params) {
|
|
||||||
Gio.app_info_launch_default_for_uri(homeUri, _makeLaunchContext(params));
|
|
||||||
});
|
|
||||||
|
|
||||||
let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
|
|
||||||
let desktopFile = Gio.file_new_for_path (desktopPath);
|
|
||||||
let desktopUri = desktopFile.get_uri();
|
|
||||||
let desktopLabel = Shell.util_get_label_for_uri (desktopUri);
|
|
||||||
let desktopIcon = Shell.util_get_icon_for_uri (desktopUri);
|
|
||||||
this._desktopMenu = new PlaceInfo('special:desktop', desktopLabel,
|
|
||||||
function(size) {
|
|
||||||
return St.TextureCache.get_default().load_gicon(null, desktopIcon, size);
|
|
||||||
},
|
|
||||||
function(params) {
|
|
||||||
Gio.app_info_launch_default_for_uri(desktopUri, _makeLaunchContext(params));
|
|
||||||
});
|
|
||||||
|
|
||||||
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
|
|
||||||
function (size) {
|
|
||||||
// do NOT use St.Icon here, it crashes the shell
|
|
||||||
// see wanda.js for details
|
|
||||||
return St.TextureCache.get_default().load_icon_name(null,
|
|
||||||
'applications-internet',
|
|
||||||
St.IconType.FULLCOLOR,
|
|
||||||
size);
|
|
||||||
},
|
|
||||||
function (params) {
|
|
||||||
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't
|
|
||||||
// launch it with the workspace from params. It's probably pretty rare
|
|
||||||
// and odd to drag this place onto a workspace in any case
|
|
||||||
|
|
||||||
Util.spawn(['nautilus-connect-server']);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._defaultPlaces.push(this._home);
|
|
||||||
this._defaultPlaces.push(this._desktopMenu);
|
|
||||||
this._defaultPlaces.push(this._connect);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Show devices, code more or less ported from nautilus-places-sidebar.c
|
|
||||||
*/
|
|
||||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
|
||||||
this._volumeMonitor.connect('volume-added', Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('volume-removed',Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('volume-changed', Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('mount-added', Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('mount-changed', Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._updateDevices));
|
|
||||||
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
|
|
||||||
this._updateDevices();
|
|
||||||
|
|
||||||
this._bookmarksPath = GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']);
|
|
||||||
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
|
|
||||||
this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
|
||||||
this._bookmarkTimeoutId = 0;
|
|
||||||
this._monitor.connect('changed', Lang.bind(this, function () {
|
|
||||||
if (this._bookmarkTimeoutId > 0)
|
|
||||||
return;
|
|
||||||
/* Defensive event compression */
|
|
||||||
this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
|
|
||||||
this._bookmarkTimeoutId = 0;
|
|
||||||
this._reloadBookmarks();
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._reloadBookmarks();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateDevices: function() {
|
|
||||||
this._mounts = [];
|
|
||||||
|
|
||||||
/* first go through all connected drives */
|
|
||||||
let drives = this._volumeMonitor.get_connected_drives();
|
|
||||||
for (let i = 0; i < drives.length; i++) {
|
|
||||||
let volumes = drives[i].get_volumes();
|
|
||||||
for(let j = 0; j < volumes.length; j++) {
|
|
||||||
let mount = volumes[j].get_mount();
|
|
||||||
if(mount != null) {
|
|
||||||
this._addMount(mount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add all volumes that is not associated with a drive */
|
|
||||||
let volumes = this._volumeMonitor.get_volumes();
|
|
||||||
for(let i = 0; i < volumes.length; i++) {
|
|
||||||
if(volumes[i].get_drive() != null)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
let mount = volumes[i].get_mount();
|
|
||||||
if(mount != null) {
|
|
||||||
this._addMount(mount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */
|
|
||||||
let mounts = this._volumeMonitor.get_mounts();
|
|
||||||
for(let i = 0; i < mounts.length; i++) {
|
|
||||||
if(mounts[i].is_shadowed())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if(mounts[i].get_volume())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
this._addMount(mounts[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We emit two signals, one for a generic 'all places' update
|
|
||||||
* and the other for one specific to mounts. We do this because
|
|
||||||
* clients like PlaceDisplay may only care about places in general
|
|
||||||
* being updated while clients like DashPlaceDisplay care which
|
|
||||||
* specific type of place got updated.
|
|
||||||
*/
|
|
||||||
this.emit('mounts-updated');
|
|
||||||
this.emit('places-updated');
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
_reloadBookmarks: function() {
|
|
||||||
|
|
||||||
this._bookmarks = [];
|
|
||||||
|
|
||||||
if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
|
|
||||||
return;
|
|
||||||
|
|
||||||
let bookmarksContent = Shell.get_file_contents_utf8_sync(this._bookmarksPath);
|
|
||||||
|
|
||||||
let bookmarks = bookmarksContent.split('\n');
|
|
||||||
|
|
||||||
let bookmarksToLabel = {};
|
|
||||||
let bookmarksOrder = [];
|
|
||||||
for (let i = 0; i < bookmarks.length; i++) {
|
|
||||||
let bookmarkLine = bookmarks[i];
|
|
||||||
let components = bookmarkLine.split(' ');
|
|
||||||
let bookmark = components[0];
|
|
||||||
if (bookmark in bookmarksToLabel)
|
|
||||||
continue;
|
|
||||||
let label = null;
|
|
||||||
if (components.length > 1)
|
|
||||||
label = components.slice(1).join(' ');
|
|
||||||
bookmarksToLabel[bookmark] = label;
|
|
||||||
bookmarksOrder.push(bookmark);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < bookmarksOrder.length; i++) {
|
|
||||||
let bookmark = bookmarksOrder[i];
|
|
||||||
let label = bookmarksToLabel[bookmark];
|
|
||||||
let file = Gio.file_new_for_uri(bookmark);
|
|
||||||
if (!file.query_exists(null))
|
|
||||||
continue;
|
|
||||||
if (label == null)
|
|
||||||
label = Shell.util_get_label_for_uri(bookmark);
|
|
||||||
if (label == null)
|
|
||||||
continue;
|
|
||||||
let icon = Shell.util_get_icon_for_uri(bookmark);
|
|
||||||
|
|
||||||
let item = new PlaceInfo('bookmark:' + bookmark, label,
|
|
||||||
function(size) {
|
|
||||||
return St.TextureCache.get_default().load_gicon(null, icon, size);
|
|
||||||
},
|
|
||||||
function(params) {
|
|
||||||
Gio.app_info_launch_default_for_uri(bookmark, _makeLaunchContext(params));
|
|
||||||
});
|
|
||||||
this._bookmarks.push(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* See comment in _updateDevices for explanation why there are two signals. */
|
|
||||||
this.emit('bookmarks-updated');
|
|
||||||
this.emit('places-updated');
|
|
||||||
},
|
|
||||||
|
|
||||||
_addMount: function(mount) {
|
|
||||||
let devItem = new PlaceDeviceInfo(mount);
|
|
||||||
this._mounts.push(devItem);
|
|
||||||
},
|
|
||||||
|
|
||||||
getAllPlaces: function () {
|
|
||||||
return this.getDefaultPlaces().concat(this.getBookmarks(), this.getMounts());
|
|
||||||
},
|
|
||||||
|
|
||||||
getDefaultPlaces: function () {
|
|
||||||
return this._defaultPlaces;
|
|
||||||
},
|
|
||||||
|
|
||||||
getBookmarks: function () {
|
|
||||||
return this._bookmarks;
|
|
||||||
},
|
|
||||||
|
|
||||||
getMounts: function () {
|
|
||||||
return this._mounts;
|
|
||||||
},
|
|
||||||
|
|
||||||
_lookupIndexById: function(sourceArray, id) {
|
|
||||||
for (let i = 0; i < sourceArray.length; i++) {
|
|
||||||
let place = sourceArray[i];
|
|
||||||
if (place.id == id)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
lookupPlaceById: function(id) {
|
|
||||||
let colonIdx = id.indexOf(':');
|
|
||||||
let type = id.substring(0, colonIdx);
|
|
||||||
let sourceArray = null;
|
|
||||||
if (type == 'special')
|
|
||||||
sourceArray = this._defaultPlaces;
|
|
||||||
else if (type == 'mount')
|
|
||||||
sourceArray = this._mounts;
|
|
||||||
else if (type == 'bookmark')
|
|
||||||
sourceArray = this._bookmarks;
|
|
||||||
return sourceArray[this._lookupIndexById(sourceArray, id)];
|
|
||||||
},
|
|
||||||
|
|
||||||
_removeById: function(sourceArray, id) {
|
|
||||||
sourceArray.splice(this._lookupIndexById(sourceArray, id), 1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Signals.addSignalMethods(PlacesManager.prototype);
|
|
||||||
|
|
||||||
const PlaceSearchProvider = new Lang.Class({
|
|
||||||
Name: 'PlaceSearchProvider',
|
|
||||||
Extends: Search.SearchProvider,
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this.parent(_("PLACES & DEVICES"));
|
|
||||||
this.placesManager = new PlacesManager();
|
|
||||||
},
|
|
||||||
|
|
||||||
getResultMetas: function(resultIds, callback) {
|
|
||||||
let metas = [];
|
|
||||||
for (let i = 0; i < resultIds.length; i++) {
|
|
||||||
let placeInfo = this.placesManager.lookupPlaceById(resultIds[i]);
|
|
||||||
if (!placeInfo)
|
|
||||||
metas.push(null);
|
|
||||||
else
|
|
||||||
metas.push({ 'id': resultIds[i],
|
|
||||||
'name': placeInfo.name,
|
|
||||||
'createIcon': function(size) {
|
|
||||||
return placeInfo.iconFactory(size);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
callback(metas);
|
|
||||||
},
|
|
||||||
|
|
||||||
activateResult: function(id, params) {
|
|
||||||
let placeInfo = this.placesManager.lookupPlaceById(id);
|
|
||||||
placeInfo.launch(params);
|
|
||||||
},
|
|
||||||
|
|
||||||
_compareResultMeta: function (idA, idB) {
|
|
||||||
let infoA = this.placesManager.lookupPlaceById(idA);
|
|
||||||
let infoB = this.placesManager.lookupPlaceById(idB);
|
|
||||||
return infoA.name.localeCompare(infoB.name);
|
|
||||||
},
|
|
||||||
|
|
||||||
_searchPlaces: function(places, terms) {
|
|
||||||
let prefixResults = [];
|
|
||||||
let substringResults = [];
|
|
||||||
|
|
||||||
terms = terms.map(String.toLowerCase);
|
|
||||||
|
|
||||||
for (let i = 0; i < places.length; i++) {
|
|
||||||
let place = places[i];
|
|
||||||
let mtype = place.matchTerms(terms);
|
|
||||||
if (mtype == Search.MatchType.PREFIX)
|
|
||||||
prefixResults.push(place.id);
|
|
||||||
else if (mtype == Search.MatchType.SUBSTRING)
|
|
||||||
substringResults.push(place.id);
|
|
||||||
}
|
|
||||||
prefixResults.sort(Lang.bind(this, this._compareResultMeta));
|
|
||||||
substringResults.sort(Lang.bind(this, this._compareResultMeta));
|
|
||||||
|
|
||||||
this.searchSystem.pushResults(this, prefixResults.concat(substringResults));
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
|
||||||
let places = this.placesManager.getAllPlaces();
|
|
||||||
this._searchPlaces(places, terms);
|
|
||||||
},
|
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, terms) {
|
|
||||||
let places = previousResults.map(Lang.bind(this, function(id) {
|
|
||||||
return this.placesManager.lookupPlaceById(id);
|
|
||||||
}));
|
|
||||||
this._searchPlaces(places, terms);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
// We stop polling if the user is idle for more than this amount of time
|
// We stop polling if the user is idle for more than this amount of time
|
||||||
@@ -40,9 +41,9 @@ const PointerWatcher = new Lang.Class({
|
|||||||
Name: 'PointerWatcher',
|
Name: 'PointerWatcher',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
let idleMonitor = Shell.IdleMonitor.get();
|
let idleMonitor = new GnomeDesktop.IdleMonitor();
|
||||||
idleMonitor.add_watch(IDLE_TIME,
|
idleMonitor.connect('became-active', Lang.bind(this, this._onIdleMonitorBecameActive));
|
||||||
Lang.bind(this, this._onIdleMonitorWatch));
|
idleMonitor.add_watch(IDLE_TIME, Lang.bind(this, this._onIdleMonitorBecameIdle));
|
||||||
this._idle = idleMonitor.get_idletime() > IDLE_TIME;
|
this._idle = idleMonitor.get_idletime() > IDLE_TIME;
|
||||||
this._watches = [];
|
this._watches = [];
|
||||||
this.pointerX = null;
|
this.pointerX = null;
|
||||||
@@ -78,11 +79,14 @@ const PointerWatcher = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onIdleMonitorWatch: function(monitor, id, userBecameIdle) {
|
_onIdleMonitorBecameActive: function(monitor) {
|
||||||
this._idle = userBecameIdle;
|
this._idle = false;
|
||||||
if (!userBecameIdle)
|
|
||||||
this._updatePointer();
|
this._updatePointer();
|
||||||
|
this._updateTimeout();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onIdleMonitorBecameIdle: function(monitor) {
|
||||||
|
this._idle = true;
|
||||||
this._updateTimeout();
|
this._updateTimeout();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -61,6 +61,9 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
this.setSensitive(this.sensitive);
|
this.setSensitive(this.sensitive);
|
||||||
|
|
||||||
|
if (!this._activatable)
|
||||||
|
this.actor.add_style_class_name('popup-inactive-menu-item');
|
||||||
|
|
||||||
if (params.style_class)
|
if (params.style_class)
|
||||||
this.actor.add_style_class_name(params.style_class);
|
this.actor.add_style_class_name(params.style_class);
|
||||||
|
|
||||||
@@ -134,6 +137,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
this.sensitive = sensitive;
|
this.sensitive = sensitive;
|
||||||
this.actor.reactive = sensitive;
|
this.actor.reactive = sensitive;
|
||||||
|
this.actor.can_focus = sensitive;
|
||||||
|
|
||||||
this.emit('sensitive-changed', sensitive);
|
this.emit('sensitive-changed', sensitive);
|
||||||
},
|
},
|
||||||
@@ -717,7 +721,8 @@ const Switch = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(state) {
|
_init: function(state) {
|
||||||
this.actor = new St.Bin({ style_class: 'toggle-switch',
|
this.actor = new St.Bin({ style_class: 'toggle-switch',
|
||||||
accessible_role: Atk.Role.CHECK_BOX});
|
accessible_role: Atk.Role.CHECK_BOX,
|
||||||
|
can_focus: true });
|
||||||
// Translators: this MUST be either "toggle-switch-us"
|
// Translators: this MUST be either "toggle-switch-us"
|
||||||
// (for toggle switches containing the English words
|
// (for toggle switches containing the English words
|
||||||
// "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
// "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
||||||
@@ -761,7 +766,7 @@ const PopupSwitchMenuItem = new Lang.Class({
|
|||||||
{ expand: true, span: -1, align: St.Align.END });
|
{ expand: true, span: -1, align: St.Align.END });
|
||||||
|
|
||||||
this._statusLabel = new St.Label({ text: '',
|
this._statusLabel = new St.Label({ text: '',
|
||||||
style_class: 'popup-inactive-menu-item'
|
style_class: 'popup-status-menu-item'
|
||||||
});
|
});
|
||||||
this._statusBin.child = this._switch.actor;
|
this._statusBin.child = this._switch.actor;
|
||||||
},
|
},
|
||||||
@@ -868,6 +873,12 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
this._activeMenuItem = null;
|
this._activeMenuItem = null;
|
||||||
this._childMenus = [];
|
this._childMenus = [];
|
||||||
this._settingsActions = { };
|
this._settingsActions = { };
|
||||||
|
|
||||||
|
this._sessionUpdatedId = Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||||
|
},
|
||||||
|
|
||||||
|
_sessionUpdated: function() {
|
||||||
|
this._setSettingsVisibility(Main.sessionMode.allowSettings);
|
||||||
},
|
},
|
||||||
|
|
||||||
addAction: function(title, callback) {
|
addAction: function(title, callback) {
|
||||||
@@ -881,9 +892,6 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addSettingsAction: function(title, desktopFile) {
|
addSettingsAction: function(title, desktopFile) {
|
||||||
if (!Main.sessionMode.allowSettings)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
let menuItem = this.addAction(title, function() {
|
let menuItem = this.addAction(title, function() {
|
||||||
let app = Shell.AppSystem.get_default().lookup_setting(desktopFile);
|
let app = Shell.AppSystem.get_default().lookup_setting(desktopFile);
|
||||||
|
|
||||||
@@ -896,12 +904,13 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
app.activate();
|
app.activate();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
menuItem.actor.visible = Main.sessionMode.allowSettings;
|
||||||
this._settingsActions[desktopFile] = menuItem;
|
this._settingsActions[desktopFile] = menuItem;
|
||||||
|
|
||||||
return menuItem;
|
return menuItem;
|
||||||
},
|
},
|
||||||
|
|
||||||
setSettingsVisibility: function(visible) {
|
_setSettingsVisibility: function(visible) {
|
||||||
for (let id in this._settingsActions) {
|
for (let id in this._settingsActions) {
|
||||||
let item = this._settingsActions[id];
|
let item = this._settingsActions[id];
|
||||||
item.actor.visible = visible;
|
item.actor.visible = visible;
|
||||||
@@ -1050,14 +1059,17 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
|
|
||||||
if (menuItem instanceof PopupMenuSection) {
|
if (menuItem instanceof PopupMenuSection) {
|
||||||
this._connectSubMenuSignals(menuItem, menuItem);
|
this._connectSubMenuSignals(menuItem, menuItem);
|
||||||
menuItem._closingId = this.connect('open-state-changed',
|
menuItem._parentOpenStateChangedId = this.connect('open-state-changed',
|
||||||
function(self, open) {
|
function(self, open) {
|
||||||
if (!open)
|
if (open)
|
||||||
menuItem.close(BoxPointer.PopupAnimation.FADE);
|
menuItem.open();
|
||||||
|
else
|
||||||
|
menuItem.close();
|
||||||
});
|
});
|
||||||
menuItem.connect('destroy', Lang.bind(this, function() {
|
menuItem.connect('destroy', Lang.bind(this, function() {
|
||||||
menuItem.disconnect(menuItem._subMenuActivateId);
|
menuItem.disconnect(menuItem._subMenuActivateId);
|
||||||
menuItem.disconnect(menuItem._subMenuActiveChangeId);
|
menuItem.disconnect(menuItem._subMenuActiveChangeId);
|
||||||
|
this.disconnect(menuItem._parentOpenStateChangedId);
|
||||||
|
|
||||||
this.length--;
|
this.length--;
|
||||||
}));
|
}));
|
||||||
@@ -1092,7 +1104,8 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
let columnWidths = [];
|
let columnWidths = [];
|
||||||
let items = this.box.get_children();
|
let items = this.box.get_children();
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
if (!items[i].visible)
|
if (!items[i].visible &&
|
||||||
|
!(items[i]._delegate instanceof PopupSubMenu && items[i-1].visible))
|
||||||
continue;
|
continue;
|
||||||
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
|
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
|
||||||
let itemColumnWidths = items[i]._delegate.getColumnWidths();
|
let itemColumnWidths = items[i]._delegate.getColumnWidths();
|
||||||
@@ -1167,6 +1180,9 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
|
|
||||||
this.emit('destroy');
|
this.emit('destroy');
|
||||||
|
|
||||||
|
Main.sessionMode.disconnect(this._sessionUpdatedId);
|
||||||
|
this._sessionUpdatedId = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(PopupMenuBase.prototype);
|
Signals.addSignalMethods(PopupMenuBase.prototype);
|
||||||
@@ -1253,14 +1269,15 @@ const PopupMenu = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
close: function(animate) {
|
close: function(animate) {
|
||||||
if (!this.isOpen)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._activeMenuItem)
|
if (this._activeMenuItem)
|
||||||
this._activeMenuItem.setActive(false);
|
this._activeMenuItem.setActive(false);
|
||||||
|
|
||||||
|
if (this._boxPointer.actor.visible)
|
||||||
this._boxPointer.hide(animate);
|
this._boxPointer.hide(animate);
|
||||||
|
|
||||||
|
if (!this.isOpen)
|
||||||
|
return;
|
||||||
|
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.emit('open-state-changed', false);
|
this.emit('open-state-changed', false);
|
||||||
}
|
}
|
||||||
@@ -1332,6 +1349,11 @@ const PopupSubMenu = new Lang.Class({
|
|||||||
this.actor.vscrollbar_policy =
|
this.actor.vscrollbar_policy =
|
||||||
needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
|
needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
|
||||||
|
|
||||||
|
if (needsScrollbar)
|
||||||
|
this.actor.add_style_pseudo_class('scrolled');
|
||||||
|
else
|
||||||
|
this.actor.remove_style_pseudo_class('scrolled');
|
||||||
|
|
||||||
// It looks funny if we animate with a scrollbar (at what point is
|
// It looks funny if we animate with a scrollbar (at what point is
|
||||||
// the scrollbar added?) so just skip that case
|
// the scrollbar added?) so just skip that case
|
||||||
if (animate && needsScrollbar)
|
if (animate && needsScrollbar)
|
||||||
@@ -1438,7 +1460,7 @@ const PopupMenuSection = new Lang.Class({
|
|||||||
|
|
||||||
// deliberately ignore any attempt to open() or close(), but emit the
|
// deliberately ignore any attempt to open() or close(), but emit the
|
||||||
// corresponding signal so children can still pick it up
|
// corresponding signal so children can still pick it up
|
||||||
open: function(animate) { this.emit('open-state-changed', true); },
|
open: function() { this.emit('open-state-changed', true); },
|
||||||
close: function() { this.emit('open-state-changed', false); },
|
close: function() { this.emit('open-state-changed', false); },
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@@ -1876,7 +1898,7 @@ const RemoteMenu = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
item.actor.reactive = action.enabled;
|
item.actor.reactive = item.actor.can_focus = action.enabled;
|
||||||
|
|
||||||
destroyId = item.connect('destroy', Lang.bind(this, function() {
|
destroyId = item.connect('destroy', Lang.bind(this, function() {
|
||||||
item.disconnect(destroyId);
|
item.disconnect(destroyId);
|
||||||
@@ -2008,7 +2030,7 @@ const RemoteMenu = new Lang.Class({
|
|||||||
if (action.items.length) {
|
if (action.items.length) {
|
||||||
for (let i = 0; i < action.items.length; i++) {
|
for (let i = 0; i < action.items.length; i++) {
|
||||||
let item = action.items[i];
|
let item = action.items[i];
|
||||||
item.actor.reactive = action.enabled;
|
item.actor.reactive = item.actor.can_focus = action.enabled;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2036,6 +2058,9 @@ const PopupMenuManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
addMenu: function(menu, position) {
|
addMenu: function(menu, position) {
|
||||||
|
if (this._findMenu(menu) > -1)
|
||||||
|
return;
|
||||||
|
|
||||||
let menudata = {
|
let menudata = {
|
||||||
menu: menu,
|
menu: menu,
|
||||||
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
|
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
|
||||||
|
|||||||
@@ -31,19 +31,37 @@ const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
|
|||||||
|
|
||||||
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
|
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
|
||||||
|
|
||||||
|
|
||||||
function loadRemoteSearchProviders(addProviderCallback) {
|
function loadRemoteSearchProviders(addProviderCallback) {
|
||||||
|
let loadState = { loadedProviders: [],
|
||||||
|
objectPaths: {},
|
||||||
|
numLoading: 0,
|
||||||
|
addProviderCallback: addProviderCallback };
|
||||||
|
|
||||||
let dataDirs = GLib.get_system_data_dirs();
|
let dataDirs = GLib.get_system_data_dirs();
|
||||||
for (let i = 0; i < dataDirs.length; i++) {
|
for (let i = 0; i < dataDirs.length; i++) {
|
||||||
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
|
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
|
||||||
let dir = Gio.file_new_for_path(path);
|
let dir = Gio.file_new_for_path(path);
|
||||||
if (!dir.query_exists(null))
|
|
||||||
continue;
|
dir.query_info_async('standard:type', Gio.FileQueryInfoFlags.NONE,
|
||||||
loadRemoteSearchProvidersFromDir(dir, addProviderCallback);
|
GLib.PRIORITY_DEFAULT, null,
|
||||||
|
function(object, res) {
|
||||||
|
let exists = false;
|
||||||
|
try {
|
||||||
|
object.query_info_finish(res);
|
||||||
|
exists = true;
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!exists)
|
||||||
|
return;
|
||||||
|
|
||||||
|
loadState.numLoading++;
|
||||||
|
loadRemoteSearchProvidersFromDir(dir, loadState);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadRemoteSearchProvidersFromDir(dir, addProviderCallback) {
|
function loadRemoteSearchProvidersFromDir(dir, loadState) {
|
||||||
let dirPath = dir.get_path();
|
let dirPath = dir.get_path();
|
||||||
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
|
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
@@ -59,61 +77,111 @@ function loadRemoteSearchProvidersFromDir(dir, addProviderCallback) {
|
|||||||
if (!keyfile.has_group(KEY_FILE_GROUP))
|
if (!keyfile.has_group(KEY_FILE_GROUP))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let remoteProvider, title;
|
let remoteProvider;
|
||||||
try {
|
try {
|
||||||
let group = KEY_FILE_GROUP;
|
let group = KEY_FILE_GROUP;
|
||||||
let busName = keyfile.get_string(group, 'BusName');
|
let busName = keyfile.get_string(group, 'BusName');
|
||||||
let objectPath = keyfile.get_string(group, 'ObjectPath');
|
let objectPath = keyfile.get_string(group, 'ObjectPath');
|
||||||
|
|
||||||
|
if (loadState.objectPaths[objectPath])
|
||||||
|
continue;
|
||||||
|
|
||||||
let appInfo = null;
|
let appInfo = null;
|
||||||
try {
|
try {
|
||||||
let desktopId = keyfile.get_string(group, 'DesktopId');
|
let desktopId = keyfile.get_string(group, 'DesktopId');
|
||||||
appInfo = Gio.DesktopAppInfo.new(desktopId);
|
appInfo = Gio.DesktopAppInfo.new(desktopId);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
log('Ignoring search provider ' + path + ': missing DesktopId');
|
||||||
|
|
||||||
let icon;
|
|
||||||
if (appInfo) {
|
|
||||||
icon = appInfo.get_icon();
|
|
||||||
title = appInfo.get_name();
|
|
||||||
} else {
|
|
||||||
let iconName = keyfile.get_string(group, 'Icon');
|
|
||||||
icon = new Gio.ThemedIcon({ name: iconName });
|
|
||||||
title = keyfile.get_locale_string(group, 'Title', null);
|
|
||||||
}
|
|
||||||
|
|
||||||
remoteProvider = new RemoteSearchProvider(title,
|
|
||||||
icon,
|
|
||||||
busName,
|
|
||||||
objectPath);
|
|
||||||
} catch(e) {
|
|
||||||
log('Failed to add search provider "%s": %s'.format(title, e.toString()));
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
addProviderCallback(remoteProvider);
|
remoteProvider = new RemoteSearchProvider(appInfo,
|
||||||
|
busName,
|
||||||
|
objectPath);
|
||||||
|
loadState.objectPaths[objectPath] = remoteProvider;
|
||||||
|
loadState.loadedProviders.push(remoteProvider);
|
||||||
|
} catch(e) {
|
||||||
|
log('Failed to add search provider %s: %s'.format(path, e.toString()));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remoteProvidersDirLoaded(loadState);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function remoteProvidersDirLoaded(loadState) {
|
||||||
|
loadState.numLoading--;
|
||||||
|
if (loadState.numLoading > 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
|
||||||
|
let sortOrder = searchSettings.get_strv('sort-order');
|
||||||
|
let numSorted = sortOrder.length;
|
||||||
|
|
||||||
|
loadState.loadedProviders.sort(
|
||||||
|
function(providerA, providerB) {
|
||||||
|
let idxA, idxB;
|
||||||
|
let appIdA, appIdB;
|
||||||
|
|
||||||
|
appIdA = providerA.appInfo.get_id();
|
||||||
|
appIdB = providerB.appInfo.get_id();
|
||||||
|
|
||||||
|
idxA = sortOrder.indexOf(appIdA);
|
||||||
|
idxB = sortOrder.indexOf(appIdB);
|
||||||
|
|
||||||
|
// if no provider is found in the order, use alphabetical order
|
||||||
|
if ((idxA == -1) && (idxB == -1))
|
||||||
|
return GLib.utf8_collate(providerA.title, providerB.title);
|
||||||
|
|
||||||
|
if (numSorted > 1) {
|
||||||
|
// if providerA is the last, it goes after everything
|
||||||
|
if ((idxA + 1) == numSorted)
|
||||||
|
return 1;
|
||||||
|
// if providerB is the last, it goes after everything
|
||||||
|
else if ((idxB + 1) == numSorted)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if providerA isn't found, it's sorted after providerB
|
||||||
|
if (idxA == -1)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// if providerB isn't found, it's sorted after providerA
|
||||||
|
if (idxB == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// finally, if both providers are found, return their order in the list
|
||||||
|
return (idxA - idxB);
|
||||||
|
});
|
||||||
|
|
||||||
|
loadState.loadedProviders.forEach(
|
||||||
|
function(provider) {
|
||||||
|
loadState.addProviderCallback(provider);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const RemoteSearchProvider = new Lang.Class({
|
const RemoteSearchProvider = new Lang.Class({
|
||||||
Name: 'RemoteSearchProvider',
|
Name: 'RemoteSearchProvider',
|
||||||
Extends: Search.SearchProvider,
|
Extends: Search.SearchProvider,
|
||||||
|
|
||||||
_init: function(title, icon, dbusName, dbusPath) {
|
_init: function(appInfo, dbusName, dbusPath) {
|
||||||
this._proxy = new SearchProviderProxy(Gio.DBus.session,
|
this._proxy = new SearchProviderProxy(Gio.DBus.session,
|
||||||
dbusName, dbusPath);
|
dbusName, dbusPath, Lang.bind(this, this._onProxyConstructed));
|
||||||
|
|
||||||
this.parent(title.toUpperCase());
|
this.parent(appInfo.get_name().toUpperCase(), appInfo, true);
|
||||||
this._cancellable = new Gio.Cancellable();
|
this._cancellable = new Gio.Cancellable();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onProxyConstructed: function(proxy) {
|
||||||
|
// Do nothing
|
||||||
|
},
|
||||||
|
|
||||||
createIcon: function(size, meta) {
|
createIcon: function(size, meta) {
|
||||||
if (meta['gicon']) {
|
if (meta['gicon']) {
|
||||||
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
||||||
icon_size: size,
|
icon_size: size });
|
||||||
icon_type: St.IconType.FULLCOLOR });
|
|
||||||
} else if (meta['icon-data']) {
|
} else if (meta['icon-data']) {
|
||||||
let [width, height, rowStride, hasAlpha,
|
let [width, height, rowStride, hasAlpha,
|
||||||
bitsPerSample, nChannels, data] = meta['icon-data'];
|
bitsPerSample, nChannels, data] = meta['icon-data'];
|
||||||
@@ -124,8 +192,7 @@ const RemoteSearchProvider = new Lang.Class({
|
|||||||
|
|
||||||
// Ugh, but we want to fall back to something ...
|
// Ugh, but we want to fall back to something ...
|
||||||
return new St.Icon({ icon_name: 'text-x-generic',
|
return new St.Icon({ icon_name: 'text-x-generic',
|
||||||
icon_size: size,
|
icon_size: size });
|
||||||
icon_type: St.IconType.FULLCOLOR });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_getResultsFinished: function(results, error) {
|
_getResultsFinished: function(results, error) {
|
||||||
|
|||||||
@@ -202,11 +202,12 @@ const RunDialog = new Lang.Class({
|
|||||||
|
|
||||||
|
|
||||||
let label = new St.Label({ style_class: 'run-dialog-label',
|
let label = new St.Label({ style_class: 'run-dialog-label',
|
||||||
text: _("Please enter a command:") });
|
text: _("Enter a Command") });
|
||||||
|
|
||||||
this.contentLayout.add(label, { y_align: St.Align.START });
|
this.contentLayout.add(label, { y_align: St.Align.START });
|
||||||
|
|
||||||
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
|
let entry = new St.Entry({ style_class: 'run-dialog-entry',
|
||||||
|
can_focus: true });
|
||||||
ShellEntry.addContextMenu(entry);
|
ShellEntry.addContextMenu(entry);
|
||||||
|
|
||||||
entry.label_actor = label;
|
entry.label_actor = label;
|
||||||
@@ -219,7 +220,9 @@ const RunDialog = new Lang.Class({
|
|||||||
|
|
||||||
this.contentLayout.add(this._errorBox, { expand: true });
|
this.contentLayout.add(this._errorBox, { expand: true });
|
||||||
|
|
||||||
let errorIcon = new St.Icon({ icon_name: 'dialog-error', icon_size: 24, style_class: 'run-dialog-error-icon' });
|
let errorIcon = new St.Icon({ icon_name: 'dialog-error-symbolic',
|
||||||
|
icon_size: 24,
|
||||||
|
style_class: 'run-dialog-error-icon' });
|
||||||
|
|
||||||
this._errorBox.add(errorIcon, { y_align: St.Align.MIDDLE });
|
this._errorBox.add(errorIcon, { y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
@@ -234,6 +237,10 @@ const RunDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._errorBox.hide();
|
this._errorBox.hide();
|
||||||
|
|
||||||
|
this.setButtons([{ action: Lang.bind(this, this.close),
|
||||||
|
label: _("Close"),
|
||||||
|
key: Clutter.Escape }]);
|
||||||
|
|
||||||
this._pathCompleter = new Gio.FilenameCompleter();
|
this._pathCompleter = new Gio.FilenameCompleter();
|
||||||
this._commandCompleter = new CommandCompleter();
|
this._commandCompleter = new CommandCompleter();
|
||||||
this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update));
|
this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update));
|
||||||
@@ -244,20 +251,12 @@ const RunDialog = new Lang.Class({
|
|||||||
let symbol = e.get_key_symbol();
|
let symbol = e.get_key_symbol();
|
||||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||||
this.popModal();
|
this.popModal();
|
||||||
if (e.get_state() & Clutter.ModifierType.CONTROL_MASK)
|
this._run(o.get_text(),
|
||||||
this._run(o.get_text(), true);
|
e.get_state() & Clutter.ModifierType.CONTROL_MASK);
|
||||||
else
|
if (!this._commandError ||
|
||||||
this._run(o.get_text(), false);
|
!this.pushModal())
|
||||||
if (!this._commandError)
|
|
||||||
this.close();
|
|
||||||
else {
|
|
||||||
if (!this.pushModal())
|
|
||||||
this.close();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (symbol == Clutter.Escape) {
|
|
||||||
this.close();
|
this.close();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (symbol == Clutter.slash) {
|
if (symbol == Clutter.slash) {
|
||||||
|
|||||||
@@ -1,29 +1,40 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Cairo = imports.cairo;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const TweenerEquations = imports.tweener.equations;
|
||||||
|
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const GnomeSession = imports.misc.gnomeSession;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const LoginManager = imports.misc.loginManager;
|
const LoginManager = imports.misc.loginManager;
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
const Overview = imports.ui.overview;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
|
||||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
const LOCK_ENABLED_KEY = 'lock-enabled';
|
||||||
|
|
||||||
const CURTAIN_SLIDE_TIME = 0.5;
|
const CURTAIN_SLIDE_TIME = 0.3;
|
||||||
// fraction of screen height the arrow must reach before completing
|
// fraction of screen height the arrow must reach before completing
|
||||||
// the slide up automatically
|
// the slide up automatically
|
||||||
const ARROW_DRAG_TRESHOLD = 0.1;
|
const ARROW_DRAG_THRESHOLD = 0.1;
|
||||||
|
|
||||||
|
// Parameters for the arrow animation
|
||||||
|
const N_ARROWS = 3;
|
||||||
|
const ARROW_ANIMATION_TIME = 0.6;
|
||||||
|
const ARROW_ANIMATION_PEAK_OPACITY = 0.4;
|
||||||
|
|
||||||
// The distance in px that the lock screen will move to when pressing
|
// The distance in px that the lock screen will move to when pressing
|
||||||
// a key that has no effect in the lock screen (bumping it)
|
// a key that has no effect in the lock screen (bumping it)
|
||||||
@@ -36,7 +47,39 @@ const SUMMARY_ICON_SIZE = 48;
|
|||||||
// STANDARD_FADE_TIME is used when the session goes idle, while
|
// STANDARD_FADE_TIME is used when the session goes idle, while
|
||||||
// SHORT_FADE_TIME is used when requesting lock explicitly from the user menu
|
// SHORT_FADE_TIME is used when requesting lock explicitly from the user menu
|
||||||
const STANDARD_FADE_TIME = 10;
|
const STANDARD_FADE_TIME = 10;
|
||||||
const SHORT_FADE_TIME = 0.8;
|
const SHORT_FADE_TIME = 0.3;
|
||||||
|
|
||||||
|
function sample(offx, offy) {
|
||||||
|
return 'texel += texture2D (sampler, tex_coord.st + pixel_step * ' +
|
||||||
|
'vec2 (' + offx + ',' + offy + '));\n'
|
||||||
|
}
|
||||||
|
const GLSL_BLUR_EFFECT_DECLARATIONS = ' \
|
||||||
|
uniform vec2 pixel_step;\n \
|
||||||
|
uniform float desaturation;\n \
|
||||||
|
vec4 apply_blur(in sampler2D sampler, in vec2 tex_coord) {\n \
|
||||||
|
vec4 texel;\n \
|
||||||
|
texel = texture2D (sampler, tex_coord.st);\n'
|
||||||
|
+ sample(-1.0, -1.0)
|
||||||
|
+ sample( 0.0, -1.0)
|
||||||
|
+ sample(+1.0, -1.0)
|
||||||
|
+ sample(-1.0, 0.0)
|
||||||
|
+ sample(+1.0, 0.0)
|
||||||
|
+ sample(-1.0, +1.0)
|
||||||
|
+ sample( 0.0, +1.0)
|
||||||
|
+ sample(+1.0, +1.0) + ' \
|
||||||
|
texel /= 9.0;\n \
|
||||||
|
return texel;\n \
|
||||||
|
}\n \
|
||||||
|
vec3 desaturate (const vec3 color)\n \
|
||||||
|
{\n \
|
||||||
|
const vec3 gray_conv = vec3 (0.299, 0.587, 0.114);\n \
|
||||||
|
vec3 gray = vec3 (dot (gray_conv, color));\n \
|
||||||
|
return vec3 (mix (color.rgb, gray, desaturation));\n \
|
||||||
|
}';
|
||||||
|
const GLSL_BLUR_EFFECT_CODE = ' \
|
||||||
|
cogl_texel = apply_blur(cogl_sampler, cogl_tex_coord.st);\n \
|
||||||
|
cogl_texel.rgb = desaturate(cogl_texel.rgb);\n';
|
||||||
|
|
||||||
|
|
||||||
const Clock = new Lang.Class({
|
const Clock = new Lang.Class({
|
||||||
Name: 'ScreenShieldClock',
|
Name: 'ScreenShieldClock',
|
||||||
@@ -85,13 +128,13 @@ const NotificationsBox = new Lang.Class({
|
|||||||
|
|
||||||
this._residentNotificationBox = new St.BoxLayout({ vertical: true,
|
this._residentNotificationBox = new St.BoxLayout({ vertical: true,
|
||||||
style_class: 'screen-shield-notifications-box' });
|
style_class: 'screen-shield-notifications-box' });
|
||||||
let scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.MIDDLE });
|
let scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.START });
|
||||||
this._persistentNotificationBox = new St.BoxLayout({ vertical: true,
|
this._persistentNotificationBox = new St.BoxLayout({ vertical: true,
|
||||||
style_class: 'screen-shield-notifications-box' });
|
style_class: 'screen-shield-notifications-box' });
|
||||||
scrollView.add_actor(this._persistentNotificationBox);
|
scrollView.add_actor(this._persistentNotificationBox);
|
||||||
|
|
||||||
this.actor.add(this._residentNotificationBox, { x_fill: true });
|
this.actor.add(this._residentNotificationBox, { x_fill: true });
|
||||||
this.actor.add(scrollView, { x_fill: true, x_align: St.Align.MIDDLE });
|
this.actor.add(scrollView, { x_fill: true, x_align: St.Align.START });
|
||||||
|
|
||||||
this._items = [];
|
this._items = [];
|
||||||
Main.messageTray.getSummaryItems().forEach(Lang.bind(this, function(item) {
|
Main.messageTray.getSummaryItems().forEach(Lang.bind(this, function(item) {
|
||||||
@@ -116,13 +159,12 @@ const NotificationsBox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateVisibility: function() {
|
_updateVisibility: function() {
|
||||||
if (this._residentNotificationBox.get_n_children() > 0) {
|
this._residentNotificationBox.visible = this._residentNotificationBox.get_n_children() > 0;
|
||||||
this.actor.show();
|
this._persistentNotificationBox.visible = this._persistentNotificationBox.get_children().some(function(a) {
|
||||||
return;
|
return a.visible;
|
||||||
}
|
});
|
||||||
|
|
||||||
let children = this._persistentNotificationBox.get_children();
|
this.actor.visible = this._residentNotificationBox.visible || this._persistentNotificationBox.visible;
|
||||||
this.actor.visible = children.some(function(a) { return a.visible; });
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_sourceIsResident: function(source) {
|
_sourceIsResident: function(source) {
|
||||||
@@ -143,7 +185,7 @@ const NotificationsBox = new Lang.Class({
|
|||||||
box.add(sourceActor.actor, { y_fill: true });
|
box.add(sourceActor.actor, { y_fill: true });
|
||||||
|
|
||||||
let textBox = new St.BoxLayout({ vertical: true });
|
let textBox = new St.BoxLayout({ vertical: true });
|
||||||
box.add(textBox);
|
box.add(textBox, { y_fill: false, y_align: St.Align.START });
|
||||||
|
|
||||||
let label = new St.Label({ text: source.title,
|
let label = new St.Label({ text: source.title,
|
||||||
style_class: 'screen-shield-notification-label' });
|
style_class: 'screen-shield-notification-label' });
|
||||||
@@ -159,8 +201,9 @@ const NotificationsBox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_summaryItemAdded: function(tray, item, dontUpdateVisibility) {
|
_summaryItemAdded: function(tray, item, dontUpdateVisibility) {
|
||||||
// Ignore transient sources
|
// Ignore transient sources, or sources explicitly marked not to show
|
||||||
if (item.source.isTransient)
|
// in the lock screen
|
||||||
|
if (item.source.isTransient || !item.source.showInLockScreen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let obj = {
|
let obj = {
|
||||||
@@ -174,11 +217,12 @@ const NotificationsBox = new Lang.Class({
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (obj.resident) {
|
if (obj.resident) {
|
||||||
|
this._residentNotificationBox.add(item.notificationStackWidget);
|
||||||
|
item.closeButton.hide();
|
||||||
item.prepareNotificationStackForShowing();
|
item.prepareNotificationStackForShowing();
|
||||||
this._residentNotificationBox.add(item.notificationStackView);
|
|
||||||
} else {
|
} else {
|
||||||
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(item.source);
|
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(item.source);
|
||||||
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.MIDDLE });
|
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.contentUpdatedId = item.connect('content-updated', Lang.bind(this, this._onItemContentUpdated));
|
obj.contentUpdatedId = item.connect('content-updated', Lang.bind(this, this._onItemContentUpdated));
|
||||||
@@ -220,18 +264,20 @@ const NotificationsBox = new Lang.Class({
|
|||||||
|
|
||||||
if (obj.resident && !itemShouldBeResident) {
|
if (obj.resident && !itemShouldBeResident) {
|
||||||
// make into a regular item
|
// make into a regular item
|
||||||
this._residentNotificationBox.remove_actor(obj.item.notificationStackView);
|
obj.item.doneShowingNotificationStack();
|
||||||
|
this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
|
||||||
|
|
||||||
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(obj.source);
|
[obj.sourceBox, obj.countLabel] = this._makeNotificationSource(obj.source);
|
||||||
this._persistentNotificationBox.add(obj.sourceBox);
|
this._persistentNotificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
|
||||||
} else if (itemShouldBeResident && !obj.resident) {
|
} else if (itemShouldBeResident && !obj.resident) {
|
||||||
// make into a resident item
|
// make into a resident item
|
||||||
obj.sourceBox.destroy();
|
obj.sourceBox.destroy();
|
||||||
obj.sourceBox = obj.countLabel = null;
|
obj.sourceBox = obj.countLabel = null;
|
||||||
obj.resident = true;
|
obj.resident = true;
|
||||||
|
|
||||||
|
this._residentNotificationBox.add(obj.item.notificationStackWidget);
|
||||||
|
obj.item.closeButton.hide();
|
||||||
obj.item.prepareNotificationStackForShowing();
|
obj.item.prepareNotificationStackForShowing();
|
||||||
this._residentNotificationBox.add(obj.item.notificationStackView);
|
|
||||||
} else {
|
} else {
|
||||||
// just update the counter
|
// just update the counter
|
||||||
let count = obj.source.unseenCount;
|
let count = obj.source.unseenCount;
|
||||||
@@ -253,8 +299,8 @@ const NotificationsBox = new Lang.Class({
|
|||||||
|
|
||||||
_removeItem: function(obj) {
|
_removeItem: function(obj) {
|
||||||
if (obj.resident) {
|
if (obj.resident) {
|
||||||
this._residentNotificationBox.remove_actor(obj.item.notificationStackView);
|
|
||||||
obj.item.doneShowingNotificationStack();
|
obj.item.doneShowingNotificationStack();
|
||||||
|
this._residentNotificationBox.remove_actor(obj.item.notificationStackWidget);
|
||||||
} else {
|
} else {
|
||||||
obj.sourceBox.destroy();
|
obj.sourceBox.destroy();
|
||||||
}
|
}
|
||||||
@@ -265,6 +311,66 @@ const NotificationsBox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Arrow = new Lang.Class({
|
||||||
|
Name: 'Arrow',
|
||||||
|
Extends: St.Bin,
|
||||||
|
|
||||||
|
_init: function(params) {
|
||||||
|
this.parent(params);
|
||||||
|
this.x_fill = this.y_fill = true;
|
||||||
|
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
|
||||||
|
|
||||||
|
this._drawingArea = new St.DrawingArea();
|
||||||
|
this._drawingArea.connect('repaint', Lang.bind(this, this._drawArrow));
|
||||||
|
this.child = this._drawingArea;
|
||||||
|
|
||||||
|
this._shadowHelper = null;
|
||||||
|
this._shadowWidth = this._shadowHeight = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
_drawArrow: function(arrow) {
|
||||||
|
let cr = arrow.get_context();
|
||||||
|
let [w, h] = arrow.get_surface_size();
|
||||||
|
let node = this.get_theme_node();
|
||||||
|
let thickness = node.get_length('-arrow-thickness');
|
||||||
|
|
||||||
|
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
||||||
|
|
||||||
|
cr.setLineCap(Cairo.LineCap.ROUND);
|
||||||
|
cr.setLineWidth(thickness);
|
||||||
|
|
||||||
|
cr.moveTo(thickness / 2, h - thickness / 2);
|
||||||
|
cr.lineTo(w/2, thickness);
|
||||||
|
cr.lineTo(w - thickness / 2, h - thickness / 2);
|
||||||
|
cr.stroke();
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_style_changed: function() {
|
||||||
|
let node = this.get_theme_node();
|
||||||
|
this._shadow = node.get_shadow('-arrow-shadow');
|
||||||
|
if (this._shadow)
|
||||||
|
this._shadowHelper = St.ShadowHelper.new(this._shadow);
|
||||||
|
else
|
||||||
|
this._shadowHelper = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
vfunc_paint: function() {
|
||||||
|
if (this._shadowHelper) {
|
||||||
|
this._shadowHelper.update(this._drawingArea);
|
||||||
|
|
||||||
|
let allocation = this._drawingArea.get_allocation_box();
|
||||||
|
let paintOpacity = this._drawingArea.get_paint_opacity();
|
||||||
|
this._shadowHelper.paint(allocation, paintOpacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._drawingArea.paint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function clamp(value, min, max) {
|
||||||
|
return Math.max(min, Math.min(max, value));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To test screen shield, make sure to kill gnome-screensaver.
|
* To test screen shield, make sure to kill gnome-screensaver.
|
||||||
*
|
*
|
||||||
@@ -281,6 +387,7 @@ const ScreenShield = new Lang.Class({
|
|||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = Main.layoutManager.screenShieldGroup;
|
this.actor = Main.layoutManager.screenShieldGroup;
|
||||||
|
|
||||||
|
this._lockScreenState = MessageTray.State.HIDDEN;
|
||||||
this._lockScreenGroup = new St.Widget({ x_expand: true,
|
this._lockScreenGroup = new St.Widget({ x_expand: true,
|
||||||
y_expand: true,
|
y_expand: true,
|
||||||
reactive: true,
|
reactive: true,
|
||||||
@@ -289,40 +396,54 @@ const ScreenShield = new Lang.Class({
|
|||||||
});
|
});
|
||||||
this._lockScreenGroup.connect('key-release-event',
|
this._lockScreenGroup.connect('key-release-event',
|
||||||
Lang.bind(this, this._onLockScreenKeyRelease));
|
Lang.bind(this, this._onLockScreenKeyRelease));
|
||||||
|
this._lockScreenGroup.connect('scroll-event',
|
||||||
|
Lang.bind(this, this._onLockScreenScroll));
|
||||||
|
Main.ctrlAltTabManager.addGroup(this._lockScreenGroup, _("Lock"), 'changes-prevent-symbolic');
|
||||||
|
|
||||||
this._lockScreenContents = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
this._lockScreenContents = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||||
name: 'lockScreenContents' });
|
name: 'lockScreenContents' });
|
||||||
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
this._lockScreenContents.add_constraint(new Layout.MonitorConstraint({ primary: true }));
|
||||||
|
|
||||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
let backgroundActor = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||||
|
backgroundActor.add_glsl_snippet(Meta.SnippetHook.TEXTURE_LOOKUP,
|
||||||
|
GLSL_BLUR_EFFECT_DECLARATIONS,
|
||||||
|
GLSL_BLUR_EFFECT_CODE,
|
||||||
|
true);
|
||||||
|
backgroundActor.set_uniform_float('desaturation',
|
||||||
|
1, 1, [0.6]);
|
||||||
|
backgroundActor.connect('notify::size', function(actor) {
|
||||||
|
actor.set_uniform_float('pixel_step', 2, 1, [1/actor.width, 1/actor.height]);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._background = new St.Bin({ style_class: 'screen-shield-background',
|
||||||
|
child: backgroundActor });
|
||||||
this._lockScreenGroup.add_actor(this._background);
|
this._lockScreenGroup.add_actor(this._background);
|
||||||
this._lockScreenGroup.add_actor(this._lockScreenContents);
|
this._lockScreenGroup.add_actor(this._lockScreenContents);
|
||||||
|
|
||||||
// FIXME: build the rest of the lock screen here
|
this._arrowContainer = new St.BoxLayout({ style_class: 'screen-shield-arrows',
|
||||||
|
vertical: true,
|
||||||
this._arrow = new St.DrawingArea({ style_class: 'arrow',
|
|
||||||
reactive: true,
|
|
||||||
x_align: Clutter.ActorAlign.CENTER,
|
x_align: Clutter.ActorAlign.CENTER,
|
||||||
y_align: Clutter.ActorAlign.END,
|
y_align: Clutter.ActorAlign.END,
|
||||||
// HACK: without these, ClutterBinLayout
|
// HACK: without these, ClutterBinLayout
|
||||||
// ignores alignment properties on the actor
|
// ignores alignment properties on the actor
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
y_expand: true
|
y_expand: true });
|
||||||
});
|
|
||||||
this._arrow.connect('repaint', Lang.bind(this, this._drawArrow));
|
|
||||||
this._lockScreenContents.add_actor(this._arrow);
|
|
||||||
|
|
||||||
let dragArea = new Clutter.Rect({ origin: new Clutter.Point({ x: 0, y: -global.screen_height, }),
|
for (let i = 0; i < N_ARROWS; i++) {
|
||||||
size: new Clutter.Size({ width: global.screen_width,
|
let arrow = new Arrow({ opacity: 0 });
|
||||||
height: global.screen_height }) });
|
this._arrowContainer.add_actor(arrow);
|
||||||
let action = new Clutter.DragAction({ drag_axis: Clutter.DragAxis.Y_AXIS,
|
}
|
||||||
drag_area: dragArea });
|
this._lockScreenContents.add_actor(this._arrowContainer);
|
||||||
action.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
|
||||||
action.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
this._dragAction = new Clutter.GestureAction();
|
||||||
this._lockScreenGroup.add_action(action);
|
this._dragAction.connect('gesture-begin', Lang.bind(this, this._onDragBegin));
|
||||||
|
this._dragAction.connect('gesture-progress', Lang.bind(this, this._onDragMotion));
|
||||||
|
this._dragAction.connect('gesture-end', Lang.bind(this, this._onDragEnd));
|
||||||
|
this._lockScreenGroup.add_action(this._dragAction);
|
||||||
|
|
||||||
this._lockDialogGroup = new St.Widget({ x_expand: true,
|
this._lockDialogGroup = new St.Widget({ x_expand: true,
|
||||||
y_expand: true,
|
y_expand: true,
|
||||||
|
pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
|
||||||
name: 'lockDialogGroup' });
|
name: 'lockDialogGroup' });
|
||||||
|
|
||||||
this.actor.add_actor(this._lockDialogGroup);
|
this.actor.add_actor(this._lockDialogGroup);
|
||||||
@@ -340,6 +461,8 @@ const ScreenShield = new Lang.Class({
|
|||||||
this._onStatusChanged(status);
|
this._onStatusChanged(status);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this._screenSaverDBus = new ShellDBus.ScreenSaverDBus(this);
|
||||||
|
|
||||||
this._loginManager = LoginManager.getLoginManager();
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
this._loginSession = this._loginManager.getCurrentSessionProxy();
|
this._loginSession = this._loginManager.getCurrentSessionProxy();
|
||||||
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
|
this._loginSession.connectSignal('Lock', Lang.bind(this, function() { this.lock(false); }));
|
||||||
@@ -348,52 +471,114 @@ const ScreenShield = new Lang.Class({
|
|||||||
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
this._settings = new Gio.Settings({ schema: SCREENSAVER_SCHEMA });
|
||||||
|
|
||||||
this._isModal = false;
|
this._isModal = false;
|
||||||
this._isLocked = false;
|
|
||||||
this._hasLockScreen = false;
|
this._hasLockScreen = false;
|
||||||
|
this._isGreeter = false;
|
||||||
|
this._isActive = false;
|
||||||
|
this._inUnlockAnimation = false;
|
||||||
|
this._activationTime = 0;
|
||||||
|
|
||||||
this._lightbox = new Lightbox.Lightbox(Main.uiGroup,
|
this._lightbox = new Lightbox.Lightbox(Main.uiGroup,
|
||||||
{ inhibitEvents: true,
|
{ inhibitEvents: true,
|
||||||
fadeInTime: STANDARD_FADE_TIME,
|
fadeInTime: STANDARD_FADE_TIME,
|
||||||
fadeFactor: 1 });
|
fadeFactor: 1 });
|
||||||
|
|
||||||
|
this.idleMonitor = new GnomeDesktop.IdleMonitor();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLockScreenKeyRelease: function(actor, event) {
|
_onLockScreenKeyRelease: function(actor, event) {
|
||||||
if (event.get_key_symbol() == Clutter.KEY_Escape) {
|
let symbol = event.get_key_symbol();
|
||||||
this._ensureUnlockDialog();
|
|
||||||
this._hideLockScreen(true);
|
// Do nothing if the lock screen is not fully shown.
|
||||||
|
// This avoids reusing the previous (and stale) unlock
|
||||||
|
// dialog if esc is pressed while the curtain is going
|
||||||
|
// down after cancel.
|
||||||
|
// Similarly, don't bump if the lock screen is not showing or is
|
||||||
|
// animating, as the bump overrides the animation and would
|
||||||
|
// remove any onComplete handler.
|
||||||
|
|
||||||
|
if (this._lockScreenState != MessageTray.State.SHOWN)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (symbol == Clutter.KEY_Escape ||
|
||||||
|
symbol == Clutter.KEY_Return ||
|
||||||
|
symbol == Clutter.KEY_KP_Enter) {
|
||||||
|
this._ensureUnlockDialog(true);
|
||||||
|
this._hideLockScreen(true, 0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the dialog is created, but hasn't received focus yet,
|
|
||||||
// the lock screen could be still focused, so bumping would
|
|
||||||
// make the curtain fall again.
|
|
||||||
if (!this._dialog)
|
|
||||||
this._bumpLockScreen();
|
this._bumpLockScreen();
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_drawArrow: function() {
|
_onLockScreenScroll: function(actor, event) {
|
||||||
let cr = this._arrow.get_context();
|
if (this._lockScreenState != MessageTray.State.SHOWN)
|
||||||
let [w, h] = this._arrow.get_surface_size();
|
return false;
|
||||||
let node = this._arrow.get_theme_node();
|
|
||||||
|
|
||||||
Clutter.cairo_set_source_color(cr, node.get_foreground_color());
|
let delta = 0;
|
||||||
|
if (event.get_scroll_direction() == Clutter.ScrollDirection.UP)
|
||||||
|
delta = 5;
|
||||||
|
else if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
|
||||||
|
delta = Math.max(0, event.get_scroll_delta()[0]);
|
||||||
|
|
||||||
cr.moveTo(0, h);
|
this._lockScreenScrollCounter += delta;
|
||||||
cr.lineTo(w/2, 0);
|
|
||||||
cr.lineTo(w, h);
|
// 7 standard scrolls to lift up
|
||||||
cr.fill();
|
if (this._lockScreenScrollCounter > 35) {
|
||||||
|
this._ensureUnlockDialog(false);
|
||||||
|
this._hideLockScreen(true, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_animateArrows: function() {
|
||||||
|
let arrows = this._arrowContainer.get_children();
|
||||||
|
let unitaryDelay = ARROW_ANIMATION_TIME / (arrows.length + 1);
|
||||||
|
let maxOpacity = 255 * ARROW_ANIMATION_PEAK_OPACITY;
|
||||||
|
for (let i = 0; i < arrows.length; i++) {
|
||||||
|
arrows.opacity = 0;
|
||||||
|
Tweener.addTween(arrows[i],
|
||||||
|
{ opacity: 0,
|
||||||
|
delay: unitaryDelay * (N_ARROWS - (i + 1)),
|
||||||
|
time: ARROW_ANIMATION_TIME,
|
||||||
|
transition: function(t, b, c, d) {
|
||||||
|
if (t < d/2)
|
||||||
|
return TweenerEquations.easeOutQuad(t, 0, maxOpacity, d/2);
|
||||||
|
else
|
||||||
|
return TweenerEquations.easeInQuad(t - d/2, maxOpacity, -maxOpacity, d/2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragBegin: function() {
|
_onDragBegin: function() {
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
Tweener.removeTweens(this._lockScreenGroup);
|
||||||
this._ensureUnlockDialog();
|
this._lockScreenState = MessageTray.State.HIDING;
|
||||||
|
this._ensureUnlockDialog(false);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDragMotion: function() {
|
||||||
|
let [origX, origY] = this._dragAction.get_press_coords(0);
|
||||||
|
let [currentX, currentY] = this._dragAction.get_motion_coords(0);
|
||||||
|
|
||||||
|
let newY = currentY - origY;
|
||||||
|
newY = clamp(newY, -global.stage.height, 0);
|
||||||
|
|
||||||
|
this._lockScreenGroup.y = newY;
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
|
_onDragEnd: function(action, actor, eventX, eventY, modifiers) {
|
||||||
if (this._lockScreenGroup.y < -(ARROW_DRAG_TRESHOLD * global.stage.height)) {
|
if (this._lockScreenGroup.y < -(ARROW_DRAG_THRESHOLD * global.stage.height)) {
|
||||||
// Complete motion automatically
|
// Complete motion automatically
|
||||||
this._hideLockScreen(true);
|
let [velocity, velocityX, velocityY] = this._dragAction.get_velocity(0);
|
||||||
|
this._hideLockScreen(true, -velocityY);
|
||||||
} else {
|
} else {
|
||||||
// restore the lock screen to its original place
|
// restore the lock screen to its original place
|
||||||
// try to use the same speed as the normal animation
|
// try to use the same speed as the normal animation
|
||||||
@@ -403,16 +588,18 @@ const ScreenShield = new Lang.Class({
|
|||||||
Tweener.addTween(this._lockScreenGroup,
|
Tweener.addTween(this._lockScreenGroup,
|
||||||
{ y: 0,
|
{ y: 0,
|
||||||
time: time,
|
time: time,
|
||||||
transition: 'linear',
|
transition: 'easeInQuad',
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
this.fixed_position_set = false;
|
this._lockScreenGroup.fixed_position_set = false;
|
||||||
}
|
this._lockScreenState = MessageTray.State.SHOWN;
|
||||||
|
},
|
||||||
|
onCompleteScope: this,
|
||||||
});
|
});
|
||||||
|
|
||||||
// If we have a unlock dialog, cancel it
|
// If we have a unlock dialog, cancel it
|
||||||
if (this._dialog) {
|
if (this._dialog) {
|
||||||
this._dialog.cancel();
|
this._dialog.cancel();
|
||||||
if (!this._keepDialog) {
|
if (!this._isGreeter) {
|
||||||
this._dialog = null;
|
this._dialog = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,38 +607,62 @@ const ScreenShield = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onStatusChanged: function(status) {
|
_onStatusChanged: function(status) {
|
||||||
if (status == GnomeSession.PresenceStatus.IDLE) {
|
if (status != GnomeSession.PresenceStatus.IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
if (this._dialog) {
|
if (this._dialog) {
|
||||||
this._dialog.cancel();
|
this._dialog.cancel();
|
||||||
if (!this._keepDialog) {
|
if (!this._isGreeter) {
|
||||||
this._dialog = null;
|
this._dialog = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._isModal) {
|
if (!this._isModal) {
|
||||||
Main.pushModal(this.actor);
|
Main.pushModal(this.actor, { keybindingMode: Main.KeybindingMode.LOCK_SCREEN });
|
||||||
this._isModal = true;
|
this._isModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this._isLocked)
|
if (!this._isActive) {
|
||||||
this._lightbox.show();
|
this._lightbox.show();
|
||||||
} else {
|
|
||||||
|
if (this._activationTime == 0)
|
||||||
|
this._activationTime = GLib.get_monotonic_time();
|
||||||
|
|
||||||
|
this._becameActiveId = this.idleMonitor.connect('became-active', Lang.bind(this, function() {
|
||||||
|
this.idleMonitor.disconnect(this._becameActiveId);
|
||||||
|
|
||||||
let lightboxWasShown = this._lightbox.shown;
|
let lightboxWasShown = this._lightbox.shown;
|
||||||
this._lightbox.hide();
|
this._lightbox.hide();
|
||||||
|
|
||||||
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
|
let shouldLock = lightboxWasShown && this._settings.get_boolean(LOCK_ENABLED_KEY);
|
||||||
if (shouldLock || this._isLocked) {
|
if (shouldLock || this._isLocked) {
|
||||||
this.lock(false);
|
this.lock(false);
|
||||||
} else if (this._isModal) {
|
} else if (this._isActive) {
|
||||||
this.unlock();
|
this.unlock();
|
||||||
}
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._isActive = true;
|
||||||
|
this.emit('lock-status-changed');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
showDialog: function() {
|
showDialog: function() {
|
||||||
this.lock(true);
|
// Ensure that the stage window is mapped, before taking a grab
|
||||||
this._ensureUnlockDialog();
|
// otherwise X errors out
|
||||||
this._hideLockScreen(false);
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||||
|
if (!this._isModal) {
|
||||||
|
Main.pushModal(this.actor);
|
||||||
|
this._isModal = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.actor.show();
|
||||||
|
this._isGreeter = Main.sessionMode.isGreeter;
|
||||||
|
this._ensureUnlockDialog(true);
|
||||||
|
this._hideLockScreen(false, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
_bumpLockScreen: function() {
|
_bumpLockScreen: function() {
|
||||||
@@ -469,35 +680,58 @@ const ScreenShield = new Lang.Class({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideLockScreen: function(animate) {
|
_hideLockScreen: function(animate, velocity) {
|
||||||
|
this._lockScreenState = MessageTray.State.HIDING;
|
||||||
|
|
||||||
if (animate) {
|
if (animate) {
|
||||||
// Tween the lock screen out of screen
|
// Tween the lock screen out of screen
|
||||||
// try to use the same speed regardless of original position
|
// if velocity is not specified (i.e. we come here from pressing ESC),
|
||||||
|
// use the same speed regardless of original position
|
||||||
|
// if velocity is specified, it's in pixels per milliseconds
|
||||||
let h = global.stage.height;
|
let h = global.stage.height;
|
||||||
let time = CURTAIN_SLIDE_TIME * (h + this._lockScreenGroup.y) / h;
|
let delta = (h + this._lockScreenGroup.y);
|
||||||
|
let min_velocity = global.stage.height / (CURTAIN_SLIDE_TIME * 1000);
|
||||||
|
|
||||||
|
velocity = Math.max(min_velocity, velocity);
|
||||||
|
let time = (delta / velocity) / 1000;
|
||||||
|
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
Tweener.removeTweens(this._lockScreenGroup);
|
||||||
Tweener.addTween(this._lockScreenGroup,
|
Tweener.addTween(this._lockScreenGroup,
|
||||||
{ y: -h,
|
{ y: -h,
|
||||||
time: time,
|
time: time,
|
||||||
transition: 'linear',
|
transition: 'easeInQuad',
|
||||||
onComplete: function() { this.hide(); }
|
onComplete: function() {
|
||||||
|
this._lockScreenState = MessageTray.State.HIDDEN;
|
||||||
|
this._lockScreenGroup.hide();
|
||||||
|
},
|
||||||
|
onCompleteScope: this,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
this._lockScreenState = MessageTray.State.HIDDEN;
|
||||||
this._lockScreenGroup.hide();
|
this._lockScreenGroup.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
global.stage.show_cursor();
|
||||||
|
|
||||||
|
if (Main.sessionMode.currentMode == 'lock-screen')
|
||||||
|
Main.sessionMode.popMode('lock-screen');
|
||||||
},
|
},
|
||||||
|
|
||||||
_ensureUnlockDialog: function() {
|
_ensureUnlockDialog: function(onPrimary) {
|
||||||
if (!this._dialog) {
|
|
||||||
[this._dialog, this._keepDialog] = Main.sessionMode.createUnlockDialog(this._lockDialogGroup);
|
|
||||||
if (!this._dialog) {
|
if (!this._dialog) {
|
||||||
|
let constructor = Main.sessionMode.unlockDialog;
|
||||||
|
if (!constructor) {
|
||||||
// This session mode has no locking capabilities
|
// This session mode has no locking capabilities
|
||||||
this.unlock();
|
this.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._dialog = new constructor(this._lockDialogGroup);
|
||||||
|
|
||||||
|
|
||||||
|
let time = global.get_current_time();
|
||||||
this._dialog.connect('loaded', Lang.bind(this, function() {
|
this._dialog.connect('loaded', Lang.bind(this, function() {
|
||||||
if (!this._dialog.open()) {
|
if (!this._dialog.open(time, onPrimary)) {
|
||||||
log('Could not open login dialog: failed to acquire grab');
|
log('Could not open login dialog: failed to acquire grab');
|
||||||
this.unlock();
|
this.unlock();
|
||||||
}
|
}
|
||||||
@@ -506,45 +740,42 @@ const ScreenShield = new Lang.Class({
|
|||||||
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
|
this._dialog.connect('failed', Lang.bind(this, this._onUnlockFailed));
|
||||||
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
|
this._dialog.connect('unlocked', Lang.bind(this, this._onUnlockSucceded));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._keepDialog) {
|
|
||||||
// Notify the other components that even though we are showing the
|
|
||||||
// screenshield, we're not in a locked state
|
|
||||||
// (this happens for the gdm greeter)
|
|
||||||
|
|
||||||
this._isLocked = false;
|
|
||||||
this.emit('lock-status-changed', false);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUnlockFailed: function() {
|
_onUnlockFailed: function() {
|
||||||
this._dialog.destroy();
|
this._resetLockScreen(true, false);
|
||||||
this._dialog = null;
|
|
||||||
|
|
||||||
this._resetLockScreen(false);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onUnlockSucceded: function() {
|
_onUnlockSucceded: function() {
|
||||||
this.unlock();
|
this._tweenUnlocked();
|
||||||
},
|
},
|
||||||
|
|
||||||
_resetLockScreen: function(animate) {
|
_resetLockScreen: function(animateLockScreen, animateLockDialog) {
|
||||||
this._lockScreenGroup.show();
|
this._ensureLockScreen();
|
||||||
|
this._lockDialogGroup.scale_x = 1;
|
||||||
|
this._lockDialogGroup.scale_y = 1;
|
||||||
|
|
||||||
if (animate) {
|
this._lockScreenGroup.show();
|
||||||
|
this._lockScreenState = MessageTray.State.SHOWING;
|
||||||
|
|
||||||
|
if (animateLockScreen) {
|
||||||
this._lockScreenGroup.y = -global.screen_height;
|
this._lockScreenGroup.y = -global.screen_height;
|
||||||
Tweener.removeTweens(this._lockScreenGroup);
|
Tweener.removeTweens(this._lockScreenGroup);
|
||||||
Tweener.addTween(this._lockScreenGroup,
|
Tweener.addTween(this._lockScreenGroup,
|
||||||
{ y: 0,
|
{ y: 0,
|
||||||
time: SHORT_FADE_TIME,
|
time: SHORT_FADE_TIME,
|
||||||
transition: 'linear',
|
transition: 'easeOutQuad',
|
||||||
onComplete: function() {
|
onComplete: function() {
|
||||||
this._lockScreenGroup.fixed_position_set = false;
|
this._lockScreenShown();
|
||||||
this.emit('lock-screen-shown');
|
|
||||||
},
|
},
|
||||||
onCompleteScope: this
|
onCompleteScope: this
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
this._lockScreenGroup.fixed_position_set = false;
|
||||||
|
this._lockScreenShown();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animateLockDialog) {
|
||||||
this._lockDialogGroup.opacity = 0;
|
this._lockDialogGroup.opacity = 0;
|
||||||
Tweener.removeTweens(this._lockDialogGroup);
|
Tweener.removeTweens(this._lockDialogGroup);
|
||||||
Tweener.addTween(this._lockDialogGroup,
|
Tweener.addTween(this._lockDialogGroup,
|
||||||
@@ -552,22 +783,55 @@ const ScreenShield = new Lang.Class({
|
|||||||
time: SHORT_FADE_TIME,
|
time: SHORT_FADE_TIME,
|
||||||
transition: 'easeOutQuad' });
|
transition: 'easeOutQuad' });
|
||||||
} else {
|
} else {
|
||||||
this._lockScreenGroup.fixed_position_set = false;
|
|
||||||
this._lockDialogGroup.opacity = 255;
|
this._lockDialogGroup.opacity = 255;
|
||||||
this.emit('lock-screen-shown');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._lockScreenGroup.grab_key_focus();
|
this._lockScreenGroup.grab_key_focus();
|
||||||
|
|
||||||
|
if (Main.sessionMode.currentMode != 'lock-screen')
|
||||||
|
Main.sessionMode.pushMode('lock-screen');
|
||||||
|
},
|
||||||
|
|
||||||
|
_lockScreenShown: function() {
|
||||||
|
if (this._dialog && !this._isGreeter) {
|
||||||
|
this._dialog.destroy();
|
||||||
|
this._dialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._arrowAnimationId)
|
||||||
|
Mainloop.source_remove(this._arrowAnimationId);
|
||||||
|
this._arrowAnimationId = Mainloop.timeout_add(6000, Lang.bind(this, this._animateArrows));
|
||||||
|
this._animateArrows();
|
||||||
|
|
||||||
|
let motionId = global.stage.connect('captured-event', function(stage, event) {
|
||||||
|
if (event.type() == Clutter.EventType.MOTION) {
|
||||||
|
global.stage.show_cursor();
|
||||||
|
global.stage.disconnect(motionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
global.stage.hide_cursor();
|
||||||
|
|
||||||
|
this._lockScreenState = MessageTray.State.SHOWN;
|
||||||
|
this._lockScreenGroup.fixed_position_set = false;
|
||||||
|
this._lockScreenScrollCounter = 0;
|
||||||
|
|
||||||
|
this.emit('lock-screen-shown');
|
||||||
},
|
},
|
||||||
|
|
||||||
// Some of the actors in the lock screen are heavy in
|
// Some of the actors in the lock screen are heavy in
|
||||||
// resources, so we only create them when needed
|
// resources, so we only create them when needed
|
||||||
_prepareLockScreen: function() {
|
_ensureLockScreen: function() {
|
||||||
|
if (this._hasLockScreen)
|
||||||
|
return;
|
||||||
|
|
||||||
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
|
this._lockScreenContentsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.CENTER,
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
y_expand: true,
|
y_expand: true,
|
||||||
vertical: true });
|
vertical: true,
|
||||||
|
style_class: 'screen-shield-contents-box' });
|
||||||
this._clock = new Clock();
|
this._clock = new Clock();
|
||||||
this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
|
this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
|
||||||
y_fill: true });
|
y_fill: true });
|
||||||
@@ -595,26 +859,47 @@ const ScreenShield = new Lang.Class({
|
|||||||
|
|
||||||
this._lockScreenContentsBox.destroy();
|
this._lockScreenContentsBox.destroy();
|
||||||
|
|
||||||
|
if (this._arrowAnimationId) {
|
||||||
|
Mainloop.source_remove(this._arrowAnimationId);
|
||||||
|
this._arrowAnimationId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
this._hasLockScreen = false;
|
this._hasLockScreen = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
get locked() {
|
get locked() {
|
||||||
return this._isLocked;
|
return this._isActive;
|
||||||
|
},
|
||||||
|
|
||||||
|
get activationTime() {
|
||||||
|
return this._activationTime;
|
||||||
|
},
|
||||||
|
|
||||||
|
_tweenUnlocked: function() {
|
||||||
|
this._inUnlockAnimation = true;
|
||||||
|
this.unlock();
|
||||||
|
Tweener.addTween(this._lockDialogGroup, {
|
||||||
|
scale_x: 0,
|
||||||
|
scale_y: 0,
|
||||||
|
time: Overview.ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: function() {
|
||||||
|
if (this._dialog) {
|
||||||
|
this._dialog.destroy();
|
||||||
|
this._dialog = null;
|
||||||
|
}
|
||||||
|
this.actor.hide();
|
||||||
|
this._inUnlockAnimation = false;
|
||||||
|
},
|
||||||
|
onCompleteScope: this
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
unlock: function() {
|
unlock: function() {
|
||||||
if (this._hasLockScreen)
|
if (this._hasLockScreen)
|
||||||
this._clearLockScreen();
|
this._clearLockScreen();
|
||||||
|
|
||||||
if (this._keepDialog) {
|
if (this._dialog && !this._isGreeter) {
|
||||||
// The dialog must be kept alive,
|
|
||||||
// so immediately go back to it
|
|
||||||
// This will also reset _isLocked
|
|
||||||
this._ensureUnlockDialog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._dialog) {
|
|
||||||
this._dialog.destroy();
|
this._dialog.destroy();
|
||||||
this._dialog = null;
|
this._dialog = null;
|
||||||
}
|
}
|
||||||
@@ -626,26 +911,102 @@ const ScreenShield = new Lang.Class({
|
|||||||
this._isModal = false;
|
this._isModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isLocked = false;
|
if (!this._inUnlockAnimation)
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
|
|
||||||
this.emit('lock-status-changed', false);
|
if (Main.sessionMode.currentMode == 'lock-screen')
|
||||||
|
Main.sessionMode.popMode('lock-screen');
|
||||||
|
if (Main.sessionMode.currentMode == 'unlock-dialog')
|
||||||
|
Main.sessionMode.popMode('unlock-dialog');
|
||||||
|
|
||||||
|
this._activationTime = 0;
|
||||||
|
this._isActive = false;
|
||||||
|
this._isLocked = false;
|
||||||
|
this.emit('lock-status-changed');
|
||||||
},
|
},
|
||||||
|
|
||||||
lock: function(animate) {
|
lock: function(animate) {
|
||||||
if (!this._hasLockScreen)
|
|
||||||
this._prepareLockScreen();
|
|
||||||
|
|
||||||
if (!this._isModal) {
|
if (!this._isModal) {
|
||||||
Main.pushModal(this.actor);
|
Main.pushModal(this.actor, { keybindingMode: Main.KeybindingMode.LOCK_SCREEN });
|
||||||
this._isModal = true;
|
this._isModal = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._isLocked = true;
|
if (this._activationTime == 0)
|
||||||
this.actor.show();
|
this._activationTime = GLib.get_monotonic_time();
|
||||||
this._resetLockScreen(animate);
|
|
||||||
|
|
||||||
this.emit('lock-status-changed', true);
|
this.actor.show();
|
||||||
|
|
||||||
|
if (Main.sessionMode.currentMode != 'unlock-dialog' &&
|
||||||
|
Main.sessionMode.currentMode != 'lock-screen') {
|
||||||
|
this._isGreeter = Main.sessionMode.isGreeter;
|
||||||
|
if (!this._isGreeter)
|
||||||
|
Main.sessionMode.pushMode('unlock-dialog');
|
||||||
|
}
|
||||||
|
|
||||||
|
this._resetLockScreen(animate, animate);
|
||||||
|
|
||||||
|
this._isActive = true;
|
||||||
|
this._isLocked = true;
|
||||||
|
this.emit('lock-status-changed');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(ScreenShield.prototype);
|
Signals.addSignalMethods(ScreenShield.prototype);
|
||||||
|
|
||||||
|
/* Fallback code to handle session locking using gnome-screensaver,
|
||||||
|
in case the required GDM dependency is not there
|
||||||
|
*/
|
||||||
|
const ScreenShieldFallback = new Lang.Class({
|
||||||
|
Name: 'ScreenShieldFallback',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
Util.spawn(['gnome-screensaver']);
|
||||||
|
|
||||||
|
this._proxy = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
|
||||||
|
g_name: 'org.gnome.ScreenSaver',
|
||||||
|
g_object_path: '/org/gnome/ScreenSaver',
|
||||||
|
g_interface_name: 'org.gnome.ScreenSaver',
|
||||||
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||||
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES),
|
||||||
|
});
|
||||||
|
this._proxy.init(null);
|
||||||
|
|
||||||
|
this._proxy.connect('g-signal', Lang.bind(this, this._onSignal));
|
||||||
|
this._proxy.connect('notify::g-name-owner', Lang.bind(this, this._onNameOwnerChanged));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onNameOwnerChanged: function(object, pspec) {
|
||||||
|
if (this._proxy.g_name_owner)
|
||||||
|
[this._locked] = this._proxy.call_sync('GetActive', null,
|
||||||
|
Gio.DBusCallFlags.NONE, -1, null).deep_unpack();
|
||||||
|
else
|
||||||
|
this._locked = false;
|
||||||
|
|
||||||
|
this.emit('lock-status-changed', this._locked);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onSignal: function(proxy, senderName, signalName, params) {
|
||||||
|
if (signalName == 'ActiveChanged') {
|
||||||
|
[this._locked] = params.deep_unpack();
|
||||||
|
this.emit('lock-status-changed', this._locked);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
get locked() {
|
||||||
|
return this._locked;
|
||||||
|
},
|
||||||
|
|
||||||
|
lock: function() {
|
||||||
|
this._proxy.call('Lock', null, Gio.DBusCallFlags.NONE, -1, null,
|
||||||
|
Lang.bind(this, function(proxy, result) {
|
||||||
|
proxy.call_finish(result);
|
||||||
|
|
||||||
|
this.emit('lock-screen-shown');
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
unlock: function() {
|
||||||
|
this._proxy.call('SetActive', GLib.Variant.new('(b)', false),
|
||||||
|
Gio.DBusCallFlags.NONE, -1, null, null);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(ScreenShieldFallback.prototype);
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ const Util = imports.misc.util;
|
|||||||
const FileUtils = imports.misc.fileUtils;
|
const FileUtils = imports.misc.fileUtils;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
|
||||||
|
|
||||||
// Not currently referenced by the search API, but
|
// Not currently referenced by the search API, but
|
||||||
// this enumeration can be useful for provider
|
// this enumeration can be useful for provider
|
||||||
// implementations.
|
// implementations.
|
||||||
@@ -74,9 +76,11 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
const SearchProvider = new Lang.Class({
|
const SearchProvider = new Lang.Class({
|
||||||
Name: 'SearchProvider',
|
Name: 'SearchProvider',
|
||||||
|
|
||||||
_init: function(title) {
|
_init: function(title, appInfo, isRemoteProvider) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
|
this.appInfo = appInfo;
|
||||||
this.searchSystem = null;
|
this.searchSystem = null;
|
||||||
|
this.isRemoteProvider = !!isRemoteProvider;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -172,12 +176,16 @@ const SearchSystem = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this._providers = [];
|
this._providers = [];
|
||||||
|
this._remoteProviders = [];
|
||||||
this.reset();
|
this.reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
registerProvider: function (provider) {
|
registerProvider: function (provider) {
|
||||||
provider.searchSystem = this;
|
provider.searchSystem = this;
|
||||||
this._providers.push(provider);
|
this._providers.push(provider);
|
||||||
|
|
||||||
|
if (provider.isRemoteProvider)
|
||||||
|
this._remoteProviders.push(provider);
|
||||||
},
|
},
|
||||||
|
|
||||||
unregisterProvider: function (provider) {
|
unregisterProvider: function (provider) {
|
||||||
@@ -186,12 +194,20 @@ const SearchSystem = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
provider.searchSystem = null;
|
provider.searchSystem = null;
|
||||||
this._providers.splice(index, 1);
|
this._providers.splice(index, 1);
|
||||||
|
|
||||||
|
let remoteIndex = this._remoteProviders.indexOf(provider);
|
||||||
|
if (remoteIndex != -1)
|
||||||
|
this._remoteProviders.splice(index, 1);
|
||||||
},
|
},
|
||||||
|
|
||||||
getProviders: function() {
|
getProviders: function() {
|
||||||
return this._providers;
|
return this._providers;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getRemoteProviders: function() {
|
||||||
|
return this._remoteProviders;
|
||||||
|
},
|
||||||
|
|
||||||
getTerms: function() {
|
getTerms: function() {
|
||||||
return this._previousTerms;
|
return this._previousTerms;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ const SearchResults = new Lang.Class({
|
|||||||
scrollView.add_actor(this._content);
|
scrollView.add_actor(this._content);
|
||||||
|
|
||||||
this.actor.add(scrollView, { x_fill: true,
|
this.actor.add(scrollView, { x_fill: true,
|
||||||
y_fill: false,
|
y_fill: true,
|
||||||
expand: true,
|
expand: true,
|
||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
@@ -205,14 +205,15 @@ const SearchResults = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||||
this._content.add(this._statusText);
|
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
|
||||||
|
y_align: St.Align.MIDDLE });
|
||||||
|
this._content.add(this._statusBin, { expand: true });
|
||||||
|
this._statusBin.add_actor(this._statusText);
|
||||||
this._providers = this._searchSystem.getProviders();
|
this._providers = this._searchSystem.getProviders();
|
||||||
this._providerMeta = [];
|
this._providerMeta = [];
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
this.createProviderMeta(this._providers[i]);
|
this.createProviderMeta(this._providers[i]);
|
||||||
}
|
}
|
||||||
this._searchProvidersBox = new St.BoxLayout({ style_class: 'search-providers-box' });
|
|
||||||
this.actor.add(this._searchProvidersBox);
|
|
||||||
|
|
||||||
this._highlightDefault = false;
|
this._highlightDefault = false;
|
||||||
this._defaultResult = null;
|
this._defaultResult = null;
|
||||||
@@ -223,7 +224,7 @@ const SearchResults = new Lang.Class({
|
|||||||
vertical: true });
|
vertical: true });
|
||||||
let title = new St.Label({ style_class: 'search-section-header',
|
let title = new St.Label({ style_class: 'search-section-header',
|
||||||
text: provider.title });
|
text: provider.title });
|
||||||
providerBox.add(title);
|
providerBox.add(title, { x_fill: false, x_align: St.Align.START });
|
||||||
|
|
||||||
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
|
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
@@ -265,14 +266,14 @@ const SearchResults = new Lang.Class({
|
|||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
this._searchSystem.reset();
|
this._searchSystem.reset();
|
||||||
this._statusText.hide();
|
this._statusBin.hide();
|
||||||
this._clearDisplay();
|
this._clearDisplay();
|
||||||
},
|
},
|
||||||
|
|
||||||
startingSearch: function() {
|
startingSearch: function() {
|
||||||
this.reset();
|
this.reset();
|
||||||
this._statusText.set_text(_("Searching..."));
|
this._statusText.set_text(_("Searching..."));
|
||||||
this._statusText.show();
|
this._statusBin.show();
|
||||||
},
|
},
|
||||||
|
|
||||||
doSearch: function (searchString) {
|
doSearch: function (searchString) {
|
||||||
@@ -299,9 +300,6 @@ const SearchResults = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!newDefaultResult)
|
|
||||||
newDefaultResult = this._searchProvidersBox.get_first_child();
|
|
||||||
|
|
||||||
if (newDefaultResult != this._defaultResult) {
|
if (newDefaultResult != this._defaultResult) {
|
||||||
if (this._defaultResult)
|
if (this._defaultResult)
|
||||||
this._defaultResult.setSelected(false);
|
this._defaultResult.setSelected(false);
|
||||||
@@ -322,10 +320,10 @@ const SearchResults = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!haveResults) {
|
if (!haveResults) {
|
||||||
this._statusText.set_text(_("No matching results."));
|
this._statusText.set_text(_("No results."));
|
||||||
this._statusText.show();
|
this._statusBin.show();
|
||||||
} else {
|
} else {
|
||||||
this._statusText.hide();
|
this._statusBin.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,100 +1,101 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
|
const DEFAULT_MODE = 'restrictive';
|
||||||
const STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION = {
|
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
|
||||||
'volume': imports.ui.status.volume.Indicator,
|
|
||||||
'battery': imports.ui.status.power.Indicator,
|
|
||||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
|
||||||
'userMenu': imports.ui.userMenu.UserMenuButton
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Config.HAVE_BLUETOOTH)
|
|
||||||
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['bluetooth'] =
|
|
||||||
imports.ui.status.bluetooth.Indicator;
|
|
||||||
|
|
||||||
try {
|
|
||||||
STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION['network'] =
|
|
||||||
imports.ui.status.network.NMApplet;
|
|
||||||
} catch(e) {
|
|
||||||
log('NMApplet is not supported. It is possible that your NetworkManager version is too old');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const DEFAULT_MODE = 'user';
|
|
||||||
|
|
||||||
const _modes = {
|
const _modes = {
|
||||||
'gdm': { hasOverview: false,
|
'restrictive': {
|
||||||
hasAppMenu: false,
|
hasOverview: false,
|
||||||
showCalendarEvents: false,
|
showCalendarEvents: false,
|
||||||
allowSettings: false,
|
allowSettings: false,
|
||||||
allowExtensions: false,
|
allowExtensions: false,
|
||||||
allowKeybindingsWhenModal: true,
|
|
||||||
hasRunDialog: false,
|
hasRunDialog: false,
|
||||||
hasWorkspaces: false,
|
hasWorkspaces: false,
|
||||||
createSession: Main.createGDMSession,
|
hasWindows: false,
|
||||||
createUnlockDialog: Main.createGDMLoginDialog,
|
hasNotifications: false,
|
||||||
extraStylesheet: null,
|
isLocked: false,
|
||||||
statusArea: {
|
isGreeter: false,
|
||||||
order: [
|
isPrimary: false,
|
||||||
'a11y', 'display', 'keyboard',
|
unlockDialog: null,
|
||||||
'volume', 'battery', 'powerMenu'
|
components: [],
|
||||||
],
|
panel: {
|
||||||
implementation: {
|
left: [],
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
center: [],
|
||||||
'volume': imports.ui.status.volume.Indicator,
|
right: []
|
||||||
'battery': imports.ui.status.power.Indicator,
|
},
|
||||||
'keyboard': imports.ui.status.keyboard.InputSourceIndicator,
|
},
|
||||||
'powerMenu': imports.gdm.powerMenu.PowerMenuButton
|
|
||||||
}
|
'gdm': {
|
||||||
|
hasNotifications: true,
|
||||||
|
isGreeter: true,
|
||||||
|
isPrimary: true,
|
||||||
|
unlockDialog: imports.gdm.loginDialog.LoginDialog,
|
||||||
|
components: ['polkitAgent'],
|
||||||
|
panel: {
|
||||||
|
left: ['logo'],
|
||||||
|
center: ['dateMenu'],
|
||||||
|
right: ['a11y', 'display', 'keyboard',
|
||||||
|
'volume', 'battery', 'powerMenu']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'initial-setup': { hasOverview: false,
|
'lock-screen': {
|
||||||
hasAppMenu: false,
|
isLocked: true,
|
||||||
showCalendarEvents: false,
|
isGreeter: undefined,
|
||||||
allowSettings: false,
|
unlockDialog: undefined,
|
||||||
allowExtensions: false,
|
components: ['polkitAgent', 'telepathyClient'],
|
||||||
allowKeybindingsWhenModal: false,
|
panel: {
|
||||||
hasRunDialog: false,
|
left: ['userMenu'],
|
||||||
hasWorkspaces: false,
|
center: [],
|
||||||
createSession: Main.createInitialSetupSession,
|
right: ['lockScreen']
|
||||||
extraStylesheet: null,
|
},
|
||||||
statusArea: {
|
},
|
||||||
order: [
|
|
||||||
'a11y', 'keyboard', 'volume'
|
'unlock-dialog': {
|
||||||
],
|
isLocked: true,
|
||||||
implementation: {
|
unlockDialog: undefined,
|
||||||
'a11y': imports.ui.status.accessibility.ATIndicator,
|
components: ['polkitAgent', 'telepathyClient'],
|
||||||
'keyboard': imports.ui.status.keyboard.XKBIndicator,
|
panel: {
|
||||||
'volume': imports.ui.status.volume.Indicator
|
left: ['userMenu'],
|
||||||
}
|
center: [],
|
||||||
|
right: ['a11y', 'keyboard', 'lockScreen']
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
'initial-setup': {
|
||||||
|
isPrimary: true,
|
||||||
|
components: ['keyring'],
|
||||||
|
panel: {
|
||||||
|
left: [],
|
||||||
|
center: ['dateMenu'],
|
||||||
|
right: ['a11y', 'keyboard', 'volume']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'user': { hasOverview: true,
|
'user': {
|
||||||
hasAppMenu: true,
|
hasOverview: true,
|
||||||
showCalendarEvents: true,
|
showCalendarEvents: true,
|
||||||
allowSettings: true,
|
allowSettings: true,
|
||||||
allowExtensions: true,
|
allowExtensions: true,
|
||||||
allowKeybindingsWhenModal: false,
|
|
||||||
hasRunDialog: true,
|
hasRunDialog: true,
|
||||||
hasWorkspaces: true,
|
hasWorkspaces: true,
|
||||||
createSession: Main.createUserSession,
|
hasWindows: true,
|
||||||
createUnlockDialog: Main.createSessionUnlockDialog,
|
hasNotifications: true,
|
||||||
extraStylesheet: null,
|
isLocked: false,
|
||||||
statusArea: {
|
isPrimary: true,
|
||||||
order: [
|
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
|
||||||
'input-method', 'a11y', 'keyboard', 'volume', 'bluetooth',
|
components: ['networkAgent', 'polkitAgent', 'telepathyClient',
|
||||||
'network', 'battery', 'userMenu'
|
'keyring', 'recorder', 'autorunManager', 'automountManager'],
|
||||||
],
|
panel: {
|
||||||
implementation: STANDARD_STATUS_AREA_SHELL_IMPLEMENTATION
|
left: ['activities', 'appMenu'],
|
||||||
|
center: ['dateMenu'],
|
||||||
|
right: ['a11y', 'keyboard', 'volume', 'bluetooth',
|
||||||
|
'network', 'battery', 'userMenu']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -102,6 +103,7 @@ const _modes = {
|
|||||||
function listModes() {
|
function listModes() {
|
||||||
let modes = Object.getOwnPropertyNames(_modes);
|
let modes = Object.getOwnPropertyNames(_modes);
|
||||||
for (let i = 0; i < modes.length; i++)
|
for (let i = 0; i < modes.length; i++)
|
||||||
|
if (_modes[modes[i]].isPrimary)
|
||||||
print(modes[i]);
|
print(modes[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,27 +111,48 @@ const SessionMode = new Lang.Class({
|
|||||||
Name: 'SessionMode',
|
Name: 'SessionMode',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
let params = _modes[global.session_mode];
|
global.connect('notify::session-mode', Lang.bind(this, this._sync));
|
||||||
|
let mode = _modes[global.session_mode].isPrimary ? global.session_mode
|
||||||
|
: 'user';
|
||||||
|
this._modeStack = [mode];
|
||||||
|
this._sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
pushMode: function(mode) {
|
||||||
|
this._modeStack.push(mode);
|
||||||
|
this._sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
popMode: function(mode) {
|
||||||
|
if (this.currentMode != mode || this._modeStack.length === 1)
|
||||||
|
throw new Error("Invalid SessionMode.popMode");
|
||||||
|
this._modeStack.pop();
|
||||||
|
this._sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
switchMode: function(to) {
|
||||||
|
if (this.currentMode == to)
|
||||||
|
return;
|
||||||
|
this._modeStack[this._modeStack.length - 1] = to;
|
||||||
|
this._sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
get currentMode() {
|
||||||
|
return this._modeStack[this._modeStack.length - 1];
|
||||||
|
},
|
||||||
|
|
||||||
|
_sync: function() {
|
||||||
|
let params = _modes[this.currentMode];
|
||||||
params = Params.parse(params, _modes[DEFAULT_MODE]);
|
params = Params.parse(params, _modes[DEFAULT_MODE]);
|
||||||
|
|
||||||
this._createSession = params.createSession;
|
// A simplified version of Lang.copyProperties, handles
|
||||||
delete params.createSession;
|
// undefined as a special case for "no change / inherit from previous mode"
|
||||||
this._createUnlockDialog = params.createUnlockDialog;
|
for (let prop in params) {
|
||||||
delete params.createUnlockDialog;
|
if (params[prop] !== undefined)
|
||||||
|
this[prop] = params[prop];
|
||||||
|
}
|
||||||
|
|
||||||
Lang.copyProperties(params, this);
|
this.emit('updated');
|
||||||
},
|
}
|
||||||
|
|
||||||
createSession: function() {
|
|
||||||
if (this._createSession)
|
|
||||||
this._createSession();
|
|
||||||
},
|
|
||||||
|
|
||||||
createUnlockDialog: function() {
|
|
||||||
if (this._createUnlockDialog)
|
|
||||||
return this._createUnlockDialog.apply(this, arguments);
|
|
||||||
else
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
Signals.addSignalMethods(SessionMode.prototype);
|
||||||
|
|||||||
@@ -57,7 +57,10 @@ const ScreenSaverIface = <interface name="org.gnome.ScreenSaver">
|
|||||||
<arg name="active" direction="out" type="b" />
|
<arg name="active" direction="out" type="b" />
|
||||||
</method>
|
</method>
|
||||||
<method name="SetActive">
|
<method name="SetActive">
|
||||||
<arg name="value" direction="in" type="u" />
|
<arg name="value" direction="in" type="b" />
|
||||||
|
</method>
|
||||||
|
<method name="GetActiveTime">
|
||||||
|
<arg name="value" direction="out" type="u" />
|
||||||
</method>
|
</method>
|
||||||
<signal name="ActiveChanged">
|
<signal name="ActiveChanged">
|
||||||
<arg name="new_value" type="b" />
|
<arg name="new_value" type="b" />
|
||||||
@@ -318,8 +321,11 @@ const GnomeShellExtensions = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
ReloadExtension: function(uuid) {
|
ReloadExtension: function(uuid) {
|
||||||
ExtensionSystem.unloadExtension(uuid);
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
ExtensionSystem.loadExtension(uuid);
|
if (!extension)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ExtensionSystem.reloadExtension(extension);
|
||||||
},
|
},
|
||||||
|
|
||||||
CheckForUpdates: function() {
|
CheckForUpdates: function() {
|
||||||
@@ -337,29 +343,46 @@ const GnomeShellExtensions = new Lang.Class({
|
|||||||
const ScreenSaverDBus = new Lang.Class({
|
const ScreenSaverDBus = new Lang.Class({
|
||||||
Name: 'ScreenSaverDBus',
|
Name: 'ScreenSaverDBus',
|
||||||
|
|
||||||
_init: function() {
|
_init: function(screenShield) {
|
||||||
this.parent();
|
this.parent();
|
||||||
|
|
||||||
Main.screenShield.connect('lock-status-changed', Lang.bind(this, function(shield, locked) {
|
this._screenShield = screenShield;
|
||||||
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [locked]));
|
screenShield.connect('lock-status-changed', Lang.bind(this, function(shield) {
|
||||||
|
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [shield.locked]));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
|
||||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
|
||||||
|
|
||||||
|
Gio.DBus.session.own_name('org.gnome.ScreenSaver', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||||
},
|
},
|
||||||
|
|
||||||
Lock: function() {
|
LockAsync: function(parameters, invocation) {
|
||||||
Main.screenShield.lock(true);
|
let tmpId = this._screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
|
||||||
|
this._screenShield.disconnect(tmpId);
|
||||||
|
|
||||||
|
invocation.return_value(null);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._screenShield.lock(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
SetActive: function(active) {
|
SetActive: function(active) {
|
||||||
if (active)
|
if (active)
|
||||||
Main.screenShield.lock(true);
|
this._screenShield.lock(true);
|
||||||
else
|
else
|
||||||
Main.screenShield.unlock();
|
this._screenShield.unlock();
|
||||||
},
|
},
|
||||||
|
|
||||||
GetActive: function() {
|
GetActive: function() {
|
||||||
return Main.screenShield.locked;
|
return this._screenShield.locked;
|
||||||
}
|
},
|
||||||
|
|
||||||
|
GetActiveTime: function() {
|
||||||
|
let started = this._screenShield.activationTime;
|
||||||
|
if (started > 0)
|
||||||
|
return Math.floor((GLib.get_monotonic_time() - started) / 1000000);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -76,6 +76,12 @@ const EntryMenu = new Lang.Class({
|
|||||||
this.actor.grab_key_focus();
|
this.actor.grab_key_focus();
|
||||||
|
|
||||||
this.parent();
|
this.parent();
|
||||||
|
this._entry.add_style_pseudo_class('focus');
|
||||||
|
},
|
||||||
|
|
||||||
|
close: function() {
|
||||||
|
this._entry.grab_key_focus();
|
||||||
|
this.parent();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateCopyItem: function() {
|
_updateCopyItem: function() {
|
||||||
@@ -126,34 +132,20 @@ function _setMenuAlignment(entry, stageX) {
|
|||||||
entry.menu.setSourceAlignment(entryX / entry.width);
|
entry.menu.setSourceAlignment(entryX / entry.width);
|
||||||
};
|
};
|
||||||
|
|
||||||
function _onClicked(action, actor) {
|
function _onButtonPressEvent(actor, event, entry) {
|
||||||
let entry = actor.menu ? actor : actor.get_parent();
|
|
||||||
|
|
||||||
if (entry.menu.isOpen) {
|
if (entry.menu.isOpen) {
|
||||||
entry.menu.close();
|
entry.menu.close();
|
||||||
} else if (action.get_button() == 3) {
|
return true;
|
||||||
let [stageX, stageY] = action.get_coords();
|
} else if (event.get_button() == 3) {
|
||||||
_setMenuAlignment(entry, stageX);
|
let [stageX, stageY] = event.get_coords();
|
||||||
entry.menu.open();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function _onLongPress(action, actor, state) {
|
|
||||||
let entry = actor.menu ? actor : actor.get_parent();
|
|
||||||
|
|
||||||
if (state == Clutter.LongPressState.QUERY)
|
|
||||||
return action.get_button() == 1 && !entry.menu.isOpen;
|
|
||||||
|
|
||||||
if (state == Clutter.LongPressState.ACTIVATE) {
|
|
||||||
let [stageX, stageY] = action.get_coords();
|
|
||||||
_setMenuAlignment(entry, stageX);
|
_setMenuAlignment(entry, stageX);
|
||||||
entry.menu.open();
|
entry.menu.open();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
function _onPopup(actor) {
|
function _onPopup(actor, entry) {
|
||||||
let entry = actor.menu ? actor : actor.get_parent();
|
|
||||||
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
let [success, textX, textY, lineHeight] = entry.clutter_text.position_to_coords(-1);
|
||||||
if (success)
|
if (success)
|
||||||
entry.menu.setSourceAlignment(textX / entry.width);
|
entry.menu.setSourceAlignment(textX / entry.width);
|
||||||
@@ -168,20 +160,11 @@ function addContextMenu(entry, params) {
|
|||||||
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
|
entry._menuManager = new PopupMenu.PopupMenuManager({ actor: entry });
|
||||||
entry._menuManager.addMenu(entry.menu);
|
entry._menuManager.addMenu(entry.menu);
|
||||||
|
|
||||||
let clickAction;
|
// Add an event handler to both the entry and its clutter_text; the former
|
||||||
|
|
||||||
// Add a click action to both the entry and its clutter_text; the former
|
|
||||||
// so padding is included in the clickable area, the latter because the
|
// so padding is included in the clickable area, the latter because the
|
||||||
// event processing of ClutterText prevents event-bubbling.
|
// event processing of ClutterText prevents event-bubbling.
|
||||||
clickAction = new Clutter.ClickAction();
|
entry.clutter_text.connect('button-press-event', Lang.bind(null, _onButtonPressEvent, entry));
|
||||||
clickAction.connect('clicked', _onClicked);
|
entry.connect('button-press-event', Lang.bind(null, _onButtonPressEvent, entry));
|
||||||
clickAction.connect('long-press', _onLongPress);
|
|
||||||
entry.clutter_text.add_action(clickAction);
|
|
||||||
|
|
||||||
clickAction = new Clutter.ClickAction();
|
entry.connect('popup-menu', Lang.bind(null, _onPopup, entry));
|
||||||
clickAction.connect('clicked', _onClicked);
|
|
||||||
clickAction.connect('long-press', _onLongPress);
|
|
||||||
entry.add_action(clickAction);
|
|
||||||
|
|
||||||
entry.connect('popup-menu', _onPopup);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ const ShellUnmountNotifier = new Lang.Class({
|
|||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('', 'media-removable', St.IconType.FULLCOLOR);
|
this.parent('', 'media-removable');
|
||||||
|
|
||||||
this._notification = null;
|
this._notification = null;
|
||||||
Main.messageTray.add(this);
|
Main.messageTray.add(this);
|
||||||
@@ -361,12 +361,12 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
if (strings[1])
|
if (strings[1])
|
||||||
description.set_text(strings[1]);
|
description.set_text(strings[1]);
|
||||||
|
|
||||||
this._passwordBox = new St.BoxLayout({ vertical: false });
|
this._passwordBox = new St.BoxLayout({ vertical: false, style_class: 'prompt-dialog-password-box' });
|
||||||
this._messageBox.add(this._passwordBox);
|
this._messageBox.add(this._passwordBox);
|
||||||
|
|
||||||
this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label',
|
this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label',
|
||||||
text: _("Passphrase") }));
|
text: _("Password") }));
|
||||||
this._passwordBox.add(this._passwordLabel);
|
this._passwordBox.add(this._passwordLabel, { y_fill: false, y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
text: "",
|
text: "",
|
||||||
@@ -386,7 +386,7 @@ const ShellMountPasswordDialog = new Lang.Class({
|
|||||||
|
|
||||||
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
|
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
|
||||||
this._rememberChoice = new CheckBox.CheckBox();
|
this._rememberChoice = new CheckBox.CheckBox();
|
||||||
this._rememberChoice.getLabelActor().text = _("Remember Passphrase");
|
this._rememberChoice.getLabelActor().text = _("Remember Password");
|
||||||
this._rememberChoice.actor.checked = true;
|
this._rememberChoice.actor.checked = true;
|
||||||
this._messageBox.add(this._rememberChoice.actor);
|
this._messageBox.add(this._rememberChoice.actor);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ const KEY_VISUAL_BELL = 'visual-bell';
|
|||||||
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
|
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
|
||||||
const KEY_GTK_THEME = 'gtk-theme';
|
const KEY_GTK_THEME = 'gtk-theme';
|
||||||
const KEY_ICON_THEME = 'icon-theme';
|
const KEY_ICON_THEME = 'icon-theme';
|
||||||
|
const KEY_WM_THEME = 'theme';
|
||||||
const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
|
const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
|
||||||
|
|
||||||
const HIGH_CONTRAST_THEME = 'HighContrast';
|
const HIGH_CONTRAST_THEME = 'HighContrast';
|
||||||
@@ -36,7 +37,7 @@ const ATIndicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('preferences-desktop-accessibility', _("Accessibility"));
|
this.parent('preferences-desktop-accessibility-symbolic', _("Accessibility"));
|
||||||
|
|
||||||
let highContrast = this._buildHCItem();
|
let highContrast = this._buildHCItem();
|
||||||
this.menu.addMenuItem(highContrast);
|
this.menu.addMenuItem(highContrast);
|
||||||
@@ -75,10 +76,6 @@ const ATIndicator = new Lang.Class({
|
|||||||
this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
|
this.menu.addSettingsAction(_("Universal Access Settings"), 'gnome-universal-access-panel.desktop');
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
this.actor.visible = !locked;
|
|
||||||
},
|
|
||||||
|
|
||||||
_buildItemExtended: function(string, initial_value, writable, on_set) {
|
_buildItemExtended: function(string, initial_value, writable, on_set) {
|
||||||
let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
|
let widget = new PopupMenu.PopupSwitchMenuItem(string, initial_value);
|
||||||
if (!writable)
|
if (!writable)
|
||||||
@@ -105,28 +102,35 @@ const ATIndicator = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_buildHCItem: function() {
|
_buildHCItem: function() {
|
||||||
let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
|
let interfaceSettings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
|
||||||
let gtkTheme = settings.get_string(KEY_GTK_THEME);
|
let wmSettings = new Gio.Settings({ schema: WM_SCHEMA });
|
||||||
let iconTheme = settings.get_string(KEY_ICON_THEME);
|
let gtkTheme = interfaceSettings.get_string(KEY_GTK_THEME);
|
||||||
|
let iconTheme = interfaceSettings.get_string(KEY_ICON_THEME);
|
||||||
|
let wmTheme = wmSettings.get_string(KEY_WM_THEME);
|
||||||
let hasHC = (gtkTheme == HIGH_CONTRAST_THEME);
|
let hasHC = (gtkTheme == HIGH_CONTRAST_THEME);
|
||||||
let highContrast = this._buildItemExtended(
|
let highContrast = this._buildItemExtended(
|
||||||
_("High Contrast"),
|
_("High Contrast"),
|
||||||
hasHC,
|
hasHC,
|
||||||
settings.is_writable(KEY_GTK_THEME) && settings.is_writable(KEY_ICON_THEME),
|
interfaceSettings.is_writable(KEY_GTK_THEME) &&
|
||||||
|
interfaceSettings.is_writable(KEY_ICON_THEME) &&
|
||||||
|
wmSettings.is_writable(KEY_WM_THEME),
|
||||||
function (enabled) {
|
function (enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
settings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
|
interfaceSettings.set_string(KEY_GTK_THEME, HIGH_CONTRAST_THEME);
|
||||||
settings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
|
interfaceSettings.set_string(KEY_ICON_THEME, HIGH_CONTRAST_THEME);
|
||||||
|
wmSettings.set_string(KEY_WM_THEME, HIGH_CONTRAST_THEME);
|
||||||
} else if(!hasHC) {
|
} else if(!hasHC) {
|
||||||
settings.set_string(KEY_GTK_THEME, gtkTheme);
|
interfaceSettings.set_string(KEY_GTK_THEME, gtkTheme);
|
||||||
settings.set_string(KEY_ICON_THEME, iconTheme);
|
interfaceSettings.set_string(KEY_ICON_THEME, iconTheme);
|
||||||
|
wmSettings.set_string(KEY_WM_THEME, wmTheme);
|
||||||
} else {
|
} else {
|
||||||
settings.reset(KEY_GTK_THEME);
|
interfaceSettings.reset(KEY_GTK_THEME);
|
||||||
settings.reset(KEY_ICON_THEME);
|
interfaceSettings.reset(KEY_ICON_THEME);
|
||||||
|
wmSettings.reset(KEY_WM_THEME);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
settings.connect('changed::' + KEY_GTK_THEME, function() {
|
interfaceSettings.connect('changed::' + KEY_GTK_THEME, function() {
|
||||||
let value = settings.get_string(KEY_GTK_THEME);
|
let value = interfaceSettings.get_string(KEY_GTK_THEME);
|
||||||
if (value == HIGH_CONTRAST_THEME) {
|
if (value == HIGH_CONTRAST_THEME) {
|
||||||
highContrast.setToggleState(true);
|
highContrast.setToggleState(true);
|
||||||
} else {
|
} else {
|
||||||
@@ -134,11 +138,16 @@ const ATIndicator = new Lang.Class({
|
|||||||
gtkTheme = value;
|
gtkTheme = value;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
settings.connect('changed::' + KEY_ICON_THEME, function() {
|
interfaceSettings.connect('changed::' + KEY_ICON_THEME, function() {
|
||||||
let value = settings.get_string(KEY_ICON_THEME);
|
let value = interfaceSettings.get_string(KEY_ICON_THEME);
|
||||||
if (value != HIGH_CONTRAST_THEME)
|
if (value != HIGH_CONTRAST_THEME)
|
||||||
iconTheme = value;
|
iconTheme = value;
|
||||||
});
|
});
|
||||||
|
wmSettings.connect('changed::' + KEY_WM_THEME, function() {
|
||||||
|
let value = wmSettings.get_string(KEY_WM_THEME);
|
||||||
|
if (value != HIGH_CONTRAST_THEME)
|
||||||
|
wmTheme = value;
|
||||||
|
});
|
||||||
return highContrast;
|
return highContrast;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const Indicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('bluetooth-disabled', _("Bluetooth"));
|
this.parent('bluetooth-disabled-symbolic', _("Bluetooth"));
|
||||||
|
|
||||||
this._applet = new GnomeBluetoothApplet.Applet();
|
this._applet = new GnomeBluetoothApplet.Applet();
|
||||||
|
|
||||||
@@ -88,11 +88,6 @@ const Indicator = new Lang.Class({
|
|||||||
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
this._applet.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
this._isLocked = locked;
|
|
||||||
this._updateKillswitch();
|
|
||||||
},
|
|
||||||
|
|
||||||
_updateKillswitch: function() {
|
_updateKillswitch: function() {
|
||||||
let current_state = this._applet.killswitch_state;
|
let current_state = this._applet.killswitch_state;
|
||||||
let on = current_state == GnomeBluetooth.KillswitchState.UNBLOCKED;
|
let on = current_state == GnomeBluetooth.KillswitchState.UNBLOCKED;
|
||||||
@@ -107,14 +102,14 @@ const Indicator = new Lang.Class({
|
|||||||
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
|
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
|
||||||
this._killswitch.setStatus(_("hardware disabled"));
|
this._killswitch.setStatus(_("hardware disabled"));
|
||||||
|
|
||||||
this.actor.visible = !this._isLocked && has_adapter;
|
this.actor.visible = has_adapter;
|
||||||
|
|
||||||
if (on) {
|
if (on) {
|
||||||
this._discoverable.actor.show();
|
this._discoverable.actor.show();
|
||||||
this.setIcon('bluetooth-active');
|
this.setIcon('bluetooth-active-symbolic');
|
||||||
} else {
|
} else {
|
||||||
this._discoverable.actor.hide();
|
this._discoverable.actor.hide();
|
||||||
this.setIcon('bluetooth-disabled');
|
this.setIcon('bluetooth-disabled-symbolic');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -244,22 +239,6 @@ const Indicator = new Lang.Class({
|
|||||||
this._applet.send_to_address(device.bdaddr, device.alias);
|
this._applet.send_to_address(device.bdaddr, device.alias);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_FILE_TRANSFER) {
|
|
||||||
item.menu.addAction(_("Browse Files..."), Lang.bind(this, function(event) {
|
|
||||||
this._applet.browse_address(device.bdaddr, event.get_time(),
|
|
||||||
Lang.bind(this, function(applet, result) {
|
|
||||||
try {
|
|
||||||
applet.browse_address_finish(result);
|
|
||||||
} catch (e) {
|
|
||||||
this._ensureSource();
|
|
||||||
this._source.notify(new MessageTray.Notification(this._source,
|
|
||||||
_("Bluetooth"),
|
|
||||||
_("Error browsing device"),
|
|
||||||
{ body: _("The requested device cannot be browsed, error is '%s'").format(e) }));
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (device.type) {
|
switch (device.type) {
|
||||||
case GnomeBluetoothApplet.Type.KEYBOARD:
|
case GnomeBluetoothApplet.Type.KEYBOARD:
|
||||||
@@ -306,7 +285,7 @@ const Indicator = new Lang.Class({
|
|||||||
|
|
||||||
_ensureSource: function() {
|
_ensureSource: function() {
|
||||||
if (!this._source) {
|
if (!this._source) {
|
||||||
this._source = new MessageTray.Source(_("Bluetooth"), 'bluetooth-active', St.IconType.SYMBOLIC);
|
this._source = new MessageTray.Source(_("Bluetooth"), 'bluetooth-active');
|
||||||
Main.messageTray.add(this._source);
|
Main.messageTray.add(this._source);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -374,6 +353,7 @@ const ConfirmNotification = new Lang.Class({
|
|||||||
_init: function(source, applet, device_path, name, long_name, pin) {
|
_init: function(source, applet, device_path, name, long_name, pin) {
|
||||||
this.parent(source,
|
this.parent(source,
|
||||||
_("Bluetooth"),
|
_("Bluetooth"),
|
||||||
|
/* Translators: argument is the device short name */
|
||||||
_("Pairing confirmation for %s").format(name),
|
_("Pairing confirmation for %s").format(name),
|
||||||
{ customContent: true });
|
{ customContent: true });
|
||||||
this.setResident(true);
|
this.setResident(true);
|
||||||
@@ -383,6 +363,7 @@ const ConfirmNotification = new Lang.Class({
|
|||||||
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
|
this.addBody(_("Device %s wants to pair with this computer").format(long_name));
|
||||||
this.addBody(_("Please confirm whether the PIN '%06d' matches the one on the device.").format(pin));
|
this.addBody(_("Please confirm whether the PIN '%06d' matches the one on the device.").format(pin));
|
||||||
|
|
||||||
|
/* Translators: this is the verb, not the noun */
|
||||||
this.addButton('matches', _("Matches"));
|
this.addButton('matches', _("Matches"));
|
||||||
this.addButton('does-not-match', _("Does not match"));
|
this.addButton('does-not-match', _("Does not match"));
|
||||||
|
|
||||||
@@ -461,7 +442,10 @@ const PinNotification = new Lang.Class({
|
|||||||
|
|
||||||
_canActivateOkButton: function() {
|
_canActivateOkButton: function() {
|
||||||
// PINs have a fixed length of 6
|
// PINs have a fixed length of 6
|
||||||
|
if (this._numeric)
|
||||||
return this._entry.clutter_text.text.length == 6;
|
return this._entry.clutter_text.text.length == 6;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
grabFocus: function(lockTray) {
|
grabFocus: function(lockTray) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const GLib = imports.gi.GLib;
|
|||||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -45,6 +46,7 @@ const IBusManager = new Lang.Class({
|
|||||||
this._panelService = null;
|
this._panelService = null;
|
||||||
this._engines = {};
|
this._engines = {};
|
||||||
this._ready = false;
|
this._ready = false;
|
||||||
|
this._registerPropertiesId = 0;
|
||||||
|
|
||||||
this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
|
this._nameWatcherId = Gio.DBus.session.watch_name(IBus.SERVICE_IBUS,
|
||||||
Gio.BusNameWatcherFlags.NONE,
|
Gio.BusNameWatcherFlags.NONE,
|
||||||
@@ -63,6 +65,7 @@ const IBusManager = new Lang.Class({
|
|||||||
this._candidatePopup.setPanelService(null);
|
this._candidatePopup.setPanelService(null);
|
||||||
this._engines = {};
|
this._engines = {};
|
||||||
this._ready = false;
|
this._ready = false;
|
||||||
|
this._registerPropertiesId = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNameAppeared: function() {
|
_onNameAppeared: function() {
|
||||||
@@ -100,6 +103,11 @@ const IBusManager = new Lang.Class({
|
|||||||
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
|
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
|
||||||
object_path: IBus.PATH_PANEL });
|
object_path: IBus.PATH_PANEL });
|
||||||
this._candidatePopup.setPanelService(this._panelService);
|
this._candidatePopup.setPanelService(this._panelService);
|
||||||
|
// Need to set this to get 'global-engine-changed' emitions
|
||||||
|
this._ibus.set_watch_ibus_signal(true);
|
||||||
|
this._ibus.connect('global-engine-changed', Lang.bind(this, this._resetProperties));
|
||||||
|
this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
|
||||||
|
this._resetProperties();
|
||||||
} else {
|
} else {
|
||||||
this._clear();
|
this._clear();
|
||||||
return;
|
return;
|
||||||
@@ -116,6 +124,39 @@ const IBusManager = new Lang.Class({
|
|||||||
this._readyCallback();
|
this._readyCallback();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_resetProperties: function() {
|
||||||
|
this.emit('properties-registered', null);
|
||||||
|
|
||||||
|
if (this._registerPropertiesId != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._registerPropertiesId =
|
||||||
|
this._panelService.connect('register-properties', Lang.bind(this, function(p, props) {
|
||||||
|
if (!props.get(0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._panelService.disconnect(this._registerPropertiesId);
|
||||||
|
this._registerPropertiesId = 0;
|
||||||
|
|
||||||
|
this.emit('properties-registered', props);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateProperty: function(panel, prop) {
|
||||||
|
this.emit('property-updated', prop);
|
||||||
|
},
|
||||||
|
|
||||||
|
activateProperty: function(key, state) {
|
||||||
|
this._panelService.property_activate(key, state);
|
||||||
|
},
|
||||||
|
|
||||||
|
hasProperties: function(id) {
|
||||||
|
if (id == 'anthy')
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
getEngineDesc: function(id) {
|
getEngineDesc: function(id) {
|
||||||
if (!IBus || !this._ready)
|
if (!IBus || !this._ready)
|
||||||
return null;
|
return null;
|
||||||
@@ -123,6 +164,7 @@ const IBusManager = new Lang.Class({
|
|||||||
return this._engines[id];
|
return this._engines[id];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
Signals.addSignalMethods(IBusManager.prototype);
|
||||||
|
|
||||||
const LayoutMenuItem = new Lang.Class({
|
const LayoutMenuItem = new Lang.Class({
|
||||||
Name: 'LayoutMenuItem',
|
Name: 'LayoutMenuItem',
|
||||||
@@ -135,6 +177,7 @@ const LayoutMenuItem = new Lang.Class({
|
|||||||
this.indicator = new St.Label({ text: shortName });
|
this.indicator = new St.Label({ text: shortName });
|
||||||
this.addActor(this.label);
|
this.addActor(this.label);
|
||||||
this.addActor(this.indicator);
|
this.addActor(this.indicator);
|
||||||
|
this.actor.label_actor = this.label;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -142,6 +185,12 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
Name: 'InputSourceIndicator',
|
Name: 'InputSourceIndicator',
|
||||||
Extends: PanelMenu.Button,
|
Extends: PanelMenu.Button,
|
||||||
|
|
||||||
|
_propertiesWhitelist: [
|
||||||
|
'InputMode',
|
||||||
|
'TypingMode',
|
||||||
|
'DictMode'
|
||||||
|
],
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(0.0, _("Keyboard"));
|
this.parent(0.0, _("Keyboard"));
|
||||||
|
|
||||||
@@ -162,56 +211,73 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
this._currentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
this._currentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
||||||
this._xkbInfo = new GnomeDesktop.XkbInfo();
|
this._xkbInfo = new GnomeDesktop.XkbInfo();
|
||||||
|
|
||||||
this._ibusManager = new IBusManager(Lang.bind(this, this._inputSourcesChanged));
|
this._propSeparator = new PopupMenu.PopupSeparatorMenuItem();
|
||||||
|
this.menu.addMenuItem(this._propSeparator);
|
||||||
|
this._propSection = new PopupMenu.PopupMenuSection();
|
||||||
|
this.menu.addMenuItem(this._propSection);
|
||||||
|
this._propSection.actor.hide();
|
||||||
|
|
||||||
|
this._properties = null;
|
||||||
|
|
||||||
|
this._ibusManager = new IBusManager(Lang.bind(this, this._inputSourcesChanged));
|
||||||
|
this._ibusManager.connect('properties-registered', Lang.bind(this, this._ibusPropertiesRegistered));
|
||||||
|
this._ibusManager.connect('property-updated', Lang.bind(this, this._ibusPropertyUpdated));
|
||||||
this._inputSourcesChanged();
|
this._inputSourcesChanged();
|
||||||
|
|
||||||
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
|
||||||
|
|
||||||
|
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||||
|
this._sessionUpdated();
|
||||||
|
|
||||||
|
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
|
||||||
|
},
|
||||||
|
|
||||||
|
_sessionUpdated: function() {
|
||||||
// re-using "allowSettings" for the keyboard layout is a bit shady,
|
// re-using "allowSettings" for the keyboard layout is a bit shady,
|
||||||
// but at least for now it is used as "allow popping up windows
|
// but at least for now it is used as "allow popping up windows
|
||||||
// from shell menus"; we can always add a separate sessionMode
|
// from shell menus"; we can always add a separate sessionMode
|
||||||
// option if need arises.
|
// option if need arises.
|
||||||
if (Main.sessionMode.allowSettings) {
|
this._showLayoutItem.actor.visible = Main.sessionMode.allowSettings;
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
||||||
this._showLayoutItem = this.menu.addAction(_("Show Keyboard Layout"), Lang.bind(this, this._showLayout));
|
|
||||||
}
|
|
||||||
this.menu.addSettingsAction(_("Region and Language Settings"), 'gnome-region-panel.desktop');
|
|
||||||
},
|
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
if (Main.sessionMode.allowSettings) {
|
|
||||||
this._showLayoutItem.actor.visible = !locked;
|
|
||||||
}
|
|
||||||
this.menu.setSettingsVisibility(!locked);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_currentInputSourceChanged: function() {
|
_currentInputSourceChanged: function() {
|
||||||
let nVisibleSources = Object.keys(this._layoutItems).length;
|
let nVisibleSources = Object.keys(this._layoutItems).length;
|
||||||
if (nVisibleSources < 2)
|
|
||||||
return;
|
|
||||||
|
|
||||||
let nSources = this._settings.get_value(KEY_INPUT_SOURCES).n_children();
|
|
||||||
let newCurrentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
let newCurrentSourceIndex = this._settings.get_uint(KEY_CURRENT_INPUT_SOURCE);
|
||||||
if (newCurrentSourceIndex >= nSources)
|
let newLayoutItem = this._layoutItems[newCurrentSourceIndex];
|
||||||
return;
|
let hasProperties;
|
||||||
|
|
||||||
if (!this._layoutItems[newCurrentSourceIndex]) {
|
if (newLayoutItem)
|
||||||
// This source index is invalid as we weren't able to
|
hasProperties = this._ibusManager.hasProperties(newLayoutItem.ibusEngineId);
|
||||||
// build a menu item for it, so we hide ourselves since we
|
else
|
||||||
// can't fix it here. *shrug*
|
hasProperties = false;
|
||||||
|
|
||||||
|
if (!newLayoutItem || (nVisibleSources < 2 && !hasProperties)) {
|
||||||
|
// This source index might be invalid if we weren't able
|
||||||
|
// to build a menu item for it, so we hide ourselves since
|
||||||
|
// we can't fix it here. *shrug*
|
||||||
|
|
||||||
|
// We also hide if we have only one visible source unless
|
||||||
|
// it's an IBus source with properties.
|
||||||
this.menu.close();
|
this.menu.close();
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
this.actor.show();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.actor.show();
|
||||||
|
|
||||||
if (this._layoutItems[this._currentSourceIndex]) {
|
if (this._layoutItems[this._currentSourceIndex]) {
|
||||||
this._layoutItems[this._currentSourceIndex].setShowDot(false);
|
this._layoutItems[this._currentSourceIndex].setShowDot(false);
|
||||||
this._container.set_skip_paint(this._labelActors[this._currentSourceIndex], true);
|
this._container.set_skip_paint(this._labelActors[this._currentSourceIndex], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._layoutItems[newCurrentSourceIndex].setShowDot(true);
|
newLayoutItem.setShowDot(true);
|
||||||
this._container.set_skip_paint(this._labelActors[newCurrentSourceIndex], false);
|
|
||||||
|
let newLabelActor = this._labelActors[newCurrentSourceIndex];
|
||||||
|
this._container.set_skip_paint(newLabelActor, false);
|
||||||
|
|
||||||
|
if (hasProperties)
|
||||||
|
newLabelActor.set_text(newLayoutItem.indicator.get_text());
|
||||||
|
|
||||||
this._currentSourceIndex = newCurrentSourceIndex;
|
this._currentSourceIndex = newCurrentSourceIndex;
|
||||||
},
|
},
|
||||||
@@ -242,9 +308,12 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
} else if (type == INPUT_SOURCE_TYPE_IBUS) {
|
} else if (type == INPUT_SOURCE_TYPE_IBUS) {
|
||||||
let engineDesc = this._ibusManager.getEngineDesc(id);
|
let engineDesc = this._ibusManager.getEngineDesc(id);
|
||||||
if (engineDesc) {
|
if (engineDesc) {
|
||||||
|
let language = IBus.get_language_name(engineDesc.get_language());
|
||||||
|
|
||||||
info.exists = true;
|
info.exists = true;
|
||||||
info.displayName = engineDesc.get_longname();
|
info.displayName = language + ' (' + engineDesc.get_longname() + ')';
|
||||||
info.shortName = engineDesc.get_symbol();
|
info.shortName = this._makeEngineShortName(engineDesc);
|
||||||
|
info.ibusEngineId = id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,13 +328,6 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
infos.push(info);
|
infos.push(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (infos.length > 1) {
|
|
||||||
this.actor.show();
|
|
||||||
} else {
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.hide();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < infos.length; i++) {
|
for (let i = 0; i < infos.length; i++) {
|
||||||
let info = infos[i];
|
let info = infos[i];
|
||||||
if (infosByShortName[info.shortName].length > 1) {
|
if (infosByShortName[info.shortName].length > 1) {
|
||||||
@@ -274,6 +336,7 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let item = new LayoutMenuItem(info.displayName, info.shortName);
|
let item = new LayoutMenuItem(info.displayName, info.shortName);
|
||||||
|
item.ibusEngineId = info.ibusEngineId;
|
||||||
this._layoutItems[info.sourceIndex] = item;
|
this._layoutItems[info.sourceIndex] = item;
|
||||||
this.menu.addMenuItem(item, i);
|
this.menu.addMenuItem(item, i);
|
||||||
item.connect('activate', Lang.bind(this, function() {
|
item.connect('activate', Lang.bind(this, function() {
|
||||||
@@ -319,6 +382,146 @@ const InputSourceIndicator = new Lang.Class({
|
|||||||
Util.spawn(['gkbd-keyboard-display', '-l', description]);
|
Util.spawn(['gkbd-keyboard-display', '-l', description]);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_makeEngineShortName: function(engineDesc) {
|
||||||
|
let symbol = engineDesc.get_symbol();
|
||||||
|
if (symbol && symbol[0])
|
||||||
|
return symbol;
|
||||||
|
|
||||||
|
let langCode = engineDesc.get_language().split('_', 1)[0];
|
||||||
|
if (langCode.length == 2 || langCode.length == 3)
|
||||||
|
return langCode.toLowerCase();
|
||||||
|
|
||||||
|
return String.fromCharCode(0x2328); // keyboard glyph
|
||||||
|
},
|
||||||
|
|
||||||
|
_propertyWhitelisted: function(prop) {
|
||||||
|
for (let i = 0; i < this._propertiesWhitelist.length; ++i) {
|
||||||
|
let key = prop.get_key();
|
||||||
|
if (key.substr(0, this._propertiesWhitelist[i].length) == this._propertiesWhitelist[i])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_ibusPropertiesRegistered: function(im, props) {
|
||||||
|
this._properties = props;
|
||||||
|
this._buildPropSection();
|
||||||
|
},
|
||||||
|
|
||||||
|
_ibusPropertyUpdated: function(im, prop) {
|
||||||
|
if (!this._propertyWhitelisted(prop))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (this._updateSubProperty(this._properties, prop))
|
||||||
|
this._buildPropSection();
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateSubProperty: function(props, prop) {
|
||||||
|
if (!props)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let p;
|
||||||
|
for (let i = 0; (p = props.get(i)) != null; ++i) {
|
||||||
|
if (p.get_key() == prop.get_key() && p.get_prop_type() == prop.get_prop_type()) {
|
||||||
|
p.update(prop);
|
||||||
|
return true;
|
||||||
|
} else if (p.get_prop_type() == IBus.PropType.MENU) {
|
||||||
|
if (this._updateSubProperty(p.get_sub_props(), prop))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateIndicatorLabel: function(text) {
|
||||||
|
let layoutItem = this._layoutItems[this._currentSourceIndex];
|
||||||
|
let hasProperties;
|
||||||
|
|
||||||
|
if (layoutItem)
|
||||||
|
hasProperties = this._ibusManager.hasProperties(layoutItem.ibusEngineId);
|
||||||
|
else
|
||||||
|
hasProperties = false;
|
||||||
|
|
||||||
|
if (hasProperties)
|
||||||
|
this._labelActors[this._currentSourceIndex].set_text(text);
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildPropSection: function() {
|
||||||
|
this._propSeparator.actor.hide();
|
||||||
|
this._propSection.actor.hide();
|
||||||
|
this._propSection.removeAll();
|
||||||
|
|
||||||
|
this._buildPropSubMenu(this._propSection, this._properties);
|
||||||
|
|
||||||
|
if (!this._propSection.isEmpty()) {
|
||||||
|
this._propSection.actor.show();
|
||||||
|
this._propSeparator.actor.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildPropSubMenu: function(menu, props) {
|
||||||
|
if (!props)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let radioGroup = [];
|
||||||
|
let p;
|
||||||
|
for (let i = 0; (p = props.get(i)) != null; ++i) {
|
||||||
|
let prop = p;
|
||||||
|
|
||||||
|
if (!this._propertyWhitelisted(prop) ||
|
||||||
|
!prop.get_visible())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (prop.get_key() == 'InputMode') {
|
||||||
|
let text;
|
||||||
|
if (prop.get_symbol)
|
||||||
|
text = prop.get_symbol().get_text();
|
||||||
|
else
|
||||||
|
text = prop.get_label().get_text();
|
||||||
|
|
||||||
|
if (text && text.length > 0 && text.length < 3)
|
||||||
|
this._updateIndicatorLabel(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
let item;
|
||||||
|
let type = prop.get_prop_type();
|
||||||
|
if (type == IBus.PropType.MENU) {
|
||||||
|
item = new PopupMenu.PopupSubMenuMenuItem(prop.get_label().get_text());
|
||||||
|
this._buildPropSubMenu(item.menu, prop.get_sub_props());
|
||||||
|
} else if (type == IBus.PropType.RADIO) {
|
||||||
|
item = new PopupMenu.PopupMenuItem(prop.get_label().get_text());
|
||||||
|
item.prop = prop;
|
||||||
|
radioGroup.push(item);
|
||||||
|
item.radioGroup = radioGroup;
|
||||||
|
item.setShowDot(prop.get_state() == IBus.PropState.CHECKED);
|
||||||
|
item.connect('activate', Lang.bind(this, function() {
|
||||||
|
if (item.prop.get_state() == IBus.PropState.CHECKED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let group = item.radioGroup;
|
||||||
|
for (let i = 0; i < group.length; ++i) {
|
||||||
|
if (group[i] == item) {
|
||||||
|
item.setShowDot(true);
|
||||||
|
item.prop.set_state(IBus.PropState.CHECKED);
|
||||||
|
this._ibusManager.activateProperty(item.prop.get_key(),
|
||||||
|
IBus.PropState.CHECKED);
|
||||||
|
} else {
|
||||||
|
group[i].setShowDot(false);
|
||||||
|
group[i].prop.set_state(IBus.PropState.UNCHECKED);
|
||||||
|
this._ibusManager.activateProperty(group[i].prop.get_key(),
|
||||||
|
IBus.PropState.UNCHECKED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.setSensitive(prop.get_sensitive());
|
||||||
|
menu.addMenuItem(item);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_containerGetPreferredWidth: function(container, for_height, alloc) {
|
_containerGetPreferredWidth: function(container, for_height, alloc) {
|
||||||
// Here, and in _containerGetPreferredHeight, we need to query
|
// Here, and in _containerGetPreferredHeight, we need to query
|
||||||
// for the height of all children, but we ignore the results
|
// for the height of all children, but we ignore the results
|
||||||
|
|||||||
57
js/ui/status/lockScreenMenu.js
Normal file
57
js/ui/status/lockScreenMenu.js
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const GObject = imports.gi.GObject;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
const VolumeMenu = imports.ui.status.volume;
|
||||||
|
|
||||||
|
const Indicator = new Lang.Class({
|
||||||
|
Name: 'LockScreenMenuIndicator',
|
||||||
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent(null, _("Volume, network, battery"));
|
||||||
|
|
||||||
|
this._volume = Main.panel.statusArea.volume;
|
||||||
|
if (this._volume) {
|
||||||
|
this._volumeIcon = this.addIcon(null);
|
||||||
|
this._volume.mainIcon.bind_property('gicon', this._volumeIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._volume.mainIcon.bind_property('visible', this._volumeIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
|
this._volumeControl = VolumeMenu.getMixerControl();
|
||||||
|
this._volumeMenu = new VolumeMenu.VolumeMenu(this._volumeControl);
|
||||||
|
this.menu.addMenuItem(this._volumeMenu);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._network = Main.panel.statusArea.network;
|
||||||
|
if (this._network) {
|
||||||
|
this._networkIcon = this.addIcon(null);
|
||||||
|
this._network.mainIcon.bind_property('gicon', this._networkIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._network.mainIcon.bind_property('visible', this._networkIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
|
this._networkSecondaryIcon = this.addIcon(null);
|
||||||
|
this._network.secondaryIcon.bind_property('gicon', this._networkSecondaryIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._network.secondaryIcon.bind_property('visible', this._networkSecondaryIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._battery = Main.panel.statusArea.battery;
|
||||||
|
if (this._battery) {
|
||||||
|
this._batteryIcon = this.addIcon(null);
|
||||||
|
this._battery.mainIcon.bind_property('gicon', this._batteryIcon, 'gicon',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._battery.mainIcon.bind_property('visible', this._batteryIcon, 'visible',
|
||||||
|
GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const GObject = imports.gi.GObject;
|
const GObject = imports.gi.GObject;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const NetworkManager = imports.gi.NetworkManager;
|
const NetworkManager = imports.gi.NetworkManager;
|
||||||
const NMClient = imports.gi.NMClient;
|
const NMClient = imports.gi.NMClient;
|
||||||
@@ -121,7 +122,7 @@ const NMNetworkMenuItem = new Lang.Class({
|
|||||||
this._secureIcon = new St.Icon({ style_class: 'popup-menu-icon' });
|
this._secureIcon = new St.Icon({ style_class: 'popup-menu-icon' });
|
||||||
if (this.bestAP._secType != NMAccessPointSecurity.UNKNOWN &&
|
if (this.bestAP._secType != NMAccessPointSecurity.UNKNOWN &&
|
||||||
this.bestAP._secType != NMAccessPointSecurity.NONE)
|
this.bestAP._secType != NMAccessPointSecurity.NONE)
|
||||||
this._secureIcon.icon_name = 'network-wireless-encrypted';
|
this._secureIcon.icon_name = 'network-wireless-encrypted-symbolic';
|
||||||
this._icons.add_actor(this._secureIcon);
|
this._icons.add_actor(this._secureIcon);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -132,9 +133,9 @@ const NMNetworkMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
_getIcon: function() {
|
_getIcon: function() {
|
||||||
if (this.bestAP.mode == NM80211Mode.ADHOC)
|
if (this.bestAP.mode == NM80211Mode.ADHOC)
|
||||||
return 'network-workgroup';
|
return 'network-workgroup-symbolic';
|
||||||
else
|
else
|
||||||
return 'network-wireless-signal-' + signalToIcon(this.bestAP.strength);
|
return 'network-wireless-signal-' + signalToIcon(this.bestAP.strength) + '-symbolic';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -167,15 +168,14 @@ const NMWiredSectionTitleMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
let newState = this._switch.state;
|
let newState = this._switch.state;
|
||||||
|
|
||||||
// Immediately reset the switch to false, it will be updated appropriately
|
let ok;
|
||||||
// by state-changed signals in devices (but fixes the VPN not being in sync
|
|
||||||
// if the ActiveConnection object is never seen by libnm-glib)
|
|
||||||
this._switch.setToggleState(false);
|
|
||||||
|
|
||||||
if (newState)
|
if (newState)
|
||||||
this._device.activate();
|
ok = this._device.activate();
|
||||||
else
|
else
|
||||||
this._device.deactivate();
|
ok = this._device.deactivate();
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
this._switch.setToggleState(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -233,20 +233,11 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const NMDevice = new Lang.Class({
|
const NMConnectionBased = new Lang.Class({
|
||||||
Name: 'NMDevice',
|
Name: 'NMConnectionBased',
|
||||||
Abstract: true,
|
Abstract: true,
|
||||||
|
|
||||||
_init: function(client, device, connections) {
|
_init: function(connections) {
|
||||||
this.device = device;
|
|
||||||
if (device) {
|
|
||||||
this.device._delegate = this;
|
|
||||||
this._stateChangedId = this.device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
|
|
||||||
} else
|
|
||||||
this._stateChangedId = 0;
|
|
||||||
|
|
||||||
// protected
|
|
||||||
this._client = client;
|
|
||||||
this._connections = [ ];
|
this._connections = [ ];
|
||||||
for (let i = 0; i < connections.length; i++) {
|
for (let i = 0; i < connections.length; i++) {
|
||||||
if (!connections[i].get_uuid())
|
if (!connections[i].get_uuid())
|
||||||
@@ -264,93 +255,6 @@ const NMDevice = new Lang.Class({
|
|||||||
this._connections.push(obj);
|
this._connections.push(obj);
|
||||||
}
|
}
|
||||||
this._connections.sort(this._connectionSortFunction);
|
this._connections.sort(this._connectionSortFunction);
|
||||||
this._activeConnection = null;
|
|
||||||
this._activeConnectionItem = null;
|
|
||||||
this._autoConnectionItem = null;
|
|
||||||
this._overflowItem = null;
|
|
||||||
|
|
||||||
if (this.device) {
|
|
||||||
this.statusItem = new PopupMenu.PopupSwitchMenuItem(this._getDescription(), this.connected, { style_class: 'popup-subtitle-menu-item' });
|
|
||||||
this._statusChanged = this.statusItem.connect('toggled', Lang.bind(this, function(item, state) {
|
|
||||||
if (state)
|
|
||||||
this.activate();
|
|
||||||
else
|
|
||||||
this.deactivate();
|
|
||||||
this.emit('enabled-changed');
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._updateStatusItem();
|
|
||||||
}
|
|
||||||
this.section = new PopupMenu.PopupMenuSection();
|
|
||||||
|
|
||||||
this._deferredWorkId = Main.initializeDeferredWork(this.section.actor, Lang.bind(this, this._createSection));
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
if (this.device)
|
|
||||||
this.device._delegate = null;
|
|
||||||
|
|
||||||
if (this._stateChangedId) {
|
|
||||||
// Need to go through GObject.Object.prototype because
|
|
||||||
// nm_device_disconnect conflicts with g_signal_disconnect
|
|
||||||
GObject.Object.prototype.disconnect.call(this.device, this._stateChangedId);
|
|
||||||
this._stateChangedId = 0;
|
|
||||||
}
|
|
||||||
if (this._carrierChangedId) {
|
|
||||||
// see above for why this is needed
|
|
||||||
GObject.Object.prototype.disconnect.call(this.device, this._carrierChangedId);
|
|
||||||
this._carrierChangedId = 0;
|
|
||||||
}
|
|
||||||
if (this._firmwareChangedId) {
|
|
||||||
GObject.Object.prototype.disconnect.call(this.device, this._firmwareChangedId);
|
|
||||||
this._firmwareChangedId = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._clearSection();
|
|
||||||
if (this.statusItem)
|
|
||||||
this.statusItem.destroy();
|
|
||||||
this.section.destroy();
|
|
||||||
},
|
|
||||||
|
|
||||||
deactivate: function() {
|
|
||||||
this.device.disconnect(null);
|
|
||||||
},
|
|
||||||
|
|
||||||
activate: function() {
|
|
||||||
if (this._activeConnection)
|
|
||||||
// nothing to do
|
|
||||||
return;
|
|
||||||
|
|
||||||
// pick the most recently used connection and connect to that
|
|
||||||
// or if no connections ever set, create an automatic one
|
|
||||||
if (this._connections.length > 0) {
|
|
||||||
this._client.activate_connection(this._connections[0].connection, this.device, null, null);
|
|
||||||
} else if (this._autoConnectionName) {
|
|
||||||
let connection = this._createAutomaticConnection();
|
|
||||||
if (connection)
|
|
||||||
this._client.add_and_activate_connection(connection, this.device, null, null);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
get connected() {
|
|
||||||
return this.device.state == NetworkManager.DeviceState.ACTIVATED;
|
|
||||||
},
|
|
||||||
|
|
||||||
setActiveConnection: function(activeConnection) {
|
|
||||||
if (activeConnection == this._activeConnection)
|
|
||||||
// nothing to do
|
|
||||||
return;
|
|
||||||
|
|
||||||
// remove any UI
|
|
||||||
if (this._activeConnectionItem) {
|
|
||||||
this._activeConnectionItem.destroy();
|
|
||||||
this._activeConnectionItem = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._activeConnection = activeConnection;
|
|
||||||
|
|
||||||
this._clearSection();
|
|
||||||
this._queueCreateSection();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
checkConnection: function(connection) {
|
checkConnection: function(connection) {
|
||||||
@@ -388,7 +292,6 @@ const NMDevice = new Lang.Class({
|
|||||||
};
|
};
|
||||||
Util.insertSorted(this._connections, obj, this._connectionSortFunction);
|
Util.insertSorted(this._connections, obj, this._connectionSortFunction);
|
||||||
|
|
||||||
this._clearSection();
|
|
||||||
this._queueCreateSection();
|
this._queueCreateSection();
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -408,13 +311,17 @@ const NMDevice = new Lang.Class({
|
|||||||
// We need to show the automatic connection again
|
// We need to show the automatic connection again
|
||||||
// (or in the case of NMDeviceWired, we want to hide
|
// (or in the case of NMDeviceWired, we want to hide
|
||||||
// the only explicit connection)
|
// the only explicit connection)
|
||||||
this._clearSection();
|
|
||||||
this._queueCreateSection();
|
this._queueCreateSection();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
connectionValid: function(connection) {
|
_findConnection: function(uuid) {
|
||||||
return this.device.connection_valid(connection);
|
for (let i = 0; i < this._connections.length; i++) {
|
||||||
|
let obj = this._connections[i];
|
||||||
|
if (obj.uuid == uuid)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
_connectionSortFunction: function(one, two) {
|
_connectionSortFunction: function(one, two) {
|
||||||
@@ -423,10 +330,136 @@ const NMDevice = new Lang.Class({
|
|||||||
|
|
||||||
return two.timestamp - one.timestamp;
|
return two.timestamp - one.timestamp;
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
Signals.addSignalMethods(NMConnectionBased.prototype);
|
||||||
|
|
||||||
|
const NMDevice = new Lang.Class({
|
||||||
|
Name: 'NMDevice',
|
||||||
|
Abstract: true,
|
||||||
|
Extends: NMConnectionBased,
|
||||||
|
|
||||||
|
_init: function(client, device, connections) {
|
||||||
|
this.device = device;
|
||||||
|
this.device._delegate = this;
|
||||||
|
this._stateChangedId = this.device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
|
||||||
|
|
||||||
|
// protected
|
||||||
|
this._client = client;
|
||||||
|
this.parent(connections);
|
||||||
|
this._activeConnection = null;
|
||||||
|
this._activeConnectionItem = null;
|
||||||
|
this._autoConnectionItem = null;
|
||||||
|
this._overflowItem = null;
|
||||||
|
|
||||||
|
this.statusItem = new PopupMenu.PopupSwitchMenuItem(this._getDescription(), this.connected, { style_class: 'popup-subtitle-menu-item' });
|
||||||
|
this._statusChanged = this.statusItem.connect('toggled', Lang.bind(this, function(item, state) {
|
||||||
|
let ok;
|
||||||
|
if (state)
|
||||||
|
ok = this.activate();
|
||||||
|
else
|
||||||
|
ok = this.deactivate();
|
||||||
|
|
||||||
|
if (!ok)
|
||||||
|
item.setToggleState(!state);
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._updateStatusItem();
|
||||||
|
this.section = new PopupMenu.PopupMenuSection();
|
||||||
|
|
||||||
|
this._deferredWorkId = Main.initializeDeferredWork(this.section.actor, Lang.bind(this, this._createSection));
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
if (this.device)
|
||||||
|
this.device._delegate = null;
|
||||||
|
|
||||||
|
if (this._stateChangedId) {
|
||||||
|
// Need to go through GObject.Object.prototype because
|
||||||
|
// nm_device_disconnect conflicts with g_signal_disconnect
|
||||||
|
GObject.Object.prototype.disconnect.call(this.device, this._stateChangedId);
|
||||||
|
this._stateChangedId = 0;
|
||||||
|
}
|
||||||
|
if (this._carrierChangedId) {
|
||||||
|
// see above for why this is needed
|
||||||
|
GObject.Object.prototype.disconnect.call(this.device, this._carrierChangedId);
|
||||||
|
this._carrierChangedId = 0;
|
||||||
|
}
|
||||||
|
if (this._firmwareChangedId) {
|
||||||
|
GObject.Object.prototype.disconnect.call(this.device, this._firmwareChangedId);
|
||||||
|
this._firmwareChangedId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._clearSection();
|
||||||
|
if (this.statusItem)
|
||||||
|
this.statusItem.destroy();
|
||||||
|
this.section.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
deactivate: function() {
|
||||||
|
this.device.disconnect(null);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
activate: function() {
|
||||||
|
if (this._activeConnection)
|
||||||
|
// nothing to do
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// If there is only one connection available, use that
|
||||||
|
// Otherwise, if no connection is currently configured,
|
||||||
|
// try automatic configuration (or summon the config dialog)
|
||||||
|
if (this._connections.length == 1) {
|
||||||
|
this._client.activate_connection(this._connections[0].connection, this.device, null, null);
|
||||||
|
return true;
|
||||||
|
} else if (this._connections.length == 0) {
|
||||||
|
return this._activateAutomaticConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_activateAutomaticConnection: function() {
|
||||||
|
let connection = this._createAutomaticConnection();
|
||||||
|
if (connection) {
|
||||||
|
this._client.add_and_activate_connection(connection, this.device, null, null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
get connected() {
|
||||||
|
return this.device.state == NetworkManager.DeviceState.ACTIVATED;
|
||||||
|
},
|
||||||
|
|
||||||
|
clearActiveConnection: function(activeConnection) {
|
||||||
|
this.setActiveConnection(null);
|
||||||
|
},
|
||||||
|
|
||||||
|
setActiveConnection: function(activeConnection) {
|
||||||
|
if (activeConnection == this._activeConnection)
|
||||||
|
// nothing to do
|
||||||
|
return;
|
||||||
|
|
||||||
|
// remove any UI
|
||||||
|
if (this._activeConnectionItem) {
|
||||||
|
this._activeConnectionItem.destroy();
|
||||||
|
this._activeConnectionItem = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._activeConnection = activeConnection;
|
||||||
|
|
||||||
|
this._clearSection();
|
||||||
|
this._queueCreateSection();
|
||||||
|
},
|
||||||
|
|
||||||
|
connectionValid: function(connection) {
|
||||||
|
return this.device.connection_valid(connection);
|
||||||
|
},
|
||||||
|
|
||||||
setEnabled: function(enabled) {
|
setEnabled: function(enabled) {
|
||||||
// do nothing by default, we want to keep the conneciton list visible
|
// do nothing by default, we want to keep the conneciton list visible
|
||||||
// in the majority of cases (wired, wwan, vpn)
|
// in the majority of cases (wired, wwan)
|
||||||
},
|
},
|
||||||
|
|
||||||
getStatusLabel: function() {
|
getStatusLabel: function() {
|
||||||
@@ -484,15 +517,6 @@ const NMDevice = new Lang.Class({
|
|||||||
throw new TypeError('Invoking pure virtual function NMDevice.createAutomaticConnection');
|
throw new TypeError('Invoking pure virtual function NMDevice.createAutomaticConnection');
|
||||||
},
|
},
|
||||||
|
|
||||||
_findConnection: function(uuid) {
|
|
||||||
for (let i = 0; i < this._connections.length; i++) {
|
|
||||||
let obj = this._connections[i];
|
|
||||||
if (obj.uuid == uuid)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
_queueCreateSection: function() {
|
_queueCreateSection: function() {
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
Main.queueDeferredWork(this._deferredWorkId);
|
Main.queueDeferredWork(this._deferredWorkId);
|
||||||
@@ -636,8 +660,6 @@ const NMDevice = new Lang.Class({
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(NMDevice.prototype);
|
|
||||||
|
|
||||||
|
|
||||||
const NMDeviceWired = new Lang.Class({
|
const NMDeviceWired = new Lang.Class({
|
||||||
Name: 'NMDeviceWired',
|
Name: 'NMDeviceWired',
|
||||||
@@ -760,7 +782,7 @@ const NMDeviceModem = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_getSignalIcon: function() {
|
_getSignalIcon: function() {
|
||||||
return 'network-cellular-signal-' + signalToIcon(this.mobileDevice.signal_quality);
|
return 'network-cellular-signal-' + signalToIcon(this.mobileDevice.signal_quality) + '-symbolic';
|
||||||
},
|
},
|
||||||
|
|
||||||
_createSection: function() {
|
_createSection: function() {
|
||||||
@@ -786,13 +808,13 @@ const NMDeviceModem = new Lang.Class({
|
|||||||
this.parent();
|
this.parent();
|
||||||
},
|
},
|
||||||
|
|
||||||
_createAutomaticConnection: function() {
|
_activateAutomaticConnection: function() {
|
||||||
// Mobile wizard is too complex for the shell UI and
|
// Mobile wizard is too complex for the shell UI and
|
||||||
// is handled by the network panel
|
// is handled by the network panel
|
||||||
Util.spawn(['gnome-control-center', 'network',
|
Util.spawn(['gnome-control-center', 'network',
|
||||||
'connect-3g', this.device.get_path()]);
|
'connect-3g', this.device.get_path()]);
|
||||||
return null;
|
return true;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const NMDeviceBluetooth = new Lang.Class({
|
const NMDeviceBluetooth = new Lang.Class({
|
||||||
@@ -821,6 +843,16 @@ const NMDeviceBluetooth = new Lang.Class({
|
|||||||
return connection;
|
return connection;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_activateAutomaticConnection: function() {
|
||||||
|
// FIXME: DUN devices are configured like modems, so
|
||||||
|
// we need to spawn the mobile wizard
|
||||||
|
// but the network panel doesn't support bluetooth at the moment
|
||||||
|
// so we just create an empty connection and hope
|
||||||
|
// that this phone supports PAN
|
||||||
|
|
||||||
|
return this.parent();
|
||||||
|
},
|
||||||
|
|
||||||
_makeConnectionName: function(device) {
|
_makeConnectionName: function(device) {
|
||||||
let name = device.name;
|
let name = device.name;
|
||||||
if (name)
|
if (name)
|
||||||
@@ -842,95 +874,6 @@ const NMDeviceBluetooth = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// Not a real device, but I save a lot code this way
|
|
||||||
const NMDeviceVPN = new Lang.Class({
|
|
||||||
Name: 'NMDeviceVPN',
|
|
||||||
Extends: NMDevice,
|
|
||||||
|
|
||||||
_init: function(client, device, connections) {
|
|
||||||
// Disable autoconnections
|
|
||||||
this._autoConnectionName = null;
|
|
||||||
this.category = NMConnectionCategory.VPN;
|
|
||||||
|
|
||||||
this.parent(client, null, connections);
|
|
||||||
},
|
|
||||||
|
|
||||||
connectionValid: function(connection) {
|
|
||||||
return connection._type == NetworkManager.SETTING_VPN_SETTING_NAME;
|
|
||||||
},
|
|
||||||
|
|
||||||
get empty() {
|
|
||||||
return this._connections.length == 0;
|
|
||||||
},
|
|
||||||
|
|
||||||
get connected() {
|
|
||||||
if (!this._activeConnection)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return this._activeConnection.vpn_state == NetworkManager.VPNConnectionState.ACTIVATED;
|
|
||||||
},
|
|
||||||
|
|
||||||
setActiveConnection: function(activeConnection) {
|
|
||||||
if (this._stateChangeId)
|
|
||||||
this._activeConnection.disconnect(this._stateChangeId);
|
|
||||||
this._stateChangeId = 0;
|
|
||||||
|
|
||||||
this.parent(activeConnection);
|
|
||||||
|
|
||||||
if (this._activeConnection)
|
|
||||||
this._stateChangeId = this._activeConnection.connect('vpn-state-changed',
|
|
||||||
Lang.bind(this, this._connectionStateChanged));
|
|
||||||
|
|
||||||
this.emit('state-changed');
|
|
||||||
},
|
|
||||||
|
|
||||||
_shouldShowConnectionList: function() {
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
deactivate: function() {
|
|
||||||
if (this._activeConnection)
|
|
||||||
this._client.deactivate_connection(this._activeConnection);
|
|
||||||
},
|
|
||||||
|
|
||||||
getStatusLabel: function() {
|
|
||||||
if (!this._activeConnection) // Same as DISCONNECTED
|
|
||||||
return null;
|
|
||||||
|
|
||||||
switch(this._activeConnection.vpn_state) {
|
|
||||||
case NetworkManager.VPNConnectionState.DISCONNECTED:
|
|
||||||
case NetworkManager.VPNConnectionState.ACTIVATED:
|
|
||||||
return null;
|
|
||||||
case NetworkManager.VPNConnectionState.PREPARE:
|
|
||||||
case NetworkManager.VPNConnectionState.CONNECT:
|
|
||||||
case NetworkManager.VPNConnectionState.IP_CONFIG_GET:
|
|
||||||
return _("connecting...");
|
|
||||||
case NetworkManager.VPNConnectionState.NEED_AUTH:
|
|
||||||
/* Translators: this is for network connections that require some kind of key or password */
|
|
||||||
return _("authentication required");
|
|
||||||
case NetworkManager.VPNConnectionState.FAILED:
|
|
||||||
return _("connection failed");
|
|
||||||
default:
|
|
||||||
log('VPN connection state invalid, is %d'.format(this.device.state));
|
|
||||||
return 'invalid';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_connectionStateChanged: function(connection, newstate, reason) {
|
|
||||||
if (newstate == NetworkManager.VPNConnectionState.FAILED) {
|
|
||||||
// FIXME: if we ever want to show something based on reason,
|
|
||||||
// we need to convert from NetworkManager.VPNConnectionStateReason
|
|
||||||
// to NetworkManager.DeviceStateReason
|
|
||||||
this.emit('activation-failed', reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Differently from real NMDevices, there is no need to queue
|
|
||||||
// an update of the menu section, contents wouldn't change anyway
|
|
||||||
this.emit('state-changed');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const NMDeviceWireless = new Lang.Class({
|
const NMDeviceWireless = new Lang.Class({
|
||||||
Name: 'NMDeviceWireless',
|
Name: 'NMDeviceWireless',
|
||||||
Extends: NMDevice,
|
Extends: NMDevice,
|
||||||
@@ -1041,44 +984,13 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
activate: function() {
|
activate: function() {
|
||||||
if (this._activeConnection)
|
if (this._activeConnection)
|
||||||
// nothing to do
|
// nothing to do
|
||||||
return;
|
return true;
|
||||||
|
|
||||||
// among all visible networks, pick the last recently used connection
|
// All possible policy we can have here is just broken
|
||||||
let best = null;
|
// NM autoconnects when wifi devices are enabled, and if it
|
||||||
let bestApObj = null;
|
// didn't, there is a good reason
|
||||||
let bestTime = 0;
|
// User, pick a connection from the list, thank you
|
||||||
for (let i = 0; i < this._networks.length; i++) {
|
return false;
|
||||||
let apObj = this._networks[i];
|
|
||||||
for (let j = 0; j < apObj.connections.length; j++) {
|
|
||||||
let connection = apObj.connections[j];
|
|
||||||
if (connection._timestamp > bestTime) {
|
|
||||||
best = connection;
|
|
||||||
bestTime = connection._timestamp;
|
|
||||||
bestApObj = apObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (best) {
|
|
||||||
for (let i = 0; i < bestApObj.accessPoints.length; i++) {
|
|
||||||
let ap = bestApObj.accessPoints[i];
|
|
||||||
if (ap.connection_valid(best)) {
|
|
||||||
this._client.activate_connection(best, this.device, ap.dbus_path, null);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX: what else to do?
|
|
||||||
// for now, just pick a random network
|
|
||||||
// (this function is called in a corner case anyway, that is, only when
|
|
||||||
// the user toggles the switch and has more than one wireless device)
|
|
||||||
if (this._networks.length > 0) {
|
|
||||||
let connection = this._createAutomaticConnection(this._networks[0]);
|
|
||||||
let accessPoints = this._networks[0].accessPoints;
|
|
||||||
this._client.add_and_activate_connection(connection, this.device, accessPoints[0].dbus_path, null);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_notifySsidCb: function(accessPoint) {
|
_notifySsidCb: function(accessPoint) {
|
||||||
@@ -1468,7 +1380,7 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
{ reactive: false });
|
{ reactive: false });
|
||||||
else
|
else
|
||||||
this._activeConnectionItem = new PopupMenu.PopupImageMenuItem(title,
|
this._activeConnectionItem = new PopupMenu.PopupImageMenuItem(title,
|
||||||
'network-wireless-connected',
|
'network-wireless-connected-symbolic',
|
||||||
{ reactive: false });
|
{ reactive: false });
|
||||||
this._activeConnectionItem.setShowDot(true);
|
this._activeConnectionItem.setShowDot(true);
|
||||||
},
|
},
|
||||||
@@ -1562,32 +1474,165 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const NMVPNSection = new Lang.Class({
|
||||||
|
Name: 'NMVPNSection',
|
||||||
|
Extends: NMConnectionBased,
|
||||||
|
category: NMConnectionCategory.VPN,
|
||||||
|
|
||||||
|
_init: function(client, connections) {
|
||||||
|
this.parent(connections);
|
||||||
|
this._client = client;
|
||||||
|
|
||||||
|
this.section = new PopupMenu.PopupMenuSection();
|
||||||
|
this._deferredWorkId = Main.initializeDeferredWork(this.section.actor, Lang.bind(this, this._createSection));
|
||||||
|
},
|
||||||
|
|
||||||
|
get empty() {
|
||||||
|
return this._connections.length == 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
connectionValid: function(connection) {
|
||||||
|
// filtering is done by NMApplet code
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
getStatusLabel: function(activeConnection) {
|
||||||
|
switch(activeConnection.vpn_state) {
|
||||||
|
case NetworkManager.VPNConnectionState.DISCONNECTED:
|
||||||
|
case NetworkManager.VPNConnectionState.ACTIVATED:
|
||||||
|
return null;
|
||||||
|
case NetworkManager.VPNConnectionState.PREPARE:
|
||||||
|
case NetworkManager.VPNConnectionState.CONNECT:
|
||||||
|
case NetworkManager.VPNConnectionState.IP_CONFIG_GET:
|
||||||
|
return _("connecting...");
|
||||||
|
case NetworkManager.VPNConnectionState.NEED_AUTH:
|
||||||
|
/* Translators: this is for network connections that require some kind of key or password */
|
||||||
|
return _("authentication required");
|
||||||
|
case NetworkManager.VPNConnectionState.FAILED:
|
||||||
|
return _("connection failed");
|
||||||
|
default:
|
||||||
|
log('VPN connection state invalid, is %d'.format(this.device.state));
|
||||||
|
return 'invalid';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
clearActiveConnection: function(activeConnection) {
|
||||||
|
let pos = this._findConnection(activeConnection.uuid);
|
||||||
|
if (pos < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let obj = this._connections[pos];
|
||||||
|
obj.active.disconnect(obj.stateChangedId);
|
||||||
|
obj.active = null;
|
||||||
|
|
||||||
|
if (obj.item) {
|
||||||
|
obj.item.setToggleState(false);
|
||||||
|
obj.item.setStatus(null);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setActiveConnection: function(activeConnection) {
|
||||||
|
let pos = this._findConnection(activeConnection.uuid);
|
||||||
|
if (pos < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let obj = this._connections[pos];
|
||||||
|
obj.active = activeConnection;
|
||||||
|
obj.stateChangedId = obj.active.connect('vpn-state-changed',
|
||||||
|
Lang.bind(this, this._connectionStateChanged));
|
||||||
|
|
||||||
|
if (obj.item) {
|
||||||
|
obj.item.setToggleState(obj.active.vpn_state ==
|
||||||
|
NetworkManager.VPNConnectionState.ACTIVATED);
|
||||||
|
obj.item.setStatus(this.getStatusLabel(obj.active));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_queueCreateSection: function() {
|
||||||
|
this.section.removeAll();
|
||||||
|
Main.queueDeferredWork(this._deferredWorkId);
|
||||||
|
},
|
||||||
|
|
||||||
|
_createConnectionItem: function(obj) {
|
||||||
|
let menuItem = new PopupMenu.PopupSwitchMenuItem(obj.name, false,
|
||||||
|
{ style_class: 'popup-subtitle-menu-item' });
|
||||||
|
menuItem.connect('toggled', Lang.bind(this, function(menuItem) {
|
||||||
|
if (menuItem.state) {
|
||||||
|
this._client.activate_connection(obj.connection, null, null, null);
|
||||||
|
// Immediately go back to disconnected, until NM tells us to change
|
||||||
|
menuItem.setToggleState(false);
|
||||||
|
} else if (obj.active) {
|
||||||
|
this._client.deactivate_connection(obj.active);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (obj.active) {
|
||||||
|
menuItem.setToggleState(obj.active.vpn_state ==
|
||||||
|
NetworkManager.VPNConnectionState.ACTIVATED);
|
||||||
|
menuItem.setStatus(this.getStatusLabel(obj.active));
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuItem;
|
||||||
|
},
|
||||||
|
|
||||||
|
_createSection: function() {
|
||||||
|
if (this._connections.length > 0) {
|
||||||
|
this.section.actor.show();
|
||||||
|
|
||||||
|
for(let j = 0; j < this._connections.length; ++j) {
|
||||||
|
let obj = this._connections[j];
|
||||||
|
obj.item = this._createConnectionItem(obj);
|
||||||
|
|
||||||
|
if (j >= NUM_VISIBLE_NETWORKS) {
|
||||||
|
if (!this._overflowItem) {
|
||||||
|
this._overflowItem = new PopupMenu.PopupSubMenuMenuItem(_("More..."));
|
||||||
|
this.section.addMenuItem(this._overflowItem);
|
||||||
|
}
|
||||||
|
this._overflowItem.menu.addMenuItem(obj.item);
|
||||||
|
} else
|
||||||
|
this.section.addMenuItem(obj.item);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.section.actor.hide()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_connectionStateChanged: function(vpnConnection, newstate, reason) {
|
||||||
|
if (newstate == NetworkManager.VPNConnectionState.FAILED) {
|
||||||
|
// FIXME: if we ever want to show something based on reason,
|
||||||
|
// we need to convert from NetworkManager.VPNConnectionStateReason
|
||||||
|
// to NetworkManager.DeviceStateReason
|
||||||
|
this.emit('activation-failed', reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = this._findConnection(vpnConnection.uuid);
|
||||||
|
if (pos >= 0) {
|
||||||
|
let obj = this._connections[pos];
|
||||||
|
if (obj.item) {
|
||||||
|
obj.item.setToggleState(vpnConnection.vpn_state ==
|
||||||
|
NetworkManager.VPNConnectionState.ACTIVATED);
|
||||||
|
obj.item.setStatus(this.getStatusLabel(vpnConnection));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log('Could not find connection for vpn-state-changed handler');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const NMApplet = new Lang.Class({
|
const NMApplet = new Lang.Class({
|
||||||
Name: 'NMApplet',
|
Name: 'NMApplet',
|
||||||
Extends: PanelMenu.Button,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(0.0, _('Network'));
|
this.parent('network-offline-symbolic', _('Network'));
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ name: 'networkMenu' });
|
this.secondaryIcon = this.addIcon(new Gio.ThemedIcon({ name: 'network-vpn-symbolic' }));
|
||||||
this.actor.add_actor (this._box);
|
this.secondaryIcon.hide();
|
||||||
this.actor.add_style_class_name('panel-status-button');
|
|
||||||
|
|
||||||
this._primaryIcon = new St.Icon({ icon_name: 'network-offline',
|
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
|
||||||
style_class: 'system-status-icon' });
|
|
||||||
this._box.add_actor(this._primaryIcon);
|
|
||||||
|
|
||||||
this._secondaryIcon = new St.Icon({ icon_name: 'network-vpn',
|
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
|
||||||
style_class: 'system-status-icon',
|
|
||||||
visible: false });
|
|
||||||
this._box.add_actor(this._secondaryIcon);
|
|
||||||
|
|
||||||
this._client = NMClient.Client.new();
|
this._client = NMClient.Client.new();
|
||||||
|
|
||||||
this._statusSection = new PopupMenu.PopupMenuSection();
|
this._statusSection = new PopupMenu.PopupMenuSection();
|
||||||
this._statusItem = new PopupMenu.PopupMenuItem('', { style_class: 'popup-inactive-menu-item', reactive: false });
|
this._statusItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
||||||
this._statusSection.addMenuItem(this._statusItem);
|
this._statusSection.addMenuItem(this._statusItem);
|
||||||
this._statusSection.addAction(_("Enable networking"), Lang.bind(this, function() {
|
this._statusSection.addAction(_("Enable networking"), Lang.bind(this, function() {
|
||||||
this._client.networking_enabled = true;
|
this._client.networking_enabled = true;
|
||||||
@@ -1639,15 +1684,9 @@ const NMApplet = new Lang.Class({
|
|||||||
this.menu.addMenuItem(this._devices.wwan.section);
|
this.menu.addMenuItem(this._devices.wwan.section);
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
|
||||||
this._devices.vpn = {
|
this._vpnSection = new NMVPNSection(this._client, this._connections);
|
||||||
section: new PopupMenu.PopupMenuSection(),
|
this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));
|
||||||
device: this._makeWrapperDevice(NMDeviceVPN, null),
|
this.menu.addMenuItem(this._vpnSection.section);
|
||||||
item: new NMWiredSectionTitleMenuItem(_("VPN Connections"))
|
|
||||||
};
|
|
||||||
this._devices.vpn.section.addMenuItem(this._devices.vpn.item);
|
|
||||||
this._devices.vpn.section.addMenuItem(this._devices.vpn.device.section);
|
|
||||||
this._devices.vpn.section.actor.hide();
|
|
||||||
this.menu.addMenuItem(this._devices.vpn.section);
|
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
this.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
|
this.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
|
||||||
|
|
||||||
@@ -1691,24 +1730,10 @@ const NMApplet = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
setIcon: function(iconName) {
|
|
||||||
this._primaryIcon.icon_name = iconName;
|
|
||||||
},
|
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
// FIXME: more design discussion is needed before we can
|
|
||||||
// expose part of this menu
|
|
||||||
|
|
||||||
if (locked)
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.reactive = !locked;
|
|
||||||
},
|
|
||||||
|
|
||||||
_ensureSource: function() {
|
_ensureSource: function() {
|
||||||
if (!this._source) {
|
if (!this._source) {
|
||||||
this._source = new MessageTray.Source(_("Network Manager"),
|
this._source = new MessageTray.Source(_("Network Manager"),
|
||||||
'network-transmit-receive',
|
'network-transmit-receive');
|
||||||
St.IconType.SYMBOLIC);
|
|
||||||
|
|
||||||
this._source.connect('destroy', Lang.bind(this, function() {
|
this._source.connect('destroy', Lang.bind(this, function() {
|
||||||
this._source = null;
|
this._source = null;
|
||||||
@@ -1730,18 +1755,6 @@ const NMApplet = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_syncSectionTitle: function(category) {
|
_syncSectionTitle: function(category) {
|
||||||
if (category == NMConnectionCategory.VPN) {
|
|
||||||
// Special case VPN: it's only one device (and a fake one
|
|
||||||
// actually), and we don't show it if empty
|
|
||||||
let device = this._devices.vpn.device;
|
|
||||||
let section = this._devices.vpn.section;
|
|
||||||
let item = this._devices.vpn.item;
|
|
||||||
|
|
||||||
section.actor.visible = !device.empty;
|
|
||||||
item.updateForDevice(device);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let devices = this._devices[category].devices;
|
let devices = this._devices[category].devices;
|
||||||
let item = this._devices[category].item;
|
let item = this._devices[category].item;
|
||||||
let section = this._devices[category].section;
|
let section = this._devices[category].section;
|
||||||
@@ -1778,12 +1791,9 @@ const NMApplet = new Lang.Class({
|
|||||||
or this._source will be cleared */
|
or this._source will be cleared */
|
||||||
this._ensureSource();
|
this._ensureSource();
|
||||||
|
|
||||||
let icon = new St.Icon({ icon_name: iconName,
|
let gicon = new Gio.ThemedIcon({ name: iconName });
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
|
||||||
icon_size: this._source.ICON_SIZE
|
|
||||||
});
|
|
||||||
device._notification = new MessageTray.Notification(this._source, title, text,
|
device._notification = new MessageTray.Notification(this._source, title, text,
|
||||||
{ icon: icon });
|
{ gicon: gicon });
|
||||||
device._notification.setUrgency(urgency);
|
device._notification.setUrgency(urgency);
|
||||||
device._notification.setTransient(true);
|
device._notification.setTransient(true);
|
||||||
device._notification.connect('destroy', function() {
|
device._notification.connect('destroy', function() {
|
||||||
@@ -1792,17 +1802,20 @@ const NMApplet = new Lang.Class({
|
|||||||
this._source.notify(device._notification);
|
this._source.notify(device._notification);
|
||||||
},
|
},
|
||||||
|
|
||||||
_makeWrapperDevice: function(wrapperClass, device) {
|
_onActivationFailed: function(device, reason) {
|
||||||
let wrapper = new wrapperClass(this._client, device, this._connections);
|
|
||||||
|
|
||||||
wrapper._activationFailedId = wrapper.connect('activation-failed', Lang.bind(this, function(device, reason) {
|
|
||||||
// XXX: nm-applet has no special text depending on reason
|
// XXX: nm-applet has no special text depending on reason
|
||||||
// but I'm not sure of this generic message
|
// but I'm not sure of this generic message
|
||||||
this._notifyForDevice(device, 'network-error',
|
this._notifyForDevice(device, 'network-error-symbolic',
|
||||||
_("Connection failed"),
|
_("Connection failed"),
|
||||||
_("Activation of network connection failed"),
|
_("Activation of network connection failed"),
|
||||||
MessageTray.Urgency.HIGH);
|
MessageTray.Urgency.HIGH);
|
||||||
}));
|
},
|
||||||
|
|
||||||
|
_makeWrapperDevice: function(wrapperClass, device) {
|
||||||
|
let wrapper = new wrapperClass(this._client, device, this._connections);
|
||||||
|
|
||||||
|
wrapper._activationFailedId = wrapper.connect('activation-failed',
|
||||||
|
Lang.bind(this, this._onActivationFailed));
|
||||||
wrapper._deviceStateChangedId = wrapper.connect('state-changed', Lang.bind(this, function(dev) {
|
wrapper._deviceStateChangedId = wrapper.connect('state-changed', Lang.bind(this, function(dev) {
|
||||||
this._syncSectionTitle(dev.category);
|
this._syncSectionTitle(dev.category);
|
||||||
}));
|
}));
|
||||||
@@ -1823,7 +1836,6 @@ const NMApplet = new Lang.Class({
|
|||||||
let wrapperClass = this._dtypes[device.get_device_type()];
|
let wrapperClass = this._dtypes[device.get_device_type()];
|
||||||
if (wrapperClass) {
|
if (wrapperClass) {
|
||||||
let wrapper = this._makeWrapperDevice(wrapperClass, device);
|
let wrapper = this._makeWrapperDevice(wrapperClass, device);
|
||||||
|
|
||||||
let section = this._devices[wrapper.category].section;
|
let section = this._devices[wrapper.category].section;
|
||||||
let devices = this._devices[wrapper.category].devices;
|
let devices = this._devices[wrapper.category].devices;
|
||||||
|
|
||||||
@@ -1886,7 +1898,7 @@ const NMApplet = new Lang.Class({
|
|||||||
for (let i = 0; i < closedConnections.length; i++) {
|
for (let i = 0; i < closedConnections.length; i++) {
|
||||||
let active = closedConnections[i];
|
let active = closedConnections[i];
|
||||||
if (active._primaryDevice) {
|
if (active._primaryDevice) {
|
||||||
active._primaryDevice.setActiveConnection(null);
|
active._primaryDevice.clearActiveConnection(active);
|
||||||
active._primaryDevice = null;
|
active._primaryDevice = null;
|
||||||
}
|
}
|
||||||
if (active._inited) {
|
if (active._inited) {
|
||||||
@@ -1953,7 +1965,7 @@ const NMApplet = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
a._primaryDevice = this._devices.vpn.device
|
a._primaryDevice = this._vpnSection;
|
||||||
|
|
||||||
if (a._primaryDevice)
|
if (a._primaryDevice)
|
||||||
a._primaryDevice.setActiveConnection(a);
|
a._primaryDevice.setActiveConnection(a);
|
||||||
@@ -2035,8 +2047,7 @@ const NMApplet = new Lang.Class({
|
|||||||
let section = connection._section;
|
let section = connection._section;
|
||||||
|
|
||||||
if (section == NMConnectionCategory.VPN) {
|
if (section == NMConnectionCategory.VPN) {
|
||||||
this._devices.vpn.device.removeConnection(connection);
|
this._vpnSection.removeConnection(connection);
|
||||||
this._syncSectionTitle(section);
|
|
||||||
} else if (section != NMConnectionCategory.INVALID) {
|
} else if (section != NMConnectionCategory.INVALID) {
|
||||||
let devices = this._devices[section].devices;
|
let devices = this._devices[section].devices;
|
||||||
for (let i = 0; i < devices.length; i++)
|
for (let i = 0; i < devices.length; i++)
|
||||||
@@ -2059,8 +2070,7 @@ const NMApplet = new Lang.Class({
|
|||||||
if (section == NMConnectionCategory.INVALID)
|
if (section == NMConnectionCategory.INVALID)
|
||||||
return;
|
return;
|
||||||
if (section == NMConnectionCategory.VPN) {
|
if (section == NMConnectionCategory.VPN) {
|
||||||
this._devices.vpn.device.checkConnection(connection);
|
this._vpnSection.checkConnection(connection);
|
||||||
this._syncSectionTitle(section);
|
|
||||||
} else {
|
} else {
|
||||||
let devices = this._devices[section].devices;
|
let devices = this._devices[section].devices;
|
||||||
for (let i = 0; i < devices.length; i++) {
|
for (let i = 0; i < devices.length; i++) {
|
||||||
@@ -2086,20 +2096,14 @@ const NMApplet = new Lang.Class({
|
|||||||
this._syncSectionTitle(NMConnectionCategory.WIRED);
|
this._syncSectionTitle(NMConnectionCategory.WIRED);
|
||||||
this._syncSectionTitle(NMConnectionCategory.WIRELESS);
|
this._syncSectionTitle(NMConnectionCategory.WIRELESS);
|
||||||
this._syncSectionTitle(NMConnectionCategory.WWAN);
|
this._syncSectionTitle(NMConnectionCategory.WWAN);
|
||||||
this._syncSectionTitle(NMConnectionCategory.VPN);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_syncNMState: function() {
|
_syncNMState: function() {
|
||||||
if (!this._client.manager_running) {
|
this.mainIcon.visible = this._client.manager_running;
|
||||||
log('NetworkManager is not running, hiding...');
|
this.actor.visible = this.mainIcon.visible;
|
||||||
this.menu.close();
|
|
||||||
this.actor.hide();
|
|
||||||
return;
|
|
||||||
} else
|
|
||||||
this.actor.show();
|
|
||||||
|
|
||||||
if (!this._client.networking_enabled) {
|
if (!this._client.networking_enabled) {
|
||||||
this.setIcon('network-offline');
|
this.setIcon('network-offline-symbolic');
|
||||||
this._hideDevices();
|
this._hideDevices();
|
||||||
this._statusItem.label.text = _("Networking is disabled");
|
this._statusItem.label.text = _("Networking is disabled");
|
||||||
this._statusSection.actor.show();
|
this._statusSection.actor.show();
|
||||||
@@ -2117,22 +2121,22 @@ const NMApplet = new Lang.Class({
|
|||||||
let hasMobileIcon = false;
|
let hasMobileIcon = false;
|
||||||
|
|
||||||
if (!mc) {
|
if (!mc) {
|
||||||
this.setIcon('network-offline');
|
this.setIcon('network-offline-symbolic');
|
||||||
} else if (mc.state == NetworkManager.ActiveConnectionState.ACTIVATING) {
|
} else if (mc.state == NetworkManager.ActiveConnectionState.ACTIVATING) {
|
||||||
switch (mc._section) {
|
switch (mc._section) {
|
||||||
case NMConnectionCategory.WWAN:
|
case NMConnectionCategory.WWAN:
|
||||||
this.setIcon('network-cellular-acquiring');
|
this.setIcon('network-cellular-acquiring-symbolic');
|
||||||
break;
|
break;
|
||||||
case NMConnectionCategory.WIRELESS:
|
case NMConnectionCategory.WIRELESS:
|
||||||
this.setIcon('network-wireless-acquiring');
|
this.setIcon('network-wireless-acquiring-symbolic');
|
||||||
break;
|
break;
|
||||||
case NMConnectionCategory.WIRED:
|
case NMConnectionCategory.WIRED:
|
||||||
this.setIcon('network-wired-acquiring');
|
this.setIcon('network-wired-acquiring-symbolic');
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// fallback to a generic connected icon
|
// fallback to a generic connected icon
|
||||||
// (it could be a private connection of some other user)
|
// (it could be a private connection of some other user)
|
||||||
this.setIcon('network-wired-acquiring');
|
this.setIcon('network-wired-acquiring-symbolic');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let dev;
|
let dev;
|
||||||
@@ -2147,17 +2151,17 @@ const NMApplet = new Lang.Class({
|
|||||||
log('An active wireless connection, in infrastructure mode, involves no access point?');
|
log('An active wireless connection, in infrastructure mode, involves no access point?');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.setIcon('network-wireless-connected');
|
this.setIcon('network-wireless-connected-symbolic');
|
||||||
} else {
|
} else {
|
||||||
if (this._activeAccessPoint != ap) {
|
if (this._activeAccessPoint != ap) {
|
||||||
if (this._accessPointUpdateId)
|
if (this._accessPointUpdateId)
|
||||||
this._activeAccessPoint.disconnect(this._accessPointUpdateId);
|
this._activeAccessPoint.disconnect(this._accessPointUpdateId);
|
||||||
this._activeAccessPoint = ap;
|
this._activeAccessPoint = ap;
|
||||||
this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(this, function() {
|
this._activeAccessPointUpdateId = ap.connect('notify::strength', Lang.bind(this, function() {
|
||||||
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
|
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic');
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength));
|
this.setIcon('network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic');
|
||||||
hasApIcon = true;
|
hasApIcon = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -2166,7 +2170,7 @@ const NMApplet = new Lang.Class({
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NMConnectionCategory.WIRED:
|
case NMConnectionCategory.WIRED:
|
||||||
this.setIcon('network-wired');
|
this.setIcon('network-wired-symbolic');
|
||||||
break;
|
break;
|
||||||
case NMConnectionCategory.WWAN:
|
case NMConnectionCategory.WWAN:
|
||||||
dev = mc._primaryDevice;
|
dev = mc._primaryDevice;
|
||||||
@@ -2176,7 +2180,7 @@ const NMApplet = new Lang.Class({
|
|||||||
}
|
}
|
||||||
if (!dev.mobileDevice) {
|
if (!dev.mobileDevice) {
|
||||||
// this can happen for bluetooth in PAN mode
|
// this can happen for bluetooth in PAN mode
|
||||||
this.setIcon('network-cellular-connected');
|
this.setIcon('network-cellular-connected-symbolic');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2185,37 +2189,37 @@ const NMApplet = new Lang.Class({
|
|||||||
this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
|
this._mobileUpdateDevice.disconnect(this._mobileUpdateId);
|
||||||
this._mobileUpdateDevice = dev.mobileDevice;
|
this._mobileUpdateDevice = dev.mobileDevice;
|
||||||
this._mobileUpdateId = dev.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
|
this._mobileUpdateId = dev.mobileDevice.connect('notify::signal-quality', Lang.bind(this, function() {
|
||||||
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
|
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality) + '-symbolic');
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality));
|
this.setIcon('network-cellular-signal-' + signalToIcon(dev.mobileDevice.signal_quality) + '-symbolic');
|
||||||
hasMobileIcon = true;
|
hasMobileIcon = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// fallback to a generic connected icon
|
// fallback to a generic connected icon
|
||||||
// (it could be a private connection of some other user)
|
// (it could be a private connection of some other user)
|
||||||
this.setIcon('network-wired');
|
this.setIcon('network-wired-symbolic');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update VPN indicator
|
// update VPN indicator
|
||||||
if (this._vpnConnection) {
|
if (this._vpnConnection) {
|
||||||
let vpnIconName = 'network-vpn';
|
let vpnIconName = 'network-vpn-symbolic';
|
||||||
if (this._vpnConnection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
if (this._vpnConnection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||||
vpnIconName = 'network-vpn-acquiring';
|
vpnIconName = 'network-vpn-acquiring-symbolic';
|
||||||
|
|
||||||
// only show a separate icon when we're using a wireless/3g connection
|
// only show a separate icon when we're using a wireless/3g connection
|
||||||
if (mc._section == NMConnectionCategory.WIRELESS ||
|
if (mc._section == NMConnectionCategory.WIRELESS ||
|
||||||
mc._section == NMConnectionCategory.WWAN) {
|
mc._section == NMConnectionCategory.WWAN) {
|
||||||
this._secondaryIcon.icon_name = vpnIconName;
|
this.secondaryIcon.icon_name = vpnIconName;
|
||||||
this._secondaryIcon.visible = true;
|
this.secondaryIcon.show();
|
||||||
} else {
|
} else {
|
||||||
this.setIcon(vpnIconName);
|
this.setIcon(vpnIconName);
|
||||||
this._secondaryIcon.visible = false;
|
this.secondaryIcon.hide();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this._secondaryIcon.visible = false;
|
this.secondaryIcon.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup stale signal connections
|
// cleanup stale signal connections
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const Indicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('battery-missing', _("Battery"));
|
this.parent('battery-missing-symbolic', _("Battery"));
|
||||||
|
|
||||||
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
||||||
|
|
||||||
@@ -76,12 +76,6 @@ const Indicator = new Lang.Class({
|
|||||||
this._devicesChanged();
|
this._devicesChanged();
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
|
||||||
if (locked)
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.reactive = !locked;
|
|
||||||
},
|
|
||||||
|
|
||||||
_readPrimaryDevice: function() {
|
_readPrimaryDevice: function() {
|
||||||
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
|
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(result, error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -102,7 +96,7 @@ const Indicator = new Lang.Class({
|
|||||||
let minutes = time % 60;
|
let minutes = time % 60;
|
||||||
let hours = Math.floor(time / 60);
|
let hours = Math.floor(time / 60);
|
||||||
let timestring;
|
let timestring;
|
||||||
if (time > 60) {
|
if (time >= 60) {
|
||||||
if (minutes == 0) {
|
if (minutes == 0) {
|
||||||
timestring = ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
|
timestring = ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
|
||||||
} else {
|
} else {
|
||||||
@@ -150,16 +144,21 @@ const Indicator = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_devicesChanged: function() {
|
_syncIcon: function() {
|
||||||
let icon = this._proxy.Icon;
|
let icon = this._proxy.Icon;
|
||||||
|
let hasIcon = false;
|
||||||
|
|
||||||
if (icon) {
|
if (icon) {
|
||||||
let gicon = Gio.icon_new_for_string(icon);
|
let gicon = Gio.icon_new_for_string(icon);
|
||||||
this.setGIcon(gicon);
|
this.setGIcon(gicon);
|
||||||
this.actor.show();
|
hasIcon = true;
|
||||||
} else {
|
|
||||||
this.menu.close();
|
|
||||||
this.actor.hide();
|
|
||||||
}
|
}
|
||||||
|
this.mainIcon.visible = hasIcon;
|
||||||
|
this.actor.visible = hasIcon;
|
||||||
|
},
|
||||||
|
|
||||||
|
_devicesChanged: function() {
|
||||||
|
this._syncIcon();
|
||||||
this._readPrimaryDevice();
|
this._readPrimaryDevice();
|
||||||
this._readOtherDevices();
|
this._readOtherDevices();
|
||||||
}
|
}
|
||||||
@@ -178,7 +177,6 @@ const DeviceItem = new Lang.Class({
|
|||||||
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
|
this._label = new St.Label({ text: this._deviceTypeToString(device_type) });
|
||||||
|
|
||||||
this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon),
|
this._icon = new St.Icon({ gicon: Gio.icon_new_for_string(icon),
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
|
|
||||||
this._box.add_actor(this._icon);
|
this._box.add_actor(this._icon);
|
||||||
|
|||||||
@@ -12,14 +12,27 @@ const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
|
|||||||
|
|
||||||
const VOLUME_NOTIFY_ID = 1;
|
const VOLUME_NOTIFY_ID = 1;
|
||||||
|
|
||||||
const Indicator = new Lang.Class({
|
// Each Gvc.MixerControl is a connection to PulseAudio,
|
||||||
Name: 'VolumeIndicator',
|
// so it's better to make it a singleton
|
||||||
Extends: PanelMenu.SystemStatusButton,
|
let _mixerControl;
|
||||||
|
function getMixerControl() {
|
||||||
|
if (_mixerControl)
|
||||||
|
return _mixerControl;
|
||||||
|
|
||||||
_init: function() {
|
_mixerControl = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
||||||
this.parent('audio-volume-muted', _("Volume"));
|
_mixerControl.open();
|
||||||
|
|
||||||
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
return _mixerControl;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VolumeMenu = new Lang.Class({
|
||||||
|
Name: 'VolumeMenu',
|
||||||
|
Extends: PopupMenu.PopupMenuSection,
|
||||||
|
|
||||||
|
_init: function(control) {
|
||||||
|
this.parent();
|
||||||
|
|
||||||
|
this._control = control;
|
||||||
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
||||||
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
|
this._control.connect('default-sink-changed', Lang.bind(this, this._readOutput));
|
||||||
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
||||||
@@ -35,10 +48,10 @@ const Indicator = new Lang.Class({
|
|||||||
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||||
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
||||||
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
this._outputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||||
this.menu.addMenuItem(this._outputTitle);
|
this.addMenuItem(this._outputTitle);
|
||||||
this.menu.addMenuItem(this._outputSlider);
|
this.addMenuItem(this._outputSlider);
|
||||||
|
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
|
||||||
this._input = null;
|
this._input = null;
|
||||||
this._inputVolumeId = 0;
|
this._inputVolumeId = 0;
|
||||||
@@ -47,22 +60,13 @@ const Indicator = new Lang.Class({
|
|||||||
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
this._inputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||||
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
|
this._inputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_input'));
|
||||||
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
this._inputSlider.connect('drag-end', Lang.bind(this, this._notifyVolumeChange));
|
||||||
this.menu.addMenuItem(this._inputTitle);
|
this.addMenuItem(this._inputTitle);
|
||||||
this.menu.addMenuItem(this._inputSlider);
|
this.addMenuItem(this._inputSlider);
|
||||||
|
|
||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
this._onControlStateChanged();
|
||||||
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
|
|
||||||
|
|
||||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
|
||||||
this._control.open();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
scroll: function(direction) {
|
||||||
this.menu.setSettingsVisibility(!locked);
|
|
||||||
},
|
|
||||||
|
|
||||||
_onScrollEvent: function(actor, event) {
|
|
||||||
let direction = event.get_scroll_direction();
|
|
||||||
let currentVolume = this._output.volume;
|
let currentVolume = this._output.volume;
|
||||||
|
|
||||||
if (direction == Clutter.ScrollDirection.DOWN) {
|
if (direction == Clutter.ScrollDirection.DOWN) {
|
||||||
@@ -88,9 +92,9 @@ const Indicator = new Lang.Class({
|
|||||||
if (this._control.get_state() == Gvc.MixerControlState.READY) {
|
if (this._control.get_state() == Gvc.MixerControlState.READY) {
|
||||||
this._readOutput();
|
this._readOutput();
|
||||||
this._readInput();
|
this._readInput();
|
||||||
this.actor.show();
|
this._maybeShowInput();
|
||||||
} else {
|
} else {
|
||||||
this.actor.hide();
|
this.emit('icon-changed', null);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -109,7 +113,7 @@ const Indicator = new Lang.Class({
|
|||||||
this._volumeChanged (null, null, '_output');
|
this._volumeChanged (null, null, '_output');
|
||||||
} else {
|
} else {
|
||||||
this._outputSlider.setValue(0);
|
this._outputSlider.setValue(0);
|
||||||
this.setIcon('audio-volume-muted-symbolic');
|
this.emit('icon-changed', 'audio-volume-muted-symbolic');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -155,14 +159,14 @@ const Indicator = new Lang.Class({
|
|||||||
|
|
||||||
_volumeToIcon: function(volume) {
|
_volumeToIcon: function(volume) {
|
||||||
if (volume <= 0) {
|
if (volume <= 0) {
|
||||||
return 'audio-volume-muted';
|
return 'audio-volume-muted-symbolic';
|
||||||
} else {
|
} else {
|
||||||
let n = Math.floor(3 * volume / this._volumeMax) + 1;
|
let n = Math.floor(3 * volume / this._volumeMax) + 1;
|
||||||
if (n < 2)
|
if (n < 2)
|
||||||
return 'audio-volume-low';
|
return 'audio-volume-low-symbolic';
|
||||||
if (n >= 3)
|
if (n >= 3)
|
||||||
return 'audio-volume-high';
|
return 'audio-volume-high-symbolic';
|
||||||
return 'audio-volume-medium';
|
return 'audio-volume-medium-symbolic';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -196,15 +200,48 @@ const Indicator = new Lang.Class({
|
|||||||
slider.setValue(muted ? 0 : (this[property].volume / this._volumeMax));
|
slider.setValue(muted ? 0 : (this[property].volume / this._volumeMax));
|
||||||
if (property == '_output') {
|
if (property == '_output') {
|
||||||
if (muted)
|
if (muted)
|
||||||
this.setIcon('audio-volume-muted');
|
this.emit('icon-changed', 'audio-volume-muted-symbolic');
|
||||||
else
|
else
|
||||||
this.setIcon(this._volumeToIcon(this._output.volume));
|
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_volumeChanged: function(object, param_spec, property) {
|
_volumeChanged: function(object, param_spec, property) {
|
||||||
this[property+'Slider'].setValue(this[property].volume / this._volumeMax);
|
this[property+'Slider'].setValue(this[property].volume / this._volumeMax);
|
||||||
if (property == '_output' && !this._output.is_muted)
|
if (property == '_output' && !this._output.is_muted)
|
||||||
this.setIcon(this._volumeToIcon(this._output.volume));
|
this.emit('icon-changed', this._volumeToIcon(this._output.volume));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Indicator = new Lang.Class({
|
||||||
|
Name: 'VolumeIndicator',
|
||||||
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent('audio-volume-muted-symbolic', _("Volume"));
|
||||||
|
|
||||||
|
this._control = getMixerControl();
|
||||||
|
this._volumeMenu = new VolumeMenu(this._control);
|
||||||
|
this._volumeMenu.connect('icon-changed', Lang.bind(this, function(menu, icon) {
|
||||||
|
this._hasPulseAudio = (icon != null);
|
||||||
|
this.setIcon(icon);
|
||||||
|
this._syncVisibility();
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.menu.addMenuItem(this._volumeMenu);
|
||||||
|
|
||||||
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
|
this.menu.addSettingsAction(_("Sound Settings"), 'gnome-sound-panel.desktop');
|
||||||
|
|
||||||
|
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||||
|
},
|
||||||
|
|
||||||
|
_syncVisibility: function() {
|
||||||
|
this.actor.visible = this._hasPulseAudio;
|
||||||
|
this.mainIcon.visible = this._hasPulseAudio;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onScrollEvent: function(actor, event) {
|
||||||
|
this._volumeMenu.scroll(event.get_scroll_direction());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const Clutter = imports.gi.Clutter;
|
|||||||
const Gdm = imports.gi.Gdm;
|
const Gdm = imports.gi.Gdm;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
|
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
@@ -23,6 +24,35 @@ const GdmUtil = imports.gdm.util;
|
|||||||
// The timeout before going back automatically to the lock screen (in seconds)
|
// The timeout before going back automatically to the lock screen (in seconds)
|
||||||
const IDLE_TIMEOUT = 2 * 60;
|
const IDLE_TIMEOUT = 2 * 60;
|
||||||
|
|
||||||
|
function versionCompare(required, reference) {
|
||||||
|
required = required.split('.');
|
||||||
|
reference = reference.split('.');
|
||||||
|
|
||||||
|
for (let i = 0; i < required.length; i++) {
|
||||||
|
if (required[i] != reference[i])
|
||||||
|
return required[i] < reference[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSupported() {
|
||||||
|
try {
|
||||||
|
let params = GLib.Variant.new('(ss)', ['org.gnome.DisplayManager.Manager', 'Version']);
|
||||||
|
let result = Gio.DBus.system.call_sync('org.gnome.DisplayManager',
|
||||||
|
'/org/gnome/DisplayManager/Manager',
|
||||||
|
'org.freedesktop.DBus.Properties',
|
||||||
|
'Get', params, null,
|
||||||
|
Gio.DBusCallFlags.NONE,
|
||||||
|
-1, null);
|
||||||
|
|
||||||
|
let version = result.deep_unpack()[0].deep_unpack();
|
||||||
|
return versionCompare('3.5.91', version);
|
||||||
|
} catch(e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// A widget showing the user avatar and name
|
// A widget showing the user avatar and name
|
||||||
const UserWidget = new Lang.Class({
|
const UserWidget = new Lang.Class({
|
||||||
Name: 'UserWidget',
|
Name: 'UserWidget',
|
||||||
@@ -33,7 +63,7 @@ const UserWidget = new Lang.Class({
|
|||||||
this.actor = new St.BoxLayout({ style_class: 'unlock-dialog-user-name-container',
|
this.actor = new St.BoxLayout({ style_class: 'unlock-dialog-user-name-container',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
|
|
||||||
this._avatar = new UserMenu.UserAvatarWidget(user, { reactive: false });
|
this._avatar = new UserMenu.UserAvatarWidget(user);
|
||||||
this.actor.add(this._avatar.actor,
|
this.actor.add(this._avatar.actor,
|
||||||
{ x_fill: true, y_fill: true });
|
{ x_fill: true, y_fill: true });
|
||||||
|
|
||||||
@@ -41,6 +71,7 @@ const UserWidget = new Lang.Class({
|
|||||||
this.actor.add(this._label,
|
this.actor.add(this._label,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
y_align: St.Align.MIDDLE });
|
y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
this._userLoadedId = this._user.connect('notify::is-loaded',
|
this._userLoadedId = this._user.connect('notify::is-loaded',
|
||||||
@@ -82,6 +113,7 @@ const UnlockDialog = new Lang.Class({
|
|||||||
_init: function(parentActor) {
|
_init: function(parentActor) {
|
||||||
this.parent({ shellReactive: true,
|
this.parent({ shellReactive: true,
|
||||||
styleClass: 'login-dialog',
|
styleClass: 'login-dialog',
|
||||||
|
keybindingMode: Main.KeybindingMode.UNLOCK_SCREEN,
|
||||||
parentActor: parentActor
|
parentActor: parentActor
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -89,13 +121,17 @@ const UnlockDialog = new Lang.Class({
|
|||||||
this._userName = GLib.get_user_name();
|
this._userName = GLib.get_user_name();
|
||||||
this._user = this._userManager.get_user(this._userName);
|
this._user = this._userManager.get_user(this._userName);
|
||||||
|
|
||||||
|
this._failCounter = 0;
|
||||||
|
this._firstQuestion = true;
|
||||||
|
|
||||||
this._greeterClient = new Gdm.Client();
|
this._greeterClient = new Gdm.Client();
|
||||||
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
|
this._userVerifier = new GdmUtil.ShellUserVerifier(this._greeterClient, { reauthenticationOnly: true });
|
||||||
|
|
||||||
this._userVerifier.connect('reset', Lang.bind(this, this._reset));
|
|
||||||
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
|
this._userVerifier.connect('ask-question', Lang.bind(this, this._onAskQuestion));
|
||||||
|
this._userVerifier.connect('show-message', Lang.bind(this, this._showMessage));
|
||||||
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
this._userVerifier.connect('verification-complete', Lang.bind(this, this._onVerificationComplete));
|
||||||
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
this._userVerifier.connect('verification-failed', Lang.bind(this, this._onVerificationFailed));
|
||||||
|
this._userVerifier.connect('reset', Lang.bind(this, this._onReset));
|
||||||
|
|
||||||
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
this._userVerifier.connect('show-login-hint', Lang.bind(this, this._showLoginHint));
|
||||||
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
this._userVerifier.connect('hide-login-hint', Lang.bind(this, this._hideLoginHint));
|
||||||
@@ -112,9 +148,13 @@ const UnlockDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
this._promptEntry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
|
||||||
can_focus: true });
|
can_focus: true });
|
||||||
ShellEntry.addContextMenu(this._promptEntry);
|
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
||||||
|
ShellEntry.addContextMenu(this._promptEntry, { isPassword: true });
|
||||||
this.setInitialKeyFocus(this._promptEntry);
|
this.setInitialKeyFocus(this._promptEntry);
|
||||||
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
|
this._promptEntry.clutter_text.connect('activate', Lang.bind(this, this._doUnlock));
|
||||||
|
this._promptEntry.clutter_text.connect('text-changed', Lang.bind(this, function() {
|
||||||
|
this._updateOkButtonSensitivity(this._promptEntry.text.length > 0);
|
||||||
|
}));
|
||||||
|
|
||||||
this._promptLayout.add(this._promptEntry,
|
this._promptLayout.add(this._promptEntry,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
@@ -122,6 +162,9 @@ const UnlockDialog = new Lang.Class({
|
|||||||
|
|
||||||
this.contentLayout.add_actor(this._promptLayout);
|
this.contentLayout.add_actor(this._promptLayout);
|
||||||
|
|
||||||
|
this._promptMessage = new St.Label({ visible: false });
|
||||||
|
this.contentLayout.add(this._promptMessage, { x_fill: true });
|
||||||
|
|
||||||
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint' });
|
this._promptLoginHint = new St.Label({ style_class: 'login-dialog-prompt-login-hint' });
|
||||||
this._promptLoginHint.hide();
|
this._promptLoginHint.hide();
|
||||||
this.contentLayout.add_actor(this._promptLoginHint);
|
this.contentLayout.add_actor(this._promptLoginHint);
|
||||||
@@ -134,8 +177,7 @@ const UnlockDialog = new Lang.Class({
|
|||||||
default: true };
|
default: true };
|
||||||
this.setButtons([cancelButton, this._okButton]);
|
this.setButtons([cancelButton, this._okButton]);
|
||||||
|
|
||||||
this._updateOkButton(false);
|
this._updateSensitivity(true);
|
||||||
this._reset();
|
|
||||||
|
|
||||||
let otherUserLabel = new St.Label({ text: _("Log in as another user"),
|
let otherUserLabel = new St.Label({ text: _("Log in as another user"),
|
||||||
style_class: 'login-dialog-not-listed-label' });
|
style_class: 'login-dialog-not-listed-label' });
|
||||||
@@ -150,34 +192,61 @@ const UnlockDialog = new Lang.Class({
|
|||||||
{ x_align: St.Align.START,
|
{ x_align: St.Align.START,
|
||||||
x_fill: false });
|
x_fill: false });
|
||||||
|
|
||||||
|
let batch = new Batch.Hold();
|
||||||
|
this._userVerifier.begin(this._userName, batch);
|
||||||
|
|
||||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, function() {
|
||||||
this.emit('loaded');
|
this.emit('loaded');
|
||||||
return false;
|
return false;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._idleMonitor = Shell.IdleMonitor.get();
|
Main.ctrlAltTabManager.addGroup(this.dialogLayout, _("Unlock Window"), 'dialog-password-symbolic');
|
||||||
// this dialog is only created after user activity (curtain drag or
|
|
||||||
// escape key press), so the timeout will fire after IDLE_TIMEOUT seconds of inactivity
|
this._idleMonitor = new GnomeDesktop.IdleMonitor();
|
||||||
this._idleWatchId = this._idleMonitor.add_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
|
this._idleWatchId = this._idleMonitor.add_watch(IDLE_TIMEOUT * 1000, Lang.bind(this, this._escape));
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateOkButton: function(sensitive) {
|
_updateSensitivity: function(sensitive) {
|
||||||
this._okButton.button.reactive = sensitive;
|
this._promptEntry.reactive = sensitive;
|
||||||
|
this._promptEntry.clutter_text.editable = sensitive;
|
||||||
|
this._updateOkButtonSensitivity(sensitive && this._promptEntry.text.length > 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
_reset: function() {
|
_updateOkButtonSensitivity: function(sensitive) {
|
||||||
this._userVerifier.begin(this._userName, new Batch.Hold());
|
this._okButton.button.reactive = sensitive;
|
||||||
|
this._okButton.button.can_focus = sensitive;
|
||||||
|
},
|
||||||
|
|
||||||
|
_showMessage: function(userVerifier, message, styleClass) {
|
||||||
|
if (message) {
|
||||||
|
this._promptMessage.text = message;
|
||||||
|
this._promptMessage.styleClass = styleClass;
|
||||||
|
GdmUtil.fadeInActor(this._promptMessage);
|
||||||
|
} else {
|
||||||
|
GdmUtil.fadeOutActor(this._promptMessage);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onAskQuestion: function(verifier, serviceName, question, passwordChar) {
|
_onAskQuestion: function(verifier, serviceName, question, passwordChar) {
|
||||||
|
if (this._firstQuestion && this._firstQuestionAnswer) {
|
||||||
|
this._userVerifier.answerQuery(serviceName, this._firstQuestionAnswer);
|
||||||
|
this._firstQuestionAnswer = null;
|
||||||
|
this._firstQuestion = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._promptLabel.text = question;
|
this._promptLabel.text = question;
|
||||||
|
|
||||||
|
if (!this._firstQuestion)
|
||||||
this._promptEntry.text = '';
|
this._promptEntry.text = '';
|
||||||
|
else
|
||||||
|
this._firstQuestion = false;
|
||||||
|
|
||||||
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
this._promptEntry.clutter_text.set_password_char(passwordChar);
|
||||||
this._promptEntry.menu.isPassword = passwordChar != '';
|
this._promptEntry.menu.isPassword = passwordChar != '';
|
||||||
|
|
||||||
this._currentQuery = serviceName;
|
this._currentQuery = serviceName;
|
||||||
this._updateOkButton(true);
|
this._updateSensitivity(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_showLoginHint: function(verifier, message) {
|
_showLoginHint: function(verifier, message) {
|
||||||
@@ -190,13 +259,22 @@ const UnlockDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_doUnlock: function() {
|
_doUnlock: function() {
|
||||||
|
if (this._firstQuestion) {
|
||||||
|
// we haven't received a query yet, so stash the answer
|
||||||
|
// and make ourself non-reactive
|
||||||
|
// the actual reply to GDM will be sent as soon as asked
|
||||||
|
this._firstQuestionAnswer = this._promptEntry.text;
|
||||||
|
this._updateSensitivity(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this._currentQuery)
|
if (!this._currentQuery)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let query = this._currentQuery;
|
let query = this._currentQuery;
|
||||||
this._currentQuery = null;
|
this._currentQuery = null;
|
||||||
|
|
||||||
this._updateOkButton(false);
|
this._updateSensitivity(false);
|
||||||
|
|
||||||
this._userVerifier.answerQuery(query, this._promptEntry.text);
|
this._userVerifier.answerQuery(query, this._promptEntry.text);
|
||||||
},
|
},
|
||||||
@@ -206,13 +284,24 @@ const UnlockDialog = new Lang.Class({
|
|||||||
this.emit('unlocked');
|
this.emit('unlocked');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onVerificationFailed: function() {
|
_onReset: function() {
|
||||||
this._userVerifier.cancel();
|
|
||||||
this.emit('failed');
|
this.emit('failed');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onVerificationFailed: function() {
|
||||||
|
this._currentQuery = null;
|
||||||
|
this._firstQuestion = true;
|
||||||
|
|
||||||
|
this._promptEntry.text = '';
|
||||||
|
this._promptEntry.clutter_text.set_password_char('\u25cf');
|
||||||
|
this._promptEntry.menu.isPassword = true;
|
||||||
|
|
||||||
|
this._updateSensitivity(false);
|
||||||
|
},
|
||||||
|
|
||||||
_escape: function() {
|
_escape: function() {
|
||||||
this._onVerificationFailed();
|
this._userVerifier.cancel();
|
||||||
|
this.emit('failed');
|
||||||
},
|
},
|
||||||
|
|
||||||
_otherUserClicked: function(button, event) {
|
_otherUserClicked: function(button, event) {
|
||||||
|
|||||||
@@ -9,10 +9,11 @@ const Pango = imports.gi.Pango;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Tp = imports.gi.TelepathyGLib;
|
const Tp = imports.gi.TelepathyGLib;
|
||||||
const UPowerGlib = imports.gi.UPowerGlib;
|
|
||||||
const Atk = imports.gi.Atk;
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
|
const BoxPointer = imports.ui.boxpointer;
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const GnomeSession = imports.misc.gnomeSession;
|
||||||
|
const LoginManager = imports.misc.loginManager;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
@@ -25,6 +26,7 @@ const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
|
|||||||
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
||||||
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
||||||
const LOCK_ENABLED_KEY = 'lock-enabled';
|
const LOCK_ENABLED_KEY = 'lock-enabled';
|
||||||
|
const ALWAYS_SHOW_LOG_OUT_KEY = 'always-show-log-out';
|
||||||
|
|
||||||
const DIALOG_ICON_SIZE = 64;
|
const DIALOG_ICON_SIZE = 64;
|
||||||
|
|
||||||
@@ -48,13 +50,21 @@ const UserAvatarWidget = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(user, params) {
|
_init: function(user, params) {
|
||||||
this._user = user;
|
this._user = user;
|
||||||
params = Params.parse(params, { reactive: true });
|
params = Params.parse(params, { reactive: false,
|
||||||
|
iconSize: DIALOG_ICON_SIZE,
|
||||||
|
styleClass: 'status-chooser-user-icon' });
|
||||||
|
this._iconSize = params.iconSize;
|
||||||
|
|
||||||
this.actor = new St.Bin({ style_class: 'status-chooser-user-icon',
|
this.actor = new St.Bin({ style_class: params.styleClass,
|
||||||
track_hover: params.reactive,
|
track_hover: params.reactive,
|
||||||
reactive: params.reactive });
|
reactive: params.reactive });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setSensitive: function(sensitive) {
|
||||||
|
this.actor.can_focus = sensitive;
|
||||||
|
this.actor.reactive = sensitive;
|
||||||
|
},
|
||||||
|
|
||||||
update: function() {
|
update: function() {
|
||||||
let iconFile = this._user.get_icon_file();
|
let iconFile = this._user.get_icon_file();
|
||||||
if (!GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
if (!GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
||||||
@@ -66,9 +76,8 @@ const UserAvatarWidget = new Lang.Class({
|
|||||||
this.actor.style = 'background-image: url("%s");'.format(iconFile);
|
this.actor.style = 'background-image: url("%s");'.format(iconFile);
|
||||||
} else {
|
} else {
|
||||||
this.actor.style = null;
|
this.actor.style = null;
|
||||||
this.actor.child = new St.Icon({ icon_name: 'avatar-default',
|
this.actor.child = new St.Icon({ icon_name: 'avatar-default-symbolic',
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
icon_size: this._iconSize });
|
||||||
icon_size: DIALOG_ICON_SIZE });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -144,7 +153,7 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
this._userManager = AccountsService.UserManager.get_default();
|
this._userManager = AccountsService.UserManager.get_default();
|
||||||
this._user = this._userManager.get_user(GLib.get_user_name());
|
this._user = this._userManager.get_user(GLib.get_user_name());
|
||||||
|
|
||||||
this._avatar = new UserAvatarWidget(this._user);
|
this._avatar = new UserAvatarWidget(this._user, { reactive: true });
|
||||||
this._iconBin = new St.Button({ child: this._avatar.actor });
|
this._iconBin = new St.Button({ child: this._avatar.actor });
|
||||||
this.addActor(this._iconBin);
|
this.addActor(this._iconBin);
|
||||||
|
|
||||||
@@ -164,22 +173,22 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
|
|
||||||
let item;
|
let item;
|
||||||
|
|
||||||
item = new IMStatusItem(_("Available"), 'user-available');
|
item = new IMStatusItem(_("Available"), 'user-available-symbolic');
|
||||||
this._combo.addMenuItem(item, IMStatus.AVAILABLE);
|
this._combo.addMenuItem(item, IMStatus.AVAILABLE);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Busy"), 'user-busy');
|
item = new IMStatusItem(_("Busy"), 'user-busy-symbolic');
|
||||||
this._combo.addMenuItem(item, IMStatus.BUSY);
|
this._combo.addMenuItem(item, IMStatus.BUSY);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Invisible"), 'user-invisible');
|
item = new IMStatusItem(_("Invisible"), 'user-invisible-symbolic');
|
||||||
this._combo.addMenuItem(item, IMStatus.HIDDEN);
|
this._combo.addMenuItem(item, IMStatus.HIDDEN);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Away"), 'user-away');
|
item = new IMStatusItem(_("Away"), 'user-away-symbolic');
|
||||||
this._combo.addMenuItem(item, IMStatus.AWAY);
|
this._combo.addMenuItem(item, IMStatus.AWAY);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Idle"), 'user-idle');
|
item = new IMStatusItem(_("Idle"), 'user-idle-symbolic');
|
||||||
this._combo.addMenuItem(item, IMStatus.IDLE);
|
this._combo.addMenuItem(item, IMStatus.IDLE);
|
||||||
|
|
||||||
item = new IMStatusItem(_("Unavailable"), 'user-offline');
|
item = new IMStatusItem(_("Offline"), 'user-offline-symbolic');
|
||||||
this._combo.addMenuItem(item, IMStatus.OFFLINE);
|
this._combo.addMenuItem(item, IMStatus.OFFLINE);
|
||||||
|
|
||||||
this._combo.connect('active-item-changed',
|
this._combo.connect('active-item-changed',
|
||||||
@@ -234,6 +243,10 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
if (this.actor.mapped)
|
if (this.actor.mapped)
|
||||||
this._updateUser();
|
this._updateUser();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.connect('sensitive-changed', function(sensitive) {
|
||||||
|
this._avatar.setSensitive(sensitive);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_restorePresence: function() {
|
_restorePresence: function() {
|
||||||
@@ -470,29 +483,32 @@ const UserMenuButton = new Lang.Class({
|
|||||||
this._presence = new GnomeSession.Presence();
|
this._presence = new GnomeSession.Presence();
|
||||||
this._session = new GnomeSession.SessionManager();
|
this._session = new GnomeSession.SessionManager();
|
||||||
this._haveShutdown = true;
|
this._haveShutdown = true;
|
||||||
|
this._haveSuspend = true;
|
||||||
|
|
||||||
this._accountMgr = Tp.AccountManager.dup();
|
this._accountMgr = Tp.AccountManager.dup();
|
||||||
|
|
||||||
this._upClient = new UPowerGlib.Client();
|
this._loginManager = LoginManager.getLoginManager();
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
|
|
||||||
this._iconBox = new St.Bin();
|
this._iconBox = new St.Bin();
|
||||||
box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
|
box.add(this._iconBox, { y_align: St.Align.MIDDLE, y_fill: false });
|
||||||
|
|
||||||
let textureCache = St.TextureCache.get_default();
|
let textureCache = St.TextureCache.get_default();
|
||||||
this._offlineIcon = new St.Icon({ icon_name: 'user-offline',
|
this._offlineIcon = new St.Icon({ icon_name: 'user-offline-symbolic',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._availableIcon = new St.Icon({ icon_name: 'user-available',
|
this._availableIcon = new St.Icon({ icon_name: 'user-available-symbolic',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._busyIcon = new St.Icon({ icon_name: 'user-busy',
|
this._busyIcon = new St.Icon({ icon_name: 'user-busy-symbolic',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._invisibleIcon = new St.Icon({ icon_name: 'user-invisible',
|
this._invisibleIcon = new St.Icon({ icon_name: 'user-invisible-symbolic',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._awayIcon = new St.Icon({ icon_name: 'user-away',
|
this._awayIcon = new St.Icon({ icon_name: 'user-away-symbolic',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._idleIcon = new St.Icon({ icon_name: 'user-idle',
|
this._idleIcon = new St.Icon({ icon_name: 'user-idle-symbolic',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
this._pendingIcon = new St.Icon({ icon_name: 'user-status-pending',
|
this._pendingIcon = new St.Icon({ icon_name: 'user-status-pending-symbolic',
|
||||||
|
style_class: 'popup-menu-icon' });
|
||||||
|
this._lockedIcon = new St.Icon({ icon_name: 'changes-prevent-symbolic',
|
||||||
style_class: 'popup-menu-icon' });
|
style_class: 'popup-menu-icon' });
|
||||||
|
|
||||||
this._accountMgr.connect('most-available-presence-changed',
|
this._accountMgr.connect('most-available-presence-changed',
|
||||||
@@ -551,17 +567,28 @@ const UserMenuButton = new Lang.Class({
|
|||||||
// the lockdown setting changes, which should be close enough.
|
// the lockdown setting changes, which should be close enough.
|
||||||
this.menu.connect('open-state-changed', Lang.bind(this,
|
this.menu.connect('open-state-changed', Lang.bind(this,
|
||||||
function(menu, open) {
|
function(menu, open) {
|
||||||
if (open)
|
if (!open)
|
||||||
|
return;
|
||||||
|
|
||||||
this._updateHaveShutdown();
|
this._updateHaveShutdown();
|
||||||
|
this._updateHaveSuspend();
|
||||||
}));
|
}));
|
||||||
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
||||||
Lang.bind(this, this._updateHaveShutdown));
|
Lang.bind(this, this._updateHaveShutdown));
|
||||||
|
|
||||||
this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
|
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||||
|
this._sessionUpdated();
|
||||||
},
|
},
|
||||||
|
|
||||||
setLockedState: function(locked) {
|
_sessionUpdated: function() {
|
||||||
this.actor.visible = !locked;
|
this.actor.visible = !Main.sessionMode.isGreeter;
|
||||||
|
|
||||||
|
let allowSettings = Main.sessionMode.allowSettings;
|
||||||
|
this._statusChooser.setSensitive(allowSettings);
|
||||||
|
this._systemSettings.visible = allowSettings;
|
||||||
|
|
||||||
|
this.setSensitive(!Main.sessionMode.isLocked);
|
||||||
|
this._updatePresenceIcon();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
@@ -584,19 +611,19 @@ const UserMenuButton = new Lang.Class({
|
|||||||
_updateSwitchUser: function() {
|
_updateSwitchUser: function() {
|
||||||
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
|
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
|
||||||
let multiUser = this._userManager.can_switch() && this._userManager.has_multiple_users;
|
let multiUser = this._userManager.can_switch() && this._userManager.has_multiple_users;
|
||||||
let multiSession = Gdm.get_session_ids().length > 1;
|
|
||||||
|
|
||||||
this._loginScreenItem.label.set_text(multiUser ? _("Switch User")
|
this._loginScreenItem.actor.visible = allowSwitch && multiUser;
|
||||||
: _("Switch Session"));
|
|
||||||
this._loginScreenItem.actor.visible = allowSwitch && (multiUser || multiSession);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateLogout: function() {
|
_updateLogout: function() {
|
||||||
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
|
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
|
||||||
|
let alwaysShow = global.settings.get_boolean(ALWAYS_SHOW_LOG_OUT_KEY);
|
||||||
|
let systemAccount = this._user.system_account;
|
||||||
|
let localAccount = this._user.local_account;
|
||||||
let multiUser = this._userManager.has_multiple_users;
|
let multiUser = this._userManager.has_multiple_users;
|
||||||
let multiSession = Gdm.get_session_ids().length > 1;
|
let multiSession = Gdm.get_session_ids().length > 1;
|
||||||
|
|
||||||
this._logoutItem.actor.visible = allowLogout && (multiUser || multiSession);
|
this._logoutItem.actor.visible = allowLogout && (alwaysShow || multiUser || multiSession || systemAccount || !localAccount);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateLockScreen: function() {
|
_updateLockScreen: function() {
|
||||||
@@ -620,9 +647,15 @@ const UserMenuButton = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateSuspendOrPowerOff: function() {
|
_updateHaveSuspend: function() {
|
||||||
this._haveSuspend = this._upClient.get_can_suspend();
|
this._loginManager.canSuspend(Lang.bind(this,
|
||||||
|
function(result) {
|
||||||
|
this._haveSuspend = result;
|
||||||
|
this._updateSuspendOrPowerOff();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateSuspendOrPowerOff: function() {
|
||||||
if (!this._suspendOrPowerOffItem)
|
if (!this._suspendOrPowerOffItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -645,7 +678,9 @@ const UserMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updatePresenceIcon: function(accountMgr, presence, status, message) {
|
_updatePresenceIcon: function(accountMgr, presence, status, message) {
|
||||||
if (presence == Tp.ConnectionPresenceType.AVAILABLE)
|
if (Main.sessionMode.isLocked)
|
||||||
|
this._iconBox.child = this._lockedIcon;
|
||||||
|
else if (presence == Tp.ConnectionPresenceType.AVAILABLE)
|
||||||
this._iconBox.child = this._availableIcon;
|
this._iconBox.child = this._availableIcon;
|
||||||
else if (presence == Tp.ConnectionPresenceType.BUSY)
|
else if (presence == Tp.ConnectionPresenceType.BUSY)
|
||||||
this._iconBox.child = this._busyIcon;
|
this._iconBox.child = this._busyIcon;
|
||||||
@@ -705,7 +740,6 @@ const UserMenuButton = new Lang.Class({
|
|||||||
let item;
|
let item;
|
||||||
|
|
||||||
item = new IMStatusChooserItem();
|
item = new IMStatusChooserItem();
|
||||||
if (Main.sessionMode.allowSettings)
|
|
||||||
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
|
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
this._statusChooser = item;
|
this._statusChooser = item;
|
||||||
@@ -718,11 +752,10 @@ const UserMenuButton = new Lang.Class({
|
|||||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
|
|
||||||
if (Main.sessionMode.allowSettings) {
|
item = new PopupMenu.PopupMenuItem(_("Settings"));
|
||||||
item = new PopupMenu.PopupMenuItem(_("System Settings"));
|
|
||||||
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
}
|
this._systemSettings = item;
|
||||||
|
|
||||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
@@ -790,13 +823,14 @@ const UserMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onLockScreenActivate: function() {
|
_onLockScreenActivate: function() {
|
||||||
|
this.menu.close(BoxPointer.PopupAnimation.NONE);
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
Main.screenShield.lock(true);
|
Main.screenShield.lock(true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onLoginScreenActivate: function() {
|
_onLoginScreenActivate: function() {
|
||||||
|
this.menu.close(BoxPointer.PopupAnimation.NONE);
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
if (this._screenSaverSettings.get_boolean(LOCK_ENABLED_KEY))
|
|
||||||
Main.screenShield.lock(false);
|
Main.screenShield.lock(false);
|
||||||
Gdm.goto_login_session_sync(null);
|
Gdm.goto_login_session_sync(null);
|
||||||
},
|
},
|
||||||
@@ -824,12 +858,13 @@ const UserMenuButton = new Lang.Class({
|
|||||||
let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
|
let tmpId = Main.screenShield.connect('lock-screen-shown', Lang.bind(this, function() {
|
||||||
Main.screenShield.disconnect(tmpId);
|
Main.screenShield.disconnect(tmpId);
|
||||||
|
|
||||||
this._upClient.suspend_sync(null);
|
this._loginManager.suspend();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
this.menu.close(BoxPointer.PopupAnimation.NONE);
|
||||||
Main.screenShield.lock(true);
|
Main.screenShield.lock(true);
|
||||||
} else {
|
} else {
|
||||||
this._upClient.suspend_sync(null);
|
this._loginManager.suspend();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
@@ -11,7 +12,6 @@ const St = imports.gi.St;
|
|||||||
|
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const PlaceDisplay = imports.ui.placeDisplay;
|
|
||||||
const RemoteSearch = imports.ui.remoteSearch;
|
const RemoteSearch = imports.ui.remoteSearch;
|
||||||
const Search = imports.ui.search;
|
const Search = imports.ui.search;
|
||||||
const SearchDisplay = imports.ui.searchDisplay;
|
const SearchDisplay = imports.ui.searchDisplay;
|
||||||
@@ -20,6 +20,7 @@ const Tweener = imports.ui.tweener;
|
|||||||
const Wanda = imports.ui.wanda;
|
const Wanda = imports.ui.wanda;
|
||||||
const WorkspacesView = imports.ui.workspacesView;
|
const WorkspacesView = imports.ui.workspacesView;
|
||||||
|
|
||||||
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
|
|
||||||
const FocusTrap = new Lang.Class({
|
const FocusTrap = new Lang.Class({
|
||||||
Name: 'FocusTrap',
|
Name: 'FocusTrap',
|
||||||
@@ -73,11 +74,9 @@ const ViewSelector = new Lang.Class({
|
|||||||
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged));
|
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged));
|
||||||
|
|
||||||
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
|
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||||
icon_name: 'edit-find',
|
icon_name: 'edit-find-symbolic' });
|
||||||
icon_type: St.IconType.SYMBOLIC });
|
|
||||||
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
|
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||||
icon_name: 'edit-clear',
|
icon_name: 'edit-clear-symbolic' });
|
||||||
icon_type: St.IconType.SYMBOLIC });
|
|
||||||
this._entry.set_secondary_icon(this._inactiveIcon);
|
this._entry.set_secondary_icon(this._inactiveIcon);
|
||||||
|
|
||||||
this._iconClickedId = 0;
|
this._iconClickedId = 0;
|
||||||
@@ -85,22 +84,26 @@ const ViewSelector = new Lang.Class({
|
|||||||
|
|
||||||
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
|
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
|
||||||
this._workspacesPage = this._addPage(this._workspacesDisplay.actor, null,
|
this._workspacesPage = this._addPage(this._workspacesDisplay.actor, null,
|
||||||
_("Windows"), 'text-x-generic');
|
_("Windows"), 'text-x-generic-symbolic');
|
||||||
|
|
||||||
this._appDisplay = new AppDisplay.AllAppDisplay();
|
this._appDisplay = new AppDisplay.AllAppDisplay();
|
||||||
this._appsPage = this._addPage(this._appDisplay.actor, null,
|
this._appsPage = this._addPage(this._appDisplay.actor, null,
|
||||||
_("Applications"), 'system-run');
|
_("Applications"), 'system-run-symbolic');
|
||||||
|
|
||||||
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
|
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
|
||||||
this._searchPage = this._addPage(this._searchResults.actor, this._entry,
|
this._searchPage = this._addPage(this._searchResults.actor, this._entry,
|
||||||
_("Search"), 'edit-find');
|
_("Search"), 'edit-find-symbolic');
|
||||||
|
|
||||||
|
this._searchSettings = new Gio.Settings({ schema: Search.SEARCH_PROVIDERS_SCHEMA });
|
||||||
|
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||||
|
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
|
||||||
|
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
|
||||||
|
|
||||||
// Default search providers
|
// Default search providers
|
||||||
// Wanda comes obviously first
|
// Wanda comes obviously first
|
||||||
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
||||||
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||||
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
||||||
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
|
||||||
|
|
||||||
// Load remote search providers provided by applications
|
// Load remote search providers provided by applications
|
||||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||||
@@ -145,6 +148,18 @@ const ViewSelector = new Lang.Class({
|
|||||||
// accessing the properties.
|
// accessing the properties.
|
||||||
this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
|
this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
|
||||||
coordinate: Clutter.BindCoordinate.HEIGHT });
|
coordinate: Clutter.BindCoordinate.HEIGHT });
|
||||||
|
|
||||||
|
Main.wm.addKeybinding('toggle-application-view',
|
||||||
|
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
||||||
|
Meta.KeyBindingFlags.NONE,
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
|
Lang.bind(this, this._toggleAppsPage));
|
||||||
|
},
|
||||||
|
|
||||||
|
_toggleAppsPage: function() {
|
||||||
|
Main.overview.show();
|
||||||
|
this._showAppsButton.checked = !this._showAppsButton.checked;
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
@@ -188,7 +203,7 @@ const ViewSelector = new Lang.Class({
|
|||||||
})
|
})
|
||||||
});;
|
});;
|
||||||
this._pageArea.add_actor(page);
|
this._pageArea.add_actor(page);
|
||||||
return page
|
return page;
|
||||||
},
|
},
|
||||||
|
|
||||||
_showPage: function(page) {
|
_showPage: function(page) {
|
||||||
@@ -313,7 +328,7 @@ const ViewSelector = new Lang.Class({
|
|||||||
|
|
||||||
startSearch: function(event) {
|
startSearch: function(event) {
|
||||||
global.stage.set_key_focus(this._text);
|
global.stage.set_key_focus(this._text);
|
||||||
this._text.event(event, false);
|
this._text.event(event, true);
|
||||||
},
|
},
|
||||||
|
|
||||||
// the entry does not show the hint
|
// the entry does not show the hint
|
||||||
@@ -425,7 +440,32 @@ const ViewSelector = new Lang.Class({
|
|||||||
this._showPage(this._searchPage);
|
this._showPage(this._searchPage);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_shouldUseSearchProvider: function(provider) {
|
||||||
|
// the disable-external GSetting only affects remote providers
|
||||||
|
if (!provider.isRemoteProvider)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (this._searchSettings.get_boolean('disable-external'))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let appId = provider.appInfo.get_id();
|
||||||
|
let disable = this._searchSettings.get_strv('disabled');
|
||||||
|
return disable.indexOf(appId) == -1;
|
||||||
|
},
|
||||||
|
|
||||||
|
_reloadRemoteProviders: function() {
|
||||||
|
// removeSearchProvider() modifies the provider list we iterate on,
|
||||||
|
// so make a copy first
|
||||||
|
let remoteProviders = this._searchSystem.getRemoteProviders().slice(0);
|
||||||
|
|
||||||
|
remoteProviders.forEach(Lang.bind(this, this.removeSearchProvider));
|
||||||
|
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||||
|
},
|
||||||
|
|
||||||
addSearchProvider: function(provider) {
|
addSearchProvider: function(provider) {
|
||||||
|
if (!this._shouldUseSearchProvider(provider))
|
||||||
|
return;
|
||||||
|
|
||||||
this._searchSystem.registerProvider(provider);
|
this._searchSystem.registerProvider(provider);
|
||||||
this._searchResults.createProviderMeta(provider);
|
this._searchResults.createProviderMeta(provider);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
|
||||||
const GdkPixbuf = imports.gi.GdkPixbuf;
|
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const Signals = imports.signals;
|
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
@@ -50,23 +48,12 @@ const WandaIcon = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
createIcon: function(iconSize) {
|
createIcon: function(iconSize) {
|
||||||
if (this._animations)
|
|
||||||
this._animations.destroy();
|
|
||||||
|
|
||||||
if (!this._imageFile) {
|
if (!this._imageFile) {
|
||||||
return new St.Icon({ icon_name: 'face-smile',
|
return new St.Icon({ icon_name: 'face-smile',
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
icon_size: iconSize });
|
||||||
icon_size: iconSize
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
|
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
|
||||||
this._animations.connect('destroy', Lang.bind(this, function() {
|
|
||||||
if (this._timeoutId)
|
|
||||||
GLib.source_remove(this._timeoutId);
|
|
||||||
this._timeoutId = 0;
|
|
||||||
this._animations = null;
|
|
||||||
}));
|
|
||||||
this._animations.connect('notify::mapped', Lang.bind(this, function() {
|
this._animations.connect('notify::mapped', Lang.bind(this, function() {
|
||||||
if (this._animations.mapped && !this._timeoutId) {
|
if (this._animations.mapped && !this._timeoutId) {
|
||||||
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
|
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
|
||||||
@@ -79,11 +66,16 @@ const WandaIcon = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._i = 0;
|
|
||||||
|
|
||||||
return this._animations;
|
return this._animations;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_createIconTexture: function(size) {
|
||||||
|
if (size == this.iconSize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.parent(size);
|
||||||
|
},
|
||||||
|
|
||||||
_update: function() {
|
_update: function() {
|
||||||
let n = this._animations.get_n_children();
|
let n = this._animations.get_n_children();
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
@@ -175,16 +167,8 @@ const WandaSearchProvider = new Lang.Class({
|
|||||||
// only one which speaks the truth!
|
// only one which speaks the truth!
|
||||||
'name': capitalize(fish[0]),
|
'name': capitalize(fish[0]),
|
||||||
'createIcon': function(iconSize) {
|
'createIcon': function(iconSize) {
|
||||||
// for DND only (maybe could be improved)
|
return new St.Icon({ gicon: Gio.icon_new_for_string('face-smile'),
|
||||||
// DON'T use St.Icon here, it crashes the shell
|
icon_size: iconSize });
|
||||||
// (dnd.js code assumes it can query the actor size
|
|
||||||
// without parenting it, while StWidget accesses
|
|
||||||
// StThemeNode in get_preferred_width/height, which
|
|
||||||
// triggers an assertion failure)
|
|
||||||
return St.TextureCache.get_default().load_icon_name(null,
|
|
||||||
'face-smile',
|
|
||||||
St.IconType.FULLCOLOR,
|
|
||||||
iconSize);
|
|
||||||
}
|
}
|
||||||
}]);
|
}]);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ const WindowAttentionHandler = new Lang.Class({
|
|||||||
let [title, banner] = this._getTitleAndBanner(app, window);
|
let [title, banner] = this._getTitleAndBanner(app, window);
|
||||||
|
|
||||||
let notification = new MessageTray.Notification(source, title, banner);
|
let notification = new MessageTray.Notification(source, title, banner);
|
||||||
|
notification.setForFeedback(true);
|
||||||
|
|
||||||
source.notify(notification);
|
source.notify(notification);
|
||||||
|
|
||||||
source.signalIDs.push(window.connect('notify::title', Lang.bind(this, function() {
|
source.signalIDs.push(window.connect('notify::title', Lang.bind(this, function() {
|
||||||
|
|||||||
@@ -27,16 +27,24 @@ const WindowDimmer = new Lang.Class({
|
|||||||
this._brightnessEffect = new Clutter.BrightnessContrastEffect();
|
this._brightnessEffect = new Clutter.BrightnessContrastEffect();
|
||||||
actor.add_effect(this._brightnessEffect);
|
actor.add_effect(this._brightnessEffect);
|
||||||
this.actor = actor;
|
this.actor = actor;
|
||||||
|
this._enabled = true;
|
||||||
this._dimFactor = 0.0;
|
this._dimFactor = 0.0;
|
||||||
|
this._syncEnabled();
|
||||||
|
},
|
||||||
|
|
||||||
|
_syncEnabled: function() {
|
||||||
|
this._brightnessEffect.enabled = (this._enabled && this._dimFactor > 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
setEnabled: function(enabled) {
|
setEnabled: function(enabled) {
|
||||||
this._brightnessEffect.enabled = enabled;
|
this._enabled = enabled;
|
||||||
|
this._syncEnabled();
|
||||||
},
|
},
|
||||||
|
|
||||||
set dimFactor(factor) {
|
set dimFactor(factor) {
|
||||||
this._dimFactor = factor;
|
this._dimFactor = factor;
|
||||||
this._brightnessEffect.set_brightness(factor * DIM_BRIGHTNESS);
|
this._brightnessEffect.set_brightness(factor * DIM_BRIGHTNESS);
|
||||||
|
this._syncEnabled();
|
||||||
},
|
},
|
||||||
|
|
||||||
get dimFactor() {
|
get dimFactor() {
|
||||||
@@ -45,10 +53,17 @@ const WindowDimmer = new Lang.Class({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function getWindowDimmer(actor) {
|
function getWindowDimmer(actor) {
|
||||||
|
let enabled = Meta.prefs_get_attach_modal_dialogs();
|
||||||
|
if (actor._windowDimmer)
|
||||||
|
actor._windowDimmer.setEnabled(enabled);
|
||||||
|
|
||||||
|
if (enabled) {
|
||||||
if (!actor._windowDimmer)
|
if (!actor._windowDimmer)
|
||||||
actor._windowDimmer = new WindowDimmer(actor);
|
actor._windowDimmer = new WindowDimmer(actor);
|
||||||
|
|
||||||
return actor._windowDimmer;
|
return actor._windowDimmer;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const WindowManager = new Lang.Class({
|
const WindowManager = new Lang.Class({
|
||||||
@@ -68,6 +83,8 @@ const WindowManager = new Lang.Class({
|
|||||||
|
|
||||||
this._animationBlockCount = 0;
|
this._animationBlockCount = 0;
|
||||||
|
|
||||||
|
this._allowedKeybindings = {};
|
||||||
|
|
||||||
this._switchData = null;
|
this._switchData = null;
|
||||||
this._shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
|
this._shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
|
||||||
this._shellwm.connect('kill-window-effects', Lang.bind(this, function (shellwm, actor) {
|
this._shellwm.connect('kill-window-effects', Lang.bind(this, function (shellwm, actor) {
|
||||||
@@ -84,37 +101,65 @@ const WindowManager = new Lang.Class({
|
|||||||
this._shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
|
this._shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
|
||||||
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
||||||
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
||||||
|
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
|
||||||
|
|
||||||
this._workspaceSwitcherPopup = null;
|
this._workspaceSwitcherPopup = null;
|
||||||
Meta.keybindings_set_custom_handler('switch-to-workspace-left',
|
this.setCustomKeybindingHandler('switch-to-workspace-left',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-to-workspace-right',
|
this.setCustomKeybindingHandler('switch-to-workspace-right',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-to-workspace-up',
|
this.setCustomKeybindingHandler('switch-to-workspace-up',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-to-workspace-down',
|
this.setCustomKeybindingHandler('switch-to-workspace-down',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('move-to-workspace-left',
|
this.setCustomKeybindingHandler('move-to-workspace-left',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('move-to-workspace-right',
|
this.setCustomKeybindingHandler('move-to-workspace-right',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('move-to-workspace-up',
|
this.setCustomKeybindingHandler('move-to-workspace-up',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('move-to-workspace-down',
|
this.setCustomKeybindingHandler('move-to-workspace-down',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW,
|
||||||
Lang.bind(this, this._showWorkspaceSwitcher));
|
Lang.bind(this, this._showWorkspaceSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-windows',
|
this.setCustomKeybindingHandler('switch-windows',
|
||||||
|
Main.KeybindingMode.NORMAL,
|
||||||
Lang.bind(this, this._startAppSwitcher));
|
Lang.bind(this, this._startAppSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-group',
|
this.setCustomKeybindingHandler('switch-group',
|
||||||
|
Main.KeybindingMode.NORMAL,
|
||||||
Lang.bind(this, this._startAppSwitcher));
|
Lang.bind(this, this._startAppSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-windows-backward',
|
this.setCustomKeybindingHandler('switch-windows-backward',
|
||||||
|
Main.KeybindingMode.NORMAL,
|
||||||
Lang.bind(this, this._startAppSwitcher));
|
Lang.bind(this, this._startAppSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-group-backward',
|
this.setCustomKeybindingHandler('switch-group-backward',
|
||||||
|
Main.KeybindingMode.NORMAL,
|
||||||
Lang.bind(this, this._startAppSwitcher));
|
Lang.bind(this, this._startAppSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-panels',
|
this.setCustomKeybindingHandler('switch-panels',
|
||||||
|
Main.KeybindingMode.NORMAL |
|
||||||
|
Main.KeybindingMode.OVERVIEW |
|
||||||
|
Main.KeybindingMode.LOCK_SCREEN |
|
||||||
|
Main.KeybindingMode.UNLOCK_SCREEN |
|
||||||
|
Main.KeybindingMode.LOGIN_SCREEN,
|
||||||
Lang.bind(this, this._startA11ySwitcher));
|
Lang.bind(this, this._startA11ySwitcher));
|
||||||
global.display.add_keybinding('open-application-menu',
|
|
||||||
|
this.addKeybinding('open-application-menu',
|
||||||
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
||||||
Meta.KeyBindingFlags.NONE,
|
Meta.KeyBindingFlags.NONE,
|
||||||
|
Main.KeybindingMode.NORMAL,
|
||||||
Lang.bind(this, this._openAppMenu));
|
Lang.bind(this, this._openAppMenu));
|
||||||
|
|
||||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||||
@@ -127,6 +172,25 @@ const WindowManager = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
setCustomKeybindingHandler: function(name, modes, handler) {
|
||||||
|
if (Meta.keybindings_set_custom_handler(name, handler))
|
||||||
|
this.allowKeybinding(name, modes);
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeybinding: function(name, settings, flags, modes, handler) {
|
||||||
|
if (global.display.add_keybinding(name, settings, flags, handler))
|
||||||
|
this.allowKeybinding(name, modes);
|
||||||
|
},
|
||||||
|
|
||||||
|
removeKeybinding: function(name) {
|
||||||
|
if (global.display.remove_keybinding(name))
|
||||||
|
this.allowKeybinding(name, Main.KeybindingMode.NONE);
|
||||||
|
},
|
||||||
|
|
||||||
|
allowKeybinding: function(name, modes) {
|
||||||
|
this._allowedKeybindings[name] = modes;
|
||||||
|
},
|
||||||
|
|
||||||
blockAnimations: function() {
|
blockAnimations: function() {
|
||||||
this._animationBlockCount++;
|
this._animationBlockCount++;
|
||||||
},
|
},
|
||||||
@@ -255,9 +319,7 @@ const WindowManager = new Lang.Class({
|
|||||||
if (!actor)
|
if (!actor)
|
||||||
return;
|
return;
|
||||||
let dimmer = getWindowDimmer(actor);
|
let dimmer = getWindowDimmer(actor);
|
||||||
let enabled = Meta.prefs_get_attach_modal_dialogs();
|
if (!dimmer)
|
||||||
dimmer.setEnabled(enabled);
|
|
||||||
if (!enabled)
|
|
||||||
return;
|
return;
|
||||||
Tweener.addTween(dimmer,
|
Tweener.addTween(dimmer,
|
||||||
{ dimFactor: 1.0,
|
{ dimFactor: 1.0,
|
||||||
@@ -271,15 +333,12 @@ const WindowManager = new Lang.Class({
|
|||||||
if (!actor)
|
if (!actor)
|
||||||
return;
|
return;
|
||||||
let dimmer = getWindowDimmer(actor);
|
let dimmer = getWindowDimmer(actor);
|
||||||
let enabled = Meta.prefs_get_attach_modal_dialogs();
|
if (!dimmer)
|
||||||
dimmer.setEnabled(enabled);
|
|
||||||
if (!enabled)
|
|
||||||
return;
|
return;
|
||||||
Tweener.addTween(dimmer,
|
Tweener.addTween(dimmer,
|
||||||
{ dimFactor: 0.0,
|
{ dimFactor: 0.0,
|
||||||
time: UNDIM_TIME,
|
time: UNDIM_TIME,
|
||||||
transition: 'linear'
|
transition: 'linear' });
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_mapWindow : function(shellwm, actor) {
|
_mapWindow : function(shellwm, actor) {
|
||||||
@@ -414,6 +473,21 @@ const WindowManager = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_filterKeybinding: function(shellwm, binding) {
|
||||||
|
if (Main.keybindingMode == Main.KeybindingMode.NONE)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// There's little sense in implementing a keybinding in mutter and
|
||||||
|
// not having it work in NORMAL mode; handle this case generically
|
||||||
|
// so we don't have to explicitly allow all builtin keybindings in
|
||||||
|
// NORMAL mode.
|
||||||
|
if (Main.keybindingMode == Main.KeybindingMode.NORMAL &&
|
||||||
|
binding.is_builtin())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return !(this._allowedKeybindings[binding.get_name()] & Main.keybindingMode);
|
||||||
|
},
|
||||||
|
|
||||||
_switchWorkspace : function(shellwm, from, to, direction) {
|
_switchWorkspace : function(shellwm, from, to, direction) {
|
||||||
if (!this._shouldAnimate()) {
|
if (!this._shouldAnimate()) {
|
||||||
shellwm.completed_switch_workspace();
|
shellwm.completed_switch_workspace();
|
||||||
|
|||||||
@@ -33,21 +33,13 @@ const DRAGGING_WINDOW_OPACITY = 100;
|
|||||||
const BUTTON_LAYOUT_SCHEMA = 'org.gnome.shell.overrides';
|
const BUTTON_LAYOUT_SCHEMA = 'org.gnome.shell.overrides';
|
||||||
const BUTTON_LAYOUT_KEY = 'button-layout';
|
const BUTTON_LAYOUT_KEY = 'button-layout';
|
||||||
|
|
||||||
// Define a layout scheme for small window counts. For larger
|
// When calculating a layout, we calculate the scale of windows and the percent
|
||||||
// counts we fall back to an algorithm. We need more schemes here
|
// of the available area the new layout uses. If the values for the new layout,
|
||||||
// unless we have a really good algorithm.
|
// when weighted with the values as below, are worse than the previous layout's,
|
||||||
|
// we stop looking for a new layout and use the previous layout.
|
||||||
// Each triplet is [xCenter, yCenter, scale] where the scale
|
// Otherwise, we keep looking for a new layout.
|
||||||
// is relative to the width of the workspace.
|
const LAYOUT_SCALE_WEIGHT = 1;
|
||||||
const POSITIONS = {
|
const LAYOUT_SPACE_WEIGHT = 0.1;
|
||||||
1: [[0.5, 0.5, 0.95]],
|
|
||||||
2: [[0.25, 0.5, 0.48], [0.75, 0.5, 0.48]],
|
|
||||||
3: [[0.25, 0.25, 0.48], [0.75, 0.25, 0.48], [0.5, 0.75, 0.48]],
|
|
||||||
4: [[0.25, 0.25, 0.47], [0.75, 0.25, 0.47], [0.75, 0.75, 0.47], [0.25, 0.75, 0.47]],
|
|
||||||
5: [[0.165, 0.25, 0.32], [0.495, 0.25, 0.32], [0.825, 0.25, 0.32], [0.25, 0.75, 0.32], [0.75, 0.75, 0.32]]
|
|
||||||
};
|
|
||||||
// Used in _orderWindowsPermutations, 5! = 120 which is probably the highest we can go
|
|
||||||
const POSITIONING_PERMUTATIONS_MAX = 5;
|
|
||||||
|
|
||||||
function _interpolate(start, end, step) {
|
function _interpolate(start, end, step) {
|
||||||
return start + (end - start) * step;
|
return start + (end - start) * step;
|
||||||
@@ -167,6 +159,24 @@ const WindowClone = new Lang.Class({
|
|||||||
this._selected = false;
|
this._selected = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get slot() {
|
||||||
|
let x, y, w, h;
|
||||||
|
|
||||||
|
if (this.inDrag) {
|
||||||
|
x = this.dragOrigX;
|
||||||
|
y = this.dragOrigY;
|
||||||
|
w = this.actor.width * this.dragOrigScale;
|
||||||
|
h = this.actor.height * this.dragOrigScale;
|
||||||
|
} else {
|
||||||
|
x = this.actor.x;
|
||||||
|
y = this.actor.y;
|
||||||
|
w = this.actor.width * this.actor.scale_x;
|
||||||
|
h = this.actor.height * this.actor.scale_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [x, y, w, h];
|
||||||
|
},
|
||||||
|
|
||||||
setStackAbove: function (actor) {
|
setStackAbove: function (actor) {
|
||||||
this._stackAbove = actor;
|
this._stackAbove = actor;
|
||||||
if (this.inDrag || this._zooming)
|
if (this.inDrag || this._zooming)
|
||||||
@@ -443,6 +453,11 @@ const WindowOverlay = new Lang.Class({
|
|||||||
this._updateCaptionId = metaWindow.connect('notify::title',
|
this._updateCaptionId = metaWindow.connect('notify::title',
|
||||||
Lang.bind(this, function(w) {
|
Lang.bind(this, function(w) {
|
||||||
this.title.text = w.title;
|
this.title.text = w.title;
|
||||||
|
// we need this for the next call to get_preferred_width
|
||||||
|
// to return useful results
|
||||||
|
this.title.set_size(-1, -1);
|
||||||
|
|
||||||
|
this._repositionSelf();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let button = new St.Button({ style_class: 'window-close' });
|
let button = new St.Button({ style_class: 'window-close' });
|
||||||
@@ -504,15 +519,16 @@ const WindowOverlay = new Lang.Class({
|
|||||||
transition: 'easeOutQuad' });
|
transition: 'easeOutQuad' });
|
||||||
},
|
},
|
||||||
|
|
||||||
chromeWidth: function () {
|
|
||||||
return this.closeButton.width - this.closeButton._overlap;
|
|
||||||
},
|
|
||||||
|
|
||||||
chromeHeights: function () {
|
chromeHeights: function () {
|
||||||
return [this.closeButton.height - this.closeButton._overlap,
|
return [this.closeButton.height - this.closeButton._overlap,
|
||||||
this.title.height + this.title._spacing];
|
this.title.height + this.title._spacing];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_repositionSelf: function() {
|
||||||
|
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
|
||||||
|
this.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight, false);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @cloneX: x position of windowClone
|
* @cloneX: x position of windowClone
|
||||||
* @cloneY: y position of windowClone
|
* @cloneY: y position of windowClone
|
||||||
@@ -550,9 +566,8 @@ const WindowOverlay = new Lang.Class({
|
|||||||
else
|
else
|
||||||
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
||||||
|
|
||||||
if (!title.fullWidth)
|
let [titleMinWidth, titleNatWidth] = title.get_preferred_width(-1);
|
||||||
title.fullWidth = title.width;
|
let titleWidth = Math.max(titleMinWidth, Math.min(titleNatWidth, cloneWidth));
|
||||||
let titleWidth = Math.min(title.fullWidth, cloneWidth);
|
|
||||||
|
|
||||||
let titleX = cloneX + (cloneWidth - titleWidth) / 2;
|
let titleX = cloneX + (cloneWidth - titleWidth) / 2;
|
||||||
let titleY = cloneY + cloneHeight + title._spacing;
|
let titleY = cloneY + cloneHeight + title._spacing;
|
||||||
@@ -668,6 +683,280 @@ const WindowPositionFlags = {
|
|||||||
ANIMATE: 1 << 1
|
ANIMATE: 1 << 1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const LayoutStrategy = new Lang.Class({
|
||||||
|
Name: 'LayoutStrategy',
|
||||||
|
Abstract: true,
|
||||||
|
|
||||||
|
_init: function(monitor, rowSpacing, columnSpacing, bottomPadding) {
|
||||||
|
this._monitor = monitor;
|
||||||
|
this._rowSpacing = rowSpacing;
|
||||||
|
this._columnSpacing = columnSpacing;
|
||||||
|
this._bottomPadding = bottomPadding;
|
||||||
|
},
|
||||||
|
|
||||||
|
_newRow: function() {
|
||||||
|
// Row properties:
|
||||||
|
//
|
||||||
|
// * x, y are the position of row, relative to area
|
||||||
|
//
|
||||||
|
// * width, height are the scaled versions of fullWidth, fullHeight
|
||||||
|
//
|
||||||
|
// * width also has the spacing in between windows. It's not in
|
||||||
|
// fullWidth, as the spacing is constant, whereas fullWidth is
|
||||||
|
// meant to be scaled
|
||||||
|
//
|
||||||
|
// * neither height/fullHeight have any sort of spacing or padding
|
||||||
|
//
|
||||||
|
// * if cellWidth is present, all windows in the row will occupy
|
||||||
|
// the space of cellWidth, centered.
|
||||||
|
return { x: 0, y: 0,
|
||||||
|
width: 0, height: 0,
|
||||||
|
fullWidth: 0, fullHeight: 0,
|
||||||
|
cellWidth: 0,
|
||||||
|
windows: [] };
|
||||||
|
},
|
||||||
|
|
||||||
|
// Compute the size and fancy scale for @window using the
|
||||||
|
// base scale, @scale.
|
||||||
|
//
|
||||||
|
// Returns a list structure: [ scaledWidth, scaledHeight, fancyScale ]
|
||||||
|
// where scaledWidth and scaledHeight are the window's
|
||||||
|
// width and height, scaled by fancyScale for convenience.
|
||||||
|
_computeWindowSizeAndScale: function(window, scale) {
|
||||||
|
let width = window.actor.width;
|
||||||
|
let height = window.actor.height;
|
||||||
|
let ratio;
|
||||||
|
|
||||||
|
if (width > height)
|
||||||
|
ratio = width / this._monitor.width;
|
||||||
|
else
|
||||||
|
ratio = height / this._monitor.height;
|
||||||
|
|
||||||
|
let fancyScale = (2 / (1 + ratio)) * scale;
|
||||||
|
return [width * fancyScale, height * fancyScale, fancyScale];
|
||||||
|
},
|
||||||
|
|
||||||
|
// Compute the size of each row, by assigning to the properties
|
||||||
|
// row.width, row.height, row.fullWidth, row.fullHeight, and
|
||||||
|
// (optionally) row.cellWidth, for each row in @layout.rows.
|
||||||
|
// This method is intended to be called by subclasses.
|
||||||
|
_computeRowSizes: function(layout) {
|
||||||
|
throw new Error('_computeRowSizes not implemented');
|
||||||
|
},
|
||||||
|
|
||||||
|
// Compute strategy-specific window slots for each window in
|
||||||
|
// @windows, given the @layout. The strategy may also use @layout
|
||||||
|
// as strategy-specific storage.
|
||||||
|
//
|
||||||
|
// This must calculate:
|
||||||
|
// * maxColumns - The maximum number of columns used by the layout.
|
||||||
|
// * gridWidth - The total width used by the grid, unscaled, unspaced.
|
||||||
|
// * gridHeight - The totial height used by the grid, unscaled, unspaced.
|
||||||
|
// * rows - A list of rows, which should be instantiated by _newRow.
|
||||||
|
computeLayout: function(windows, layout) {
|
||||||
|
throw new Error('computeLayout not implemented');
|
||||||
|
},
|
||||||
|
|
||||||
|
// Given @layout, compute the overall scale and space of the layout.
|
||||||
|
// The scale is the individual, non-fancy scale of each window, and
|
||||||
|
// the space is the percentage of the available area eventually
|
||||||
|
// used by the layout.
|
||||||
|
|
||||||
|
// This method does not return anything, but instead installs
|
||||||
|
// the properties "scale" and "space" on @layout directly.
|
||||||
|
//
|
||||||
|
// Make sure to call this methods before calling computeWindowSlots(),
|
||||||
|
// as it depends on the scale property installed in @layout here.
|
||||||
|
computeScaleAndSpace: function(layout) {
|
||||||
|
let area = layout.area;
|
||||||
|
|
||||||
|
let hspacing = (layout.maxColumns - 1) * this._columnSpacing;
|
||||||
|
let vspacing = (layout.numRows - 1) * this._rowSpacing + this._bottomPadding;
|
||||||
|
|
||||||
|
let spacedWidth = area.width - hspacing;
|
||||||
|
let spacedHeight = area.height - vspacing;
|
||||||
|
|
||||||
|
let horizontalScale = spacedWidth / layout.gridWidth;
|
||||||
|
let verticalScale = spacedHeight / layout.gridHeight;
|
||||||
|
|
||||||
|
// Thumbnails should be less than 70% of the original size
|
||||||
|
let scale = Math.min(horizontalScale, verticalScale, WINDOW_CLONE_MAXIMUM_SCALE);
|
||||||
|
|
||||||
|
let scaledLayoutWidth = layout.gridWidth * scale + hspacing;
|
||||||
|
let scaledLayoutHeight = layout.gridHeight * scale + vspacing;
|
||||||
|
let space = (scaledLayoutWidth * scaledLayoutHeight) / (area.width * area.height);
|
||||||
|
|
||||||
|
layout.scale = scale;
|
||||||
|
layout.space = space;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeWindowSlots: function(layout, area) {
|
||||||
|
this._computeRowSizes(layout);
|
||||||
|
|
||||||
|
let { rows: rows, scale: scale, state: state } = layout;
|
||||||
|
|
||||||
|
let slots = [];
|
||||||
|
|
||||||
|
let y = 0;
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
let row = rows[i];
|
||||||
|
row.x = area.x + (area.width - row.width) / 2;
|
||||||
|
row.y = area.y + y;
|
||||||
|
y += row.height + this._rowSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
let height = y - this._rowSpacing + this._bottomPadding;
|
||||||
|
let baseY = (area.height - height) / 2;
|
||||||
|
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
let row = rows[i];
|
||||||
|
row.y += baseY;
|
||||||
|
let baseX = row.x;
|
||||||
|
for (let j = 0; j < row.windows.length; j++) {
|
||||||
|
let window = row.windows[j];
|
||||||
|
|
||||||
|
let [width, height, s] = this._computeWindowSizeAndScale(window, scale);
|
||||||
|
let y = row.y + row.height - height;
|
||||||
|
|
||||||
|
let x = baseX;
|
||||||
|
if (row.cellWidth) {
|
||||||
|
x += (row.cellWidth - width) / 2;
|
||||||
|
width = row.cellWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
slots.push([x, y, s]);
|
||||||
|
baseX += width + this._columnSpacing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const UnalignedLayoutStrategy = new Lang.Class({
|
||||||
|
Name: 'UnalignedLayoutStrategy',
|
||||||
|
Extends: LayoutStrategy,
|
||||||
|
|
||||||
|
_computeRowSizes: function(layout) {
|
||||||
|
let { rows: rows, scale: scale } = layout;
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
let row = rows[i];
|
||||||
|
row.width = row.fullWidth * scale + (row.windows.length - 1) * this._columnSpacing;
|
||||||
|
row.height = row.fullHeight * scale;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_keepSameRow: function(row, window, width, idealRowWidth) {
|
||||||
|
if (row.fullWidth + width <= idealRowWidth)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
let oldRatio = row.fullWidth / idealRowWidth;
|
||||||
|
let newRatio = (row.fullWidth + width) / idealRowWidth;
|
||||||
|
|
||||||
|
if (Math.abs(1 - newRatio) < Math.abs(1 - oldRatio))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
computeLayout: function(windows, layout) {
|
||||||
|
let numRows = layout.numRows;
|
||||||
|
|
||||||
|
let rows = [];
|
||||||
|
let totalWidth = 0;
|
||||||
|
for (let i = 0; i < windows.length; i++) {
|
||||||
|
totalWidth += windows[i].actor.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
let idealRowWidth = totalWidth / numRows;
|
||||||
|
let windowIdx = 0;
|
||||||
|
for (let i = 0; i < numRows; i++) {
|
||||||
|
let col = 0;
|
||||||
|
let row = this._newRow();
|
||||||
|
rows.push(row);
|
||||||
|
|
||||||
|
for (; windowIdx < windows.length; windowIdx++) {
|
||||||
|
let window = windows[windowIdx];
|
||||||
|
let [width, height] = this._computeWindowSizeAndScale(window, 1);
|
||||||
|
row.fullHeight = Math.max(row.fullHeight, height);
|
||||||
|
|
||||||
|
// either new width is < idealWidth or new width is nearer from idealWidth then oldWidth
|
||||||
|
if (this._keepSameRow(row, window, width, idealRowWidth) || (i == numRows - 1)) {
|
||||||
|
row.windows.push(window);
|
||||||
|
row.fullWidth += width;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let gridHeight = 0;
|
||||||
|
let maxRow;
|
||||||
|
for (let i = 0; i < numRows; i++) {
|
||||||
|
let row = rows[i];
|
||||||
|
if (!maxRow || row.fullWidth > maxRow.fullWidth)
|
||||||
|
maxRow = row;
|
||||||
|
gridHeight += row.fullHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.rows = rows;
|
||||||
|
layout.maxColumns = maxRow.windows.length;
|
||||||
|
layout.gridWidth = maxRow.fullWidth;
|
||||||
|
layout.gridHeight = gridHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const GridLayoutStrategy = new Lang.Class({
|
||||||
|
Name: 'GridLayoutStrategy',
|
||||||
|
Extends: LayoutStrategy,
|
||||||
|
|
||||||
|
_computeRowSizes: function(layout) {
|
||||||
|
let { rows: rows, scale: scale } = layout;
|
||||||
|
|
||||||
|
let gridWidth = layout.numColumns * layout.maxWindowWidth;
|
||||||
|
let hspacing = (layout.numColumns - 1) * this._columnSpacing;
|
||||||
|
for (let i = 0; i < rows.length; i++) {
|
||||||
|
let row = rows[i];
|
||||||
|
row.fullWidth = layout.gridWidth;
|
||||||
|
row.fullHeight = layout.maxWindowHeight;
|
||||||
|
|
||||||
|
row.width = row.fullWidth * scale + hspacing;
|
||||||
|
row.height = row.fullHeight * scale;
|
||||||
|
row.cellWidth = layout.maxWindowWidth * scale;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computeLayout: function(windows, layout) {
|
||||||
|
let { numRows: numRows, numColumns: numColumns } = layout;
|
||||||
|
let rows = [];
|
||||||
|
let windowIdx = 0;
|
||||||
|
|
||||||
|
let maxWindowWidth = 0;
|
||||||
|
let maxWindowHeight = 0;
|
||||||
|
for (let i = 0; i < numRows; i++) {
|
||||||
|
let row = this._newRow();
|
||||||
|
rows.push(row);
|
||||||
|
for (; windowIdx < windows.length; windowIdx++) {
|
||||||
|
if (row.windows.length >= numColumns)
|
||||||
|
break;
|
||||||
|
|
||||||
|
let window = windows[windowIdx];
|
||||||
|
row.windows.push(window);
|
||||||
|
|
||||||
|
let [width, height] = this._computeWindowSizeAndScale(window, 1);
|
||||||
|
maxWindowWidth = Math.max(maxWindowWidth, width);
|
||||||
|
maxWindowHeight = Math.max(maxWindowHeight, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layout.rows = rows;
|
||||||
|
layout.maxColumns = numColumns;
|
||||||
|
layout.gridWidth = numColumns * maxWindowWidth;
|
||||||
|
layout.gridHeight = numRows * maxWindowHeight;
|
||||||
|
layout.maxWindowWidth = maxWindowWidth;
|
||||||
|
layout.maxWindowHeight = maxWindowHeight;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @metaWorkspace: a #Meta.Workspace, or null
|
* @metaWorkspace: a #Meta.Workspace, or null
|
||||||
*/
|
*/
|
||||||
@@ -689,7 +978,7 @@ const Workspace = new Lang.Class({
|
|||||||
// Without this the drop area will be overlapped.
|
// Without this the drop area will be overlapped.
|
||||||
this._windowOverlaysGroup.set_size(0, 0);
|
this._windowOverlaysGroup.set_size(0, 0);
|
||||||
|
|
||||||
this.actor = new Clutter.Group();
|
this.actor = new St.Widget({ style_class: 'window-picker' });
|
||||||
this.actor.set_size(0, 0);
|
this.actor.set_size(0, 0);
|
||||||
|
|
||||||
this._dropRect = new Clutter.Rectangle({ opacity: 0 });
|
this._dropRect = new Clutter.Rectangle({ opacity: 0 });
|
||||||
@@ -729,6 +1018,8 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
this._positionWindowsFlags = 0;
|
this._positionWindowsFlags = 0;
|
||||||
this._positionWindowsId = 0;
|
this._positionWindowsId = 0;
|
||||||
|
|
||||||
|
this._currentLayout = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
setGeometry: function(x, y, width, height) {
|
setGeometry: function(x, y, width, height) {
|
||||||
@@ -763,238 +1054,15 @@ const Workspace = new Lang.Class({
|
|||||||
return this._windows.length == 0;
|
return this._windows.length == 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
// Only use this for n <= 20 say
|
|
||||||
_factorial: function(n) {
|
|
||||||
let result = 1;
|
|
||||||
for (let i = 2; i <= n; i++)
|
|
||||||
result *= i;
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _permutation:
|
|
||||||
* @permutationIndex: An integer from [0, list.length!)
|
|
||||||
* @list: (inout): Array of objects to permute; will be modified in place
|
|
||||||
*
|
|
||||||
* Given an integer between 0 and length of array, re-order the array in-place
|
|
||||||
* into a permutation denoted by the index.
|
|
||||||
*/
|
|
||||||
_permutation: function(permutationIndex, list) {
|
|
||||||
for (let j = 2; j <= list.length; j++) {
|
|
||||||
let firstIndex = (permutationIndex % j);
|
|
||||||
let secondIndex = j - 1;
|
|
||||||
// Swap
|
|
||||||
let tmp = list[firstIndex];
|
|
||||||
list[firstIndex] = list[secondIndex];
|
|
||||||
list[secondIndex] = tmp;
|
|
||||||
permutationIndex = Math.floor(permutationIndex / j);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _forEachPermutations:
|
|
||||||
* @list: Array
|
|
||||||
* @func: Function which takes a single array argument
|
|
||||||
*
|
|
||||||
* Call @func with each permutation of @list as an argument.
|
|
||||||
*/
|
|
||||||
_forEachPermutations: function(list, func) {
|
|
||||||
let nCombinations = this._factorial(list.length);
|
|
||||||
for (let i = 0; i < nCombinations; i++) {
|
|
||||||
let listCopy = list.concat();
|
|
||||||
this._permutation(i, listCopy);
|
|
||||||
func(listCopy);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _computeWindowMotion:
|
|
||||||
* @actor: A #WindowClone's #ClutterActor
|
|
||||||
* @slot: An element of #POSITIONS
|
|
||||||
* @slotGeometry: Layout of @slot
|
|
||||||
*
|
|
||||||
* Returns a number corresponding to how much perceived motion
|
|
||||||
* would be involved in moving the window to the given slot.
|
|
||||||
* Currently this is the square of the distance between the
|
|
||||||
* centers.
|
|
||||||
*/
|
|
||||||
_computeWindowMotion: function (actor, slot) {
|
|
||||||
let [xCenter, yCenter, fraction] = slot;
|
|
||||||
let xDelta, yDelta, distanceSquared;
|
|
||||||
let actorWidth, actorHeight;
|
|
||||||
|
|
||||||
let x = actor.x;
|
|
||||||
let y = actor.y;
|
|
||||||
let scale = actor.scale_x;
|
|
||||||
|
|
||||||
if (actor._delegate.inDrag) {
|
|
||||||
x = actor._delegate.dragOrigX;
|
|
||||||
y = actor._delegate.dragOrigY;
|
|
||||||
scale = actor._delegate.dragOrigScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
actorWidth = actor.width * scale;
|
|
||||||
actorHeight = actor.height * scale;
|
|
||||||
xDelta = x + actorWidth / 2.0 - xCenter * this._width - this._x;
|
|
||||||
yDelta = y + actorHeight / 2.0 - yCenter * this._height - this._y;
|
|
||||||
distanceSquared = xDelta * xDelta + yDelta * yDelta;
|
|
||||||
|
|
||||||
return distanceSquared;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _orderWindowsPermutations:
|
|
||||||
*
|
|
||||||
* Iterate over all permutations of the windows, and determine the
|
|
||||||
* permutation which has the least total motion.
|
|
||||||
*/
|
|
||||||
_orderWindowsPermutations: function (clones, slots) {
|
|
||||||
let minimumMotionPermutation = null;
|
|
||||||
let minimumMotion = -1;
|
|
||||||
let permIndex = 0;
|
|
||||||
this._forEachPermutations(clones, Lang.bind(this, function (permutation) {
|
|
||||||
let motion = 0;
|
|
||||||
for (let i = 0; i < permutation.length; i++) {
|
|
||||||
let cloneActor = permutation[i].actor;
|
|
||||||
let slot = slots[i];
|
|
||||||
|
|
||||||
let delta = this._computeWindowMotion(cloneActor, slot);
|
|
||||||
|
|
||||||
motion += delta;
|
|
||||||
|
|
||||||
// Bail out early if we're already larger than the
|
|
||||||
// previous best
|
|
||||||
if (minimumMotionPermutation != null &&
|
|
||||||
motion > minimumMotion)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minimumMotionPermutation == null || motion < minimumMotion) {
|
|
||||||
minimumMotionPermutation = permutation;
|
|
||||||
minimumMotion = motion;
|
|
||||||
}
|
|
||||||
permIndex++;
|
|
||||||
}));
|
|
||||||
return minimumMotionPermutation;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _orderWindowsGreedy:
|
|
||||||
*
|
|
||||||
* Iterate over available slots in order, placing into each one the window
|
|
||||||
* we find with the smallest motion to that slot.
|
|
||||||
*/
|
|
||||||
_orderWindowsGreedy: function(clones, slots) {
|
|
||||||
let result = [];
|
|
||||||
let slotIndex = 0;
|
|
||||||
// Copy since we mutate below
|
|
||||||
let clonesCopy = clones.concat();
|
|
||||||
for (let i = 0; i < slots.length; i++) {
|
|
||||||
let slot = slots[i];
|
|
||||||
let minimumMotionIndex = -1;
|
|
||||||
let minimumMotion = -1;
|
|
||||||
for (let j = 0; j < clonesCopy.length; j++) {
|
|
||||||
let cloneActor = clonesCopy[j].actor;
|
|
||||||
let delta = this._computeWindowMotion(cloneActor, slot);
|
|
||||||
if (minimumMotionIndex == -1 || delta < minimumMotion) {
|
|
||||||
minimumMotionIndex = j;
|
|
||||||
minimumMotion = delta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result.push(clonesCopy[minimumMotionIndex]);
|
|
||||||
clonesCopy.splice(minimumMotionIndex, 1);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _orderWindowsByMotionAndStartup:
|
|
||||||
* @windows: Array of #MetaWindow
|
|
||||||
* @slots: Array of slots
|
|
||||||
*
|
|
||||||
* Returns a copy of @windows, ordered in such a way that they require least motion
|
|
||||||
* to move to the final screen coordinates of @slots. Ties are broken in a stable
|
|
||||||
* fashion by the order in which the windows were created.
|
|
||||||
*/
|
|
||||||
_orderWindowsByMotionAndStartup: function(clones, slots) {
|
|
||||||
clones.sort(function(w1, w2) {
|
|
||||||
return w2.metaWindow.get_stable_sequence() - w1.metaWindow.get_stable_sequence();
|
|
||||||
});
|
|
||||||
if (clones.length <= POSITIONING_PERMUTATIONS_MAX)
|
|
||||||
return this._orderWindowsPermutations(clones, slots);
|
|
||||||
else
|
|
||||||
return this._orderWindowsGreedy(clones, slots);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _getSlotGeometry:
|
|
||||||
* @slot: A layout slot
|
|
||||||
*
|
|
||||||
* Returns: the screen-relative [x, y, width, height]
|
|
||||||
* of a given window layout slot.
|
|
||||||
*/
|
|
||||||
_getSlotGeometry: function(slot) {
|
|
||||||
let [xCenter, yCenter, fraction] = slot;
|
|
||||||
|
|
||||||
let width = this._width * fraction;
|
|
||||||
let height = this._height * fraction;
|
|
||||||
|
|
||||||
let x = this._x + xCenter * this._width - width / 2 ;
|
|
||||||
let y = this._y + yCenter * this._height - height / 2;
|
|
||||||
|
|
||||||
return [x, y, width, height];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* _computeWindowLayout:
|
|
||||||
* @metaWindow: A #MetaWindow
|
|
||||||
* @slot: A layout slot
|
|
||||||
*
|
|
||||||
* Given a window and slot to fit it in, compute its
|
|
||||||
* screen-relative [x, y, scale] where scale applies
|
|
||||||
* to both X and Y directions.
|
|
||||||
*/
|
|
||||||
_computeWindowLayout: function(metaWindow, slot) {
|
|
||||||
let [x, y, width, height] = this._getSlotGeometry(slot);
|
|
||||||
|
|
||||||
let rect = metaWindow.get_outer_rect();
|
|
||||||
let buttonOuterHeight, captionHeight;
|
|
||||||
let buttonOuterWidth = 0;
|
|
||||||
|
|
||||||
if (this._windowOverlays[0]) {
|
|
||||||
[buttonOuterHeight, captionHeight] = this._windowOverlays[0].chromeHeights();
|
|
||||||
buttonOuterWidth = this._windowOverlays[0].chromeWidth();
|
|
||||||
} else
|
|
||||||
[buttonOuterHeight, captionHeight] = [0, 0];
|
|
||||||
|
|
||||||
let scale = Math.min((width - buttonOuterWidth) / rect.width,
|
|
||||||
(height - buttonOuterHeight - captionHeight) / rect.height,
|
|
||||||
WINDOW_CLONE_MAXIMUM_SCALE);
|
|
||||||
|
|
||||||
x = Math.floor(x + (width - scale * rect.width) / 2);
|
|
||||||
|
|
||||||
// We want to center the window in case we have just one
|
|
||||||
if (metaWindow.get_workspace().n_windows == 1)
|
|
||||||
y = Math.floor(y + (height - scale * rect.height) / 2);
|
|
||||||
else
|
|
||||||
y = Math.floor(y + height - rect.height * scale - captionHeight);
|
|
||||||
|
|
||||||
return [x, y, scale];
|
|
||||||
},
|
|
||||||
|
|
||||||
setReservedSlot: function(clone) {
|
setReservedSlot: function(clone) {
|
||||||
if (this._reservedSlot == clone)
|
if (this._reservedSlot == clone)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (clone && this.containsMetaWindow(clone.metaWindow)) {
|
if (clone && this.containsMetaWindow(clone.metaWindow))
|
||||||
this._reservedSlot = null;
|
clone = null;
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (clone)
|
|
||||||
this._reservedSlot = clone;
|
this._reservedSlot = clone;
|
||||||
else
|
this._currentLayout = null;
|
||||||
this._reservedSlot = null;
|
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1025,6 +1093,11 @@ const Workspace = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let clones = this._windows.slice();
|
let clones = this._windows.slice();
|
||||||
|
|
||||||
|
clones.sort(function(a, b) {
|
||||||
|
return a.metaWindow.get_stable_sequence() - b.metaWindow.get_stable_sequence();
|
||||||
|
});
|
||||||
|
|
||||||
if (this._reservedSlot)
|
if (this._reservedSlot)
|
||||||
clones.push(this._reservedSlot);
|
clones.push(this._reservedSlot);
|
||||||
|
|
||||||
@@ -1032,8 +1105,7 @@ const Workspace = new Lang.Class({
|
|||||||
let animate = flags & WindowPositionFlags.ANIMATE;
|
let animate = flags & WindowPositionFlags.ANIMATE;
|
||||||
|
|
||||||
// Start the animations
|
// Start the animations
|
||||||
let slots = this._computeAllWindowSlots(clones.length);
|
let slots = this._computeAllWindowSlots(clones);
|
||||||
clones = this._orderWindowsByMotionAndStartup(clones, slots);
|
|
||||||
|
|
||||||
let currentWorkspace = global.screen.get_active_workspace();
|
let currentWorkspace = global.screen.get_active_workspace();
|
||||||
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
|
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
|
||||||
@@ -1050,10 +1122,11 @@ const Workspace = new Lang.Class({
|
|||||||
if (clone.inDrag)
|
if (clone.inDrag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
|
let [x, y, scale] = slot;
|
||||||
|
|
||||||
if (overlay && initialPositioning)
|
if (overlay && initialPositioning)
|
||||||
overlay.hide();
|
overlay.hide();
|
||||||
|
|
||||||
if (animate && isOnCurrentWorkspace) {
|
if (animate && isOnCurrentWorkspace) {
|
||||||
if (!metaWindow.showing_on_its_workspace()) {
|
if (!metaWindow.showing_on_its_workspace()) {
|
||||||
/* Hidden windows should fade in and grow
|
/* Hidden windows should fade in and grow
|
||||||
@@ -1077,6 +1150,8 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
|
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
|
||||||
} else {
|
} else {
|
||||||
|
// cancel any active tweens (otherwise they might override our changes)
|
||||||
|
Tweener.removeTweens(clone.actor);
|
||||||
clone.actor.set_position(x, y);
|
clone.actor.set_position(x, y);
|
||||||
clone.actor.set_scale(scale, scale);
|
clone.actor.set_scale(scale, scale);
|
||||||
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
|
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
|
||||||
@@ -1118,11 +1193,11 @@ const Workspace = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
|
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
|
||||||
|
if (!overlay)
|
||||||
|
return;
|
||||||
|
|
||||||
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
||||||
cloneWidth = scale * cloneWidth;
|
overlay.updatePositions(x, y, cloneWidth * scale, cloneHeight * scale, animate);
|
||||||
cloneHeight = scale * cloneHeight;
|
|
||||||
if (overlay)
|
|
||||||
overlay.updatePositions(x, y, cloneWidth, cloneHeight, animate);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_showWindowOverlay: function(clone, overlay, fade) {
|
_showWindowOverlay: function(clone, overlay, fade) {
|
||||||
@@ -1216,6 +1291,7 @@ const Workspace = new Lang.Class({
|
|||||||
this._cursorX = x;
|
this._cursorX = x;
|
||||||
this._cursorY = y;
|
this._cursorY = y;
|
||||||
|
|
||||||
|
this._currentLayout = null;
|
||||||
this._repositionWindowsId = Mainloop.timeout_add(750,
|
this._repositionWindowsId = Mainloop.timeout_add(750,
|
||||||
Lang.bind(this, this._delayedWindowRepositioning));
|
Lang.bind(this, this._delayedWindowRepositioning));
|
||||||
},
|
},
|
||||||
@@ -1268,6 +1344,7 @@ const Workspace = new Lang.Class({
|
|||||||
clone.actor.set_position (this._x, this._y);
|
clone.actor.set_position (this._x, this._y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._currentLayout = null;
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1305,6 +1382,8 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
// Animate the full-screen to Overview transition.
|
// Animate the full-screen to Overview transition.
|
||||||
zoomToOverview : function() {
|
zoomToOverview : function() {
|
||||||
|
this._currentLayout = null;
|
||||||
|
|
||||||
// Position and scale the windows.
|
// Position and scale the windows.
|
||||||
if (Main.overview.animationInProgress)
|
if (Main.overview.animationInProgress)
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
|
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
|
||||||
@@ -1469,29 +1548,108 @@ const Workspace = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_computeWindowSlot : function(windowIndex, numberOfWindows) {
|
_isBetterLayout: function(oldLayout, newLayout) {
|
||||||
if (numberOfWindows in POSITIONS)
|
if (oldLayout.scale === undefined)
|
||||||
return POSITIONS[numberOfWindows][windowIndex];
|
return true;
|
||||||
|
|
||||||
// If we don't have a predefined scheme for this window count,
|
let spacePower = (newLayout.space - oldLayout.space) * LAYOUT_SPACE_WEIGHT;
|
||||||
// arrange the windows in a grid pattern.
|
let scalePower = (newLayout.scale - oldLayout.scale) * LAYOUT_SCALE_WEIGHT;
|
||||||
let gridWidth = Math.ceil(Math.sqrt(numberOfWindows));
|
|
||||||
let gridHeight = Math.ceil(numberOfWindows / gridWidth);
|
|
||||||
|
|
||||||
let fraction = 0.95 * (1. / gridWidth);
|
if (newLayout.scale > oldLayout.scale && newLayout.space > oldLayout.space) {
|
||||||
|
// Win win -- better scale and better space
|
||||||
let xCenter = (.5 / gridWidth) + ((windowIndex) % gridWidth) / gridWidth;
|
return true;
|
||||||
let yCenter = (.5 / gridHeight) + Math.floor((windowIndex / gridWidth)) / gridHeight;
|
} else if (newLayout.scale > oldLayout.scale && newLayout.space <= oldLayout.space) {
|
||||||
|
// Keep new layout only if scale gain outweights aspect space loss
|
||||||
return [xCenter, yCenter, fraction];
|
return scalePower > spacePower;
|
||||||
|
} else if (newLayout.scale <= oldLayout.scale && newLayout.space > oldLayout.space) {
|
||||||
|
// Keep new layout only if aspect space gain outweights scale loss
|
||||||
|
return spacePower > scalePower;
|
||||||
|
} else {
|
||||||
|
// Lose -- worse scale and space
|
||||||
|
return false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_computeAllWindowSlots: function(totalWindows) {
|
_computeLayout: function(windows, area, rowSpacing, columnSpacing, bottomPadding) {
|
||||||
let slots = [];
|
// We look for the largest scale that allows us to fit the
|
||||||
for (let i = 0; i < totalWindows; i++) {
|
// largest row/tallest column on the workspace.
|
||||||
slots.push(this._computeWindowSlot(i, totalWindows));
|
|
||||||
|
let lastLayout = {};
|
||||||
|
|
||||||
|
for (let numRows = 1; ; numRows++) {
|
||||||
|
let numColumns = Math.ceil(windows.length / numRows);
|
||||||
|
|
||||||
|
// If adding a new row does not change column count just stop
|
||||||
|
// (for instance: 9 windows, with 3 rows -> 3 columns, 4 rows ->
|
||||||
|
// 3 columns as well => just use 3 rows then)
|
||||||
|
if (numColumns == lastLayout.numColumns)
|
||||||
|
break;
|
||||||
|
|
||||||
|
let strategyClass = numRows > 2 ? GridLayoutStrategy : UnalignedLayoutStrategy;
|
||||||
|
let strategy = new strategyClass(this._monitor, rowSpacing, columnSpacing, bottomPadding);
|
||||||
|
|
||||||
|
let layout = { area: area, strategy: strategy, numRows: numRows, numColumns: numColumns };
|
||||||
|
strategy.computeLayout(windows, layout);
|
||||||
|
strategy.computeScaleAndSpace(layout);
|
||||||
|
|
||||||
|
if (!this._isBetterLayout(lastLayout, layout))
|
||||||
|
break;
|
||||||
|
|
||||||
|
lastLayout = layout;
|
||||||
}
|
}
|
||||||
return slots;
|
|
||||||
|
return lastLayout;
|
||||||
|
},
|
||||||
|
|
||||||
|
_rectEqual: function(one, two) {
|
||||||
|
if (one == two)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return (one.x == two.x &&
|
||||||
|
one.y == two.y &&
|
||||||
|
one.width == two.width &&
|
||||||
|
one.height == two.height);
|
||||||
|
},
|
||||||
|
|
||||||
|
_computeAllWindowSlots: function(windows) {
|
||||||
|
let totalWindows = windows.length;
|
||||||
|
let node = this.actor.get_theme_node();
|
||||||
|
|
||||||
|
// Window grid spacing
|
||||||
|
let columnSpacing = node.get_length('-horizontal-spacing');
|
||||||
|
let rowSpacing = node.get_length('-vertical-spacing');
|
||||||
|
|
||||||
|
if (!totalWindows)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
let closeButtonHeight, captionHeight;
|
||||||
|
if (this._windowOverlays.length) {
|
||||||
|
// All of the overlays have the same chrome sizes,
|
||||||
|
// so just pick the first one.
|
||||||
|
let overlay = this._windowOverlays[0];
|
||||||
|
[closeButtonHeight, captionHeight] = overlay.chromeHeights();
|
||||||
|
} else {
|
||||||
|
[closeButtonHeight, captionHeight] = [0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
rowSpacing += captionHeight;
|
||||||
|
|
||||||
|
let area = { x: this._x, y: this._y, width: this._width, height: this._height };
|
||||||
|
area.y += closeButtonHeight;
|
||||||
|
area.height -= closeButtonHeight;
|
||||||
|
|
||||||
|
if (!this._currentLayout)
|
||||||
|
this._currentLayout = this._computeLayout(windows, area, rowSpacing, columnSpacing, captionHeight);
|
||||||
|
|
||||||
|
let layout = this._currentLayout;
|
||||||
|
let strategy = layout.strategy;
|
||||||
|
|
||||||
|
if (!this._rectEqual(area, layout.area)) {
|
||||||
|
layout.area = area;
|
||||||
|
strategy.computeScaleAndSpace(layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strategy.computeWindowSlots(layout, area);
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCloneSelected : function (clone, time) {
|
_onCloneSelected : function (clone, time) {
|
||||||
|
|||||||
@@ -620,9 +620,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
if (!source.realWindow && !source.shellWorkspaceLaunch && source != Main.xdndHandler)
|
if (!source.realWindow && !source.shellWorkspaceLaunch && source != Main.xdndHandler)
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
if (!Meta.prefs_get_dynamic_workspaces())
|
let canCreateWorkspaces = Meta.prefs_get_dynamic_workspaces();
|
||||||
return DND.DragMotionResult.CONTINUE;
|
|
||||||
|
|
||||||
let spacing = this.actor.get_theme_node().get_length('spacing');
|
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||||
|
|
||||||
this._dropWorkspace = -1;
|
this._dropWorkspace = -1;
|
||||||
@@ -647,7 +645,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
if (i == this._dropPlaceholderPos)
|
if (i == this._dropPlaceholderPos)
|
||||||
targetBottom += this._dropPlaceholder.get_height();
|
targetBottom += this._dropPlaceholder.get_height();
|
||||||
|
|
||||||
if (y > targetTop && y <= targetBottom && source != Main.xdndHandler) {
|
if (y > targetTop && y <= targetBottom && source != Main.xdndHandler && canCreateWorkspaces) {
|
||||||
placeholderPos = i;
|
placeholderPos = i;
|
||||||
break;
|
break;
|
||||||
} else if (y > targetBottom && y <= nextTargetTop) {
|
} else if (y > targetBottom && y <= nextTargetTop) {
|
||||||
@@ -785,7 +783,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
this._indicator.raise_top();
|
this._indicator.raise_top();
|
||||||
},
|
},
|
||||||
|
|
||||||
removeThumbmails: function(start, count) {
|
removeThumbnails: function(start, count) {
|
||||||
let currentPos = 0;
|
let currentPos = 0;
|
||||||
for (let k = 0; k < this._thumbnails.length; k++) {
|
for (let k = 0; k < this._thumbnails.length; k++) {
|
||||||
let thumbnail = this._thumbnails[k];
|
let thumbnail = this._thumbnails[k];
|
||||||
@@ -1045,9 +1043,16 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
childBox.y2 = box.y2;
|
childBox.y2 = box.y2;
|
||||||
this._background.allocate(childBox, flags);
|
this._background.allocate(childBox, flags);
|
||||||
|
|
||||||
let indicatorY = this._indicatorY;
|
let indicatorY1 = this._indicatorY;
|
||||||
|
let indicatorY2;
|
||||||
// when not animating, the workspace position overrides this._indicatorY
|
// when not animating, the workspace position overrides this._indicatorY
|
||||||
let indicatorWorkspace = !this._animatingIndicator ? global.screen.get_active_workspace() : null;
|
let indicatorWorkspace = !this._animatingIndicator ? global.screen.get_active_workspace() : null;
|
||||||
|
let indicatorThemeNode = this._indicator.get_theme_node();
|
||||||
|
|
||||||
|
let indicatorTopFullBorder = indicatorThemeNode.get_padding(St.Side.TOP) + indicatorThemeNode.get_border_width(St.Side.TOP);
|
||||||
|
let indicatorBottomFullBorder = indicatorThemeNode.get_padding(St.Side.BOTTOM) + indicatorThemeNode.get_border_width(St.Side.BOTTOM);
|
||||||
|
let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) + indicatorThemeNode.get_border_width(St.Side.LEFT);
|
||||||
|
let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) + indicatorThemeNode.get_border_width(St.Side.RIGHT);
|
||||||
|
|
||||||
let y = contentBox.y1;
|
let y = contentBox.y1;
|
||||||
|
|
||||||
@@ -1093,8 +1098,10 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
let y2 = Math.round(y + thumbnailHeight);
|
let y2 = Math.round(y + thumbnailHeight);
|
||||||
let roundedVScale = (y2 - y1) / portholeHeight;
|
let roundedVScale = (y2 - y1) / portholeHeight;
|
||||||
|
|
||||||
if (thumbnail.metaWorkspace == indicatorWorkspace)
|
if (thumbnail.metaWorkspace == indicatorWorkspace) {
|
||||||
indicatorY = y1;
|
indicatorY1 = y1;
|
||||||
|
indicatorY2 = y2;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocating a scaled actor is funny - x1/y1 correspond to the origin
|
// Allocating a scaled actor is funny - x1/y1 correspond to the origin
|
||||||
// of the actor, but x2/y2 are increased by the *unscaled* size.
|
// of the actor, but x2/y2 are increased by the *unscaled* size.
|
||||||
@@ -1119,8 +1126,10 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
childBox.x1 = contentBox.x2 - thumbnailWidth;
|
childBox.x1 = contentBox.x2 - thumbnailWidth;
|
||||||
childBox.x2 = contentBox.x2;
|
childBox.x2 = contentBox.x2;
|
||||||
}
|
}
|
||||||
childBox.y1 = indicatorY;
|
childBox.x1 -= indicatorLeftFullBorder;
|
||||||
childBox.y2 = childBox.y1 + thumbnailHeight;
|
childBox.x2 += indicatorRightFullBorder;
|
||||||
|
childBox.y1 = indicatorY1 - indicatorTopFullBorder;
|
||||||
|
childBox.y2 = (indicatorY2 ? indicatorY2 : (indicatorY1 + thumbnailHeight)) + indicatorBottomFullBorder;
|
||||||
this._indicator.allocate(childBox, flags);
|
this._indicator.allocate(childBox, flags);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1135,7 +1144,9 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._animatingIndicator = true;
|
this._animatingIndicator = true;
|
||||||
this.indicatorY = this._indicator.allocation.y1;
|
let indicatorThemeNode = this._indicator.get_theme_node();
|
||||||
|
let indicatorTopFullBorder = indicatorThemeNode.get_padding(St.Side.TOP) + indicatorThemeNode.get_border_width(St.Side.TOP);
|
||||||
|
this.indicatorY = this._indicator.allocation.y1 + indicatorTopFullBorder;
|
||||||
Tweener.addTween(this,
|
Tweener.addTween(this,
|
||||||
{ indicatorY: thumbnail.actor.allocation.y1,
|
{ indicatorY: thumbnail.actor.allocation.y1,
|
||||||
time: WorkspacesView.WORKSPACE_SWITCH_TIME,
|
time: WorkspacesView.WORKSPACE_SWITCH_TIME,
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._clipY = 0;
|
this._clipY = 0;
|
||||||
this._clipWidth = 0;
|
this._clipWidth = 0;
|
||||||
this._clipHeight = 0;
|
this._clipHeight = 0;
|
||||||
this._workspaceRatioSpacing = 0;
|
|
||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
this._animating = false; // tweening
|
this._animating = false; // tweening
|
||||||
this._scrolling = false; // swipe-scrolling
|
this._scrolling = false; // swipe-scrolling
|
||||||
@@ -72,6 +71,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._workspaces[w].actor.reparent(this.actor);
|
this._workspaces[w].actor.reparent(this.actor);
|
||||||
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
||||||
|
|
||||||
|
this._extraWorkspaces = [];
|
||||||
this._updateExtraWorkspaces();
|
this._updateExtraWorkspaces();
|
||||||
|
|
||||||
// Position/scale the desktop windows and their children after the
|
// Position/scale the desktop windows and their children after the
|
||||||
@@ -83,8 +83,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
this._workspaces[w].zoomToOverview();
|
this._workspaces[w].zoomToOverview();
|
||||||
if (!this._extraWorkspaces)
|
|
||||||
return;
|
|
||||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||||
this._extraWorkspaces[w].zoomToOverview();
|
this._extraWorkspaces[w].zoomToOverview();
|
||||||
}));
|
}));
|
||||||
@@ -124,7 +122,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
if (!this._settings.get_boolean('workspaces-only-on-primary'))
|
if (!this._settings.get_boolean('workspaces-only-on-primary'))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._extraWorkspaces = [];
|
|
||||||
let monitors = Main.layoutManager.monitors;
|
let monitors = Main.layoutManager.monitors;
|
||||||
for (let i = 0; i < monitors.length; i++) {
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
if (i == Main.layoutManager.primaryIndex)
|
if (i == Main.layoutManager.primaryIndex)
|
||||||
@@ -139,23 +136,20 @@ const WorkspacesView = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_destroyExtraWorkspaces: function() {
|
_destroyExtraWorkspaces: function() {
|
||||||
if (!this._extraWorkspaces)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (let m = 0; m < this._extraWorkspaces.length; m++)
|
for (let m = 0; m < this._extraWorkspaces.length; m++)
|
||||||
this._extraWorkspaces[m].destroy();
|
this._extraWorkspaces[m].destroy();
|
||||||
this._extraWorkspaces = null;
|
this._extraWorkspaces = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
setGeometry: function(x, y, width, height, spacing) {
|
setGeometry: function(x, y, width, height) {
|
||||||
if (this._x == x && this._y == y &&
|
if (this._x == x && this._y == y &&
|
||||||
this._width == width && this._height == height)
|
this._width == width && this._height == height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._width = width;
|
this._width = width;
|
||||||
this._height = height;
|
this._height = height;
|
||||||
this._x = x;
|
this._x = x;
|
||||||
this._y = y;
|
this._y = y;
|
||||||
this._workspaceRatioSpacing = spacing;
|
|
||||||
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setGeometry(x, y, width, height);
|
this._workspaces[i].setGeometry(x, y, width, height);
|
||||||
@@ -191,8 +185,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
this._workspaces[w].zoomFromOverview();
|
this._workspaces[w].zoomFromOverview();
|
||||||
if (!this._extraWorkspaces)
|
|
||||||
return;
|
|
||||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||||
this._extraWorkspaces[w].zoomFromOverview();
|
this._extraWorkspaces[w].zoomFromOverview();
|
||||||
},
|
},
|
||||||
@@ -204,8 +196,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
syncStacking: function(stackIndices) {
|
syncStacking: function(stackIndices) {
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].syncStacking(stackIndices);
|
this._workspaces[i].syncStacking(stackIndices);
|
||||||
if (!this._extraWorkspaces)
|
|
||||||
return;
|
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].syncStacking(stackIndices);
|
this._extraWorkspaces[i].syncStacking(stackIndices);
|
||||||
},
|
},
|
||||||
@@ -234,7 +224,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
Tweener.removeTweens(workspace.actor);
|
Tweener.removeTweens(workspace.actor);
|
||||||
|
|
||||||
let y = (w - active) * (this._height + this._spacing + this._workspaceRatioSpacing);
|
let y = (w - active) * (this._height + this._spacing);
|
||||||
|
|
||||||
if (showAnimation) {
|
if (showAnimation) {
|
||||||
let params = { y: y,
|
let params = { y: y,
|
||||||
@@ -317,8 +307,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
this._updateWorkspaceActors(false);
|
this._updateWorkspaceActors(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._scrollToActive(true);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
_activeWorkspaceChanged: function(wm, from, to, direction) {
|
||||||
@@ -378,9 +366,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._firstDragMotion = false;
|
this._firstDragMotion = false;
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||||
if (!this._extraWorkspaces)
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
|
||||||
|
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||||
}
|
}
|
||||||
@@ -394,9 +379,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setReservedSlot(null);
|
this._workspaces[i].setReservedSlot(null);
|
||||||
|
|
||||||
if (!this._extraWorkspaces)
|
|
||||||
return;
|
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].setReservedSlot(null);
|
this._extraWorkspaces[i].setReservedSlot(null);
|
||||||
},
|
},
|
||||||
@@ -543,6 +525,16 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._notifyOpacityId = 0;
|
this._notifyOpacityId = 0;
|
||||||
this._swipeScrollBeginId = 0;
|
this._swipeScrollBeginId = 0;
|
||||||
this._swipeScrollEndId = 0;
|
this._swipeScrollEndId = 0;
|
||||||
|
|
||||||
|
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
|
||||||
|
this._settings.connect('changed::dynamic-workspaces',
|
||||||
|
Lang.bind(this, this._updateSwitcherVisibility));
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateSwitcherVisibility: function() {
|
||||||
|
this._thumbnailsBox.actor.visible =
|
||||||
|
this._settings.get_boolean('dynamic-workspaces') ||
|
||||||
|
global.screen.n_workspaces > 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
@@ -565,6 +557,7 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
|
|
||||||
this._controls.show();
|
this._controls.show();
|
||||||
this._thumbnailsBox.show();
|
this._thumbnailsBox.show();
|
||||||
|
this._updateSwitcherVisibility();
|
||||||
|
|
||||||
this._updateWorkspacesViews();
|
this._updateWorkspacesViews();
|
||||||
|
|
||||||
@@ -866,24 +859,15 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||||
|
|
||||||
let clipWidth = width - controlsVisible;
|
let clipWidth = width - controlsVisible;
|
||||||
let clipHeight = (fullHeight / fullWidth) * clipWidth;
|
let clipHeight = fullHeight;
|
||||||
let clipX = rtl ? x + controlsVisible : x;
|
let clipX = rtl ? x + controlsVisible : x;
|
||||||
let clipY = y + (fullHeight - clipHeight) / 2;
|
let clipY = y + (fullHeight - clipHeight) / 2;
|
||||||
|
|
||||||
if (this._zoomOut) {
|
let widthAdjust = this._zoomOut ? controlsNatural : controlsVisible;
|
||||||
width -= controlsNatural;
|
widthAdjust += Main.overview._spacing;
|
||||||
|
width -= widthAdjust;
|
||||||
if (rtl)
|
if (rtl)
|
||||||
x += controlsNatural;
|
x += widthAdjust;
|
||||||
} else {
|
|
||||||
width -= controlsVisible;
|
|
||||||
if (rtl)
|
|
||||||
x += controlsVisible;
|
|
||||||
}
|
|
||||||
|
|
||||||
height = (fullHeight / fullWidth) * width;
|
|
||||||
let difference = fullHeight - height;
|
|
||||||
y += difference / 2;
|
|
||||||
|
|
||||||
|
|
||||||
let monitors = Main.layoutManager.monitors;
|
let monitors = Main.layoutManager.monitors;
|
||||||
let m = 0;
|
let m = 0;
|
||||||
@@ -891,8 +875,7 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
if (i == this._primaryIndex) {
|
if (i == this._primaryIndex) {
|
||||||
this._workspacesViews[m].setClipRect(clipX, clipY,
|
this._workspacesViews[m].setClipRect(clipX, clipY,
|
||||||
clipWidth, clipHeight);
|
clipWidth, clipHeight);
|
||||||
this._workspacesViews[m].setGeometry(x, y, width, height,
|
this._workspacesViews[m].setGeometry(x, y, width, height);
|
||||||
difference);
|
|
||||||
m++;
|
m++;
|
||||||
} else if (!this._workspacesOnlyOnPrimary) {
|
} else if (!this._workspacesOnlyOnPrimary) {
|
||||||
this._workspacesViews[m].setClipRect(monitors[i].x,
|
this._workspacesViews[m].setClipRect(monitors[i].x,
|
||||||
@@ -902,7 +885,7 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._workspacesViews[m].setGeometry(monitors[i].x,
|
this._workspacesViews[m].setGeometry(monitors[i].x,
|
||||||
monitors[i].y,
|
monitors[i].y,
|
||||||
monitors[i].width,
|
monitors[i].width,
|
||||||
monitors[i].height, 0);
|
monitors[i].height);
|
||||||
m++;
|
m++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,16 +922,17 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
let monitors = Main.layoutManager.monitors;
|
let monitors = Main.layoutManager.monitors;
|
||||||
let m = 0;
|
let m = 0;
|
||||||
for (let i = 0; i < monitors.length; i++) {
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
if (this._workspacesOnlyOnPrimaryChanged &&
|
if (this._workspacesOnlyOnPrimary &&
|
||||||
i != this._primaryIndex)
|
i != this._primaryIndex)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Assume workspaces are only added at the end
|
// Assume workspaces are only added at the end
|
||||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||||
this._workspaces[m++][w] =
|
this._workspaces[m][w] =
|
||||||
new Workspace.Workspace(metaWorkspace, i);
|
new Workspace.Workspace(metaWorkspace, i);
|
||||||
}
|
}
|
||||||
|
m++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
|
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
|
||||||
@@ -975,12 +959,13 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
|
this._thumbnailsBox.removeThumbnails(removedIndex, removedNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
|
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
|
||||||
newNumWorkspaces);
|
newNumWorkspaces);
|
||||||
|
this._updateSwitcherVisibility();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateZoom : function() {
|
_updateZoom : function() {
|
||||||
|
|||||||
@@ -1 +1,19 @@
|
|||||||
dist_man_MANS = gnome-shell.1
|
XSLTPROC_FLAGS = \
|
||||||
|
--nonet \
|
||||||
|
--stringparam man.output.quietly 1 \
|
||||||
|
--stringparam funcsynopsis.style ansi \
|
||||||
|
--stringparam man.th.extra1.suppress 1 \
|
||||||
|
--stringparam man.authors.section.enabled 0 \
|
||||||
|
--stringparam man.copyright.section.enabled 0
|
||||||
|
|
||||||
|
.xml.1:
|
||||||
|
$(AM_V_GEN) $(XSLTPROC) $(XSLTPROC_FLAGS) http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl $<
|
||||||
|
|
||||||
|
man_MANS = \
|
||||||
|
gnome-shell.1
|
||||||
|
|
||||||
|
xml_files = $(man_MANS:.1=.xml)
|
||||||
|
|
||||||
|
EXTRA_DIST = $(xml_files)
|
||||||
|
|
||||||
|
DISTCLEANFILES = $(man_MANS)
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
.\" Copyright (c) 2009, Marcelo Jorge Vieira (metal) <metal@alucinados.com>
|
|
||||||
.\"
|
|
||||||
.\" This is free documentation; you can redistribute it and/or
|
|
||||||
.\" modify it under the terms of the GNU General Public License as
|
|
||||||
.\" published by the Free Software Foundation; either version 2 of
|
|
||||||
.\" the License, or (at your option) any later version.
|
|
||||||
.\"
|
|
||||||
.\" The GNU General Public License's references to "object code"
|
|
||||||
.\" and "executables" are to be interpreted as the output of any
|
|
||||||
.\" document formatting or typesetting system, including
|
|
||||||
.\" intermediate and printed output.
|
|
||||||
.\"
|
|
||||||
.\" This manual is distributed in the hope that it will be useful,
|
|
||||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
.\" GNU General Public License for more details.
|
|
||||||
.\"
|
|
||||||
.\" You should have received a copy of the GNU General Public
|
|
||||||
.\" License along with this manual; if not, write to the Free
|
|
||||||
.\" Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
||||||
.\" Boston, MA 02111-1301 USA.
|
|
||||||
.TH GNOME-SHELL 1
|
|
||||||
.SH NAME
|
|
||||||
gnome-shell \- Graphical shell for the GNOME desktop
|
|
||||||
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B gnome-shell [options]
|
|
||||||
|
|
||||||
.SH DESCRIPTION
|
|
||||||
GNOME Shell provides core user interface functions for the GNOME 3
|
|
||||||
desktop, like switching to windows and launching applications. GNOME
|
|
||||||
Shell takes advantage of the capabilities of modern graphics hardware
|
|
||||||
and introduces innovative user interface concepts to provide a
|
|
||||||
visually attractive and easy to use experience.
|
|
||||||
|
|
||||||
.SH OPTIONS
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-replace
|
|
||||||
Replace the running window manager
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-sm-disable
|
|
||||||
Disable connection to the session manager
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-sm-client-id=ID
|
|
||||||
Specify session management ID
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-sm-save-file=FILE
|
|
||||||
Initialize session from savefile
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-screen=SCREEN
|
|
||||||
X screen to use
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-d, \-\-display=DISPLAY
|
|
||||||
X display to use
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-sync
|
|
||||||
Make X calls synchronous
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-version
|
|
||||||
Print version and exit
|
|
||||||
.br
|
|
||||||
|
|
||||||
.TP
|
|
||||||
.B \-\-help
|
|
||||||
Display help and exit
|
|
||||||
.br
|
|
||||||
|
|
||||||
.SH BUGS
|
|
||||||
The bug tracker can be reached by visiting the website
|
|
||||||
\fIhttps://bugzilla.gnome.org/buglist.cgi?product=gnome-shell\fR
|
|
||||||
|
|
||||||
Before sending a bug report, please verify that you have the latest
|
|
||||||
version of gnome-shell. Many bugs (major and minor) are fixed at each
|
|
||||||
release, and if yours is out of date, the problem may already have
|
|
||||||
been solved.
|
|
||||||
|
|
||||||
.SH ADDITIONAL INFORMATION
|
|
||||||
|
|
||||||
For further information, visit the website \fIhttp://live.gnome.org/GnomeShell\fR
|
|
||||||
159
man/gnome-shell.xml
Normal file
159
man/gnome-shell.xml
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
<?xml version='1.0'?>
|
||||||
|
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||||
|
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||||
|
|
||||||
|
<refentry id="gnome-shell">
|
||||||
|
|
||||||
|
<refentryinfo>
|
||||||
|
<title>gnome-shell</title>
|
||||||
|
<productname>gnome-shell</productname>
|
||||||
|
|
||||||
|
<authorgroup>
|
||||||
|
<author>
|
||||||
|
<contrib>wrote the original gnome-shell man page</contrib>
|
||||||
|
<firstname>Marcelo Jorge</firstname>
|
||||||
|
<surname>Vieira</surname>
|
||||||
|
<email>metal@alucinados.com</email>
|
||||||
|
</author>
|
||||||
|
</authorgroup>
|
||||||
|
|
||||||
|
</refentryinfo>
|
||||||
|
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle>gnome-shell</refentrytitle>
|
||||||
|
<manvolnum>1</manvolnum>
|
||||||
|
</refmeta>
|
||||||
|
|
||||||
|
<refnamediv>
|
||||||
|
<refname>gnome-shell</refname>
|
||||||
|
<refpurpose>Graphical shell for the GNOME desktop</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<cmdsynopsis>
|
||||||
|
<command>gnome-shell <arg choice="opt" rep="repeat">OPTION</arg></command>
|
||||||
|
</cmdsynopsis>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Description</title>
|
||||||
|
|
||||||
|
<para>GNOME shell provides core user
|
||||||
|
interface functions for the GNOME 3 desktop, like switching
|
||||||
|
to windows and launching applications. GNOME shell takes
|
||||||
|
advantage of the capabilities of modern graphics hardware
|
||||||
|
and introduces innovative user interface concepts to provide
|
||||||
|
a visually attractive and easy to use experience.</para>
|
||||||
|
|
||||||
|
<para>gnome-shell is a required component of
|
||||||
|
the GNOME desktop, i.e. it is listed in the
|
||||||
|
RequiredComponents field of
|
||||||
|
<filename>/usr/share/gnome-session/sessions/gnome.session</filename>.
|
||||||
|
It is started in the window manager phase of the session.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Options</title>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-r</option>, <option>--replace</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Replace the running window manager</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--sm-disable</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Disable connection to the session manager</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--sm-client-id=<replaceable>ID</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>Specify session management <replaceable>ID</replaceable></para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--sm-save-file=<replaceable>FILE</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>Initialize session from <replaceable>FILE</replaceable></para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--screen=<replaceable>SCREEN</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>X screen to use</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-d</option>, <option>--display=<replaceable>DISPLAY</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>X Display to use</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--sync</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Make X calls synchronous</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--version</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Print version and exit</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--help</option></term>
|
||||||
|
|
||||||
|
<listitem><para>Display help and exit</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--mode=<replaceable>MODE</replaceable></option></term>
|
||||||
|
|
||||||
|
<listitem><para>Use a specific mode, e.g. "gdm" for login screen</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>--list-modes</option></term>
|
||||||
|
|
||||||
|
<listitem><para>List possible modes and exit</para></listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Files</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<filename>/usr/share/gnome-session/sessions/gnome.session</filename>,
|
||||||
|
<filename>/usr/share/applications/gnome-shell.desktop</filename>.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Bugs</title>
|
||||||
|
|
||||||
|
<para>The bug tracker can be reached by visiting the
|
||||||
|
website <ulink url="https://bugzilla.gnome.org/buglist.cgi?product=gnome-shell">https://bugzilla.gnome.org/buglist.cgi?product=gnome-shell</ulink>.
|
||||||
|
Before sending a bug report, please verify that you have
|
||||||
|
the latest version of gnome-shell. Many bugs (major and
|
||||||
|
minor) are fixed at each release, and if yours is out of
|
||||||
|
date, the problem may already have been solved.</para>
|
||||||
|
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Additional Information</title>
|
||||||
|
|
||||||
|
<para>For further information, visit the website
|
||||||
|
<ulink url="http://live.gnome.org/GnomeShell">http://live.gnome.org/GnomeShell</ulink>.</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
</refentry>
|
||||||
@@ -34,6 +34,7 @@ kk
|
|||||||
kn
|
kn
|
||||||
ko
|
ko
|
||||||
ku
|
ku
|
||||||
|
ky
|
||||||
lt
|
lt
|
||||||
lv
|
lv
|
||||||
ml
|
ml
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
data/50-gnome-shell-screenshot.xml.in
|
||||||
|
data/50-gnome-shell-system.xml.in
|
||||||
data/gnome-shell.desktop.in.in
|
data/gnome-shell.desktop.in.in
|
||||||
data/gnome-shell-extension-prefs.desktop.in.in
|
data/gnome-shell-extension-prefs.desktop.in.in
|
||||||
data/org.gnome.shell.gschema.xml.in.in
|
data/org.gnome.shell.gschema.xml.in.in
|
||||||
@@ -8,24 +10,25 @@ js/gdm/util.js
|
|||||||
js/misc/util.js
|
js/misc/util.js
|
||||||
js/ui/appDisplay.js
|
js/ui/appDisplay.js
|
||||||
js/ui/appFavorites.js
|
js/ui/appFavorites.js
|
||||||
js/ui/autorunManager.js
|
|
||||||
js/ui/calendar.js
|
js/ui/calendar.js
|
||||||
|
js/ui/components/autorunManager.js
|
||||||
|
js/ui/components/keyring.js
|
||||||
|
js/ui/components/networkAgent.js
|
||||||
|
js/ui/components/polkitAgent.js
|
||||||
|
js/ui/components/recorder.js
|
||||||
|
js/ui/components/telepathyClient.js
|
||||||
js/ui/dash.js
|
js/ui/dash.js
|
||||||
js/ui/dateMenu.js
|
js/ui/dateMenu.js
|
||||||
js/ui/endSessionDialog.js
|
js/ui/endSessionDialog.js
|
||||||
js/ui/extensionDownloader.js
|
js/ui/extensionDownloader.js
|
||||||
js/ui/extensionSystem.js
|
js/ui/extensionSystem.js
|
||||||
js/ui/keyboard.js
|
js/ui/keyboard.js
|
||||||
js/ui/keyringPrompt.js
|
|
||||||
js/ui/lookingGlass.js
|
js/ui/lookingGlass.js
|
||||||
js/ui/main.js
|
js/ui/main.js
|
||||||
js/ui/messageTray.js
|
js/ui/messageTray.js
|
||||||
js/ui/networkAgent.js
|
|
||||||
js/ui/notificationDaemon.js
|
js/ui/notificationDaemon.js
|
||||||
js/ui/overview.js
|
js/ui/overview.js
|
||||||
js/ui/panel.js
|
js/ui/panel.js
|
||||||
js/ui/placeDisplay.js
|
|
||||||
js/ui/polkitAuthenticationAgent.js
|
|
||||||
js/ui/popupMenu.js
|
js/ui/popupMenu.js
|
||||||
js/ui/runDialog.js
|
js/ui/runDialog.js
|
||||||
js/ui/screenShield.js
|
js/ui/screenShield.js
|
||||||
@@ -35,10 +38,10 @@ js/ui/shellMountOperation.js
|
|||||||
js/ui/status/accessibility.js
|
js/ui/status/accessibility.js
|
||||||
js/ui/status/bluetooth.js
|
js/ui/status/bluetooth.js
|
||||||
js/ui/status/keyboard.js
|
js/ui/status/keyboard.js
|
||||||
|
js/ui/status/lockScreenMenu.js
|
||||||
js/ui/status/network.js
|
js/ui/status/network.js
|
||||||
js/ui/status/power.js
|
js/ui/status/power.js
|
||||||
js/ui/status/volume.js
|
js/ui/status/volume.js
|
||||||
js/ui/telepathyClient.js
|
|
||||||
js/ui/unlockDialog.js
|
js/ui/unlockDialog.js
|
||||||
js/ui/userMenu.js
|
js/ui/userMenu.js
|
||||||
js/ui/viewSelector.js
|
js/ui/viewSelector.js
|
||||||
|
|||||||
1649
po/ca@valencia.po
1649
po/ca@valencia.po
File diff suppressed because it is too large
Load Diff
1633
po/en_GB.po
1633
po/en_GB.po
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