Compare commits
645 Commits
2.91.90
...
goa-client
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a69e45b5eb | ||
|
|
a355398b0f | ||
|
|
4bfc3bafcb | ||
|
|
898b2b903d | ||
|
|
7921954a31 | ||
|
|
0e42de9149 | ||
|
|
8e4a5f1ac5 | ||
|
|
61577e176e | ||
|
|
4b008b1ada | ||
|
|
bee37b5bc4 | ||
|
|
b5ab8b6ed5 | ||
|
|
4d6bd91d16 | ||
|
|
5428db5385 | ||
|
|
6e6b1e6052 | ||
|
|
bc2b47974d | ||
|
|
2244b6ff1b | ||
|
|
fb384fc291 | ||
|
|
73cae8ce9a | ||
|
|
dcd07eb23f | ||
|
|
fa24448489 | ||
|
|
c975740f92 | ||
|
|
1e0187fa57 | ||
|
|
cbdf060bca | ||
|
|
19a8dff975 | ||
|
|
72f9f482d6 | ||
|
|
88de26138a | ||
|
|
57bd964cb3 | ||
|
|
74a39ae57c | ||
|
|
5090a4ccce | ||
|
|
ae0652d13f | ||
|
|
101a07a3d7 | ||
|
|
b012e93121 | ||
|
|
c31109800b | ||
|
|
c0dc363a3d | ||
|
|
739bb28220 | ||
|
|
aab2794e05 | ||
|
|
75c8c1bfb6 | ||
|
|
6f8bd96195 | ||
|
|
25f0d098bd | ||
|
|
56d584b7c6 | ||
|
|
20bf53add1 | ||
|
|
0d440bb0a2 | ||
|
|
8ec62ce46b | ||
|
|
79927faaec | ||
|
|
e4c7f1f3c4 | ||
|
|
68710c4647 | ||
|
|
7d7cbde1f3 | ||
|
|
bafd9c777a | ||
|
|
42a5531f15 | ||
|
|
227da25776 | ||
|
|
2028f33e38 | ||
|
|
145bf19636 | ||
|
|
d1675c44e2 | ||
|
|
6934e4db26 | ||
|
|
cae3414854 | ||
|
|
90d061edaf | ||
|
|
2e02918323 | ||
|
|
e77a1fd33b | ||
|
|
dd01c24c34 | ||
|
|
f88fbee80d | ||
|
|
fe08edbe2b | ||
|
|
d2a16bca10 | ||
|
|
a87f51487e | ||
|
|
76fce94b66 | ||
|
|
d104f9210a | ||
|
|
d0780d1622 | ||
|
|
9d5906dae3 | ||
|
|
07a0960265 | ||
|
|
72bee6d7ca | ||
|
|
249f26d23c | ||
|
|
7813c5b93f | ||
|
|
e38d83fd44 | ||
|
|
d97657b151 | ||
|
|
7e857dede3 | ||
|
|
c3218f6b03 | ||
|
|
1060d0db60 | ||
|
|
b8925a091c | ||
|
|
79cca07a41 | ||
|
|
c1d189c9ad | ||
|
|
b1a973ee5a | ||
|
|
93ef560779 | ||
|
|
c28d35ad86 | ||
|
|
9c654a6ab5 | ||
|
|
64a54e379c | ||
|
|
8f4ec8583b | ||
|
|
f4852d7264 | ||
|
|
092e1a691d | ||
|
|
16ac42421d | ||
|
|
1d2eadb9c0 | ||
|
|
35c85d9fac | ||
|
|
f0622c1896 | ||
|
|
6d11247417 | ||
|
|
59c3e3a179 | ||
|
|
42e26a8682 | ||
|
|
db6caac9cc | ||
|
|
ba4a57ba0b | ||
|
|
018e3bc35f | ||
|
|
a56bc9d933 | ||
|
|
5b93525ce8 | ||
|
|
6abb86dff6 | ||
|
|
6a27d5ed80 | ||
|
|
8232684672 | ||
|
|
2d855ce5cf | ||
|
|
b2b685e46d | ||
|
|
ef552846d1 | ||
|
|
c7dfd0894e | ||
|
|
5b1a76aeff | ||
|
|
529b6ca935 | ||
|
|
625a4c0766 | ||
|
|
3c3ea2f575 | ||
|
|
57a332bb08 | ||
|
|
73ac98b193 | ||
|
|
59e3cbb36b | ||
|
|
fb019a7cbf | ||
|
|
09607f6aa7 | ||
|
|
1c4a33eb78 | ||
|
|
b7513097ea | ||
|
|
a35677a9bf | ||
|
|
89de3a81c6 | ||
|
|
b9828bf5de | ||
|
|
d6c3868a7c | ||
|
|
a73f02ac23 | ||
|
|
7e9594456b | ||
|
|
d25418ba04 | ||
|
|
a7df1a3d77 | ||
|
|
50951d15ea | ||
|
|
30076884ae | ||
|
|
1eff22a90b | ||
|
|
41bdbc203d | ||
|
|
7932585656 | ||
|
|
68bf4e7b70 | ||
|
|
92f09a60f6 | ||
|
|
d19f2bb6d2 | ||
|
|
b06dce5bf8 | ||
|
|
82e2ab89c5 | ||
|
|
db198b183c | ||
|
|
90bab650e2 | ||
|
|
fa1cc556f9 | ||
|
|
69b23b0e48 | ||
|
|
af69945e5b | ||
|
|
f36f7644c8 | ||
|
|
20f1457d15 | ||
|
|
38bcd52065 | ||
|
|
38219fec99 | ||
|
|
6c3300bc2f | ||
|
|
d1a110d4ca | ||
|
|
5b61485143 | ||
|
|
6b95a357eb | ||
|
|
60bdc726ce | ||
|
|
429f809b71 | ||
|
|
9396d736f2 | ||
|
|
cc9b812466 | ||
|
|
5b0f2dc0cf | ||
|
|
7ffea1606d | ||
|
|
342bc1e72d | ||
|
|
0127eb5892 | ||
|
|
39023269d6 | ||
|
|
35e3cd97fe | ||
|
|
a63a171ec3 | ||
|
|
7f1763f32f | ||
|
|
2d6326815c | ||
|
|
ee4c8cca8c | ||
|
|
2104e0f411 | ||
|
|
84e69f57ea | ||
|
|
aba43125f3 | ||
|
|
de5fc58fcb | ||
|
|
4831dde3fb | ||
|
|
b5cbfc5e7a | ||
|
|
1124d164ec | ||
|
|
9d9391bd95 | ||
|
|
0121d74b92 | ||
|
|
f81af32963 | ||
|
|
8f5198821e | ||
|
|
96c2b5ef32 | ||
|
|
c5eb324cf0 | ||
|
|
f117d9bfd3 | ||
|
|
b470736246 | ||
|
|
b2a2a00cd8 | ||
|
|
659130856c | ||
|
|
9a21008177 | ||
|
|
8f58bc5b19 | ||
|
|
3a0220a875 | ||
|
|
9f438d0ec6 | ||
|
|
22c22e0d7a | ||
|
|
bc48bd5f4a | ||
|
|
905c4bb4a5 | ||
|
|
94bfaf6896 | ||
|
|
25b743b03c | ||
|
|
8da4e6ce5e | ||
|
|
cedd297ba6 | ||
|
|
b6e0c5e0ea | ||
|
|
bf3f7d0dc4 | ||
|
|
7b42a84422 | ||
|
|
8b7c065706 | ||
|
|
c6a4b3d9b0 | ||
|
|
0ef32f2b8d | ||
|
|
f7fdcb7bf1 | ||
|
|
848d36ff39 | ||
|
|
07ce3e7cdf | ||
|
|
cfec145ae2 | ||
|
|
641d7a4ea4 | ||
|
|
da0650fda6 | ||
|
|
6724133927 | ||
|
|
c0ded8ef5f | ||
|
|
7382de51dc | ||
|
|
96a1121e6b | ||
|
|
323bbb0692 | ||
|
|
59e235623a | ||
|
|
40dc85d975 | ||
|
|
6006a42cbb | ||
|
|
c2e0278bd9 | ||
|
|
c1ba920c86 | ||
|
|
7b997e9374 | ||
|
|
dfb97c1ed7 | ||
|
|
fc49fb2f4f | ||
|
|
63078fba5b | ||
|
|
b0176546c2 | ||
|
|
a234ba91a4 | ||
|
|
526d11809f | ||
|
|
3bbdecc6b3 | ||
|
|
00fc4a2eb7 | ||
|
|
924b31233b | ||
|
|
475161f716 | ||
|
|
31b12635d1 | ||
|
|
d2de0865bf | ||
|
|
9b4dbd0e83 | ||
|
|
4577cd7497 | ||
|
|
4ebf07c725 | ||
|
|
da852a94bd | ||
|
|
9b51ff7241 | ||
|
|
aa0137e7ce | ||
|
|
3889ae7627 | ||
|
|
c97a8602a1 | ||
|
|
affc9f9058 | ||
|
|
1582819259 | ||
|
|
05e8ae33dc | ||
|
|
219d5fb66b | ||
|
|
92ff57c0ea | ||
|
|
5233429b6f | ||
|
|
475cf7179e | ||
|
|
f608c65962 | ||
|
|
6cf0a35b4c | ||
|
|
bac006ebc1 | ||
|
|
be5f74e37f | ||
|
|
5c29bff23d | ||
|
|
68968d2b40 | ||
|
|
038f4e8bde | ||
|
|
f8874fec0f | ||
|
|
ee6693e6e3 | ||
|
|
bfba97647e | ||
|
|
82d5194afe | ||
|
|
bf449b9f61 | ||
|
|
9530048867 | ||
|
|
090d54516e | ||
|
|
c91b716a63 | ||
|
|
80cdb0dc4e | ||
|
|
aaa6b54673 | ||
|
|
a3b61ec8c8 | ||
|
|
6c41d6b66a | ||
|
|
1838ab1412 | ||
|
|
72e8d38586 | ||
|
|
9259e2221d | ||
|
|
42ea979b06 | ||
|
|
46824adb97 | ||
|
|
3758f4952e | ||
|
|
8fdbbe78f4 | ||
|
|
5a86b0f9e3 | ||
|
|
604722b775 | ||
|
|
812812d817 | ||
|
|
f07fe0a8e7 | ||
|
|
1d7cef5bfe | ||
|
|
34b12e6a6a | ||
|
|
eb6ba563bd | ||
|
|
281b2e9b0e | ||
|
|
5437629e89 | ||
|
|
e1df2f8ff5 | ||
|
|
12fad6f05f | ||
|
|
4208078750 | ||
|
|
dba02f8f08 | ||
|
|
35e410fe96 | ||
|
|
7dcd2313d8 | ||
|
|
40750f2dc6 | ||
|
|
85c007431b | ||
|
|
cbd187369e | ||
|
|
d20d89a0b9 | ||
|
|
80eb37ef60 | ||
|
|
d19cdc206b | ||
|
|
02078255ea | ||
|
|
bea2d40f79 | ||
|
|
a5d3259cfe | ||
|
|
4a93ce703e | ||
|
|
661ea906d9 | ||
|
|
b382b4cb94 | ||
|
|
087e86fb32 | ||
|
|
afffa76c17 | ||
|
|
69ca18f36b | ||
|
|
f84c62f0be | ||
|
|
90c554ad42 | ||
|
|
e2cb6cc4da | ||
|
|
02da366cc2 | ||
|
|
54e3a54489 | ||
|
|
8798ec653d | ||
|
|
d1ffd3cf35 | ||
|
|
133b854f1b | ||
|
|
33125e78c8 | ||
|
|
4118bf1a5e | ||
|
|
8282db456b | ||
|
|
7b5eacf671 | ||
|
|
12bd374477 | ||
|
|
9ef4cc0ab9 | ||
|
|
528fc9bc47 | ||
|
|
c58b8498b3 | ||
|
|
c81c564941 | ||
|
|
b16de0e374 | ||
|
|
d38f41a459 | ||
|
|
30346884fe | ||
|
|
1518dc9b60 | ||
|
|
fd3f2289c3 | ||
|
|
22bfd4f7c3 | ||
|
|
2782011ce8 | ||
|
|
7f17fcfafc | ||
|
|
a40daa3c22 | ||
|
|
1e366aa56e | ||
|
|
bad8dbc2d2 | ||
|
|
d0dd37fe94 | ||
|
|
b2df3fcd1d | ||
|
|
96f89ce4ae | ||
|
|
e886a3d891 | ||
|
|
0eaf141ae4 | ||
|
|
291ef07cf3 | ||
|
|
b9066ac997 | ||
|
|
206f4604a4 | ||
|
|
adbc1d97a0 | ||
|
|
70ae700461 | ||
|
|
b81ad3ed39 | ||
|
|
77cdb17cee | ||
|
|
d4e329b76d | ||
|
|
fb24585dd8 | ||
|
|
bd5efd5968 | ||
|
|
650f35c1f3 | ||
|
|
14e65168c9 | ||
|
|
f00c47c21a | ||
|
|
547d105b2e | ||
|
|
de671103ca | ||
|
|
2c48efa3fd | ||
|
|
7f35b2dc43 | ||
|
|
6ae914da2f | ||
|
|
06ea78af1b | ||
|
|
2ea12a7699 | ||
|
|
8ab25de6c6 | ||
|
|
e0424a7017 | ||
|
|
f259162d64 | ||
|
|
6bb5cdeb2f | ||
|
|
384c30b6fd | ||
|
|
67a75d4439 | ||
|
|
0d963df7b3 | ||
|
|
99efde5673 | ||
|
|
c8ff699c4b | ||
|
|
0718a888d0 | ||
|
|
b7be4df603 | ||
|
|
8bece0b49e | ||
|
|
47d6edc3c8 | ||
|
|
26bb56396d | ||
|
|
dd99ed73a9 | ||
|
|
36ce460a39 | ||
|
|
e92c845dfd | ||
|
|
492263c2e9 | ||
|
|
0c99f66547 | ||
|
|
df440496ee | ||
|
|
09f2028d6a | ||
|
|
05736ba0a1 | ||
|
|
e5f05bc9d8 | ||
|
|
cdd1209b55 | ||
|
|
0e6458a630 | ||
|
|
a1a068a377 | ||
|
|
2c5657e8a9 | ||
|
|
87fbd715a3 | ||
|
|
fc8cba9598 | ||
|
|
147725bf7a | ||
|
|
06d2c0af35 | ||
|
|
708f1a97dd | ||
|
|
d8bd9f5a66 | ||
|
|
079953c3ee | ||
|
|
fea8b6da2f | ||
|
|
4bf1df0894 | ||
|
|
b4f16c4df8 | ||
|
|
61282737c5 | ||
|
|
d8c2290099 | ||
|
|
830ab599df | ||
|
|
0de5c5e8a3 | ||
|
|
c6170ed751 | ||
|
|
2ea762cfc9 | ||
|
|
2646741297 | ||
|
|
f5df5faf71 | ||
|
|
cab9a580e8 | ||
|
|
c8ac3fd4f5 | ||
|
|
7f67c34b39 | ||
|
|
e27293edbc | ||
|
|
8d57c5052c | ||
|
|
1314559833 | ||
|
|
735397aa89 | ||
|
|
c0d0c792e1 | ||
|
|
43020b20b7 | ||
|
|
0a3d80b86e | ||
|
|
a9505d0426 | ||
|
|
4d804c2a29 | ||
|
|
e8eec2d357 | ||
|
|
971e3f679f | ||
|
|
7c90f078e7 | ||
|
|
5957bd1abb | ||
|
|
b16380e7e5 | ||
|
|
b72a32c70d | ||
|
|
90f15b3c5a | ||
|
|
44bbf26cb2 | ||
|
|
fcfd17e973 | ||
|
|
73853cf147 | ||
|
|
ddbc263da2 | ||
|
|
982d8a0dc0 | ||
|
|
5a269db9d5 | ||
|
|
525da01a62 | ||
|
|
12df10b2d0 | ||
|
|
e6aee5d7ea | ||
|
|
6ff69da0de | ||
|
|
ebcb87c163 | ||
|
|
79d9df9bb1 | ||
|
|
8c40c2086a | ||
|
|
f4a000cb59 | ||
|
|
4029202635 | ||
|
|
29d473f2fa | ||
|
|
7ad89dc46b | ||
|
|
4b2d6f8a99 | ||
|
|
9b55de1c6b | ||
|
|
8b45211a8f | ||
|
|
f079501cff | ||
|
|
e375e1789b | ||
|
|
30d2cfdf56 | ||
|
|
44d61e6857 | ||
|
|
3466829766 | ||
|
|
d3703516d9 | ||
|
|
bdebaa986b | ||
|
|
c2d400846b | ||
|
|
034e147910 | ||
|
|
25015c9c3a | ||
|
|
43cf60f563 | ||
|
|
057348763b | ||
|
|
7230452e23 | ||
|
|
438317c1e9 | ||
|
|
cfe719c962 | ||
|
|
44e2d88628 | ||
|
|
6e50e77709 | ||
|
|
02ed28d68d | ||
|
|
73274e201b | ||
|
|
f6fc88cc2d | ||
|
|
d16acc43d9 | ||
|
|
239aa7b8d5 | ||
|
|
44a1bc5396 | ||
|
|
821583acae | ||
|
|
c6a2814881 | ||
|
|
1954a02352 | ||
|
|
8a28022a6b | ||
|
|
43a243b24a | ||
|
|
7c937c8704 | ||
|
|
bdd1f82777 | ||
|
|
cbb8876815 | ||
|
|
f8cdaaae30 | ||
|
|
74314bacd7 | ||
|
|
04473f607b | ||
|
|
88958270cb | ||
|
|
856f7ecee9 | ||
|
|
9f5584a157 | ||
|
|
eda8a94d5b | ||
|
|
5956b13588 | ||
|
|
162d029c81 | ||
|
|
7f3920dbb7 | ||
|
|
6d07c3a1df | ||
|
|
a0a83428cf | ||
|
|
dc2cae07b2 | ||
|
|
f8b44cd30e | ||
|
|
c3eca3d754 | ||
|
|
1ea005f6a6 | ||
|
|
16a675b7ce | ||
|
|
df2f939f3a | ||
|
|
5743224817 | ||
|
|
a80e88e33e | ||
|
|
0207f1f29b | ||
|
|
72120bb87f | ||
|
|
7eaca86bf1 | ||
|
|
db5f72c868 | ||
|
|
69d6ae4141 | ||
|
|
edabafc0fc | ||
|
|
e9f2aa6010 | ||
|
|
e054dd7813 | ||
|
|
76d788a186 | ||
|
|
3944df1bd2 | ||
|
|
49f6280645 | ||
|
|
84eb66d5aa | ||
|
|
026fc531ba | ||
|
|
8d14df0ced | ||
|
|
f27547dcff | ||
|
|
6f15d1c4c4 | ||
|
|
46ffff8438 | ||
|
|
8dcd08f47e | ||
|
|
2515d5ad6c | ||
|
|
e6b1853908 | ||
|
|
e2b26c4014 | ||
|
|
d4b7a3478e | ||
|
|
e187961d72 | ||
|
|
ae96b0c971 | ||
|
|
c4dad3d2c1 | ||
|
|
36287fc33b | ||
|
|
edd5a5f185 | ||
|
|
bb7388a7fe | ||
|
|
797368bf9f | ||
|
|
0cccf1d4cc | ||
|
|
7aa326a836 | ||
|
|
fe16f2b058 | ||
|
|
af4fcc831e | ||
|
|
868bf5838d | ||
|
|
4282748483 | ||
|
|
7790a07c08 | ||
|
|
ef6cce8988 | ||
|
|
df848fdb4d | ||
|
|
b4489d9ea6 | ||
|
|
1496d6af2f | ||
|
|
52a05090bf | ||
|
|
38235ecb97 | ||
|
|
bf8b9b4906 | ||
|
|
727f2ce994 | ||
|
|
8b3309f4f6 | ||
|
|
5e08b248e8 | ||
|
|
0b1bf5f642 | ||
|
|
8ed191283a | ||
|
|
fefe2df6b5 | ||
|
|
aff9b419cf | ||
|
|
cae081950d | ||
|
|
06bf8d3470 | ||
|
|
a532b70f70 | ||
|
|
cf85477864 | ||
|
|
614176b269 | ||
|
|
03401bbb58 | ||
|
|
75ae209653 | ||
|
|
8ce97961b4 | ||
|
|
8ffe5957e5 | ||
|
|
47e2c4ae6c | ||
|
|
0065e2cfac | ||
|
|
2ee4f57395 | ||
|
|
e01971eac7 | ||
|
|
d6e29be980 | ||
|
|
6fbf8fa9e4 | ||
|
|
c64242c276 | ||
|
|
440b222664 | ||
|
|
1c759384fa | ||
|
|
602fa1c657 | ||
|
|
d964d2baae | ||
|
|
d235c205d6 | ||
|
|
b1654af406 | ||
|
|
29e5768f9b | ||
|
|
3a6b4f3eb5 | ||
|
|
84889d6dea | ||
|
|
34ce17c4b3 | ||
|
|
7723e59a72 | ||
|
|
7f5135016e | ||
|
|
08e0485213 | ||
|
|
04afea76e3 | ||
|
|
aa9a0aaf17 | ||
|
|
3f792df631 | ||
|
|
b36aa6f41b | ||
|
|
6a5345aeed | ||
|
|
b9cb37da5e | ||
|
|
6207c68439 | ||
|
|
0b149a941d | ||
|
|
5e8f7ec590 | ||
|
|
6e3c15e2ab | ||
|
|
3bee2e4228 | ||
|
|
89dcd9027d | ||
|
|
102b2e2ca6 | ||
|
|
998ea53b46 | ||
|
|
2337373a17 | ||
|
|
af29174cb6 | ||
|
|
412c6bf4b5 | ||
|
|
7fc6a3670c | ||
|
|
70fbfea5f5 | ||
|
|
9616b45518 | ||
|
|
3916b5973d | ||
|
|
5b3974b6b4 | ||
|
|
e8e36e8a66 | ||
|
|
88bcd0a9ce | ||
|
|
29eb3215b3 | ||
|
|
7c534a87cf | ||
|
|
e9e30138bd | ||
|
|
ddc135839b | ||
|
|
474ff2e997 | ||
|
|
0d2eb76cee | ||
|
|
6172cd3627 | ||
|
|
c71a6073e3 | ||
|
|
91b0e28b28 | ||
|
|
e15a9f2e73 | ||
|
|
cac134076b | ||
|
|
39e67016b5 | ||
|
|
c72241df5b | ||
|
|
a78e75775d | ||
|
|
91b84e0b06 | ||
|
|
3403215698 | ||
|
|
260e6662f0 | ||
|
|
5137cee3d6 | ||
|
|
9915038e9b | ||
|
|
7ddf54c4d3 | ||
|
|
cc72819579 | ||
|
|
6d902633e9 | ||
|
|
be775b9206 | ||
|
|
15ec185be5 | ||
|
|
e1f33739b0 | ||
|
|
dff8d579ca | ||
|
|
ef2265de4f | ||
|
|
f7b4f99d4c | ||
|
|
d5735496af | ||
|
|
3755783d41 | ||
|
|
5b8d3ba1d6 | ||
|
|
63be52e191 | ||
|
|
d15122c4b2 | ||
|
|
6d6ec46f25 | ||
|
|
8d78c3a2ab | ||
|
|
7077e57d53 | ||
|
|
031e606972 | ||
|
|
d6601645d6 | ||
|
|
97bb5b6680 | ||
|
|
adb04eb010 | ||
|
|
ff171e3651 | ||
|
|
172d68d1fe | ||
|
|
885f668d53 | ||
|
|
7cf311dac0 | ||
|
|
259c84ed9a | ||
|
|
196d10454a | ||
|
|
06198702c2 | ||
|
|
12d991f336 | ||
|
|
2b740dc34c | ||
|
|
855bbd523c | ||
|
|
a2a72d1998 | ||
|
|
9a048af1fb | ||
|
|
697139043f | ||
|
|
29ce02b1d2 | ||
|
|
60ae784c01 | ||
|
|
e3511127c7 | ||
|
|
fbf7528728 | ||
|
|
e46a26aec1 |
8
.gitignore
vendored
@@ -7,7 +7,6 @@ ChangeLog
|
||||
INSTALL
|
||||
Makefile
|
||||
Makefile.in
|
||||
NEWS
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
config.h
|
||||
@@ -40,8 +39,13 @@ src/*-enum-types.[ch]
|
||||
src/*-marshal.[ch]
|
||||
src/Makefile
|
||||
src/Makefile.in
|
||||
src/gnomeshell-taskpanel
|
||||
src/calendar-server/org.gnome.Shell.CalendarServer.service
|
||||
src/gnome-shell
|
||||
src/gnome-shell-calendar-server
|
||||
src/gnome-shell-extension-tool
|
||||
src/gnome-shell-jhbuild
|
||||
src/gnome-shell-perf-helper
|
||||
src/gnome-shell-real
|
||||
src/run-js-test
|
||||
src/test-recorder
|
||||
src/test-recorder.ogg
|
||||
|
||||
146
NEWS
Normal file
@@ -0,0 +1,146 @@
|
||||
3.0.1
|
||||
=====
|
||||
|
||||
* Network menu
|
||||
- Fix problems updating the menu for mobile broadband devices [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646395
|
||||
- Fix missing device descriptions with multiple devices of the
|
||||
same type [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646074
|
||||
- Label ad-hoc neworks with an appropriate icon [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646141
|
||||
- Fix displaying some devices states as "invalid" [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646946
|
||||
- Fix problems with access points that don't report a SSID [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=647040
|
||||
- Miscellaneous minor bug fixes [Dan, Giovanni, Owen]
|
||||
645981, 646558, 646443, 646708, 646968
|
||||
* Application menu and icon
|
||||
- Fix bug where application menu icon was missing at GNOME Shell
|
||||
startup. [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=644122
|
||||
- Fix missing application menu for dialog windows [Colin]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=647082
|
||||
- When launching an application through an alternate launcher
|
||||
(like for a System Settings pane), association the windows with
|
||||
the application, not the launcher. [Colin]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646689
|
||||
* Activities overview
|
||||
- Load the applications view incrementally to avoid potentially freezing
|
||||
for multiple seconds [Colin]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=647778
|
||||
- Fix bug where package installation while the overview
|
||||
was up could result in a corrupted application display. [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=645801
|
||||
- Fix dragging from the search results to launch apps and docs [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=645990
|
||||
- Fix flickering of selection when searching in the overview [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646019
|
||||
- Fix bug when typing into the search box when text was already
|
||||
selected [Nohemi]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=636341
|
||||
* Fix layout of notifications for right-to-left languages [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646921
|
||||
* Remove a confusing special case where Alt-Tab sometimes switched
|
||||
to a different window of the same application rather than to
|
||||
a different application. [Rui]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=648132
|
||||
* Fix a crash that could happen when a window was opened on a
|
||||
workspace that was immediately removed [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=648132
|
||||
* Fix keyboard navigation in logout/reboot dialogs [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646740
|
||||
* Fix missing inspector icon in Looking Glass console [Dan]
|
||||
* Miscellaneous minor bug fixes [Adel, Colin, Dan, Florian, Nohemi]
|
||||
645648, 646205, 646257, 646855, 647098, 646730
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Nohemi Fernandez, Adel Gadllah, Rui Matos, Florian Müllner,
|
||||
Owen Taylor, Colin Walters, Dan Winship
|
||||
|
||||
Translations:
|
||||
Hendrik Richter [de], Jorge González [es], Arash Mousavi [fa],
|
||||
Fran Diéguez [gl], Jiro Matsuzawa [ja], Piotr Drąg [pl], Daniel Nylander [sv],
|
||||
Sira Nokyoongtong [th], Muhammet Kara [tr], Nguyễn Thái Ngọc Duy [vi],
|
||||
Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||
|
||||
3.0.0.2
|
||||
=======
|
||||
|
||||
* Fix missing import that was preventing extensions from loading.
|
||||
[Maxim Ermilov]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646333
|
||||
|
||||
Translations:
|
||||
Timo Jyrinki [fi]
|
||||
|
||||
3.0.0.1
|
||||
=======
|
||||
|
||||
* Fix problem with stuck event handling if network menu pops down while
|
||||
user is using the scrollbar. [Owen Taylor]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646825
|
||||
|
||||
Contributors to GNOME Shell 3.0
|
||||
===============================
|
||||
|
||||
Code:
|
||||
|
||||
Josh Adams, Kiyoshi Aman, Nuno Araujo, Emmanuele Bassi, Dirk-Jan C. Binnema,
|
||||
Wouter Bolsterlee, Raphael Bosshard, Milan Bouchet-Valat, Christina Boumpouka,
|
||||
Mathieu Bridon, Alban Browaeys, Phil Bull, Micro Cai, Giovanni Campagna,
|
||||
Cosimo Cecchi, Tor-björn Claesson, Matthias Clasen, Jason D. Clinton,
|
||||
Frederic Crozat, Guillaume Desmottes, Sander Dijkhuis, Neha Doijode,
|
||||
Maxim Ermilov, Diego Escalante Urrelo, Luca Ferretti, Steve Frécinaux,
|
||||
Takao Fujiwara, Adel Gadllah, Vadim Girlin, Nick Glynn, Guido Günther,
|
||||
Leon Handreke, Lex Hider, Richard Hughes, Javier Jardón, Abderrahim Kitouni,
|
||||
Andre Klapper, Alexander Larsson, Nickolas Lloyd, Ryan Lortie, Kjartan Maraas,
|
||||
Koop Mast, Rui Matos, Jonathan Matthew, William Jon McCann, Morten Mjelva,
|
||||
Federico Mena Quintero, Florian Müllner, Jon Nettleton, Hellyna Ng,
|
||||
Discardi Nicola, Carlos Martín Nieto, Bastien Nocera, Bill Nottingham,
|
||||
Matt Novenstern, Marc-Antoine Perennou, Neil Perry, Frédéric Péters,
|
||||
Alejandro Piñeiro, Siegfried-Angel Gevatter Pujals, "res", Neil Roberts,
|
||||
"Sardem FF7", Florian Scandella, Joseph Scheuhammer, Christian Schramm,
|
||||
Gustavo Noronha Silva, Jasper St. Pierre, Eric Springer, Jakub Steiner,
|
||||
Jonathan Strander, Ray Strode, Owen Taylor, Rico Tzschichholz,
|
||||
Sergey V. Udaltsov, Daiki Ueno, Vincent Untz, Marcelo Jorge Vieira,
|
||||
Mads Villadsen, Colin Walters, Dan Winship, William Wolf, Thomas Wood,
|
||||
Pierre Yager, David Zeuthen, Marina Zhurakhinskaya
|
||||
|
||||
Design:
|
||||
|
||||
Allan Day, William Jon McCann, Jeremy Perry, Jakub Steiner
|
||||
2008 Boston GNOME design hackfest participants (especially Neil J. Patel
|
||||
for turning the resulting sketches into our first mockups.)
|
||||
Everybody on irc.gnome.org:#gnome-design
|
||||
|
||||
Translations:
|
||||
|
||||
Friedel Wolff (af), Khaled Hosny (ar), Ivaylo Valkov (bg), Jamil Ahmed (bn)
|
||||
Runa Bhattacharjee (bn_IN), Gil Forcada, Siegfried-Angel Gevatter Pujals,
|
||||
Jordi Serratosa (ca), Andre Klapper, Petr Kovar (cs), Kenneth Nielsen,
|
||||
Kris Thomsen (da), Mario Blättermann, Hendrik Brandt, Christian Kirbach,
|
||||
Hendrik Richter, Wolfgang Stöggl (de), Michael Kotsarinis, Kostas Papadimas,
|
||||
Jennie Petoumenou, Sterios Prosiniklis, Fotis Tsamis, Simos Xenitellis (el),
|
||||
Bruce Cowan, Philip Withnall (en_GB), Jorge Gonzalez, Daniel Mustieles (es),
|
||||
Mattias Põldaru, Ivar Smolin (et), Inaki Larranaga Murgoitio (eu),
|
||||
Mahyar Moghimi (fa), Timo Jyrinki (fi), Cyril Arnaud, Bruno Brouard,
|
||||
Pablo Martin-Gomez, Claude Paroz, Frédéric Peters (fr), Seán de Búrca (ga)
|
||||
Francisco Diéguez, Antón Méixome (gl), Sweta Kothari (gu), Liel Fridman,
|
||||
Yaron Shahrabani (he), Rajesh Ranjan (hi), Gabor Kelemen (hu), Milo Casagrande,
|
||||
Luca Ferretti (it), Dirgita, Andika Triwidada (id), Takayuki KUSANO,
|
||||
Takayoshi OKANO, Kiyotaka NISHIBORI, Futoshi NISHIO (ja), Shankar Prasad (kn),
|
||||
Young-Ho Cha, Changwoo Ryu (ko), Žygimantas Beručka, Gintautas Miliauskas (lt),
|
||||
Rudolfs Mazurs (lv), Sandeep Shedmake (mr), Kjartan Maraas (nb),
|
||||
Wouter Bolsterlee, Sander Dijkhuis, Reinout van Schouwen (nl),
|
||||
Torstein Winterseth (nn), A S Alam (pa), Tomasz Dominikowski, Piotr Drąg (pl),
|
||||
Duarte Loreto (pt), Felipe Borges, Rodrigo Padula de Oliveira,
|
||||
Rodrigo L. M. Flores, Amanda Magalhães, Og B. Maciel, Gabriel F. Vilar,
|
||||
Jonh Wendell (pt_BR), Lucian Adrian Grijincu, Daniel Șerbănescu (ro),
|
||||
Sergey V. Kovylov, Andrey Korzinev, Yuri Myasoedov, Marina Zhurakhinskaya (ru),
|
||||
Daniel Nylander (se), Matej Urbančič, Andrej Žnidaršič (sl),
|
||||
Miloš Popović (sr, sr@latin), Miroslav Nikolić (sr), Tirumurti Vasudevan (ta),
|
||||
Sira Nokyoongtong (th), Baris Cicek (tr), Abduxukur Abdurixit,
|
||||
Gheyret T. Kenji (ug), Maxim V. Dziumanenko, Daniel Korostil (uk),
|
||||
Nguyễn Thái Ngọc Duy (vi), Jessica Ban, 'jiero', Wei Li, YunQiang Su, Ray Wang,
|
||||
Aron Xu (zh_CN), Chao-Hsiung Liao (zh_HK, zh_TW)
|
||||
93
configure.ac
@@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[2.91.90],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.0.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@@ -52,8 +52,8 @@ AC_MSG_CHECKING([for GStreamer (needed for recording functionality)])
|
||||
if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
build_recorder=true
|
||||
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 xfixes"
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0)
|
||||
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11"
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
@@ -63,50 +63,63 @@ AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
CLUTTER_MIN_VERSION=1.5.15
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=0.7.11
|
||||
MUTTER_MIN_VERSION=2.91.90
|
||||
MUTTER_MIN_VERSION=3.0.0
|
||||
GTK_MIN_VERSION=3.0.0
|
||||
GIO_MIN_VERSION=2.25.9
|
||||
LIBECAL_REQUIRED=1.6.0
|
||||
LIBEDATASERVER_REQUIRED=1.2.0
|
||||
LIBEDATASERVERUI2_REQUIRED=1.2.0
|
||||
LIBEDATASERVERUI3_REQUIRED=2.91.6
|
||||
LIBECAL_MIN_VERSION=2.32.0
|
||||
LIBEDATASERVER_MIN_VERSION=1.2.0
|
||||
LIBEDATASERVERUI2_MIN_VERSION=1.2.0
|
||||
LIBEDATASERVERUI3_MIN_VERSION=2.91.6
|
||||
TELEPATHY_GLIB_MIN_VERSION=0.13.12
|
||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||
POLKIT_MIN_VERSION=0.100
|
||||
|
||||
# Collect more than 20 libraries for a prize!
|
||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-2.0 >= $GIO_MIN_VERSION
|
||||
gio-unix-2.0 dbus-glib-1 libxml-2.0
|
||||
gtk+-3.0 >= $GTK_MIN_VERSION
|
||||
mutter-plugins >= $MUTTER_MIN_VERSION
|
||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
||||
libgnome-menu $recorder_modules gconf-2.0
|
||||
gdk-x11-3.0
|
||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||
libstartup-notification-1.0
|
||||
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
|
||||
libcanberra
|
||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||
polkit-agent-1 >= $POLKIT_MIN_VERSION)
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
|
||||
gio-unix-2.0 dbus-glib-1 libxml-2.0
|
||||
gtk+-3.0 >= $GTK_MIN_VERSION
|
||||
libmutter >= $MUTTER_MIN_VERSION
|
||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
||||
libgnome-menu $recorder_modules gconf-2.0
|
||||
gdk-x11-3.0
|
||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||
libstartup-notification-1.0
|
||||
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
|
||||
libcanberra
|
||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
||||
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes)
|
||||
|
||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||
|
||||
GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0`
|
||||
AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to])
|
||||
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
|
||||
|
||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||
JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR"
|
||||
# NM is the only typelib we use that we don't jhbuild
|
||||
PKG_CHECK_EXISTS([libnm-glib >= 0.8.999],
|
||||
[NM_TYPELIBDIR=`$PKG_CONFIG --variable=libdir libnm-glib`/girepository-1.0
|
||||
if test "$INTROSPECTION_TYPELIBDIR" != "$NM_TYPELIBDIR"; then
|
||||
JHBUILD_TYPELIBDIR="$JHBUILD_TYPELIBDIR:$NM_TYPELIBDIR"
|
||||
fi])
|
||||
AC_SUBST(JHBUILD_TYPELIBDIR)
|
||||
|
||||
saved_CFLAGS=$CFLAGS
|
||||
saved_LIBS=$LIBS
|
||||
CFLAGS=$MUTTER_PLUGIN_CFLAGS
|
||||
LIBS=$MUTTER_PLUGIN_LIBS
|
||||
CFLAGS=$GNOME_SHELL_CFLAGS
|
||||
LIBS=$GNOME_SHELL_LIBS
|
||||
# sn_startup_sequence_get_application_id, we can replace with a version check later
|
||||
AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id)
|
||||
AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id XFixesCreatePointerBarrier)
|
||||
CFLAGS=$saved_CFLAGS
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0)
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11)
|
||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
|
||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
||||
PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0)
|
||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
|
||||
|
||||
AC_MSG_CHECKING([for bluetooth support])
|
||||
@@ -125,20 +138,17 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
|
||||
# Default to libedataserverui-3.0, but allow falling back to 1.2
|
||||
PKG_CHECK_EXISTS(libedataserverui-3.0,
|
||||
[EDS_API=3.0
|
||||
LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI3_REQUIRED],
|
||||
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI3_MIN_VERSION],
|
||||
[EDS_API=1.2
|
||||
LIBEDATASERVERUI_REQUIRED=$LIBEDATASERVERUI2_REQUIRED])
|
||||
PKG_CHECK_MODULES(LIBECAL, libecal-1.2 >= $LIBECAL_REQUIRED libedataserver-1.2 >= $LIBEDATASERVER_REQUIRED libedataserverui-$EDS_API >= $LIBEDATASERVERUI_REQUIRED)
|
||||
AC_SUBST(LIBECAL_CFLAGS)
|
||||
AC_SUBST(LIBECAL_LIBS)
|
||||
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI2_MIN_VERSION])
|
||||
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-$EDS_API >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
|
||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||
AC_SUBST(CALENDAR_SERVER_LIBS)
|
||||
|
||||
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
|
||||
# FIXME: metacity-plugins.pc should point directly to its .gir file
|
||||
MUTTER_LIB_DIR=`$PKG_CONFIG --variable=libdir mutter-plugins`
|
||||
MUTTER_PLUGIN_DIR=`$PKG_CONFIG --variable=plugindir mutter-plugins`
|
||||
AC_SUBST(MUTTER_BIN_DIR)
|
||||
AC_SUBST(MUTTER_LIB_DIR)
|
||||
AC_SUBST(MUTTER_PLUGIN_DIR)
|
||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
|
||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
|
||||
AC_SUBST(MUTTER_GIR_DIR)
|
||||
AC_SUBST(MUTTER_TYPELIB_DIR)
|
||||
|
||||
GJS_CONSOLE=`$PKG_CONFIG --variable=gjs_console gjs-1.0`
|
||||
AC_SUBST(GJS_CONSOLE)
|
||||
@@ -187,8 +197,9 @@ if test "$enable_compile_warnings" != no ; then
|
||||
fi
|
||||
changequote([,])dnl
|
||||
|
||||
AC_PATH_PROG(mutter, [mutter])
|
||||
AC_SUBST(mutter)
|
||||
AC_ARG_ENABLE(jhbuild-wrapper-script,
|
||||
AS_HELP_STRING([--jhbuild-wrapper-script=yes],[Make "gnome-shell" script work for jhbuild]),,enable_jhbuild_wrapper_script=no)
|
||||
AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes)
|
||||
|
||||
AC_CONFIG_FILES([
|
||||
Makefile
|
||||
|
||||
@@ -24,29 +24,21 @@ dist_theme_DATA = \
|
||||
theme/calendar-today.svg \
|
||||
theme/close-window.svg \
|
||||
theme/close.svg \
|
||||
theme/corner-ripple.png \
|
||||
theme/corner-ripple-ltr.png \
|
||||
theme/corner-ripple-rtl.png \
|
||||
theme/dash-placeholder.svg \
|
||||
theme/filter-selected.svg \
|
||||
theme/filter-selected-ltr.svg \
|
||||
theme/filter-selected-rtl.svg \
|
||||
theme/gnome-shell.css \
|
||||
theme/mosaic-view-active.svg \
|
||||
theme/mosaic-view.svg \
|
||||
theme/move-window-on-new.svg \
|
||||
theme/panel-border.svg \
|
||||
theme/panel-button-border.svg \
|
||||
theme/panel-button-highlight-narrow.svg \
|
||||
theme/panel-button-highlight-wide.svg \
|
||||
theme/process-working.png \
|
||||
theme/process-working.svg \
|
||||
theme/running-indicator.svg \
|
||||
theme/scroll-button-down-hover.png \
|
||||
theme/scroll-button-down.png \
|
||||
theme/scroll-button-up-hover.png \
|
||||
theme/scroll-button-up.png \
|
||||
theme/scroll-hhandle.svg \
|
||||
theme/scroll-vhandle.svg \
|
||||
theme/section-more.svg \
|
||||
theme/section-more-open.svg \
|
||||
theme/separator-white.png \
|
||||
theme/single-view-active.svg \
|
||||
theme/single-view.svg \
|
||||
theme/source-button-border.svg \
|
||||
theme/toggle-off-us.svg \
|
||||
theme/toggle-off-intl.svg \
|
||||
theme/toggle-on-us.svg \
|
||||
@@ -71,11 +63,6 @@ all-local: gschemas.compiled
|
||||
gconfschemadir = @GCONF_SCHEMA_FILE_DIR@
|
||||
gconfschema_DATA = gnome-shell.schemas
|
||||
|
||||
menudir = $(sysconfdir)/xdg/menus
|
||||
|
||||
menu_DATA = \
|
||||
gs-applications.menu
|
||||
|
||||
shadersdir = $(pkgdatadir)/shaders
|
||||
shaders_DATA = \
|
||||
shaders/dim-window.glsl
|
||||
|
||||
@@ -13,3 +13,4 @@ NoDisplay=true
|
||||
X-GNOME-Autostart-Phase=WindowManager
|
||||
X-GNOME-Provides=panel;windowmanager;
|
||||
X-GNOME-Autostart-Notify=true
|
||||
X-GNOME-AutoRestart=true
|
||||
|
||||
@@ -81,5 +81,20 @@
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/windows/workspaces_only_on_primary</key>
|
||||
<applyto>/desktop/gnome/shell/windows/workspaces_only_on_primary</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<locale name="C">
|
||||
<short>Workspaces only on primary monitor</short>
|
||||
<long>
|
||||
This key overrides /apps/mutter/general/workspaces_only_on_primary when
|
||||
running GNOME Shell.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
</schemalist>
|
||||
</gconfschemafile>
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
<Menu>
|
||||
<DefaultLayout>
|
||||
<Menuname>Accessories</Menuname>
|
||||
<Menuname>Games</Menuname>
|
||||
<Menuname>Graphics</Menuname>
|
||||
<Menuname>Internet</Menuname>
|
||||
<Menuname>Multimedia</Menuname>
|
||||
<Menuname>Office</Menuname>
|
||||
<Menuname>Other</Menuname>
|
||||
</DefaultLayout>
|
||||
|
||||
<Name>Applications</Name>
|
||||
<AppDir>/usr/local/share/applications</AppDir>
|
||||
<DefaultAppDirs/>
|
||||
|
||||
<Menu>
|
||||
<Name>Accessories</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Utility</Category>
|
||||
<Not>
|
||||
<Category>System</Category>
|
||||
</Not>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Games</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Game</Category>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Graphics</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Graphics</Category>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Internet</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Network</Category>
|
||||
<Not><Category>Settings</Category></Not>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Multimedia</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>AudioVideo</Category>
|
||||
<Not><Category>Settings</Category></Not>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Office</Name>
|
||||
<Include>
|
||||
<And>
|
||||
<Category>Office</Category>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
|
||||
<Menu>
|
||||
<Name>Other</Name>
|
||||
<OnlyUnallocated/>
|
||||
<Include>
|
||||
<And>
|
||||
<Not><Category>Settings</Category></Not>
|
||||
<Not><Category>Screensaver</Category></Not>
|
||||
</And>
|
||||
</Include>
|
||||
</Menu>
|
||||
</Menu>
|
||||
@@ -1,5 +1,5 @@
|
||||
<schemalist>
|
||||
<schema id="org.gnome.shell" path="/apps/gnome-shell/"
|
||||
<schema id="org.gnome.shell" path="/org/gnome/shell/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="development-tools" type="b">
|
||||
<default>true</default>
|
||||
@@ -54,7 +54,7 @@
|
||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.calendar" path="/apps/gnome-shell/calendar/"
|
||||
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="show-weekdate" type="b">
|
||||
<default>false</default>
|
||||
@@ -65,7 +65,7 @@
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.clock" path="/apps/gnome-shell/clock/"
|
||||
<schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="show-seconds" type="b">
|
||||
<default>false</default>
|
||||
@@ -83,7 +83,7 @@
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.recorder" path="/apps/gnome-shell/recorder/"
|
||||
<schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="framerate" type="i">
|
||||
<default>15</default>
|
||||
|
||||
@@ -1,24 +1,26 @@
|
||||
<?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="22"
|
||||
height="22"
|
||||
viewBox="0 0 16 16"
|
||||
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.46"
|
||||
inkscape:version="0.48+devel r10081 custom"
|
||||
sodipodi:docname="close-window.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||
id="metadata2399"><rdf:RDF><cc:Work
|
||||
@@ -37,11 +39,49 @@
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="16 : 8 : 1"
|
||||
inkscape:persp3d-origin="8 : 5.3333333 : 1"
|
||||
id="perspective2401" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="999"
|
||||
inkscape:window-width="1680"
|
||||
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:#7b7b7b;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop16500-8" /><stop
|
||||
style="stop-color:#101010;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop16502-0" /></linearGradient><filter
|
||||
color-interpolation-filters="sRGB"
|
||||
inkscape:collect="always"
|
||||
id="filter16524-9"
|
||||
x="-0.212979"
|
||||
width="1.425958"
|
||||
y="-0.21305652"
|
||||
height="1.426113"><feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.71020915"
|
||||
id="feGaussianBlur16526-0" /></filter></defs><sodipodi:namedview
|
||||
inkscape:window-height="1114"
|
||||
inkscape:window-width="1463"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageopacity="0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
@@ -50,27 +90,63 @@
|
||||
pagecolor="#000000"
|
||||
id="base"
|
||||
showgrid="false"
|
||||
inkscape:zoom="25.648691"
|
||||
inkscape:cx="8.8097603"
|
||||
inkscape:cy="9.0472789"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="10.720189"
|
||||
inkscape:cy="13.739577"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:current-layer="Foreground"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true" />
|
||||
inkscape:guide-bbox="true"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-maximized="0"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid11246"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" /></sodipodi:namedview>
|
||||
|
||||
<g
|
||||
id="g3175"><path
|
||||
sodipodi:nodetypes="csssc"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.59217799;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2394"
|
||||
d="M 0.83987936,8.0425327 C 0.83987936,4.0805265 4.0712155,0.86823453 8.0567103,0.86823453 C 12.042205,0.86823453 15.273542,4.0805265 15.273542,8.0425327 C 15.273542,12.004539 12.042205,15.216831 8.0567103,15.216831 C 4.0712155,15.216831 0.83987936,12.004539 0.83987936,8.0425327 z"
|
||||
clip-rule="evenodd" /><g
|
||||
id="g3172"><path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 5.4242673,5.3313047 L 10.515414,10.421272 L 10.714004,10.646491"
|
||||
id="path3152" /></g></g><path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 5.4402527,10.650392 L 10.688082,5.3573033"
|
||||
id="path3154"
|
||||
sodipodi:nodetypes="cc" /></svg>
|
||||
style="display:inline"
|
||||
id="g16402-8"
|
||||
transform="translate(4.7533483,2.8238929)"><g
|
||||
id="g3175-4"><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
|
||||
transform="matrix(0.72727273,0,0,0.72727273,2.368236,2.1803254)"
|
||||
style="fill:#ffffff;fill-opacity:1;display:inline"
|
||||
id="g27275-6-6"
|
||||
inkscape:label="window-close"><g
|
||||
style="fill:#ffffff;fill-opacity:1;display:inline"
|
||||
id="g27277-1-1"
|
||||
transform="translate(-41,-760)"><path
|
||||
sodipodi:type="inkscape:offset"
|
||||
inkscape:radius="0"
|
||||
inkscape:original="M 44.21875 764.1875 L 44.21875 765.1875 C 44.19684 765.46825 44.289258 765.74287 44.5 765.9375 L 46.78125 768.21875 L 44.5 770.46875 C 44.31181 770.65692 44.218747 770.92221 44.21875 771.1875 L 44.21875 772.1875 L 45.21875 772.1875 C 45.48404 772.1875 45.749336 772.09444 45.9375 771.90625 L 48.21875 769.625 L 50.5 771.90625 C 50.688164 772.0944 50.953449 772.18749 51.21875 772.1875 L 52.21875 772.1875 L 52.21875 771.1875 C 52.218742 770.9222 52.125688 770.65692 51.9375 770.46875 L 49.6875 768.21875 L 51.96875 765.9375 C 52.18441 765.73815 52.21875 765.47397 52.21875 765.1875 L 52.21875 764.1875 L 51.21875 764.1875 C 50.977922 764.1945 50.796875 764.2695 50.53125 764.5 L 48.21875 766.78125 L 45.9375 764.5 C 45.75987 764.31608 45.504951 764.1987 45.25 764.1875 C 45.23954 764.18704 45.22912 764.18738 45.21875 764.1875 L 44.21875 764.1875 z "
|
||||
xlink:href="#path27279-0-5"
|
||||
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter16524-9);enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
id="path16506-5"
|
||||
inkscape:href="#path27279-0-5"
|
||||
d="m 44.21875,764.1875 0,1 c -0.02191,0.28075 0.07051,0.55537 0.28125,0.75 l 2.28125,2.28125 -2.28125,2.25 c -0.18819,0.18817 -0.281253,0.45346 -0.28125,0.71875 l 0,1 1,0 c 0.26529,0 0.530586,-0.0931 0.71875,-0.28125 L 48.21875,769.625 50.5,771.90625 c 0.188164,0.18815 0.453449,0.28124 0.71875,0.28125 l 1,0 0,-1 c -8e-6,-0.2653 -0.09306,-0.53058 -0.28125,-0.71875 l -2.25,-2.25 2.28125,-2.28125 c 0.21566,-0.19935 0.25,-0.46353 0.25,-0.75 l 0,-1 -1,0 c -0.240828,0.007 -0.421875,0.082 -0.6875,0.3125 l -2.3125,2.28125 L 45.9375,764.5 c -0.17763,-0.18392 -0.432549,-0.3013 -0.6875,-0.3125 -0.01046,-4.6e-4 -0.02088,-1.2e-4 -0.03125,0 l -1,0 z"
|
||||
transform="translate(0,1.3535534)" /><path
|
||||
sodipodi:nodetypes="ccsccccccccccccccccccccccc"
|
||||
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#bebebe;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.78124988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
id="path27279-0-5"
|
||||
inkscape:connector-curvature="0"
|
||||
d="m 44.226475,764.17222 1,0 c 0.01037,-1.2e-4 0.02079,-4.6e-4 0.03125,0 0.254951,0.0112 0.50987,0.12858 0.6875,0.3125 l 2.28125,2.28125 2.3125,-2.28125 c 0.265625,-0.2305 0.446672,-0.3055 0.6875,-0.3125 l 1,0 0,1 c 0,0.28647 -0.03434,0.55065 -0.25,0.75 l -2.28125,2.28125 2.25,2.25 c 0.188188,0.18817 0.281242,0.45345 0.28125,0.71875 l 0,1 -1,0 c -0.265301,-1e-5 -0.530586,-0.0931 -0.71875,-0.28125 l -2.28125,-2.28125 -2.28125,2.28125 c -0.188164,0.18819 -0.45346,0.28125 -0.71875,0.28125 l -1,0 0,-1 c -3e-6,-0.26529 0.09306,-0.53058 0.28125,-0.71875 l 2.28125,-2.25 -2.28125,-2.28125 c -0.210742,-0.19463 -0.30316,-0.46925 -0.28125,-0.75 l 0,-1 z" /></g></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
BIN
data/theme/corner-ripple-rtl.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
@@ -9,23 +9,23 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6446"
|
||||
width="10"
|
||||
height="20"
|
||||
id="svg10003"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="single-view-active.svg">
|
||||
inkscape:version="0.48.1 r9760"
|
||||
sodipodi:docname="filter-selected-ltr.svg">
|
||||
<defs
|
||||
id="defs6448">
|
||||
id="defs10005">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_x="0 : 32 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6454" />
|
||||
inkscape:vp_z="64 : 32 : 1"
|
||||
inkscape:persp3d-origin="32 : 21.333333 : 1"
|
||||
id="perspective10011" />
|
||||
<inkscape:perspective
|
||||
id="perspective6441"
|
||||
id="perspective9998"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
@@ -37,29 +37,29 @@
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="0.014720032"
|
||||
inkscape:cy="16"
|
||||
inkscape:zoom="5.5"
|
||||
inkscape:cx="32.363636"
|
||||
inkscape:cy="10.181818"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:window-width="1440"
|
||||
inkscape:window-height="839"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6451">
|
||||
id="metadata10008">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
@@ -67,15 +67,15 @@
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-17)">
|
||||
<rect
|
||||
ry="0.5"
|
||||
rx="0.49999979"
|
||||
y="17.483809"
|
||||
x="0.53483802"
|
||||
height="15"
|
||||
width="23"
|
||||
id="rect5304"
|
||||
style="fill:#cccccc;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
|
||||
transform="translate(0,-44)">
|
||||
<path
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/home/jimmac/src/cvs/gnome/gnome-shell-design/mockups/app-picker.png"
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect34320"
|
||||
d="m 10.369085,54.181804 -10.55634072,10.55636 -1e-5,-21.11269 z"
|
||||
style="opacity:0.21000001;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.99999988;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.7 KiB |
@@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6503"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="mosaic-view-active.svg">
|
||||
<defs
|
||||
id="defs6505">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6511" />
|
||||
<inkscape:perspective
|
||||
id="perspective6494"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="-15.97056"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6508">
|
||||
<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>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-16)">
|
||||
<g
|
||||
style="display:inline;fill:#cbcbcb;fill-opacity:1"
|
||||
transform="translate(-449.85476,-685.85869)"
|
||||
id="g5306">
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none"
|
||||
id="rect5308"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
|
||||
id="rect5310"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999976000000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
|
||||
id="rect5312"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
|
||||
id="rect5314"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.7 KiB |
@@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6503"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="New document 19">
|
||||
<defs
|
||||
id="defs6505">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6511" />
|
||||
<inkscape:perspective
|
||||
id="perspective6494"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="16"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6508">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-16)">
|
||||
<g
|
||||
style="display:inline"
|
||||
transform="translate(-449.85476,-685.85869)"
|
||||
id="g5306">
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none"
|
||||
id="rect5308"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
|
||||
id="rect5310"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
|
||||
id="rect5312"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
|
||||
id="rect5314"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="98"
|
||||
height="98"
|
||||
id="svg6375"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="add-workspace.svg">
|
||||
<defs
|
||||
id="defs6377">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6383" />
|
||||
<inkscape:perspective
|
||||
id="perspective6366"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.9590209"
|
||||
inkscape:cx="56.650687"
|
||||
inkscape:cy="20.635343"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6380">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,66)">
|
||||
<g
|
||||
id="g2824"
|
||||
transform="matrix(11.568551,0,0,11.698271,-78.828159,-304.81518)">
|
||||
<path
|
||||
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 11.07363,21.36834 0,6.43903"
|
||||
id="path5322" />
|
||||
<path
|
||||
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
d="m 14.29314,24.58786 -6.43902,0"
|
||||
id="path5324" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:0.98823529"
|
||||
d="m 48.239516,97.908047 c -0.41677,-0.05102 -1.269253,-0.222408 -1.894408,-0.380859 -4.088493,-1.036262 -7.520781,-4.753234 -8.330163,-9.021094 -0.154947,-0.817026 -0.257819,-6.68112 -0.257819,-14.696556 l 0,-13.337088 -13.829177,-0.08909 C 10.802042,60.298796 10.026884,60.268266 8.6851548,59.783022 3.6288503,57.954375 0.62673331,53.828648 0.62673331,48.708554 c 0,-5.625522 4.25936019,-10.425065 9.97721469,-11.242548 0.987903,-0.141242 7.368912,-0.254994 14.460646,-0.257791 l 12.692532,-0.005 0,-13.586668 c 0,-14.6441583 0.03287,-15.0698926 1.364686,-17.6753047 2.185477,-4.2754229 6.938193,-6.75739913 11.687647,-6.10355607 3.382776,0.46569661 6.737962,2.72496967 8.414081,5.66577137 1.480816,2.5981315 1.519067,3.0522448 1.519067,18.0333334 l 0,13.666424 12.692533,0.005 c 7.091733,0.0028 13.472742,0.116549 14.460646,0.257791 6.395303,0.914337 10.804785,6.623716 9.941157,12.871766 -0.698243,5.051565 -4.792685,9.104635 -9.941157,9.840713 -0.987904,0.141242 -7.368913,0.254995 -14.460646,0.257791 l -12.692533,0.005 0,13.801945 c 0,13.031417 -0.02798,13.895893 -0.501177,15.484801 -1.526902,5.127058 -6.919246,8.802262 -12.001914,8.18002 z"
|
||||
id="path2828"
|
||||
transform="translate(0,-66)" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
33
data/theme/panel-border.svg
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="3"
|
||||
height="10"
|
||||
id="svg2"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1">
|
||||
<rect
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.43599999000000000;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="rect3779"
|
||||
width="3"
|
||||
height="10"
|
||||
x="0"
|
||||
y="0" />
|
||||
<rect
|
||||
style="fill:#536272;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="rect3796"
|
||||
width="3"
|
||||
height="1"
|
||||
x="0"
|
||||
y="9" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 787 B |
|
Before Width: | Height: | Size: 4.0 KiB |
261
data/theme/process-working.svg
Normal file
@@ -0,0 +1,261 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
id="svg5369"
|
||||
version="1.1"
|
||||
inkscape:version="0.48+devel r10053 custom"
|
||||
width="96"
|
||||
height="48"
|
||||
sodipodi:docname="process-working.svg"
|
||||
style="display:inline">
|
||||
<metadata
|
||||
id="metadata5375">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs5373" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#808080"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1975"
|
||||
inkscape:window-height="1098"
|
||||
id="namedview5371"
|
||||
showgrid="true"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:zoom="16"
|
||||
inkscape:cx="53.997662"
|
||||
inkscape:cy="22.367695"
|
||||
inkscape:window-x="1600"
|
||||
inkscape:window-y="33"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="layer2">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid11933"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
inkscape:label="tiles"
|
||||
style="display:none">
|
||||
<rect
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect12451"
|
||||
width="24"
|
||||
height="24"
|
||||
x="0"
|
||||
y="0" />
|
||||
<rect
|
||||
y="24"
|
||||
x="0"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect12453"
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="0"
|
||||
x="24"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect12455"
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect12457"
|
||||
width="24"
|
||||
height="24"
|
||||
x="24"
|
||||
y="24" />
|
||||
<rect
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect12459"
|
||||
width="24"
|
||||
height="24"
|
||||
x="48"
|
||||
y="0" />
|
||||
<rect
|
||||
y="24"
|
||||
x="48"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect12461"
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
y="0"
|
||||
x="72"
|
||||
height="24"
|
||||
width="24"
|
||||
id="rect12463"
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<rect
|
||||
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect12465"
|
||||
width="24"
|
||||
height="24"
|
||||
x="72"
|
||||
y="24" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer2"
|
||||
inkscape:label="spinner">
|
||||
<g
|
||||
transform="matrix(0.28240106,0,0,0.28240106,146.92015,-382.52444)"
|
||||
id="g10450-5"
|
||||
style="display:inline">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m -477.76072,1373.3569 0,9.4717"
|
||||
id="path18768"
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:transform-center-y="-4.6808838" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:transform-center-y="-3.3099227"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path18770"
|
||||
d="m -461.0171,1380.2922 -7.23427,7.3824"
|
||||
style="opacity:0.7;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
inkscape:transform-center-x="-3.3098966" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:transform-center-x="-4.6808962"
|
||||
style="opacity:0.8;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m -454.08163,1397.0359 -9.47165,0"
|
||||
id="path18772"
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:transform-center-y="-2.6596956e-05" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path18774"
|
||||
d="m -461.01709,1413.7796 -6.93831,-7.0864"
|
||||
style="opacity:0.9;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
inkscape:transform-center-x="-3.3098966"
|
||||
inkscape:transform-center-y="3.3098652" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:transform-center-y="4.6808757"
|
||||
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m -477.76074,1420.715 9e-5,-9.4716"
|
||||
id="path18776"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path18778"
|
||||
d="m -494.50442,1413.7796 6.79048,-6.9384"
|
||||
style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
inkscape:transform-center-y="3.3098769"
|
||||
inkscape:transform-center-x="3.3098883" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:transform-center-x="4.6808941"
|
||||
style="opacity:0.4;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
d="m -501.43987,1397.0359 9.47174,0"
|
||||
id="path18780"
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:transform-center-y="-2.6596956e-05" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path18782"
|
||||
d="m -494.5044,1380.2922 6.64243,6.9384"
|
||||
style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:7.08212566;stroke-linecap:round;stroke-opacity:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
inkscape:transform-center-x="3.3098902"
|
||||
inkscape:transform-center-y="-3.3099302" />
|
||||
</g>
|
||||
<use
|
||||
style="display:inline"
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#g10450-5"
|
||||
id="use4981"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,36,-4.9705636)"
|
||||
width="400"
|
||||
height="400" />
|
||||
<use
|
||||
style="display:inline"
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#use4981"
|
||||
id="use4983"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,43.032478,-21.909695)"
|
||||
width="400"
|
||||
height="400" />
|
||||
<use
|
||||
style="display:inline"
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#use4983"
|
||||
id="use4985"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,50.081986,-38.904617)"
|
||||
width="400"
|
||||
height="400" />
|
||||
<use
|
||||
style="display:inline"
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#use4985"
|
||||
id="use4987"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,-38.919996,-31.872139)"
|
||||
width="400"
|
||||
height="400" />
|
||||
<use
|
||||
style="display:inline"
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#use4987"
|
||||
id="use4989"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,52.986628,2.0890543)"
|
||||
width="400"
|
||||
height="400" />
|
||||
<use
|
||||
style="display:inline"
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#use4989"
|
||||
id="use4991"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,60.013026,-14.912936)"
|
||||
width="400"
|
||||
height="400" />
|
||||
<use
|
||||
style="display:inline"
|
||||
x="0"
|
||||
y="0"
|
||||
xlink:href="#use4991"
|
||||
id="use4993"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,67.022396,-31.859127)"
|
||||
width="400"
|
||||
height="400" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 225 B |
|
Before Width: | Height: | Size: 211 B |
|
Before Width: | Height: | Size: 211 B |
@@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="5.8600588"
|
||||
height="9"
|
||||
id="svg3647"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="section-more.svg">
|
||||
<defs
|
||||
id="defs3649">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3655" />
|
||||
<inkscape:perspective
|
||||
id="perspective3603"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="82.777778"
|
||||
inkscape:cx="2.9300294"
|
||||
inkscape:cy="5.466443"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3652">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-262.78425,-490.71933)">
|
||||
<path
|
||||
transform="matrix(0,-0.98149546,0.71467449,0,25.404986,578.15569)"
|
||||
d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="1.5707963"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="5"
|
||||
sodipodi:cy="337.5"
|
||||
sodipodi:cx="84.5"
|
||||
sodipodi:sides="3"
|
||||
id="path5497-5"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
sodipodi:type="star" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB |
@@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="5.8600588"
|
||||
height="9"
|
||||
id="svg3647"
|
||||
version="1.1"
|
||||
inkscape:version="0.46+devel"
|
||||
sodipodi:docname="New document 6">
|
||||
<defs
|
||||
id="defs3649">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3655" />
|
||||
<inkscape:perspective
|
||||
id="perspective3603"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="112.21575"
|
||||
inkscape:cy="-32.642856"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="609"
|
||||
inkscape:window-height="501"
|
||||
inkscape:window-x="164"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata3652">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-262.78425,-490.71933)">
|
||||
<path
|
||||
transform="matrix(0,0.98149546,-0.71467449,0,506.02358,412.28296)"
|
||||
d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="1.5707963"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="5"
|
||||
sodipodi:cy="337.5"
|
||||
sodipodi:cx="84.5"
|
||||
sodipodi:sides="3"
|
||||
id="path5497-5"
|
||||
style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
sodipodi:type="star" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 531 B |
@@ -1,81 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6446"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="single-view.svg">
|
||||
<defs
|
||||
id="defs6448">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6454" />
|
||||
<inkscape:perspective
|
||||
id="perspective6441"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="0.014720032"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6451">
|
||||
<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>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-17)">
|
||||
<rect
|
||||
ry="0.5"
|
||||
rx="0.49999979"
|
||||
y="17.483809"
|
||||
x="0.53483802"
|
||||
height="15"
|
||||
width="23"
|
||||
id="rect5304"
|
||||
style="fill:#626262;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.4 KiB |
74
data/theme/source-button-border.svg
Normal file
@@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="21"
|
||||
height="10"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="source-button-border.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#000000"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="44.8"
|
||||
inkscape:cx="8.704132"
|
||||
inkscape:cy="5.7029946"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="1145"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1"
|
||||
guidetolerance="10000"
|
||||
objecttolerance="10000">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3792"
|
||||
empspacing="10"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<rect
|
||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke-width:0.43599999;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="rect3796"
|
||||
width="19"
|
||||
height="2"
|
||||
x="1"
|
||||
y="8" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
@@ -6,6 +6,22 @@
|
||||
|
||||
<name xml:lang="en">GNOME Shell</name>
|
||||
<shortdesc xml:lang="en">Next generation GNOME desktop shell</shortdesc>
|
||||
<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.
|
||||
|
||||
Tarball releases are provided largely for distributions to build
|
||||
packages. If you are interested in building GNOME Shell from source,
|
||||
we would recommend building from version control using the build
|
||||
script described at:
|
||||
|
||||
http://live.gnome.org/GnomeShell
|
||||
|
||||
Not only will that give you the very latest version of this rapidly
|
||||
changing project, it will be much easier than get GNOME Shell and
|
||||
its dependencies to build from tarballs.</description>
|
||||
<!--
|
||||
<homepage rdf:resource="http://live.gnome.org/GnomeShell" />
|
||||
-->
|
||||
|
||||
@@ -8,6 +8,7 @@ nobase_dist_js_DATA = \
|
||||
misc/format.js \
|
||||
misc/gnomeSession.js \
|
||||
misc/history.js \
|
||||
misc/modemManager.js \
|
||||
misc/params.js \
|
||||
misc/util.js \
|
||||
perf/core.js \
|
||||
@@ -25,6 +26,7 @@ nobase_dist_js_DATA = \
|
||||
ui/endSessionDialog.js \
|
||||
ui/environment.js \
|
||||
ui/extensionSystem.js \
|
||||
ui/goaClient.js \
|
||||
ui/iconGrid.js \
|
||||
ui/lightbox.js \
|
||||
ui/link.js \
|
||||
@@ -50,6 +52,7 @@ nobase_dist_js_DATA = \
|
||||
ui/statusMenu.js \
|
||||
ui/status/accessibility.js \
|
||||
ui/status/keyboard.js \
|
||||
ui/status/network.js \
|
||||
ui/status/power.js \
|
||||
ui/status/volume.js \
|
||||
ui/status/bluetooth.js \
|
||||
|
||||
@@ -7,7 +7,8 @@ const Signals = imports.signals;
|
||||
const PresenceIface = {
|
||||
name: 'org.gnome.SessionManager.Presence',
|
||||
methods: [{ name: 'SetStatus',
|
||||
inSignature: 'u' }],
|
||||
inSignature: 'u',
|
||||
outSignature: '' }],
|
||||
properties: [{ name: 'status',
|
||||
signature: 'u',
|
||||
access: 'readwrite' }],
|
||||
@@ -101,3 +102,24 @@ Inhibitor.prototype = {
|
||||
};
|
||||
DBus.proxifyPrototype(Inhibitor.prototype, InhibitorIface);
|
||||
Signals.addSignalMethods(Inhibitor.prototype);
|
||||
|
||||
|
||||
// Not the full interface, only the methods we use
|
||||
const SessionManagerIface = {
|
||||
name: 'org.gnome.SessionManager',
|
||||
methods: [
|
||||
{ name: 'Logout', inSignature: 'u', outSignature: '' },
|
||||
{ name: 'Shutdown', inSignature: '', outSignature: '' }
|
||||
]
|
||||
};
|
||||
|
||||
function SessionManager() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
SessionManager.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.gnome.SessionManager', '/org/gnome/SessionManager');
|
||||
}
|
||||
};
|
||||
DBus.proxifyPrototype(SessionManager.prototype, SessionManagerIface);
|
||||
@@ -2,22 +2,40 @@
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
const DEFAULT_LIMIT = 512;
|
||||
|
||||
function HistoryManager(settings_key) {
|
||||
this._init(settings_key);
|
||||
function HistoryManager(params) {
|
||||
this._init(params);
|
||||
}
|
||||
|
||||
HistoryManager.prototype = {
|
||||
_init: function(settings_key, limit) {
|
||||
this._limit = limit || DEFAULT_LIMIT;
|
||||
this._key = settings_key;
|
||||
this._history = global.settings.get_strv(settings_key);
|
||||
this._historyIndex = -1;
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { gsettingsKey: null,
|
||||
limit: DEFAULT_LIMIT,
|
||||
entry: null });
|
||||
|
||||
global.settings.connect('changed::' + settings_key,
|
||||
Lang.bind(this, this._historyChanged));
|
||||
this._key = params.gsettingsKey;
|
||||
this._limit = params.limit;
|
||||
|
||||
this._historyIndex = 0;
|
||||
if (this._key) {
|
||||
this._history = global.settings.get_strv(this._key);
|
||||
global.settings.connect('changed::' + this._key,
|
||||
Lang.bind(this, this._historyChanged));
|
||||
|
||||
} else {
|
||||
this._history = [];
|
||||
}
|
||||
|
||||
this._entry = params.entry;
|
||||
|
||||
if (this._entry) {
|
||||
this._entry.connect('key-press-event',
|
||||
Lang.bind(this, this._onEntryKeyPress));
|
||||
}
|
||||
},
|
||||
|
||||
_historyChanged: function() {
|
||||
@@ -26,18 +44,32 @@ HistoryManager.prototype = {
|
||||
},
|
||||
|
||||
prevItem: function(text) {
|
||||
this._setHistory(this._historyIndex--, text);
|
||||
if (this._historyIndex <= 0)
|
||||
return text;
|
||||
|
||||
if (text)
|
||||
this._history[this._historyIndex] = text;
|
||||
this._historyIndex--;
|
||||
return this._indexChanged();
|
||||
},
|
||||
|
||||
nextItem: function(text) {
|
||||
this._setHistory(this._historyIndex++, text);
|
||||
if (this._historyIndex >= this._history.length)
|
||||
return text;
|
||||
|
||||
if (text)
|
||||
this._history[this._historyIndex] = text;
|
||||
this._historyIndex++;
|
||||
return this._indexChanged();
|
||||
},
|
||||
|
||||
lastItem: function() {
|
||||
this._historyIndex = this._history.length;
|
||||
return this._indexChanged();
|
||||
if (this._historyIndex != this._history.length) {
|
||||
this._historyIndex = this._history.length;
|
||||
this._indexChanged();
|
||||
}
|
||||
|
||||
return this._historyIndex[this._history.length];
|
||||
},
|
||||
|
||||
addItem: function(input) {
|
||||
@@ -46,27 +78,38 @@ HistoryManager.prototype = {
|
||||
|
||||
this._history.push(input);
|
||||
this._save();
|
||||
}
|
||||
}
|
||||
this._historyIndex = this._history.length;
|
||||
},
|
||||
|
||||
_onEntryKeyPress: function(entry, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_Up) {
|
||||
this.prevItem(entry.get_text());
|
||||
return true;
|
||||
} else if (symbol == Clutter.KEY_Down) {
|
||||
this.nextItem(entry.get_text());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_indexChanged: function() {
|
||||
let current = this._history[this._historyIndex] || '';
|
||||
this.emit('changed', current);
|
||||
|
||||
if (this._entry)
|
||||
this._entry.set_text(current);
|
||||
|
||||
return current;
|
||||
},
|
||||
|
||||
_setHistory: function(index, text) {
|
||||
this._historyIndex = Math.max(this._historyIndex, 0);
|
||||
this._historyIndex = Math.min(this._historyIndex, this._history.length);
|
||||
|
||||
if (text)
|
||||
this._history[index] = text;
|
||||
},
|
||||
|
||||
_save: function() {
|
||||
if (this._history.length > this._limit)
|
||||
this._history.splice(0, this._history.length - this._key);
|
||||
global.settings.set_strv(this._key, this._history);
|
||||
this._history.splice(0, this._history.length - this._limit);
|
||||
|
||||
if (this._key)
|
||||
global.settings.set_strv(this._key, this._history);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(HistoryManager.prototype);
|
||||
|
||||
225
js/misc/modemManager.js
Normal file
@@ -0,0 +1,225 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
// The following are not the complete interfaces, just the methods we need
|
||||
// (or may need in the future)
|
||||
|
||||
const ModemGsmNetworkInterface = {
|
||||
name: 'org.freedesktop.ModemManager.Modem.Gsm.Network',
|
||||
methods: [
|
||||
{ name: 'GetRegistrationInfo', inSignature: '', outSignature: 'uss' },
|
||||
{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' }
|
||||
],
|
||||
properties: [
|
||||
{ name: 'AccessTechnology', signature: 'u', access: 'read' }
|
||||
],
|
||||
signals: [
|
||||
{ name: 'SignalQuality', inSignature: 'u' },
|
||||
{ name: 'RegistrationInfo', inSignature: 'uss' }
|
||||
]
|
||||
};
|
||||
const ModemGsmNetworkProxy = DBus.makeProxyClass(ModemGsmNetworkInterface);
|
||||
|
||||
const ModemCdmaInterface = {
|
||||
name: 'org.freedesktop.ModemManager.Modem.Cdma',
|
||||
methods: [
|
||||
{ name: 'GetSignalQuality', inSignature: '', outSignature: 'u' },
|
||||
{ name: 'GetServingSystem', inSignature: '', outSignature: 'usu' }
|
||||
],
|
||||
signals: [
|
||||
{ name: 'SignalQuality', inSignature: 'u' }
|
||||
]
|
||||
};
|
||||
const ModemCdmaProxy = DBus.makeProxyClass(ModemCdmaInterface);
|
||||
|
||||
let _providersTable;
|
||||
function _getProvidersTable() {
|
||||
if (_providersTable)
|
||||
return _providersTable;
|
||||
let [providers, countryCodes] = Shell.mobile_providers_parse();
|
||||
return _providersTable = providers;
|
||||
}
|
||||
|
||||
function ModemGsm() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
ModemGsm.prototype = {
|
||||
_init: function(path) {
|
||||
this._proxy = new ModemGsmNetworkProxy(DBus.system, 'org.freedesktop.ModemManager', path);
|
||||
|
||||
this.signal_quality = 0;
|
||||
this.operator_name = null;
|
||||
|
||||
// Code is duplicated because the function have different signatures
|
||||
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
|
||||
this.signal_quality = quality;
|
||||
this.emit('notify::signal-quality');
|
||||
}));
|
||||
this._proxy.connect('RegistrationInfo', Lang.bind(this, function(proxy, status, code, name) {
|
||||
this.operator_name = this._findOperatorName(name, code);
|
||||
this.emit('notify::operator-name');
|
||||
}));
|
||||
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) {
|
||||
if (err) {
|
||||
log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
let [status, code, name] = result;
|
||||
this.operator_name = this._findOperatorName(name, code);
|
||||
this.emit('notify::operator-name');
|
||||
}));
|
||||
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
|
||||
if (err) {
|
||||
// it will return an error if the device is not connected
|
||||
this.signal_quality = 0;
|
||||
} else {
|
||||
let [quality] = result;
|
||||
this.signal_quality = quality;
|
||||
}
|
||||
this.emit('notify::signal-quality');
|
||||
}));
|
||||
},
|
||||
|
||||
_findOperatorName: function(name, opCode) {
|
||||
if (name.length != 0 && (name.length > 6 || name.length < 5)) {
|
||||
// this looks like a valid name, i.e. not an MCCMNC (that some
|
||||
// devices return when not yet connected
|
||||
return name;
|
||||
}
|
||||
if (isNaN(parseInt(name))) {
|
||||
// name is definitely not a MCCMNC, so it may be a name
|
||||
// after all; return that
|
||||
return name;
|
||||
}
|
||||
|
||||
let needle;
|
||||
if (name.length == 0 && opCode)
|
||||
needle = opCode;
|
||||
else if (name.length == 6 || name.length == 5)
|
||||
needle = name;
|
||||
else // nothing to search
|
||||
return null;
|
||||
|
||||
return this._findProviderForMCCMNC(needle);
|
||||
},
|
||||
|
||||
_findProviderForMCCMNC: function(needle) {
|
||||
let table = _getProvidersTable();
|
||||
let needlemcc = needle.substring(0, 3);
|
||||
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);
|
||||
|
||||
function ModemCdma() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
ModemCdma.prototype = {
|
||||
_init: function(path) {
|
||||
this._proxy = new ModemCdmaProxy(DBus.system, 'org.freedesktop.ModemManager', path);
|
||||
|
||||
this.signal_quality = 0;
|
||||
this.operator_name = null;
|
||||
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, quality) {
|
||||
this.signal_quality = quality;
|
||||
this.emit('notify::signal-quality');
|
||||
|
||||
// receiving this signal means the device got activated
|
||||
// and we can finally call GetServingSystem
|
||||
if (this.operator_name == null)
|
||||
this._refreshServingSystem();
|
||||
}));
|
||||
this._proxy.GetSignalQualityRemote(Lang.bind(this, function(result, err) {
|
||||
if (err) {
|
||||
// it will return an error if the device is not connected
|
||||
this.signal_quality = 0;
|
||||
} else {
|
||||
let [quality] = result;
|
||||
this.signal_quality = quality;
|
||||
}
|
||||
this.emit('notify::signal-quality');
|
||||
}));
|
||||
},
|
||||
|
||||
_refreshServingSystem: function() {
|
||||
this._proxy.GetServingSystemRemote(Lang.bind(this, function(result, err) {
|
||||
if (err) {
|
||||
// it will return an error if the device is not connected
|
||||
this.operator_name = null;
|
||||
} else {
|
||||
let [bandClass, band, id] = result;
|
||||
if (name.length > 0)
|
||||
this.operator_name = this._findProviderForSid(id);
|
||||
else
|
||||
this.operator_name = null;
|
||||
}
|
||||
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);
|
||||
132
js/misc/util.js
@@ -6,10 +6,6 @@ const GLib = imports.gi.GLib;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
|
||||
const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)([^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\\".,<>?«»“”‘’]))', 'gi');
|
||||
@@ -56,20 +52,6 @@ function spawnCommandLine(command_line) {
|
||||
}
|
||||
}
|
||||
|
||||
// spawnDesktop:
|
||||
// @id: a desktop file ID
|
||||
//
|
||||
// Spawns the desktop file identified by @id using startup notification,
|
||||
// etc, handling any errors that occur when trying to find or start
|
||||
// the program.
|
||||
function spawnDesktop(id) {
|
||||
try {
|
||||
trySpawnDesktop(id);
|
||||
} catch (err) {
|
||||
_handleSpawnError(id, err);
|
||||
}
|
||||
}
|
||||
|
||||
// trySpawn:
|
||||
// @argv: an argv array
|
||||
//
|
||||
@@ -117,41 +99,9 @@ function trySpawnCommandLine(command_line) {
|
||||
trySpawn(argv);
|
||||
}
|
||||
|
||||
// trySpawnDesktop:
|
||||
// @id: a desktop file ID
|
||||
//
|
||||
// Spawns the desktop file identified by @id using startup notification.
|
||||
// On error, throws an exception.
|
||||
function trySpawnDesktop(id) {
|
||||
let app;
|
||||
|
||||
// shell_app_system_load_from_desktop_file() will end up returning
|
||||
// a stupid error message if the desktop file doesn't exist, but
|
||||
// that's the only case it returns an error for, so we just
|
||||
// substitute our own error in instead
|
||||
try {
|
||||
app = Shell.AppSystem.get_default().load_from_desktop_file(id + '.desktop');
|
||||
} catch (err) {
|
||||
throw new Error(_("No such application"));
|
||||
}
|
||||
|
||||
try {
|
||||
app.launch();
|
||||
} catch(err) {
|
||||
// see trySpawn
|
||||
err.message = err.message.replace(/.*\((.+)\)/, '$1');
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function _handleSpawnError(command, err) {
|
||||
let title = _("Execution of '%s' failed:").format(command);
|
||||
|
||||
let source = new MessageTray.SystemNotificationSource();
|
||||
Main.messageTray.add(source);
|
||||
let notification = new MessageTray.Notification(source, title, err.message);
|
||||
notification.setTransient(true);
|
||||
source.notify(notification);
|
||||
Main.notifyError(title, err.message);
|
||||
}
|
||||
|
||||
// killall:
|
||||
@@ -178,3 +128,83 @@ function killall(processName) {
|
||||
logError(e, 'Failed to kill ' + processName);
|
||||
}
|
||||
}
|
||||
|
||||
// This was ported from network-manager-applet
|
||||
// Copyright 2007 - 2011 Red Hat, Inc.
|
||||
// Author: Dan Williams <dcbw@redhat.com>
|
||||
|
||||
const _IGNORED_WORDS = [
|
||||
'Semiconductor',
|
||||
'Components',
|
||||
'Corporation',
|
||||
'Communications',
|
||||
'Company',
|
||||
'Corp.',
|
||||
'Corp',
|
||||
'Co.',
|
||||
'Inc.',
|
||||
'Inc',
|
||||
'Incorporated',
|
||||
'Ltd.',
|
||||
'Limited.',
|
||||
'Intel',
|
||||
'chipset',
|
||||
'adapter',
|
||||
'[hex]',
|
||||
'NDIS',
|
||||
'Module'
|
||||
];
|
||||
|
||||
const _IGNORED_PHRASES = [
|
||||
'Multiprotocol MAC/baseband processor',
|
||||
'Wireless LAN Controller',
|
||||
'Wireless LAN Adapter',
|
||||
'Wireless Adapter',
|
||||
'Network Connection',
|
||||
'Wireless Cardbus Adapter',
|
||||
'Wireless CardBus Adapter',
|
||||
'54 Mbps Wireless PC Card',
|
||||
'Wireless PC Card',
|
||||
'Wireless PC',
|
||||
'PC Card with XJACK(r) Antenna',
|
||||
'Wireless cardbus',
|
||||
'Wireless LAN PC Card',
|
||||
'Technology Group Ltd.',
|
||||
'Communication S.p.A.',
|
||||
'Business Mobile Networks BV',
|
||||
'Mobile Broadband Minicard Composite Device',
|
||||
'Mobile Communications AB',
|
||||
'(PC-Suite Mode)'
|
||||
];
|
||||
|
||||
function fixupPCIDescription(desc) {
|
||||
desc = desc.replace(/[_,]/, ' ');
|
||||
|
||||
/* Attempt to shorten ID by ignoring certain phrases */
|
||||
for (let i = 0; i < _IGNORED_PHRASES.length; i++) {
|
||||
let item = _IGNORED_PHRASES[i];
|
||||
let pos = desc.indexOf(item);
|
||||
if (pos != -1) {
|
||||
let before = desc.substring(0, pos);
|
||||
let after = desc.substring(pos + item.length, desc.length);
|
||||
desc = before + after;
|
||||
}
|
||||
}
|
||||
|
||||
/* Attmept to shorten ID by ignoring certain individual words */
|
||||
let words = desc.split(' ');
|
||||
let out = [ ];
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
let item = words[i];
|
||||
|
||||
// skip empty items (that come out from consecutive spaces)
|
||||
if (item.length == 0)
|
||||
continue;
|
||||
|
||||
if (_IGNORED_WORDS.indexOf(item) == -1) {
|
||||
out.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return out.join(' ');
|
||||
}
|
||||
|
||||
@@ -21,26 +21,77 @@ let METRICS = {
|
||||
overviewFpsSubsequent:
|
||||
{ description: "Frames rate when going to the overview, second time",
|
||||
units: "frames / s" },
|
||||
overviewFps5Windows:
|
||||
{ description: "Frames rate when going to the overview, 5 windows open",
|
||||
units: "frames / s" },
|
||||
overviewFps10Windows:
|
||||
{ description: "Frames rate when going to the overview, 10 windows open",
|
||||
units: "frames / s" },
|
||||
overviewFps5Maximized:
|
||||
{ description: "Frames rate when going to the overview, 5 maximized windows open",
|
||||
units: "frames / s" },
|
||||
overviewFps10Maximized:
|
||||
{ description: "Frames rate when going to the overview, 10 maximized windows open",
|
||||
units: "frames / s" },
|
||||
overviewFps5Alpha:
|
||||
{ description: "Frames rate when going to the overview, 5 alpha-transparent windows open",
|
||||
units: "frames / s" },
|
||||
overviewFps10Alpha:
|
||||
{ description: "Frames rate when going to the overview, 10 alpha-transparent windows open",
|
||||
units: "frames / s" },
|
||||
usedAfterOverview:
|
||||
{ description: "Malloc'ed bytes after the overview is shown once",
|
||||
units: "B" },
|
||||
leakedAfterOverview:
|
||||
{ description: "Additional malloc'ed bytes the second time the overview is shown",
|
||||
units: "B" }
|
||||
units: "B" },
|
||||
applicationsShowTimeFirst:
|
||||
{ description: "Time to switch to applications view, first time",
|
||||
units: "us" },
|
||||
applicationsShowTimeSubsequent:
|
||||
{ description: "Time to switch to applications view, second time",
|
||||
units: "us"}
|
||||
};
|
||||
|
||||
let WINDOW_CONFIGS = [
|
||||
{ width: 640, height: 480, alpha: false, maximized: false, count: 1, metric: 'overviewFpsSubsequent' },
|
||||
{ width: 640, height: 480, alpha: false, maximized: false, count: 5, metric: 'overviewFps5Windows' },
|
||||
{ width: 640, height: 480, alpha: false, maximized: false, count: 10, metric: 'overviewFps10Windows' },
|
||||
{ width: 640, height: 480, alpha: false, maximized: true, count: 5, metric: 'overviewFps5Maximized' },
|
||||
{ width: 640, height: 480, alpha: false, maximized: true, count: 10, metric: 'overviewFps10Maximized' },
|
||||
{ width: 640, height: 480, alpha: true, maximized: false, count: 5, metric: 'overviewFps5Alpha' },
|
||||
{ width: 640, height: 480, alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha' }
|
||||
];
|
||||
|
||||
function run() {
|
||||
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
|
||||
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
|
||||
Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
|
||||
Scripting.defineScriptEvent("applicationsShowStart", "Starting to switch to applications view");
|
||||
Scripting.defineScriptEvent("applicationsShowDone", "Done switching to applications view");
|
||||
|
||||
Main.overview.connect('shown', function() {
|
||||
Scripting.scriptEvent('overviewShowDone');
|
||||
});
|
||||
|
||||
yield Scripting.sleep(1000);
|
||||
yield Scripting.waitLeisure();
|
||||
for (let i = 0; i < 2; i++) {
|
||||
|
||||
for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
|
||||
// We go to the overview twice for each configuration; the first time
|
||||
// to calculate the mipmaps for the windows, the second time to get
|
||||
// a clean set of numbers.
|
||||
if ((i % 2) == 0) {
|
||||
let config = WINDOW_CONFIGS[i / 2];
|
||||
yield Scripting.destroyTestWindows();
|
||||
|
||||
for (let k = 0; k < config.count; k++)
|
||||
yield Scripting.createTestWindow(config.width, config.height, config.alpha, config.maximized);
|
||||
|
||||
yield Scripting.waitTestWindows();
|
||||
yield Scripting.sleep(1000);
|
||||
yield Scripting.waitLeisure();
|
||||
}
|
||||
|
||||
Scripting.scriptEvent('overviewShowStart');
|
||||
Main.overview.show();
|
||||
|
||||
@@ -53,6 +104,21 @@ function run() {
|
||||
Scripting.collectStatistics();
|
||||
Scripting.scriptEvent('afterShowHide');
|
||||
}
|
||||
|
||||
yield Scripting.destroyTestWindows();
|
||||
yield Scripting.sleep(1000);
|
||||
|
||||
Main.overview.show();
|
||||
yield Scripting.waitLeisure();
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
Scripting.scriptEvent('applicationsShowStart');
|
||||
Main.overview.viewSelector.switchTab('applications');
|
||||
yield Scripting.waitLeisure();
|
||||
Scripting.scriptEvent('applicationsShowDone');
|
||||
Main.overview.viewSelector.switchTab('windows');
|
||||
yield Scripting.waitLeisure();
|
||||
}
|
||||
}
|
||||
|
||||
let showingOverview = false;
|
||||
@@ -64,6 +130,8 @@ let mallocUsedSize = 0;
|
||||
let overviewShowCount = 0;
|
||||
let firstOverviewUsedSize;
|
||||
let haveSwapComplete = false;
|
||||
let applicationsShowStart;
|
||||
let applicationsShowCount = 0;
|
||||
|
||||
function script_overviewShowStart(time) {
|
||||
showingOverview = true;
|
||||
@@ -79,6 +147,18 @@ function script_overviewShowDone(time) {
|
||||
finishedShowingOverview = true;
|
||||
}
|
||||
|
||||
function script_applicationsShowStart(time) {
|
||||
applicationsShowStart = time;
|
||||
}
|
||||
|
||||
function script_applicationsShowDone(time) {
|
||||
applicationsShowCount++;
|
||||
if (applicationsShowCount == 1)
|
||||
METRICS.applicationsShowTimeFirst.value = time - applicationsShowStart;
|
||||
else
|
||||
METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
|
||||
}
|
||||
|
||||
function script_afterShowHide(time) {
|
||||
if (overviewShowCount == 1) {
|
||||
METRICS.usedAfterOverview.value = mallocUsedSize;
|
||||
@@ -113,9 +193,15 @@ function _frameDone(time) {
|
||||
if (overviewShowCount == 1) {
|
||||
METRICS.overviewLatencyFirst.value = overviewLatency;
|
||||
METRICS.overviewFpsFirst.value = fps;
|
||||
} else {
|
||||
} else if (overviewShowCount == 2) {
|
||||
METRICS.overviewLatencySubsequent.value = overviewLatency;
|
||||
METRICS.overviewFpsSubsequent.value = fps;
|
||||
}
|
||||
|
||||
// Other than overviewFpsFirst, we collect FPS metrics the second
|
||||
// we show each window configuration. overviewShowCount is 1,2,3...
|
||||
if (overviewShowCount % 2 == 0) {
|
||||
let config = WINDOW_CONFIGS[(overviewShowCount / 2) - 1];
|
||||
METRICS[config.metric].value = fps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ AltTabPopup.prototype = {
|
||||
let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(primary.width - hPadding);
|
||||
let [childMinWidth, childNaturalWidth] = this._appSwitcher.actor.get_preferred_width(childNaturalHeight);
|
||||
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
|
||||
childBox.x2 = Math.min(childBox.x1 + primary.width - hPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||
this._appSwitcher.actor.allocate(childBox, flags);
|
||||
@@ -145,6 +145,12 @@ AltTabPopup.prototype = {
|
||||
|
||||
this._appIcons = this._appSwitcher.icons;
|
||||
|
||||
// Need to force an allocation so we can figure out whether we
|
||||
// need to scroll when selecting
|
||||
this.actor.opacity = 0;
|
||||
this.actor.show();
|
||||
this.actor.get_allocation_box();
|
||||
|
||||
// Make the initial selection
|
||||
if (switch_group) {
|
||||
if (backward) {
|
||||
@@ -156,29 +162,11 @@ AltTabPopup.prototype = {
|
||||
this._select(0, 0);
|
||||
}
|
||||
} else if (this._appIcons.length == 1) {
|
||||
if (!backward && this._appIcons[0].cachedWindows.length > 1) {
|
||||
// For compatibility with the multi-app case below
|
||||
this._select(0, 1, true);
|
||||
} else
|
||||
this._select(0);
|
||||
this._select(0);
|
||||
} else if (backward) {
|
||||
this._select(this._appIcons.length - 1);
|
||||
} else {
|
||||
let firstWindows = this._appIcons[0].cachedWindows;
|
||||
if (firstWindows.length > 1) {
|
||||
let curAppNextWindow = firstWindows[1];
|
||||
let nextAppWindow = this._appIcons[1].cachedWindows[0];
|
||||
|
||||
// If the next window of the current app is more-recently-used
|
||||
// than the first window of the next app, then select it.
|
||||
if (curAppNextWindow.get_workspace() == global.screen.get_active_workspace() &&
|
||||
curAppNextWindow.get_user_time() > nextAppWindow.get_user_time())
|
||||
this._select(0, 1, true);
|
||||
else
|
||||
this._select(1);
|
||||
} else {
|
||||
this._select(1);
|
||||
}
|
||||
this._select(1);
|
||||
}
|
||||
|
||||
// There's a race condition; if the user released Alt before
|
||||
@@ -192,8 +180,6 @@ AltTabPopup.prototype = {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.actor.opacity = 0;
|
||||
this.actor.show();
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: POPUP_FADE_TIME,
|
||||
@@ -376,7 +362,15 @@ AltTabPopup.prototype = {
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
_popModal: function() {
|
||||
if (this._haveModal) {
|
||||
Main.popModal(this.actor);
|
||||
this._haveModal = false;
|
||||
}
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
this._popModal();
|
||||
if (this.actor.visible) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
@@ -392,8 +386,7 @@ AltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
_onDestroy : function() {
|
||||
if (this._haveModal)
|
||||
Main.popModal(this.actor);
|
||||
this._popModal();
|
||||
|
||||
if (this._thumbnails)
|
||||
this._destroyThumbnails();
|
||||
@@ -594,7 +587,7 @@ SwitcherList.prototype = {
|
||||
this._rightArrow.opacity = this._rightGradient.opacity;
|
||||
},
|
||||
|
||||
addItem : function(item) {
|
||||
addItem : function(item, label) {
|
||||
let bbox = new St.Button({ style_class: 'item-box',
|
||||
reactive: true });
|
||||
|
||||
@@ -605,6 +598,8 @@ SwitcherList.prototype = {
|
||||
bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
|
||||
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
|
||||
|
||||
bbox.label_actor = label;
|
||||
|
||||
this._items.push(bbox);
|
||||
},
|
||||
|
||||
@@ -820,7 +815,7 @@ AppIcon.prototype = {
|
||||
this.actor = new St.BoxLayout({ style_class: 'alt-tab-app',
|
||||
vertical: true });
|
||||
this.icon = null;
|
||||
this._iconBin = new St.Bin();
|
||||
this._iconBin = new St.Bin({ x_fill: true, y_fill: true });
|
||||
|
||||
this.actor.add(this._iconBin, { x_fill: false, y_fill: false } );
|
||||
this.label = new St.Label({ text: this.app.get_name() });
|
||||
@@ -990,7 +985,7 @@ AppSwitcher.prototype = {
|
||||
|
||||
_addIcon : function(appIcon) {
|
||||
this.icons.push(appIcon);
|
||||
this.addItem(appIcon.actor);
|
||||
this.addItem(appIcon.actor, appIcon.label);
|
||||
|
||||
let n = this._arrows.length;
|
||||
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
||||
@@ -1060,9 +1055,12 @@ ThumbnailList.prototype = {
|
||||
this._labels.push(bin);
|
||||
bin.add_actor(name);
|
||||
box.add_actor(bin);
|
||||
|
||||
this.addItem(box, name);
|
||||
} else {
|
||||
this.addItem(box, null);
|
||||
}
|
||||
|
||||
this.addItem(box);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
const DND = imports.ui.dnd;
|
||||
@@ -21,7 +21,9 @@ const Tweener = imports.ui.tweener;
|
||||
const Workspace = imports.ui.workspace;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
const MAX_APPLICATION_WORK_MILLIS = 75;
|
||||
const MENU_POPUP_TIMEOUT = 600;
|
||||
const SCROLL_TIME = 0.1;
|
||||
|
||||
function AlphabeticalView() {
|
||||
this._init();
|
||||
@@ -32,6 +34,8 @@ AlphabeticalView.prototype = {
|
||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
|
||||
this._pendingAppLaterId = 0;
|
||||
this._apps = [];
|
||||
this._filterApp = null;
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
@@ -66,6 +70,7 @@ AlphabeticalView.prototype = {
|
||||
let appIcon = new AppWellIcon(this._appSystem.get_app(appInfo.get_id()));
|
||||
|
||||
this._grid.addItem(appIcon.actor);
|
||||
appIcon.actor.connect('key-focus-in', Lang.bind(this, this._ensureIconVisible));
|
||||
|
||||
appIcon._appInfo = appInfo;
|
||||
if (this._filterApp && !this._filterApp(appInfo))
|
||||
@@ -74,12 +79,62 @@ AlphabeticalView.prototype = {
|
||||
this._apps.push(appIcon);
|
||||
},
|
||||
|
||||
_ensureIconVisible: function(icon) {
|
||||
let adjustment = this.actor.vscroll.adjustment;
|
||||
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
||||
|
||||
let offset = 0;
|
||||
let vfade = this.actor.get_effect("vfade");
|
||||
if (vfade)
|
||||
offset = vfade.fade_offset;
|
||||
|
||||
// If this gets called as part of a right-click, the actor
|
||||
// will be needs_allocation, and so "icon.y" would return 0
|
||||
let box = icon.get_allocation_box();
|
||||
|
||||
if (box.y1 < value + offset)
|
||||
value = Math.max(0, box.y1 - offset);
|
||||
else if (box.y2 > value + pageSize - offset)
|
||||
value = Math.min(upper, box.y2 + offset - pageSize);
|
||||
else
|
||||
return;
|
||||
|
||||
Tweener.addTween(adjustment,
|
||||
{ value: value,
|
||||
time: SCROLL_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
},
|
||||
|
||||
setFilter: function(filter) {
|
||||
this._filterApp = filter;
|
||||
for (let i = 0; i < this._apps.length; i++)
|
||||
this._apps[i].actor.visible = filter(this._apps[i]._appInfo);
|
||||
},
|
||||
|
||||
// Create actors for the applications in an idle to avoid blocking
|
||||
// for too long; see bug 647778
|
||||
_addPendingApps: function() {
|
||||
let i;
|
||||
let startTimeMillis = new Date().getTime();
|
||||
for (i = 0; i < this._pendingAppIds.length; i++) {
|
||||
let id = this._pendingAppIds[i];
|
||||
this._addApp(this._pendingApps[id]);
|
||||
|
||||
let currentTimeMillis = new Date().getTime();
|
||||
if (currentTimeMillis - startTimeMillis > MAX_APPLICATION_WORK_MILLIS)
|
||||
break;
|
||||
}
|
||||
this._pendingAppIds.splice(0, i + 1);
|
||||
if (this._pendingAppIds.length > 0) {
|
||||
return true;
|
||||
} else {
|
||||
this._pendingAppLaterId = 0;
|
||||
this._pendingAppIds = null;
|
||||
this._pendingApps = null;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(apps) {
|
||||
let ids = [];
|
||||
for (let i in apps)
|
||||
@@ -90,9 +145,12 @@ AlphabeticalView.prototype = {
|
||||
|
||||
this._removeAll();
|
||||
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
this._addApp(apps[ids[i]]);
|
||||
}
|
||||
this._pendingAppIds = ids;
|
||||
this._pendingApps = apps;
|
||||
if (this._pendingAppLaterId)
|
||||
Meta.later_remove(this._pendingAppLaterId);
|
||||
this._pendingAppLaterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this, this._addPendingApps));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -108,7 +166,14 @@ ViewByCategories.prototype = {
|
||||
|
||||
this._view = new AlphabeticalView();
|
||||
|
||||
this._filters = new St.BoxLayout({ vertical: true });
|
||||
// categories can be -1 (the All view) or 0...n-1, where n
|
||||
// is the number of sections
|
||||
// -2 is a flag to indicate that nothing is selected
|
||||
// (used only before the actor is mapped the first time)
|
||||
this._currentCategory = -2;
|
||||
this._filters = new St.BoxLayout({ vertical: true, reactive: true });
|
||||
this._filters.connect('scroll-event', Lang.bind(this, this._scrollFilter));
|
||||
|
||||
this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
|
||||
this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
|
||||
|
||||
@@ -120,9 +185,28 @@ ViewByCategories.prototype = {
|
||||
}));
|
||||
|
||||
this._sections = [];
|
||||
|
||||
// We need a dummy actor to catch the keyboard focus if the
|
||||
// user Ctrl-Alt-Tabs here before the deferred work creates
|
||||
// our real contents
|
||||
this._focusDummy = new St.Bin({ can_focus: true });
|
||||
this.actor.add(this._focusDummy);
|
||||
},
|
||||
|
||||
_scrollFilter: function(actor, event) {
|
||||
let direction = event.get_scroll_direction();
|
||||
if (direction == Clutter.ScrollDirection.UP)
|
||||
this._selectCategory(Math.max(this._currentCategory - 1, -1))
|
||||
else if (direction == Clutter.ScrollDirection.DOWN)
|
||||
this._selectCategory(Math.min(this._currentCategory + 1, this._sections.length - 1));
|
||||
},
|
||||
|
||||
_selectCategory: function(num) {
|
||||
if (this._currentCategory == num) // nothing to do
|
||||
return;
|
||||
|
||||
this._currentCategory = num;
|
||||
|
||||
if (num != -1)
|
||||
this._allFilter.remove_style_pseudo_class('selected');
|
||||
else
|
||||
@@ -143,9 +227,10 @@ ViewByCategories.prototype = {
|
||||
},
|
||||
|
||||
_addFilter: function(name, num) {
|
||||
let button = new St.Button({ label: name,
|
||||
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
|
||||
style_class: 'app-filter',
|
||||
x_align: St.Align.START });
|
||||
x_align: St.Align.START,
|
||||
can_focus: true });
|
||||
this._filters.add(button, { expand: true, x_fill: true, y_fill: false });
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
this._selectCategory(num);
|
||||
@@ -168,7 +253,6 @@ ViewByCategories.prototype = {
|
||||
|
||||
let sections = this._appSystem.get_sections();
|
||||
this._apps = apps;
|
||||
this._view.refresh(apps);
|
||||
|
||||
/* Translators: Filter to display all applications */
|
||||
this._addFilter(_("All"), -1);
|
||||
@@ -180,6 +264,15 @@ ViewByCategories.prototype = {
|
||||
this._addFilter(sections[i], i);
|
||||
|
||||
this._selectCategory(-1);
|
||||
this._view.refresh(apps);
|
||||
|
||||
if (this._focusDummy) {
|
||||
let focused = this._focusDummy.has_key_focus();
|
||||
this._focusDummy.destroy();
|
||||
this._focusDummy = null;
|
||||
if (focused)
|
||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -230,7 +323,10 @@ BaseAppSearchProvider.prototype = {
|
||||
return null;
|
||||
return { 'id': resultId,
|
||||
'name': app.get_name(),
|
||||
'icon': app.create_icon_texture(Search.RESULT_ICON_SIZE)};
|
||||
'createIcon': function(size) {
|
||||
return app.create_icon_texture(size);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
activateResult: function(id, params) {
|
||||
@@ -246,7 +342,7 @@ BaseAppSearchProvider.prototype = {
|
||||
timestamp: null });
|
||||
|
||||
let app = this._appSys.get_app(id);
|
||||
app.open_new_window(params.workspace ? params.workspace.get_index() : -1);
|
||||
app.open_new_window(params.workspace ? params.workspace.index() : -1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -273,10 +369,6 @@ AppSearchProvider.prototype = {
|
||||
let app = this._appSys.get_app(resultMeta['id']);
|
||||
let icon = new AppWellIcon(app);
|
||||
return icon.actor;
|
||||
},
|
||||
|
||||
expandSearch: function(terms) {
|
||||
log('TODO expand search');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -288,7 +380,7 @@ PrefsSearchProvider.prototype = {
|
||||
__proto__: BaseAppSearchProvider.prototype,
|
||||
|
||||
_init: function() {
|
||||
BaseAppSearchProvider.prototype._init.call(this, _("PREFERENCES"));
|
||||
BaseAppSearchProvider.prototype._init.call(this, _("SETTINGS"));
|
||||
},
|
||||
|
||||
getInitialResultSet: function(terms) {
|
||||
@@ -297,12 +389,6 @@ PrefsSearchProvider.prototype = {
|
||||
|
||||
getSubsearchResultSet: function(previousResults, terms) {
|
||||
return this._appSys.subsearch(true, previousResults, terms);
|
||||
},
|
||||
|
||||
expandSearch: function(terms) {
|
||||
let controlCenter = this._appSys.load_from_desktop_file('gnomecc.desktop');
|
||||
controlCenter.launch();
|
||||
Main.overview.hide();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -338,6 +424,7 @@ AppWellIcon.prototype = {
|
||||
this.actor = new St.Button({ style_class: 'app-well-app',
|
||||
reactive: true,
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
|
||||
can_focus: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
this.actor._delegate = this;
|
||||
@@ -345,8 +432,11 @@ AppWellIcon.prototype = {
|
||||
this.icon = new AppIcon(app, iconParams);
|
||||
this.actor.set_child(this.icon.actor);
|
||||
|
||||
this.actor.label_actor = this.icon.label;
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));
|
||||
|
||||
this._menu = null;
|
||||
this._menuManager = new PopupMenu.PopupMenuManager(this);
|
||||
@@ -357,6 +447,10 @@ AppWellIcon.prototype = {
|
||||
this._removeMenuTimeout();
|
||||
Main.overview.beginItemDrag(this);
|
||||
}));
|
||||
this._draggable.connect('drag-cancelled', Lang.bind(this,
|
||||
function () {
|
||||
Main.overview.cancelledItemDrag(this);
|
||||
}));
|
||||
this._draggable.connect('drag-end', Lang.bind(this,
|
||||
function () {
|
||||
Main.overview.endItemDrag(this);
|
||||
@@ -423,6 +517,11 @@ AppWellIcon.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
_onKeyboardPopupMenu: function() {
|
||||
this.popupMenu();
|
||||
this._menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
},
|
||||
|
||||
getId: function() {
|
||||
return this.app.get_id();
|
||||
},
|
||||
@@ -440,10 +539,13 @@ AppWellIcon.prototype = {
|
||||
if (!isPoppedUp)
|
||||
this._onMenuPoppedDown();
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function () { this._menu.close(); }));
|
||||
|
||||
this._menuManager.addMenu(this._menu);
|
||||
}
|
||||
|
||||
this.actor.set_hover(true);
|
||||
this.actor.show_tooltip();
|
||||
this._menu.popup();
|
||||
|
||||
return false;
|
||||
@@ -507,6 +609,9 @@ AppIconMenu.prototype = {
|
||||
|
||||
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, 0.5, side, 0);
|
||||
|
||||
// We want to keep the item hovered while the menu is up
|
||||
this.blockSourceEvents = true;
|
||||
|
||||
this._source = source;
|
||||
|
||||
this.connect('activate', Lang.bind(this, this._onActivate));
|
||||
@@ -548,10 +653,9 @@ AppIconMenu.prototype = {
|
||||
|
||||
let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
|
||||
|
||||
this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null;
|
||||
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
|
||||
this._appendSeparator();
|
||||
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
|
||||
: _("Add to Favorites"));
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
@@ -40,80 +41,80 @@ BoxPointer.prototype = {
|
||||
this._border.connect('repaint', Lang.bind(this, this._drawBorder));
|
||||
this._container.add_actor(this._border);
|
||||
this.bin.raise(this._border);
|
||||
this._xOffset = 0;
|
||||
this._yOffset = 0;
|
||||
this._xPosition = 0;
|
||||
this._yPosition = 0;
|
||||
},
|
||||
|
||||
show: function(animate, onComplete) {
|
||||
let x = this.actor.x;
|
||||
let y = this.actor.y;
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let rise = themeNode.get_length('-arrow-rise');
|
||||
|
||||
this.actor.opacity = 0;
|
||||
this.opacity = 0;
|
||||
this.actor.show();
|
||||
|
||||
if (animate) {
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
this.actor.y -= rise;
|
||||
this.yOffset = -rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
this.actor.y += rise;
|
||||
this.yOffset = rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
this.actor.x -= rise;
|
||||
this.xOffset = -rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
this.actor.x += rise;
|
||||
this.xOffset = rise;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Tweener.addTween(this.actor, { opacity: 255,
|
||||
x: x,
|
||||
y: y,
|
||||
transition: "linear",
|
||||
onComplete: onComplete,
|
||||
time: POPUP_ANIMATION_TIME });
|
||||
Tweener.addTween(this, { opacity: 255,
|
||||
xOffset: 0,
|
||||
yOffset: 0,
|
||||
transition: "linear",
|
||||
onComplete: onComplete,
|
||||
time: POPUP_ANIMATION_TIME });
|
||||
},
|
||||
|
||||
hide: function(animate, onComplete) {
|
||||
let x = this.actor.x;
|
||||
let y = this.actor.y;
|
||||
let originalX = this.actor.x;
|
||||
let originalY = this.actor.y;
|
||||
let xOffset = 0;
|
||||
let yOffset = 0;
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let rise = themeNode.get_length('-arrow-rise');
|
||||
|
||||
if (animate) {
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
y += rise;
|
||||
yOffset = rise;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
y -= rise;
|
||||
yOffset = -rise;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
x += rise;
|
||||
xOffset = rise;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
x -= rise;
|
||||
xOffset = -rise;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Tweener.addTween(this.actor, { opacity: 0,
|
||||
x: x,
|
||||
y: y,
|
||||
transition: "linear",
|
||||
time: POPUP_ANIMATION_TIME,
|
||||
onComplete: Lang.bind(this, function () {
|
||||
this.actor.hide();
|
||||
this.actor.x = originalX;
|
||||
this.actor.y = originalY;
|
||||
if (onComplete)
|
||||
onComplete();
|
||||
})
|
||||
});
|
||||
Tweener.addTween(this, { opacity: 0,
|
||||
xOffset: xOffset,
|
||||
yOffset: yOffset,
|
||||
transition: "linear",
|
||||
time: POPUP_ANIMATION_TIME,
|
||||
onComplete: Lang.bind(this, function () {
|
||||
this.actor.hide();
|
||||
this.xOffset = 0;
|
||||
this.yOffset = 0;
|
||||
if (onComplete)
|
||||
onComplete();
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
_adjustAllocationForArrow: function(isWidth, alloc) {
|
||||
@@ -176,6 +177,9 @@ BoxPointer.prototype = {
|
||||
break;
|
||||
}
|
||||
this.bin.allocate(childBox, flags);
|
||||
|
||||
if (this._sourceActor && this._sourceActor.mapped)
|
||||
this._reposition(this._sourceActor, this._gap, this._alignment);
|
||||
},
|
||||
|
||||
_drawBorder: function(area) {
|
||||
@@ -306,13 +310,20 @@ BoxPointer.prototype = {
|
||||
// so that we can query the correct size.
|
||||
this.actor.show();
|
||||
|
||||
this._sourceActor = sourceActor;
|
||||
this._gap = gap;
|
||||
this._alignment = alignment;
|
||||
|
||||
this._reposition(sourceActor, gap, alignment);
|
||||
},
|
||||
|
||||
_reposition: function(sourceActor, gap, alignment) {
|
||||
// Position correctly relative to the sourceActor
|
||||
let sourceNode = sourceActor.get_theme_node();
|
||||
let sourceContentBox = sourceNode.get_content_box(sourceActor.get_allocation_box());
|
||||
let [sourceX, sourceY] = sourceActor.get_transformed_position();
|
||||
let [sourceWidth, sourceHeight] = sourceActor.get_transformed_size();
|
||||
let sourceCenterX = sourceX + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2;
|
||||
let sourceCenterY = sourceY + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2;
|
||||
let sourceAllocation = Shell.util_get_transformed_allocation(sourceActor);
|
||||
let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) / 2;
|
||||
let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) / 2;
|
||||
let [minWidth, minHeight, natWidth, natHeight] = this.actor.get_preferred_size();
|
||||
|
||||
// We also want to keep it onscreen, and separated from the
|
||||
@@ -330,16 +341,16 @@ BoxPointer.prototype = {
|
||||
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
resY = sourceY + sourceHeight + gap;
|
||||
resY = sourceAllocation.y2 + gap;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
resY = sourceY - natHeight - gap;
|
||||
resY = sourceAllocation.y1 - natHeight - gap;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
resX = sourceX + sourceWidth + gap;
|
||||
resX = sourceAllocation.x2 + gap;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
resX = sourceX - natWidth - gap;
|
||||
resX = sourceAllocation.x1 - natWidth - gap;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -373,9 +384,9 @@ BoxPointer.prototype = {
|
||||
parent = parent.get_parent();
|
||||
}
|
||||
|
||||
// Actually set the position
|
||||
this.actor.x = Math.floor(x);
|
||||
this.actor.y = Math.floor(y);
|
||||
this._xPosition = Math.floor(x);
|
||||
this._yPosition = Math.floor(y);
|
||||
this._shiftActor();
|
||||
},
|
||||
|
||||
// @origin: Coordinate specifying middle of the arrow, along
|
||||
@@ -386,5 +397,42 @@ BoxPointer.prototype = {
|
||||
this._arrowOrigin = origin;
|
||||
this._border.queue_repaint();
|
||||
}
|
||||
},
|
||||
|
||||
_shiftActor : function() {
|
||||
// Since the position of the BoxPointer depends on the allocated size
|
||||
// of the BoxPointer and the position of the source actor, trying
|
||||
// to position the BoxPoiner via the x/y properties will result in
|
||||
// allocation loops and warnings. Instead we do the positioning via
|
||||
// the anchor point, which is independent of allocation, and leave
|
||||
// x == y == 0.
|
||||
this.actor.set_anchor_point(-(this._xPosition + this._xOffset),
|
||||
-(this._yPosition + this._yOffset));
|
||||
},
|
||||
|
||||
set xOffset(offset) {
|
||||
this._xOffset = offset;
|
||||
this._shiftActor();
|
||||
},
|
||||
|
||||
get xOffset() {
|
||||
return this._xOffset;
|
||||
},
|
||||
|
||||
set yOffset(offset) {
|
||||
this._yOffset = offset;
|
||||
this._shiftActor();
|
||||
},
|
||||
|
||||
get yOffset() {
|
||||
return this._yOffset;
|
||||
},
|
||||
|
||||
set opacity(opacity) {
|
||||
this.actor.opacity = opacity;
|
||||
},
|
||||
|
||||
get opacity() {
|
||||
return this.actor.opacity;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
@@ -7,9 +8,6 @@ const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const C_ = Gettext.pgettext;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
@@ -158,13 +156,14 @@ function _getEventDayAbbreviation(dayNumber) {
|
||||
|
||||
// Abstraction for an appointment/event in a calendar
|
||||
|
||||
function CalendarEvent(date, summary, allDay) {
|
||||
this._init(date, summary, allDay);
|
||||
function CalendarEvent(date, end, summary, allDay) {
|
||||
this._init(date, end, summary, allDay);
|
||||
}
|
||||
|
||||
CalendarEvent.prototype = {
|
||||
_init: function(date, summary, allDay) {
|
||||
_init: function(date, end, summary, allDay) {
|
||||
this.date = date;
|
||||
this.end = end;
|
||||
this.summary = summary;
|
||||
this.allDay = allDay;
|
||||
}
|
||||
@@ -196,139 +195,136 @@ EmptyEventSource.prototype = {
|
||||
};
|
||||
Signals.addSignalMethods(EmptyEventSource.prototype);
|
||||
|
||||
// Second, wrap native Evolution event source
|
||||
function EvolutionEventSource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
EvolutionEventSource.prototype = {
|
||||
_init: function() {
|
||||
this._native = new Shell.EvolutionEventSource();
|
||||
this._native.connect('changed', Lang.bind(this, function() {
|
||||
this.emit('changed');
|
||||
}));
|
||||
},
|
||||
|
||||
requestRange: function(begin, end) {
|
||||
this._native.request_range(begin.getTime(), end.getTime());
|
||||
},
|
||||
|
||||
getEvents: function(begin, end) {
|
||||
let result = [];
|
||||
let nativeEvents = this._native.get_events(begin.getTime(), end.getTime());
|
||||
for (let n = 0; n < nativeEvents.length; n++) {
|
||||
let nativeEvent = nativeEvents[n];
|
||||
result.push(new CalendarEvent(new Date(nativeEvent.msec_begin), nativeEvent.summary, nativeEvent.all_day));
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
hasEvents: function(day) {
|
||||
let dayBegin = _getBeginningOfDay(day);
|
||||
let dayEnd = _getEndOfDay(day);
|
||||
|
||||
let events = this.getEvents(dayBegin, dayEnd);
|
||||
|
||||
if (events.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
const CalendarServerIface = {
|
||||
name: 'org.gnome.Shell.CalendarServer',
|
||||
methods: [{ name: 'GetEvents',
|
||||
inSignature: 'xxb',
|
||||
outSignature: 'a(sssbxxa{sv})' }],
|
||||
signals: [{ name: 'Changed',
|
||||
inSignature: '' }]
|
||||
};
|
||||
Signals.addSignalMethods(EvolutionEventSource.prototype);
|
||||
|
||||
// Finally, an implementation with fake events
|
||||
function FakeEventSource() {
|
||||
const CalendarServer = function () {
|
||||
this._init();
|
||||
};
|
||||
|
||||
CalendarServer.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.gnome.Shell.CalendarServer', '/org/gnome/Shell/CalendarServer');
|
||||
}
|
||||
};
|
||||
|
||||
DBus.proxifyPrototype(CalendarServer.prototype, CalendarServerIface);
|
||||
|
||||
// an implementation that reads data from a session bus service
|
||||
function DBusEventSource(owner) {
|
||||
this._init(owner);
|
||||
}
|
||||
|
||||
FakeEventSource.prototype = {
|
||||
_init: function() {
|
||||
function _datesEqual(a, b) {
|
||||
if (a < b)
|
||||
return false;
|
||||
else if (a > b)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
this._fakeEvents = [];
|
||||
function _dateIntervalsOverlap(a0, a1, b0, b1)
|
||||
{
|
||||
if (a1 <= b0)
|
||||
return false;
|
||||
else if (b1 <= a0)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
// Generate fake events
|
||||
//
|
||||
let midnightToday = _getBeginningOfDay(new Date());
|
||||
let summary = '';
|
||||
|
||||
// '10-oclock pow-wow' is an event occuring IN THE PAST every four days at 10am
|
||||
for (let n = 0; n < 10; n++) {
|
||||
let t = new Date(midnightToday.getTime() - n * 4 * 86400 * 1000);
|
||||
t.setHours(10);
|
||||
summary = '10-oclock pow-wow (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, false));
|
||||
}
|
||||
DBusEventSource.prototype = {
|
||||
_init: function(owner) {
|
||||
this._resetCache();
|
||||
|
||||
// '11-oclock thing' is an event occuring every three days at 11am
|
||||
for (let n = 0; n < 10; n++) {
|
||||
let t = new Date(midnightToday.getTime() + n * 3 * 86400 * 1000);
|
||||
t.setHours(11);
|
||||
summary = '11-oclock thing (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, false));
|
||||
}
|
||||
this._dbusProxy = new CalendarServer(owner);
|
||||
this._dbusProxy.connect('Changed', Lang.bind(this, this._onChanged));
|
||||
|
||||
// 'Weekly Meeting' is an event occuring every seven days at 1:45pm (two days displaced)
|
||||
for (let n = 0; n < 5; n++) {
|
||||
let t = new Date(midnightToday.getTime() + (n * 7 + 2) * 86400 * 1000);
|
||||
t.setHours(13);
|
||||
t.setMinutes(45);
|
||||
summary = 'Weekly Meeting (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, false));
|
||||
}
|
||||
|
||||
// 'Fun All Day' is an all-day event occuring every fortnight (three days displayed)
|
||||
for (let n = 0; n < 10; n++) {
|
||||
let t = new Date(midnightToday.getTime() + (n * 14 + 3) * 86400 * 1000);
|
||||
summary = 'Fun All Day (n=' + n + ')';
|
||||
this._fakeEvents.push(new CalendarEvent(t, summary, true));
|
||||
}
|
||||
|
||||
// 'Get Married' is an event that actually reflects reality (Dec 4, 2010) :-)
|
||||
this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 4, 16, 0), 'Get Married', false));
|
||||
|
||||
// ditto for 'NE Patriots vs NY Jets'
|
||||
this._fakeEvents.push(new CalendarEvent(new Date(2010, 11, 6, 20, 30), 'NE Patriots vs NY Jets', false));
|
||||
|
||||
// An event for tomorrow @6:30pm that is added/removed every five
|
||||
// seconds (to check that the ::changed signal works)
|
||||
let transientEventDate = new Date(midnightToday.getTime() + 86400 * 1000);
|
||||
transientEventDate.setHours(18);
|
||||
transientEventDate.setMinutes(30);
|
||||
transientEventDate.setSeconds(0);
|
||||
Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
|
||||
this._includeTransientEvent = false;
|
||||
this._transientEvent = new CalendarEvent(transientEventDate, 'A Transient Event', false);
|
||||
this._transientEventCounter = 1;
|
||||
DBus.session.watch_name('org.gnome.Shell.CalendarServer',
|
||||
false, // do not launch a name-owner if none exists
|
||||
Lang.bind(this, this._onNameAppeared),
|
||||
Lang.bind(this, this._onNameVanished));
|
||||
},
|
||||
|
||||
_updateTransientEvent: function() {
|
||||
this._includeTransientEvent = !this._includeTransientEvent;
|
||||
this._transientEventCounter = this._transientEventCounter + 1;
|
||||
this._transientEvent.summary = 'A Transient Event (' + this._transientEventCounter + ')';
|
||||
_resetCache: function() {
|
||||
this._events = [];
|
||||
this._lastRequestBegin = null;
|
||||
this._lastRequestEnd = null;
|
||||
},
|
||||
|
||||
_onNameAppeared: function(owner) {
|
||||
this._resetCache();
|
||||
this._loadEvents(true);
|
||||
},
|
||||
|
||||
_onNameVanished: function(oldOwner) {
|
||||
this._resetCache();
|
||||
this.emit('changed');
|
||||
Mainloop.timeout_add(5000, Lang.bind(this, this._updateTransientEvent));
|
||||
},
|
||||
|
||||
requestRange: function(begin, end) {
|
||||
_onChanged: function() {
|
||||
this._loadEvents(false);
|
||||
},
|
||||
|
||||
_onEventsReceived: function(appointments) {
|
||||
let newEvents = [];
|
||||
if (appointments != null) {
|
||||
for (let n = 0; n < appointments.length; n++) {
|
||||
let a = appointments[n];
|
||||
let date = new Date(a[4] * 1000);
|
||||
let end = new Date(a[5] * 1000);
|
||||
let summary = a[1];
|
||||
let allDay = a[3];
|
||||
let event = new CalendarEvent(date, end, summary, allDay);
|
||||
newEvents.push(event);
|
||||
}
|
||||
newEvents.sort(function(event1, event2) {
|
||||
return event1.date.getTime() - event2.date.getTime();
|
||||
});
|
||||
}
|
||||
|
||||
this._events = newEvents;
|
||||
this.emit('changed');
|
||||
},
|
||||
|
||||
_loadEvents: function(forceReload) {
|
||||
if (this._curRequestBegin && this._curRequestEnd){
|
||||
let callFlags = 0;
|
||||
if (forceReload)
|
||||
callFlags |= DBus.CALL_FLAG_START;
|
||||
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
||||
this._curRequestEnd.getTime() / 1000,
|
||||
forceReload,
|
||||
Lang.bind(this, this._onEventsReceived),
|
||||
callFlags);
|
||||
}
|
||||
},
|
||||
|
||||
requestRange: function(begin, end, forceReload) {
|
||||
if (forceReload || !(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
||||
this._lastRequestBegin = begin;
|
||||
this._lastRequestEnd = end;
|
||||
this._curRequestBegin = begin;
|
||||
this._curRequestEnd = end;
|
||||
this._loadEvents(forceReload);
|
||||
}
|
||||
},
|
||||
|
||||
getEvents: function(begin, end) {
|
||||
let result = [];
|
||||
//log('begin:' + begin);
|
||||
//log('end: ' + end);
|
||||
for(let n = 0; n < this._fakeEvents.length; n++) {
|
||||
let event = this._fakeEvents[n];
|
||||
if (event.date >= begin && event.date <= end) {
|
||||
for(let n = 0; n < this._events.length; n++) {
|
||||
let event = this._events[n];
|
||||
if (_dateIntervalsOverlap (event.date, event.end, begin, end)) {
|
||||
result.push(event);
|
||||
}
|
||||
//log('when:' + event.date + ' summary:' + event.summary);
|
||||
}
|
||||
if (this._includeTransientEvent && this._transientEvent.date >= begin && this._transientEvent.date <= end)
|
||||
result.push(this._transientEvent);
|
||||
result.sort(function(event1, event2) {
|
||||
return event1.date.getTime() - event2.date.getTime();
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
@@ -343,9 +339,8 @@ FakeEventSource.prototype = {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
Signals.addSignalMethods(FakeEventSource.prototype);
|
||||
Signals.addSignalMethods(DBusEventSource.prototype);
|
||||
|
||||
// Calendar:
|
||||
// @eventSource: is an object implementing the EventSource API, e.g. the
|
||||
@@ -358,7 +353,10 @@ Calendar.prototype = {
|
||||
_init: function(eventSource) {
|
||||
this._eventSource = eventSource;
|
||||
|
||||
this._eventSource.connect('changed', Lang.bind(this, this._update));
|
||||
this._eventSource.connect('changed', Lang.bind(this,
|
||||
function() {
|
||||
this._update(false);
|
||||
}));
|
||||
|
||||
// FIXME: This is actually the fallback method for GTK+ for the week start;
|
||||
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
|
||||
@@ -407,15 +405,17 @@ Calendar.prototype = {
|
||||
Lang.bind(this, this._onScroll));
|
||||
|
||||
this._buildHeader ();
|
||||
this._update();
|
||||
},
|
||||
|
||||
// Sets the calendar to show a specific date
|
||||
setDate: function(date) {
|
||||
setDate: function(date, forceReload) {
|
||||
if (!_sameDay(date, this._selectedDate)) {
|
||||
this._selectedDate = date;
|
||||
this._update();
|
||||
this._update(forceReload);
|
||||
this.emit('selected-date-changed', new Date(this._selectedDate));
|
||||
} else {
|
||||
if (forceReload)
|
||||
this._update(forceReload);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -510,7 +510,7 @@ Calendar.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
this.setDate(newDate);
|
||||
this.setDate(newDate, false);
|
||||
},
|
||||
|
||||
_onNextMonthButtonClicked: function() {
|
||||
@@ -532,16 +532,16 @@ Calendar.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
this.setDate(newDate);
|
||||
this.setDate(newDate, false);
|
||||
},
|
||||
|
||||
_onSettingsChange: function() {
|
||||
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
|
||||
this._buildHeader();
|
||||
this._update();
|
||||
this._update(false);
|
||||
},
|
||||
|
||||
_update: function() {
|
||||
_update: function(forceReload) {
|
||||
let now = new Date();
|
||||
|
||||
if (_sameYear(this._selectedDate, now))
|
||||
@@ -570,7 +570,7 @@ Calendar.prototype = {
|
||||
let iterStr = iter.toUTCString();
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
let newlySelectedDate = new Date(iterStr);
|
||||
this.setDate(newlySelectedDate);
|
||||
this.setDate(newlySelectedDate, false);
|
||||
}));
|
||||
|
||||
let hasEvents = this._eventSource.hasEvents(iter);
|
||||
@@ -620,7 +620,7 @@ Calendar.prototype = {
|
||||
}
|
||||
// Signal to the event source that we are interested in events
|
||||
// only from this date range
|
||||
this._eventSource.requestRange(beginDate, iter);
|
||||
this._eventSource.requestRange(beginDate, iter, forceReload);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -698,7 +698,7 @@ EventsList.prototype = {
|
||||
if (events.length == 0 && showNothingScheduled) {
|
||||
let now = new Date();
|
||||
/* Translators: Text to show if there are no events */
|
||||
let nothingEvent = new CalendarEvent(now, _("Nothing Scheduled"), true);
|
||||
let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
|
||||
let timeString = _formatEventTime(nothingEvent, clockFormat);
|
||||
this._addEvent(dayNameBox, timeBox, eventTitleBox, false, "", timeString, nothingEvent.summary);
|
||||
}
|
||||
|
||||
212
js/ui/chrome.js
@@ -13,12 +13,6 @@ const Params = imports.misc.params;
|
||||
// normal mode (ie, outside the Overview), that surrounds the main
|
||||
// workspace content.
|
||||
|
||||
const Visibility = {
|
||||
FULL: 1,
|
||||
FULLSCREEN: 2,
|
||||
OVERVIEW: 3
|
||||
};
|
||||
|
||||
const defaultParams = {
|
||||
visibleInOverview: false,
|
||||
visibleInFullscreen: false,
|
||||
@@ -37,12 +31,13 @@ Chrome.prototype = {
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocated));
|
||||
|
||||
this._inFullscreen = false;
|
||||
this._monitors = [];
|
||||
this._inOverview = false;
|
||||
this.visibility = Visibility.FULL;
|
||||
|
||||
this._trackedActors = [];
|
||||
|
||||
global.screen.connect('monitors-changed',
|
||||
Lang.bind(this, this._monitorsChanged));
|
||||
global.screen.connect('restacked',
|
||||
Lang.bind(this, this._windowsRestacked));
|
||||
|
||||
@@ -55,6 +50,8 @@ Chrome.prototype = {
|
||||
Main.overview.connect('hidden',
|
||||
Lang.bind(this, this._overviewHidden));
|
||||
|
||||
this._updateMonitors();
|
||||
this._updateFullscreen();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
@@ -194,24 +191,12 @@ Chrome.prototype = {
|
||||
let actorData = this._trackedActors[i];
|
||||
if (this._inOverview && !actorData.visibleInOverview)
|
||||
this.actor.set_skip_paint(actorData.actor, true);
|
||||
else if (!this._inOverview && this._inFullscreen && !actorData.visibleInFullscreen)
|
||||
else if (!this._inOverview && !actorData.visibleInFullscreen &&
|
||||
this._findMonitorForActor(actorData.actor).inFullscreen)
|
||||
this.actor.set_skip_paint(actorData.actor, true);
|
||||
else
|
||||
this.actor.set_skip_paint(actorData.actor, false);
|
||||
}
|
||||
|
||||
let newVisibility;
|
||||
if (this._inOverview)
|
||||
newVisibility = Visibility.OVERVIEW;
|
||||
else if (this._inFullscreen)
|
||||
newVisibility = Visibility.FULLSCREEN;
|
||||
else
|
||||
newVisibility = Visibility.FULL;
|
||||
|
||||
if (newVisibility != this.visibility) {
|
||||
this.visibility = newVisibility;
|
||||
this.emit('visibility-changed', this.visibility);
|
||||
}
|
||||
},
|
||||
|
||||
_overviewShowing: function() {
|
||||
@@ -226,15 +211,77 @@ Chrome.prototype = {
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_updateMonitors: function() {
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
this._monitors = monitors;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let monitor = monitors[i];
|
||||
if (monitor.x == primary.x &&
|
||||
monitor.y == primary.y &&
|
||||
monitor.width == primary.width &&
|
||||
monitor.height == primary.height)
|
||||
this._primaryMonitor = monitor;
|
||||
}
|
||||
},
|
||||
|
||||
_findMonitorForRect: function(x, y, w, h) {
|
||||
// First look at what monitor the center of the rectangle is at
|
||||
let cx = x + w/2;
|
||||
let cy = y + h/2;
|
||||
for (let i = 0; i < this._monitors.length; i++) {
|
||||
let monitor = this._monitors[i];
|
||||
if (cx >= monitor.x && cx < monitor.x + monitor.width &&
|
||||
cy >= monitor.y && cy < monitor.y + monitor.height)
|
||||
return monitor;
|
||||
}
|
||||
// If the center is not on a monitor, return the first overlapping monitor
|
||||
for (let i = 0; i < this._monitors.length; i++) {
|
||||
let monitor = this._monitors[i];
|
||||
if (x + w > monitor.x && x < monitor.x + monitor.width &&
|
||||
y + h > monitor.y && y < monitor.y + monitor.height)
|
||||
return monitor;
|
||||
}
|
||||
// otherwise on no monitor
|
||||
return null;
|
||||
},
|
||||
|
||||
_findMonitorForWindow: function(window) {
|
||||
return this._findMonitorForRect(window.x, window.y, window.width, window.height);
|
||||
},
|
||||
|
||||
// This call guarantees that we return some monitor to simplify usage of it
|
||||
// In practice all tracked actors should be visible on some monitor anyway
|
||||
_findMonitorForActor: function(actor) {
|
||||
let [x, y] = actor.get_transformed_position();
|
||||
let [w, h] = actor.get_transformed_size();
|
||||
let monitor = this._findMonitorForRect(x, y, w, h);
|
||||
if (monitor)
|
||||
return monitor;
|
||||
return this._primaryMonitor; // Not on any monitor, pretend its on the primary
|
||||
},
|
||||
|
||||
_monitorsChanged: function() {
|
||||
this._updateMonitors();
|
||||
|
||||
// Update everything that depends on monitor positions
|
||||
this._updateFullscreen();
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_queueUpdateRegions: function() {
|
||||
if (!this._updateRegionIdle)
|
||||
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
|
||||
Meta.PRIORITY_BEFORE_REDRAW);
|
||||
},
|
||||
|
||||
_windowsRestacked: function() {
|
||||
_updateFullscreen: function() {
|
||||
let windows = Main.getWindowActorsForWorkspace(global.screen.get_active_workspace_index());
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
// Reset all monitors to not fullscreen
|
||||
for (let i = 0; i < this._monitors.length; i++)
|
||||
this._monitors[i].inFullscreen = false;
|
||||
|
||||
// The chrome layer should be visible unless there is a window
|
||||
// with layer FULLSCREEN, or a window with layer
|
||||
@@ -248,42 +295,51 @@ Chrome.prototype = {
|
||||
|
||||
// @windows is sorted bottom to top.
|
||||
|
||||
let wasInFullscreen = this._inFullscreen;
|
||||
this._inFullscreen = false;
|
||||
for (let i = windows.length - 1; i > -1; i--) {
|
||||
let layer = windows[i].get_meta_window().get_layer();
|
||||
|
||||
// There are 3 cases we check here for:
|
||||
// 1.) Monitor sized window
|
||||
// 2.) Window with a position somewhere on the primary screen having the _NET_WM_FULLSCREEN flag set
|
||||
// 3.) Window that is partly off screen (tries to hide its decorations) which might have negative coords
|
||||
// We check for 1.) and 2.) by checking if the upper right corner is on the primary monitor, but avoid the case
|
||||
// where it overlaps with the secondary screen (like window.x + window.width == primary.x + primary.width)
|
||||
// For 3.) we just ignore negative values as they don't really make sense
|
||||
let window = windows[i];
|
||||
let layer = window.get_meta_window().get_layer();
|
||||
|
||||
if (layer == Meta.StackLayer.FULLSCREEN) {
|
||||
if (Math.max(windows[i].x, 0) >= primary.x && Math.max(windows[i].x, 0) < primary.x + primary.width &&
|
||||
Math.max(windows[i].y, 0) >= primary.y && Math.max(windows[i].y, 0) < primary.y + primary.height) {
|
||||
this._inFullscreen = true;
|
||||
break;
|
||||
}
|
||||
let monitor = this._findMonitorForWindow(window);
|
||||
if (monitor)
|
||||
monitor.inFullscreen = true;
|
||||
}
|
||||
if (layer == Meta.StackLayer.OVERRIDE_REDIRECT) {
|
||||
if (windows[i].x <= primary.x &&
|
||||
windows[i].x + windows[i].width >= primary.x + primary.width &&
|
||||
windows[i].y <= primary.y &&
|
||||
windows[i].y + windows[i].height >= primary.y + primary.height) {
|
||||
this._inFullscreen = true;
|
||||
break;
|
||||
}
|
||||
let monitor = this._findMonitorForWindow(window);
|
||||
if (monitor &&
|
||||
window.x <= monitor.x &&
|
||||
window.x + window.width >= monitor.x + monitor.width &&
|
||||
window.y <= monitor.y &&
|
||||
window.y + window.height >= monitor.y + monitor.height)
|
||||
monitor.inFullscreen = true;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
if (this._inFullscreen != wasInFullscreen) {
|
||||
_windowsRestacked: function() {
|
||||
let wasInFullscreen = [];
|
||||
for (let i = 0; i < this._monitors.length; i++)
|
||||
wasInFullscreen[i] = this._monitors[i].inFullscreen;
|
||||
|
||||
this._updateFullscreen();
|
||||
|
||||
let changed = false;
|
||||
for (let i = 0; i < wasInFullscreen.length; i++) {
|
||||
if (wasInFullscreen[i] != this._monitors[i].inFullscreen) {
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
}
|
||||
|
||||
// Figure out where the pointer is in case we lost track of
|
||||
// it during a grab. (In particular, if a trayicon popup menu
|
||||
// is dismissed, see if we need to close the message tray.)
|
||||
global.sync_pointer();
|
||||
},
|
||||
|
||||
_updateRegions: function() {
|
||||
@@ -312,41 +368,75 @@ Chrome.prototype = {
|
||||
if (!actorData.affectsStruts)
|
||||
continue;
|
||||
|
||||
// Limit struts to the size of the screen
|
||||
let x1 = Math.max(x, 0);
|
||||
let x2 = Math.min(x + w, global.screen_width);
|
||||
let y1 = Math.max(y, 0);
|
||||
let y2 = Math.min(y + h, global.screen_height);
|
||||
|
||||
// NetWM struts are not really powerful enought to handle
|
||||
// a multi-monitor scenario, they only describe what happens
|
||||
// around the outer sides of the full display region. However
|
||||
// it can describe a partial region along each side, so
|
||||
// we can support having the struts only affect the
|
||||
// primary monitor. This should be enough as we only have
|
||||
// chrome affecting the struts on the primary monitor so
|
||||
// far.
|
||||
//
|
||||
// Metacity wants to know what side of the screen the
|
||||
// strut is considered to be attached to. If the actor is
|
||||
// only touching one edge, or is touching the entire
|
||||
// width/height of one edge, then it's obvious which side
|
||||
// to call it. If it's in a corner, we pick a side
|
||||
// border of the primary monitor, then it's obvious which
|
||||
// side to call it. If it's in a corner, we pick a side
|
||||
// arbitrarily. If it doesn't touch any edges, or it spans
|
||||
// the width/height across the middle of the screen, then
|
||||
// we don't create a strut for it at all.
|
||||
let side;
|
||||
if (w >= global.screen_width) {
|
||||
if (y <= 0)
|
||||
let primary = this._primaryMonitor;
|
||||
if (x1 <= primary.x && x2 >= primary.x + primary.width) {
|
||||
if (y1 <= primary.y)
|
||||
side = Meta.Side.TOP;
|
||||
else if (y + h >= global.screen_height)
|
||||
else if (y2 >= primary.y + primary.height)
|
||||
side = Meta.Side.BOTTOM;
|
||||
else
|
||||
continue;
|
||||
} else if (h >= global.screen_height) {
|
||||
if (x <= 0)
|
||||
} else if (y1 <= primary.y && y2 >= primary.y + primary.height) {
|
||||
if (x1 <= 0)
|
||||
side = Meta.Side.LEFT;
|
||||
else if (x + w >= global.screen_width)
|
||||
else if (x2 >= global.screen_width)
|
||||
side = Meta.Side.RIGHT;
|
||||
else
|
||||
continue;
|
||||
} else if (x <= 0)
|
||||
} else if (x1 <= 0)
|
||||
side = Meta.Side.LEFT;
|
||||
else if (y <= 0)
|
||||
else if (y1 <= 0)
|
||||
side = Meta.Side.TOP;
|
||||
else if (x + w >= global.screen_width)
|
||||
else if (x2 >= global.screen_width)
|
||||
side = Meta.Side.RIGHT;
|
||||
else if (y + h >= global.screen_height)
|
||||
else if (y2 >= global.screen_height)
|
||||
side = Meta.Side.BOTTOM;
|
||||
else
|
||||
continue;
|
||||
|
||||
let strut = new Meta.Strut({ rect: rect, side: side });
|
||||
// Ensure that the strut rects goes all the way to the screen edge,
|
||||
// as this really what mutter expects.
|
||||
switch (side) {
|
||||
case Meta.Side.TOP:
|
||||
y1 = 0;
|
||||
break;
|
||||
case Meta.Side.BOTTOM:
|
||||
y2 = global.screen_height;
|
||||
break;
|
||||
case Meta.Side.LEFT:
|
||||
x1 = 0;
|
||||
break;
|
||||
case Meta.Side.RIGHT:
|
||||
x2 = global.screen_width;
|
||||
break;
|
||||
}
|
||||
|
||||
let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1});
|
||||
let strut = new Meta.Strut({ rect: strutRect, side: side });
|
||||
struts.push(strut);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,18 @@ const St = imports.gi.St;
|
||||
|
||||
const AltTab = imports.ui.altTab;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const POPUP_APPICON_SIZE = 96;
|
||||
const POPUP_FADE_TIME = 0.1; // seconds
|
||||
|
||||
const SortGroup = {
|
||||
TOP: 0,
|
||||
MIDDLE: 1,
|
||||
BOTTOM: 2
|
||||
};
|
||||
|
||||
function CtrlAltTabManager() {
|
||||
this._init();
|
||||
}
|
||||
@@ -23,14 +30,18 @@ CtrlAltTabManager.prototype = {
|
||||
_init: function() {
|
||||
this._items = [];
|
||||
this._focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||
Main.wm.setKeybindingHandler('switch_panels', Lang.bind(this,
|
||||
function (shellwm, binding, window, backwards) {
|
||||
this.popup(backwards);
|
||||
}));
|
||||
},
|
||||
|
||||
addGroup: function(root, name, icon) {
|
||||
this._items.push({ root: root, name: name, iconName: icon });
|
||||
addGroup: function(root, name, icon, params) {
|
||||
let item = Params.parse(params, { sortGroup: SortGroup.MIDDLE,
|
||||
proxy: root,
|
||||
focusCallback: null });
|
||||
|
||||
item.root = root;
|
||||
item.name = name;
|
||||
item.iconName = icon;
|
||||
|
||||
this._items.push(item);
|
||||
root.connect('destroy', Lang.bind(this, function() { this.removeGroup(root); }));
|
||||
this._focusManager.add_group(root);
|
||||
},
|
||||
@@ -45,38 +56,73 @@ CtrlAltTabManager.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
focusGroup: function(root) {
|
||||
focusGroup: function(item) {
|
||||
if (global.stage_input_mode == Shell.StageInputMode.NONREACTIVE ||
|
||||
global.stage_input_mode == Shell.StageInputMode.NORMAL)
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FOCUSED);
|
||||
root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
|
||||
if (item.window)
|
||||
Main.activateWindow(item.window);
|
||||
else if (item.focusCallback)
|
||||
item.focusCallback();
|
||||
else
|
||||
item.root.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
},
|
||||
|
||||
// Sort the items into a consistent order; panel first, tray last,
|
||||
// and everything else in between, sorted by X coordinate, so that
|
||||
// they will have the same left-to-right ordering in the
|
||||
// Ctrl-Alt-Tab dialog as they do onscreen.
|
||||
_sortItems: function(a, b) {
|
||||
if (a.sortGroup != b.sortGroup)
|
||||
return a.sortGroup - b.sortGroup;
|
||||
|
||||
let y;
|
||||
if (a.x == undefined) {
|
||||
if (a.window)
|
||||
a.x = a.window.get_compositor_private().x;
|
||||
else
|
||||
[a.x, y] = a.proxy.get_transformed_position();
|
||||
}
|
||||
if (b.x == undefined) {
|
||||
if (b.window)
|
||||
b.x = b.window.get_compositor_private().x;
|
||||
else
|
||||
[b.x, y] = b.proxy.get_transformed_position();
|
||||
}
|
||||
|
||||
return a.x - b.x;
|
||||
},
|
||||
|
||||
popup: function(backwards) {
|
||||
// Start with the set of focus groups that are currently mapped
|
||||
let items = this._items.filter(function (item) { return item.root.mapped; });
|
||||
let items = this._items.filter(function (item) { return item.proxy.mapped; });
|
||||
|
||||
// And add the windows metacity would show in its Ctrl-Alt-Tab list
|
||||
let screen = global.screen;
|
||||
let display = screen.get_display();
|
||||
let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
|
||||
let windowTracker = Shell.WindowTracker.get_default();
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let icon;
|
||||
let app = windowTracker.get_window_app(windows[i]);
|
||||
if (app)
|
||||
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
|
||||
else
|
||||
icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
|
||||
items.push({ window: windows[i],
|
||||
name: windows[i].title,
|
||||
iconActor: icon });
|
||||
if (!Main.overview.visible) {
|
||||
let screen = global.screen;
|
||||
let display = screen.get_display();
|
||||
let windows = display.get_tab_list(Meta.TabList.DOCKS, screen, screen.get_active_workspace ());
|
||||
let windowTracker = Shell.WindowTracker.get_default();
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let icon;
|
||||
let app = windowTracker.get_window_app(windows[i]);
|
||||
if (app)
|
||||
icon = app.create_icon_texture(POPUP_APPICON_SIZE);
|
||||
else
|
||||
icon = textureCache.bind_pixbuf_property(windows[i], 'icon');
|
||||
items.push({ window: windows[i],
|
||||
name: windows[i].title,
|
||||
iconActor: icon,
|
||||
sortGroup: SortGroup.MIDDLE });
|
||||
}
|
||||
}
|
||||
|
||||
if (!items.length)
|
||||
return;
|
||||
|
||||
items.sort(Lang.bind(this, this._sortItems));
|
||||
new CtrlAltTabPopup().show(items, backwards);
|
||||
}
|
||||
};
|
||||
@@ -91,12 +137,12 @@ function CtrlAltTabPopup() {
|
||||
|
||||
CtrlAltTabPopup.prototype = {
|
||||
_init : function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
this.actor = new St.BoxLayout({ name: 'ctrlAltTabPopup',
|
||||
reactive: true,
|
||||
x: primary.x + primary.width / 2,
|
||||
y: primary.y + primary.height / 2,
|
||||
anchor_gravity: Clutter.Gravity.CENTER });
|
||||
this.actor = new Shell.GenericContainer({ name: 'ctrlAltTabPopup',
|
||||
reactive: true });
|
||||
|
||||
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('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
@@ -106,6 +152,37 @@ CtrlAltTabPopup.prototype = {
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
alloc.min_size = primary.width;
|
||||
alloc.natural_size = primary.width;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
alloc.min_size = primary.height;
|
||||
alloc.natural_size = primary.height;
|
||||
},
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
|
||||
let vPadding = this.actor.get_theme_node().get_vertical_padding();
|
||||
let hPadding = this.actor.get_theme_node().get_horizontal_padding();
|
||||
|
||||
let [childMinHeight, childNaturalHeight] = this._switcher.actor.get_preferred_height(primary.width - hPadding);
|
||||
let [childMinWidth, childNaturalWidth] = this._switcher.actor.get_preferred_width(childNaturalHeight);
|
||||
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
|
||||
childBox.x2 = Math.min(primary.width - hPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||
this._switcher.actor.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
show : function(items, startBackwards) {
|
||||
if (!Main.pushModal(this.actor))
|
||||
return false;
|
||||
@@ -180,11 +257,7 @@ CtrlAltTabPopup.prototype = {
|
||||
_finish : function() {
|
||||
this.destroy();
|
||||
|
||||
let item = this._items[this._selection];
|
||||
if (item.root)
|
||||
Main.ctrlAltTabManager.focusGroup(item.root);
|
||||
else
|
||||
Main.activateWindow(item.window);
|
||||
Main.ctrlAltTabManager.focusGroup(this._items[this._selection]);
|
||||
},
|
||||
|
||||
_popModal: function() {
|
||||
@@ -208,6 +281,7 @@ CtrlAltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
_onDestroy : function() {
|
||||
this._popModal();
|
||||
if (this._keyPressEventId)
|
||||
this.actor.disconnect(this._keyPressEventId);
|
||||
if (this._keyReleaseEventId)
|
||||
@@ -249,6 +323,6 @@ CtrlAltTabSwitcher.prototype = {
|
||||
let text = new St.Label({ text: item.name });
|
||||
box.add(text, { x_fill: false });
|
||||
|
||||
this.addItem(box);
|
||||
this.addItem(box, text);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -6,8 +6,6 @@ const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
@@ -262,11 +260,6 @@ Dash.prototype = {
|
||||
clip_to_allocation: true });
|
||||
this._box._delegate = this;
|
||||
|
||||
// This will eventually be automatic, see
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=584662
|
||||
if (St.Widget.get_default_direction () == St.TextDirection.RTL)
|
||||
this._box.add_style_pseudo_class('rtl');
|
||||
|
||||
this.actor = new St.Bin({ y_align: St.Align.START, child: this._box });
|
||||
this.actor.connect('notify::height', Lang.bind(this,
|
||||
function() {
|
||||
@@ -288,20 +281,37 @@ Dash.prototype = {
|
||||
Lang.bind(this, this._onDragBegin));
|
||||
Main.overview.connect('item-drag-end',
|
||||
Lang.bind(this, this._onDragEnd));
|
||||
Main.overview.connect('item-drag-cancelled',
|
||||
Lang.bind(this, this._onDragCancelled));
|
||||
Main.overview.connect('window-drag-begin',
|
||||
Lang.bind(this, this._onDragBegin));
|
||||
Main.overview.connect('window-drag-cancelled',
|
||||
Lang.bind(this, this._onDragCancelled));
|
||||
Main.overview.connect('window-drag-end',
|
||||
Lang.bind(this, this._onDragEnd));
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
this._dragCancelled = false;
|
||||
this._dragMonitor = {
|
||||
dragMotion: Lang.bind(this, this._onDragMotion)
|
||||
};
|
||||
DND.addDragMonitor(this._dragMonitor);
|
||||
},
|
||||
|
||||
_onDragCancelled: function() {
|
||||
this._dragCancelled = true;
|
||||
this._endDrag();
|
||||
},
|
||||
|
||||
_onDragEnd: function() {
|
||||
if (this._dragCancelled)
|
||||
return;
|
||||
|
||||
this._endDrag();
|
||||
},
|
||||
|
||||
_endDrag: function() {
|
||||
this._clearDragPlaceholder();
|
||||
if (this._favRemoveTarget) {
|
||||
this._favRemoveTarget.actor.hide();
|
||||
@@ -377,6 +387,8 @@ Dash.prototype = {
|
||||
Lang.bind(this, function() {
|
||||
display.actor.opacity = 255;
|
||||
}));
|
||||
display.actor.set_tooltip_text(app.get_name());
|
||||
|
||||
let item = new DashItemContainer();
|
||||
item.setChild(display.actor);
|
||||
|
||||
|
||||
@@ -8,8 +8,6 @@ const Cairo = imports.cairo;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Util = imports.misc.util;
|
||||
const Main = imports.ui.main;
|
||||
@@ -52,9 +50,7 @@ DateMenuButton.prototype = {
|
||||
let hbox;
|
||||
let vbox;
|
||||
|
||||
//this._eventSource = new Calendar.EmptyEventSource();
|
||||
//this._eventSource = new Calendar.FakeEventSource();
|
||||
this._eventSource = new Calendar.EvolutionEventSource();
|
||||
this._eventSource = new Calendar.DBusEventSource();
|
||||
|
||||
let menuAlignment = 0.25;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
@@ -92,6 +88,7 @@ DateMenuButton.prototype = {
|
||||
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
item = new PopupMenu.PopupMenuItem(_("Date and Time Settings"));
|
||||
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
||||
item.actor.can_focus = false;
|
||||
vbox.add(item.actor);
|
||||
|
||||
// Add vertical separator
|
||||
@@ -104,20 +101,34 @@ DateMenuButton.prototype = {
|
||||
// Fill up the second column
|
||||
|
||||
vbox = new St.BoxLayout({vertical: true});
|
||||
hbox.add(vbox);
|
||||
hbox.add(vbox, { expand: true });
|
||||
|
||||
// Event list
|
||||
vbox.add(this._eventList.actor);
|
||||
vbox.add(this._eventList.actor, { expand: true });
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Open Calendar"));
|
||||
item.connect('activate', Lang.bind(this, this._onOpenCalendarActivate));
|
||||
item.actor.can_focus = false;
|
||||
vbox.add(item.actor, {y_align: St.Align.END, expand: true, y_fill: false});
|
||||
|
||||
// Whenever the menu is opened, select today
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, function(menu, isOpen) {
|
||||
if (isOpen) {
|
||||
let now = new Date();
|
||||
this._calendar.setDate(now);
|
||||
/* Passing true to setDate() forces events to be reloaded. We
|
||||
* want this behavior, because
|
||||
*
|
||||
* o It will cause activation of the calendar server which is
|
||||
* useful if it has crashed
|
||||
*
|
||||
* o It will cause the calendar server to reload events which
|
||||
* is useful if dynamic updates are not supported or not
|
||||
* properly working
|
||||
*
|
||||
* Since this only happens when the menu is opened, the cost
|
||||
* isn't very big.
|
||||
*/
|
||||
this._calendar.setDate(now, true);
|
||||
// No need to update this._eventList as ::selected-date-changed
|
||||
// signal will fire
|
||||
}
|
||||
@@ -172,21 +183,6 @@ DateMenuButton.prototype = {
|
||||
}
|
||||
|
||||
let displayDate = new Date();
|
||||
let msecRemaining;
|
||||
if (showSeconds) {
|
||||
msecRemaining = 1000 - displayDate.getMilliseconds();
|
||||
if (msecRemaining < 50) {
|
||||
displayDate.setSeconds(displayDate.getSeconds() + 1);
|
||||
msecRemaining += 1000;
|
||||
}
|
||||
} else {
|
||||
msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
|
||||
displayDate.getMilliseconds());
|
||||
if (msecRemaining < 500) {
|
||||
displayDate.setMinutes(displayDate.getMinutes() + 1);
|
||||
msecRemaining += 60000;
|
||||
}
|
||||
}
|
||||
|
||||
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
|
||||
|
||||
@@ -196,19 +192,19 @@ DateMenuButton.prototype = {
|
||||
dateFormat = _("%A %B %e, %Y");
|
||||
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
|
||||
|
||||
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClockAndDate));
|
||||
Mainloop.timeout_add_seconds(1, Lang.bind(this, this._updateClockAndDate));
|
||||
return false;
|
||||
},
|
||||
|
||||
_onPreferencesActivate: function() {
|
||||
this.menu.close();
|
||||
Util.spawnDesktop('gnome-datetime-panel');
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-datetime-panel.desktop');
|
||||
app.activate(-1);
|
||||
},
|
||||
|
||||
_onOpenCalendarActivate: function() {
|
||||
this.menu.close();
|
||||
// TODO: pass '-c calendar' (to force the calendar at startup)
|
||||
// TODO: pass the selected day
|
||||
Util.spawnDesktop('evolution');
|
||||
},
|
||||
Util.spawn(['evolution', '-c', 'calendar']);
|
||||
}
|
||||
};
|
||||
|
||||
55
js/ui/dnd.js
@@ -87,6 +87,10 @@ _Draggable.prototype = {
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, function() {
|
||||
this._actorDestroyed = true;
|
||||
// If the drag actor is destroyed and we were going to fix
|
||||
// up its hover state, fix up the parent hover state instead
|
||||
if (this.actor == this._firstLeaveActor)
|
||||
this._firstLeaveActor = this._dragOrigParent;
|
||||
if (this._dragInProgress)
|
||||
this._cancelDrag(global.get_current_time());
|
||||
this.disconnectAll();
|
||||
@@ -101,6 +105,12 @@ _Draggable.prototype = {
|
||||
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
|
||||
this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
|
||||
|
||||
// During the drag, we eat enter/leave events so that actors don't prelight or show
|
||||
// tooltips. But we remember the actors that we first left/last entered so we can
|
||||
// fix up the hover state after the drag ends.
|
||||
this._firstLeaveActor = null;
|
||||
this._lastEnterActor = null;
|
||||
|
||||
this._eventsGrabbed = false;
|
||||
},
|
||||
|
||||
@@ -144,6 +154,8 @@ _Draggable.prototype = {
|
||||
|
||||
_ungrabActor: function() {
|
||||
Clutter.ungrab_pointer();
|
||||
if (!this._onEventId)
|
||||
return;
|
||||
this.actor.disconnect(this._onEventId);
|
||||
this._onEventId = null;
|
||||
},
|
||||
@@ -198,6 +210,11 @@ _Draggable.prototype = {
|
||||
this._cancelDrag(event.get_time());
|
||||
return true;
|
||||
}
|
||||
} else if (event.type() == Clutter.EventType.LEAVE) {
|
||||
if (this._firstLeaveActor == null)
|
||||
this._firstLeaveActor = event.get_source();
|
||||
} else if (event.type() == Clutter.EventType.ENTER) {
|
||||
this._lastEnterActor = event.get_source();
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -463,7 +480,9 @@ _Draggable.prototype = {
|
||||
let [parentX, parentY] = this._dragOrigParent.get_transformed_position();
|
||||
let [parentWidth, parentHeight] = this._dragOrigParent.get_size();
|
||||
let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size();
|
||||
let parentScale = parentScaledWidth / parentWidth;
|
||||
let parentScale = 1.0;
|
||||
if (parentWidth != 0)
|
||||
parentScale = parentScaledWidth / parentWidth;
|
||||
|
||||
x = parentX + parentScale * this._dragOrigX;
|
||||
y = parentY + parentScale * this._dragOrigY;
|
||||
@@ -479,14 +498,18 @@ _Draggable.prototype = {
|
||||
},
|
||||
|
||||
_cancelDrag: function(eventTime) {
|
||||
this.emit('drag-cancelled', eventTime);
|
||||
this._dragInProgress = false;
|
||||
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
|
||||
|
||||
if (this._actorDestroyed) {
|
||||
global.unset_cursor();
|
||||
if (!this._buttonDown)
|
||||
this._ungrabEvents();
|
||||
this._dragComplete();
|
||||
this.emit('drag-end', eventTime, false);
|
||||
if (!this._dragOrigParent)
|
||||
this._dragActor.destroy();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -542,12 +565,36 @@ _Draggable.prototype = {
|
||||
this._dragComplete();
|
||||
},
|
||||
|
||||
// Actor is an actor we have entered or left during the drag; call
|
||||
// st_widget_sync_hover on all StWidget ancestors
|
||||
_syncHover: function(actor) {
|
||||
while (actor) {
|
||||
let parent = actor.get_parent();
|
||||
if (actor instanceof St.Widget)
|
||||
actor.sync_hover();
|
||||
|
||||
actor = parent;
|
||||
}
|
||||
},
|
||||
|
||||
_dragComplete: function() {
|
||||
Shell.util_set_hidden_from_pick(this._dragActor, false);
|
||||
if (!this._actorDestroyed)
|
||||
Shell.util_set_hidden_from_pick(this._dragActor, false);
|
||||
|
||||
this._ungrabEvents();
|
||||
|
||||
if (this._firstLeaveActor) {
|
||||
this._syncHover(this._firstLeaveActor);
|
||||
this._firstLeaveActor = null;
|
||||
}
|
||||
|
||||
if (this._lastEnterActor) {
|
||||
this._syncHover(this._lastEnterActor);
|
||||
this._lastEnterActor = null;
|
||||
}
|
||||
|
||||
this._dragActor = undefined;
|
||||
currentDraggable = null;
|
||||
this._ungrabEvents();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DocInfo = imports.misc.docInfo;
|
||||
const Params = imports.misc.params;
|
||||
const Search = imports.ui.search;
|
||||
@@ -26,7 +23,10 @@ DocSearchProvider.prototype = {
|
||||
return null;
|
||||
return { 'id': resultId,
|
||||
'name': docInfo.name,
|
||||
'icon': docInfo.createIcon(Search.RESULT_ICON_SIZE)};
|
||||
'createIcon': function(size) {
|
||||
return docInfo.createIcon(size);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
activateResult: function(id, params) {
|
||||
@@ -43,9 +43,5 @@ DocSearchProvider.prototype = {
|
||||
|
||||
getSubsearchResultSet: function(previousResults, terms) {
|
||||
return this._docManager.subsearch(previousResults, terms);
|
||||
},
|
||||
|
||||
expandSearch: function(terms) {
|
||||
log('TODO expand docs search');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -22,9 +22,6 @@ const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdm = imports.gi.Gdm;
|
||||
const GLib = imports.gi.GLib;
|
||||
@@ -54,7 +51,7 @@ const EndSessionDialogIface = {
|
||||
}
|
||||
],
|
||||
signals: [{ name: 'Canceled',
|
||||
outSignature: '',
|
||||
inSignature: '',
|
||||
}],
|
||||
properties: []
|
||||
};
|
||||
@@ -66,16 +63,20 @@ const logoutDialogContent = {
|
||||
uninhibitedDescriptionWithUser: _("%s will be logged out automatically in %d seconds."),
|
||||
uninhibitedDescription: _("You will be logged out automatically in %d seconds."),
|
||||
endDescription: _("Logging out of the system."),
|
||||
confirmButtonText: _("Log Out"),
|
||||
confirmButtons: [{ signal: 'ConfirmedLogout',
|
||||
label: _("Log Out") }],
|
||||
iconStyleClass: 'end-session-dialog-logout-icon'
|
||||
};
|
||||
|
||||
const shutdownDialogContent = {
|
||||
subject: _("Shut Down"),
|
||||
inhibitedDescription: _("Click Shut Down to quit these applications and shut down the system."),
|
||||
uninhibitedDescription: _("The system will shut down automatically in %d seconds."),
|
||||
endDescription: _("Shutting down the system."),
|
||||
confirmButtonText: _("Shut Down"),
|
||||
subject: _("Power Off"),
|
||||
inhibitedDescription: _("Click Power Off to quit these applications and power off the system."),
|
||||
uninhibitedDescription: _("The system will power off automatically in %d seconds."),
|
||||
endDescription: _("Powering off the system."),
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: _("Restart") },
|
||||
{ signal: 'ConfirmedShutdown',
|
||||
label: _("Power Off") }],
|
||||
iconName: 'system-shutdown',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||
};
|
||||
@@ -85,7 +86,8 @@ const restartDialogContent = {
|
||||
inhibitedDescription: _("Click Restart to quit these applications and restart the system."),
|
||||
uninhibitedDescription: _("The system will restart automatically in %d seconds."),
|
||||
endDescription: _("Restarting the system."),
|
||||
confirmButtonText: _("Restart"),
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: _("Restart") }],
|
||||
iconName: 'system-shutdown',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon'
|
||||
};
|
||||
@@ -233,7 +235,7 @@ EndSessionDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
|
||||
_init: function() {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this);
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'end-session-dialog' });
|
||||
|
||||
this._user = Gdm.UserManager.ref_default().get_user(GLib.get_user_name());
|
||||
|
||||
@@ -288,12 +290,26 @@ EndSessionDialog.prototype = {
|
||||
this.contentLayout.add(scrollView,
|
||||
{ x_fill: true,
|
||||
y_fill: true });
|
||||
scrollView.hide();
|
||||
|
||||
this._applicationList = new St.BoxLayout({ vertical: true });
|
||||
scrollView.add_actor(this._applicationList,
|
||||
{ x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
this._applicationList.connect('actor-added',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 1)
|
||||
scrollView.show();
|
||||
}));
|
||||
|
||||
this._applicationList.connect('actor-removed',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 0)
|
||||
scrollView.hide();
|
||||
}));
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
@@ -347,8 +363,10 @@ EndSessionDialog.prototype = {
|
||||
|
||||
if (this._user.is_loaded && !dialogContent.iconName) {
|
||||
let iconFile = this._user.get_icon_file();
|
||||
|
||||
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
|
||||
if (GLib.file_test(iconFile, GLib.FileTest.EXISTS))
|
||||
this._setIconFromFile(iconFile, dialogContent.iconStyleClass);
|
||||
else
|
||||
this._setIconFromName('avatar-default', dialogContent.iconStyleClass);
|
||||
} else if (dialogContent.iconName) {
|
||||
this._setIconFromName(dialogContent.iconName,
|
||||
dialogContent.iconStyleClass);
|
||||
@@ -387,23 +405,28 @@ EndSessionDialog.prototype = {
|
||||
},
|
||||
|
||||
_updateButtons: function() {
|
||||
if (this.state != ModalDialog.State.OPENING &&
|
||||
this.state != ModalDialog.State.OPENED)
|
||||
return;
|
||||
|
||||
let dialogContent = DialogContent[this._type];
|
||||
let confirmButtonText = _("Confirm");
|
||||
let buttons = [{ action: Lang.bind(this, this.cancel),
|
||||
label: _("Cancel"),
|
||||
key: Clutter.Escape }];
|
||||
|
||||
if (dialogContent.confirmButtonText)
|
||||
confirmButtonText = dialogContent.confirmButtonText;
|
||||
for (let i = 0; i < dialogContent.confirmButtons.length; i++) {
|
||||
let signal = dialogContent.confirmButtons[i].signal;
|
||||
let label = dialogContent.confirmButtons[i].label;
|
||||
buttons.push({ action: Lang.bind(this, function() {
|
||||
this._confirm(signal);
|
||||
}),
|
||||
label: label });
|
||||
}
|
||||
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: Lang.bind(this, this.cancel),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: confirmButtonText,
|
||||
action: Lang.bind(this, this._confirm)
|
||||
}]);
|
||||
this.setButtons(buttons);
|
||||
},
|
||||
|
||||
close: function() {
|
||||
ModalDialog.ModalDialog.prototype.close.call(this);
|
||||
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
|
||||
'org.gnome.SessionManager.EndSessionDialog',
|
||||
'Closed', '', []);
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
@@ -414,12 +437,12 @@ EndSessionDialog.prototype = {
|
||||
this.close(global.get_current_time());
|
||||
},
|
||||
|
||||
_confirm: function() {
|
||||
_confirm: function(signal) {
|
||||
this._fadeOutDialog();
|
||||
this._stopTimer();
|
||||
DBus.session.emit_signal('/org/gnome/SessionManager/EndSessionDialog',
|
||||
'org.gnome.SessionManager.EndSessionDialog',
|
||||
'Confirmed', '', []);
|
||||
signal, '', []);
|
||||
},
|
||||
|
||||
_onOpened: function() {
|
||||
@@ -434,7 +457,11 @@ EndSessionDialog.prototype = {
|
||||
time: this._secondsLeft,
|
||||
transition: 'linear',
|
||||
onUpdate: Lang.bind(this, this._updateContent),
|
||||
onComplete: Lang.bind(this, this._confirm),
|
||||
onComplete: Lang.bind(this, function() {
|
||||
let dialogContent = DialogContent[this._type];
|
||||
let button = dialogContent.confirmButtons[dialogContent.confirmButtons.length - 1];
|
||||
this._confirm(button.signal);
|
||||
}),
|
||||
});
|
||||
},
|
||||
|
||||
@@ -487,11 +514,12 @@ EndSessionDialog.prototype = {
|
||||
this._inhibitors.push(inhibitor);
|
||||
}
|
||||
|
||||
this._updateButtons();
|
||||
|
||||
if (!this.open(timestamp))
|
||||
throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError',
|
||||
"Cannot grab pointer and keyboard");
|
||||
|
||||
this._updateButtons();
|
||||
this._updateContent();
|
||||
|
||||
let signalId = this.connect('opened',
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
imports.gi.versions.Clutter = '1.0';
|
||||
imports.gi.versions.Gio = '2.0';
|
||||
imports.gi.versions.Gdk = '3.0';
|
||||
imports.gi.versions.GdkPixbuf = '2.0';
|
||||
imports.gi.versions.Gtk = '3.0';
|
||||
|
||||
const Clutter = imports.gi.Clutter;;
|
||||
const Gettext = imports.gettext;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
|
||||
|
||||
const Tweener = imports.ui.tweener;
|
||||
// We can't import shell JS modules yet, because they may have
|
||||
// variable initializations, etc, that depend on init() already having
|
||||
// been run.
|
||||
|
||||
const Format = imports.misc.format;
|
||||
|
||||
// "monkey patch" in some varargs ClutterContainer methods; we need
|
||||
// to do this per-container class since there is no representation
|
||||
@@ -17,7 +25,7 @@ function _patchContainerClass(containerClass) {
|
||||
// This one is a straightforward mapping of the C method
|
||||
containerClass.prototype.child_set = function(actor, props) {
|
||||
let meta = this.get_child_meta(actor);
|
||||
for (prop in props)
|
||||
for (let prop in props)
|
||||
meta[prop] = props[prop];
|
||||
};
|
||||
|
||||
@@ -61,21 +69,20 @@ function _blockMethod(method, replacement, reason) {
|
||||
}
|
||||
|
||||
function init() {
|
||||
Tweener.init();
|
||||
String.prototype.format = Format.format;
|
||||
// Add some bindings to the global JS namespace; (gjs keeps the web
|
||||
// browser convention of having that namespace be called 'window'.)
|
||||
window.global = Shell.Global.get();
|
||||
|
||||
window._ = Gettext.gettext;
|
||||
window.C_ = Gettext.pgettext;
|
||||
window.ngettext = Gettext.ngettext;
|
||||
|
||||
// Set the default direction for St widgets (this needs to be done before any use of St)
|
||||
if (Gettext_gtk30.gettext('default:LTR') == 'default:RTL') {
|
||||
if (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) {
|
||||
St.Widget.set_default_direction(St.TextDirection.RTL);
|
||||
}
|
||||
|
||||
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
|
||||
if (slowdownEnv) {
|
||||
let factor = parseFloat(slowdownEnv);
|
||||
if (!isNaN(factor) && factor > 0.0)
|
||||
St.set_slow_down_factor(factor);
|
||||
}
|
||||
|
||||
// Miscellaneous monkeypatching
|
||||
_patchContainerClass(St.BoxLayout);
|
||||
_patchContainerClass(St.Table);
|
||||
|
||||
@@ -83,8 +90,14 @@ function init() {
|
||||
return St.describe_actor(this);
|
||||
};
|
||||
|
||||
if (window.global === undefined) // test environment
|
||||
return;
|
||||
let origToString = Object.prototype.toString;
|
||||
Object.prototype.toString = function() {
|
||||
let base = origToString.call(this);
|
||||
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
||||
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
|
||||
else
|
||||
return base;
|
||||
};
|
||||
|
||||
_blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
|
||||
'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
|
||||
@@ -96,4 +109,23 @@ function init() {
|
||||
// Shell.Global.prototype itself is read-only.
|
||||
global.set_property_mutable('imports.gi.Shell.Global.prototype', 'set_property_mutable', true);
|
||||
Shell.Global.prototype.set_property_mutable = undefined;
|
||||
|
||||
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
||||
Date.prototype.toLocaleFormat = function(format) {
|
||||
return Shell.util_format_date(format, this.getTime());
|
||||
};
|
||||
|
||||
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
|
||||
if (slowdownEnv) {
|
||||
let factor = parseFloat(slowdownEnv);
|
||||
if (!isNaN(factor) && factor > 0.0)
|
||||
St.set_slow_down_factor(factor);
|
||||
}
|
||||
|
||||
// OK, now things are initialized enough that we can import shell JS
|
||||
const Format = imports.misc.format;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
Tweener.init();
|
||||
String.prototype.format = Format.format;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
|
||||
@@ -67,7 +68,13 @@ function loadExtension(dir, enabled, type) {
|
||||
return;
|
||||
}
|
||||
|
||||
let [success, metadataContents, len, etag] = metadataFile.load_contents(null);
|
||||
let metadataContents;
|
||||
try {
|
||||
metadataContents = Shell.get_file_contents_utf8_sync(metadataFile.get_path());
|
||||
} catch (e) {
|
||||
global.logError(baseErrorString + 'Failed to load metadata.json: ' + e);
|
||||
return;
|
||||
}
|
||||
let meta;
|
||||
try {
|
||||
meta = JSON.parse(metadataContents);
|
||||
@@ -174,8 +181,15 @@ function init() {
|
||||
}
|
||||
|
||||
function _loadExtensionsIn(dir, type) {
|
||||
let fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||
let fileEnum;
|
||||
let file, info;
|
||||
try {
|
||||
fileEnum = dir.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NONE, null);
|
||||
} catch (e) {
|
||||
global.logError('' + e);
|
||||
return;
|
||||
}
|
||||
|
||||
while ((info = fileEnum.next_file(null)) != null) {
|
||||
let fileType = info.get_file_type();
|
||||
if (fileType != Gio.FileType.DIRECTORY)
|
||||
|
||||
500
js/ui/goaClient.js
Normal file
@@ -0,0 +1,500 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Goa = imports.gi.Goa;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const C_ = Gettext.pgettext;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Pango = imports.gi.Pango;
|
||||
|
||||
const History = imports.misc.history;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
function Client() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Client.prototype = {
|
||||
_init : function() {
|
||||
this._client = null;
|
||||
|
||||
this._accountIdToMailMonitor = {}
|
||||
this._mailSource = null;
|
||||
|
||||
// TODO: need to call refreshAllMonitors() when network-connectivity changes
|
||||
|
||||
Goa.Client.new(null, /* cancellable */
|
||||
Lang.bind(this, this._onClientConstructed));
|
||||
},
|
||||
|
||||
_onClientConstructed : function(object, asyncRes) {
|
||||
this._client = object.new_finish(asyncRes);
|
||||
this._updateAccounts();
|
||||
this._client.connect('account-added', Lang.bind(this, this._updateAccounts));
|
||||
this._client.connect('account-removed', Lang.bind(this, this._updateAccounts));
|
||||
this._client.connect('account-changed', Lang.bind(this, this._updateAccounts));
|
||||
},
|
||||
|
||||
_updateAccounts : function () {
|
||||
|
||||
let objects = this._client.get_accounts();
|
||||
let mailIds = {};
|
||||
|
||||
// Add monitors for accounts that now exist
|
||||
for (let n = 0; n < objects.length; n++) {
|
||||
let object = objects[n];
|
||||
let id = object.account.id;
|
||||
|
||||
if (object.mail) {
|
||||
mailIds[id] = true;
|
||||
if (!(id in this._accountIdToMailMonitor)) {
|
||||
let monitor = new MailMonitor(this, object);
|
||||
this._accountIdToMailMonitor[id] = monitor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Nuke monitors for accounts that are now non-existant
|
||||
let monitorsToRemove = []
|
||||
for (let existingMonitorId in this._accountIdToMailMonitor) {
|
||||
if (!(existingMonitorId in mailIds)) {
|
||||
monitorsToRemove.push(existingMonitorId);
|
||||
}
|
||||
}
|
||||
for (let n = 0; n < monitorsToRemove.length; n++) {
|
||||
let id = monitorsToRemove[n];
|
||||
let monitor = this._accountIdToMailMonitor[id];
|
||||
delete this._accountIdToMailMonitor[id]
|
||||
monitor.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
_ensureMailSource: function() {
|
||||
if (!this._mailSource) {
|
||||
this._mailSource = new MailSource(this);
|
||||
this._mailSource.connect('destroy', Lang.bind(this,
|
||||
function () {
|
||||
this._mailSource = null;
|
||||
}));
|
||||
Main.messageTray.add(this._mailSource);
|
||||
}
|
||||
},
|
||||
|
||||
addPendingMessage: function(message) {
|
||||
this._ensureMailSource();
|
||||
this._mailSource.addMessage(message);
|
||||
},
|
||||
|
||||
refreshAllMonitors: function() {
|
||||
log('Refreshing all mail monitors');
|
||||
for (let id in this._accountIdToMailMonitor) {
|
||||
let monitor = this._accountIdToMailMonitor[id];
|
||||
monitor.refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
function Message(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred) {
|
||||
this._init(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred);
|
||||
}
|
||||
|
||||
Message.prototype = {
|
||||
_init: function(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred) {
|
||||
this.uid = uid;
|
||||
this.from = from;
|
||||
this.subject = subject;
|
||||
this.excerpt = excerpt;
|
||||
this.uri = uri;
|
||||
this.can_be_marked_as_spam = can_be_marked_as_spam;
|
||||
this.can_be_starred = can_be_starred;
|
||||
this.receivedAt = new Date();
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
function MailMonitor(client, accountObject) {
|
||||
this._init(client, accountObject);
|
||||
}
|
||||
|
||||
MailMonitor.prototype = {
|
||||
_init : function(client, accountObject) {
|
||||
this._client = client;
|
||||
this._accountObject = accountObject;
|
||||
this._account = this._accountObject.get_account();
|
||||
this._mail = this._accountObject.get_mail();
|
||||
|
||||
// Create the remote monitor object
|
||||
this._proxy = null;
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
this._mail.call_create_monitor(this._cancellable, Lang.bind(this, this._onMonitorCreated));
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
this._cancellable.cancel();
|
||||
if (this._proxy) {
|
||||
// We don't really care if this fails or not
|
||||
this._proxy.call_close(null, Lang.bind(this, function() { }));
|
||||
this._proxy.disconnect(this._messageReceivedId);
|
||||
this._proxy = null;
|
||||
}
|
||||
},
|
||||
|
||||
refresh : function() {
|
||||
if (this._proxy) {
|
||||
// We don't really care if this fails or not
|
||||
log('Refreshing mail monitor for account ' + this._account.name);
|
||||
this._proxy.call_refresh(null, Lang.bind(this, function() { }));
|
||||
}
|
||||
},
|
||||
|
||||
_onMonitorCreated : function(mail, asyncRes) {
|
||||
// TODO: a (gboolean, object_path) tuple is returned here
|
||||
// See https://bugzilla.gnome.org/show_bug.cgi?id=649657
|
||||
let ret = mail.call_create_monitor_finish(asyncRes);
|
||||
let object_path = ret[1];
|
||||
Goa.MailMonitorProxy.new_for_bus(Gio.BusType.SESSION,
|
||||
Gio.DBusProxyFlags.NONE,
|
||||
'org.gnome.OnlineAccounts',
|
||||
object_path,
|
||||
null, /* cancellable */
|
||||
Lang.bind(this, this._onMonitorProxyConstructed));
|
||||
},
|
||||
|
||||
_onMonitorProxyConstructed : function(monitor, asyncRes) {
|
||||
this._proxy = monitor.new_for_bus_finish(asyncRes);
|
||||
|
||||
// Now listen for changes on the mail monitor proxy
|
||||
this._messageReceivedId = this._proxy.connect('message-received',
|
||||
Lang.bind(this, this._onMessageReceived));
|
||||
},
|
||||
|
||||
_onMessageReceived : function(monitor, uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred) {
|
||||
let message = new Message(uid, from, subject, excerpt, uri, can_be_marked_as_spam, can_be_starred);
|
||||
if (!Main.messageTray.getBusy()) {
|
||||
let source = new Source(this._client, message);
|
||||
let notification = new Notification(source, this._client, this, message);
|
||||
// If the user is not marked as busy, present the notification to the user
|
||||
Main.messageTray.add(source);
|
||||
source.notify(notification);
|
||||
} else {
|
||||
// ... otherwise, if the user is busy, just add it to the MailSource's list
|
||||
// of pending messages
|
||||
this._client.addPendingMessage(message);
|
||||
}
|
||||
},
|
||||
|
||||
MessageAddStar: function (message) {
|
||||
this._proxy.call_add_star(message.uid,
|
||||
null, /* cancellable */
|
||||
Lang.bind(this,
|
||||
function(object, asyncRes) {
|
||||
this._proxy.call_add_star_finish(asyncRes);
|
||||
}));
|
||||
},
|
||||
|
||||
MessageMarkAsSpam: function (message) {
|
||||
this._proxy.call_mark_as_spam(message.uid,
|
||||
null, /* cancellable */
|
||||
Lang.bind(this,
|
||||
function(object, asyncRes) {
|
||||
this._proxy.call_add_star_finish(asyncRes);
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
function Source(client, message) {
|
||||
this._init(client, message);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init : function(client, message) {
|
||||
this._client = client;
|
||||
this._message = message;
|
||||
|
||||
// Init super class and add ourselves to the message tray
|
||||
MessageTray.Source.prototype._init.call(this, 'Message from ' + _stripEmailAddress(this._message.from));
|
||||
this.setTransient(true);
|
||||
this.isChat = true;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
|
||||
createNotificationIcon : function() {
|
||||
// TODO: use account icon
|
||||
let icon = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: this.ICON_SIZE,
|
||||
icon_name: 'mail-send'});
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
function _stripEmailAddress(name_and_addr) {
|
||||
let bracketStartPos = name_and_addr.indexOf(' <');
|
||||
if (bracketStartPos == -1) {
|
||||
return name_and_addr;
|
||||
} else {
|
||||
return name_and_addr.slice(0, bracketStartPos);
|
||||
}
|
||||
}
|
||||
|
||||
function Notification(source, client, monitor, message) {
|
||||
this._init(source, client, monitor, message);
|
||||
}
|
||||
|
||||
Notification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init : function(source, client, monitor, message) {
|
||||
this._client = client;
|
||||
this._monitor = monitor
|
||||
this._message = message;
|
||||
this._ignore = false;
|
||||
this._alreadyExpanded = false;
|
||||
|
||||
this._strippedFrom = _stripEmailAddress(this._message.from);
|
||||
|
||||
let title = this._strippedFrom;
|
||||
let banner = this._message.subject + ' \u2014 ' + this._message.excerpt; // — U+2014 EM DASH
|
||||
|
||||
// Init super class
|
||||
MessageTray.Notification.prototype._init.call(this, source, title, banner);
|
||||
|
||||
// Change the contents once expanded
|
||||
this.connect('expanded', Lang.bind (this, this._onExpanded));
|
||||
|
||||
this.update(title, banner);
|
||||
this.setUrgency(MessageTray.Urgency.NORMAL);
|
||||
this.setTransient(true);
|
||||
|
||||
this.addButton('ignore', 'Ignore');
|
||||
if (message.can_be_starred)
|
||||
this.addButton('star', 'Star');
|
||||
if (message.can_be_marked_as_spam)
|
||||
this.addButton('spam', 'Junk');
|
||||
if (this._message.uri.length > 0) {
|
||||
this.addButton('open', 'Open');
|
||||
}
|
||||
this.connect('action-invoked', Lang.bind(this,
|
||||
function(notification, id) {
|
||||
if (id == 'ignore') {
|
||||
this._actionIgnore();
|
||||
} else if (id == 'star') {
|
||||
this._actionStar();
|
||||
} else if (id == 'spam') {
|
||||
this._actionSpam();
|
||||
} else if (id == 'open') {
|
||||
this._actionOpen();
|
||||
}
|
||||
}));
|
||||
this.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
if (this._message.uri.length > 0) {
|
||||
this._actionOpen();
|
||||
}
|
||||
}));
|
||||
// Hmm, should be ::done-displaying instead?
|
||||
this.connect('destroy', Lang.bind(this, this._onDestroyed));
|
||||
},
|
||||
|
||||
_onExpanded : function() {
|
||||
if (this._alreadyExpanded)
|
||||
return;
|
||||
this._alreadyExpanded = true;
|
||||
let escapedExcerpt = GLib.markup_escape_text(this._message.excerpt, -1);
|
||||
let bannerMarkup = '<b>Subject:</b> ' + this._message.subject + '\n';
|
||||
// TODO: if available, insert other headers such as Cc
|
||||
bannerMarkup += '\n' + escapedExcerpt;
|
||||
this.update(this._strippedFrom, bannerMarkup, {bannerMarkup: true});
|
||||
},
|
||||
|
||||
_onDestroyed : function(reason) {
|
||||
// If not ignoring the message, push it onto the Mail source
|
||||
if (!this._ignore) {
|
||||
this._client.addPendingMessage(this._message);
|
||||
}
|
||||
},
|
||||
|
||||
_actionIgnore : function() {
|
||||
this._ignore = true;
|
||||
},
|
||||
|
||||
_actionStar : function() {
|
||||
this._ignore = true;
|
||||
this._monitor.MessageAddStar(this._message);
|
||||
},
|
||||
|
||||
_actionSpam : function() {
|
||||
this._ignore = true;
|
||||
this._monitor.MessageMarkAsSpam(this._message);
|
||||
},
|
||||
|
||||
_actionOpen : function() {
|
||||
this._ignore = true;
|
||||
Gio.app_info_launch_default_for_uri(this._message.uri,
|
||||
global.create_app_launch_context());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------------------
|
||||
|
||||
function _sameDay(dateA, dateB) {
|
||||
return (dateA.getDate() == dateB.getDate() &&
|
||||
dateA.getMonth() == dateB.getMonth() &&
|
||||
dateA.getYear() == dateB.getYear());
|
||||
}
|
||||
|
||||
function _sameYear(dateA, dateB) {
|
||||
return (dateA.getYear() == dateB.getYear());
|
||||
}
|
||||
|
||||
function _formatRelativeDate(date) {
|
||||
let ret = ''
|
||||
let now = new Date();
|
||||
if (_sameDay(date, now)) {
|
||||
ret = date.toLocaleFormat("%l:%M %p");
|
||||
} else {
|
||||
if (_sameYear(date, now)) {
|
||||
ret = date.toLocaleFormat("%B %e");
|
||||
} else {
|
||||
ret = date.toLocaleFormat("%B %e, %Y");
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
function _addMessageToTable(table, message) {
|
||||
let formattedExcerpt = message.excerpt.replace(/\r/g, '').replace(/\n/g, ' ');
|
||||
let formattedDate = _formatRelativeDate(message.receivedAt);
|
||||
|
||||
let fromLabel = new St.Label({ style_class: 'goa-message-base goa-message-from',
|
||||
text: _stripEmailAddress(message.from)});
|
||||
let hbox = new St.BoxLayout({ style_class: 'goa-message-hbox', vertical: false });
|
||||
let subjectLabel = new St.Label({ style_class: 'goa-message-base goa-message-subject',
|
||||
text: message.subject });
|
||||
let excerptLabel = new St.Label({ style_class: 'goa-message-base goa-message-excerpt',
|
||||
text: formattedExcerpt });
|
||||
let dateLabel = new St.Label({ style_class: 'goa-message-base goa-message-date',
|
||||
text: formattedDate });
|
||||
|
||||
excerptLabel.clutter_text.line_wrap = false;
|
||||
excerptLabel.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
||||
|
||||
hbox.add(subjectLabel, { x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
hbox.add(excerptLabel, { x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let n = table.get_row_count();
|
||||
table.add(fromLabel, { x_fill: true, x_expand: true, row: n, col: 0 });
|
||||
table.add(hbox, { row: n, col: 1 });
|
||||
table.add(dateLabel, { row: n, col: 2 });
|
||||
}
|
||||
|
||||
function MailSource(client) {
|
||||
this._init(client);
|
||||
}
|
||||
|
||||
MailSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init : function(client) {
|
||||
this._client = client;
|
||||
this._pendingMessages = [];
|
||||
|
||||
// Init super class and add ourselves to the message tray
|
||||
MessageTray.Source.prototype._init.call(this, 'Mail');
|
||||
|
||||
// Create the notification
|
||||
this._notification = new MessageTray.Notification(this)
|
||||
this._notification.setUrgency(MessageTray.Urgency.NORMAL);
|
||||
this._notification.setResident(true);
|
||||
this._updateNotification();
|
||||
this.pushNotification(this._notification);
|
||||
// Refresh all monitors everytime the "Mail" notification is displayed
|
||||
this._notification.connect('expanded', Lang.bind(this,
|
||||
function() {
|
||||
this._client.refreshAllMonitors();
|
||||
}));
|
||||
},
|
||||
|
||||
createNotificationIcon : function() {
|
||||
let numPending = this._pendingMessages.length;
|
||||
let baseIcon = new Gio.ThemedIcon({ name: 'mail-mark-unread'});
|
||||
let numerableIcon = new Gtk.NumerableIcon({ gicon: baseIcon });
|
||||
numerableIcon.set_count(numPending);
|
||||
let icon = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: this.ICON_SIZE });
|
||||
icon.set_gicon(numerableIcon);
|
||||
return icon;
|
||||
},
|
||||
|
||||
_updateNotification: function() {
|
||||
if (!this._notification)
|
||||
return
|
||||
|
||||
let title = 'Mail';
|
||||
let banner = ''
|
||||
let table = new St.Table({ homogeneous: false,
|
||||
style_class: 'goa-message-table',
|
||||
reactive: true });
|
||||
|
||||
for (let n = 0; n < this._pendingMessages.length; n++)
|
||||
_addMessageToTable (table, this._pendingMessages[n]);
|
||||
|
||||
this._notification.update(title, banner, { clear: true,
|
||||
icon: this.createNotificationIcon() });
|
||||
this._notification.addActor(table);
|
||||
this._notification.addButton('close', 'Close');
|
||||
this._notification.addButton('ignore-all', 'Ignore All');
|
||||
this._notification.connect('action-invoked', Lang.bind(this,
|
||||
function(notification, id) {
|
||||
if (id == 'close') {
|
||||
// TODO: Can't find another way hide it
|
||||
notification._onClicked();
|
||||
} else if (id == 'ignore-all') {
|
||||
this.clearMessages();
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
addMessage: function(message) {
|
||||
this._pendingMessages.push(message);
|
||||
// Update notification
|
||||
this._updateNotification();
|
||||
// Update icon with latest pending count
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
|
||||
clearMessages: function() {
|
||||
let notification = this._notification;
|
||||
this._notification = null;
|
||||
if (notification)
|
||||
notification.destroy();
|
||||
this.destroy();
|
||||
},
|
||||
}
|
||||
|
||||
@@ -42,18 +42,17 @@ BaseIcon.prototype = {
|
||||
box.add_actor(this._iconBin);
|
||||
|
||||
if (params.showLabel) {
|
||||
this._name = new St.Label({ text: label });
|
||||
box.add_actor(this._name);
|
||||
this.label = new St.Label({ text: label });
|
||||
box.add_actor(this.label);
|
||||
} else {
|
||||
this._name = null;
|
||||
this.label = null;
|
||||
}
|
||||
|
||||
if (params.createIcon)
|
||||
this.createIcon = params.createIcon;
|
||||
this._setSizeManually = params.setSizeManually;
|
||||
|
||||
this.icon = this.createIcon(this.iconSize);
|
||||
this._iconBin.set_child(this.icon);
|
||||
this.icon = null;
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
@@ -68,8 +67,8 @@ BaseIcon.prototype = {
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
if (this._name) {
|
||||
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1);
|
||||
if (this.label) {
|
||||
let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(-1);
|
||||
preferredHeight += this._spacing + labelNatHeight;
|
||||
|
||||
let labelHeight = availHeight >= preferredHeight ? labelNatHeight
|
||||
@@ -80,7 +79,7 @@ BaseIcon.prototype = {
|
||||
childBox.x2 = availWidth;
|
||||
childBox.y1 = iconSize + this._spacing;
|
||||
childBox.y2 = childBox.y1 + labelHeight;
|
||||
this._name.allocate(childBox, flags);
|
||||
this.label.allocate(childBox, flags);
|
||||
}
|
||||
|
||||
childBox.x1 = Math.floor((availWidth - iconNatWidth) / 2);
|
||||
@@ -99,8 +98,8 @@ BaseIcon.prototype = {
|
||||
alloc.min_size = iconMinHeight;
|
||||
alloc.natural_size = iconNatHeight;
|
||||
|
||||
if (this._name) {
|
||||
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth);
|
||||
if (this.label) {
|
||||
let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(forWidth);
|
||||
alloc.min_size += this._spacing + labelMinHeight;
|
||||
alloc.natural_size += this._spacing + labelNatHeight;
|
||||
}
|
||||
@@ -116,16 +115,23 @@ BaseIcon.prototype = {
|
||||
if (!this._setSizeManually)
|
||||
throw new Error('setSizeManually has to be set to use setIconsize');
|
||||
|
||||
this._setIconSize(size);
|
||||
},
|
||||
|
||||
_setIconSize: function(size) {
|
||||
if (size == this.iconSize)
|
||||
return;
|
||||
|
||||
this.icon.destroy();
|
||||
this._createIconTexture(size);
|
||||
},
|
||||
|
||||
_createIconTexture: function(size) {
|
||||
if (this.icon)
|
||||
this.icon.destroy();
|
||||
this.iconSize = size;
|
||||
this.icon = this.createIcon(this.iconSize);
|
||||
|
||||
// The icon returned by createIcon() might actually be smaller than
|
||||
// the requested icon size (for instance StTextureCache does this
|
||||
// for fallback icons), so set the size explicitly.
|
||||
this.icon.set_size(this.iconSize, this.iconSize);
|
||||
|
||||
this._iconBin.child = this.icon;
|
||||
},
|
||||
|
||||
@@ -133,12 +139,15 @@ BaseIcon.prototype = {
|
||||
let node = this.actor.get_theme_node();
|
||||
this._spacing = node.get_length('spacing');
|
||||
|
||||
if (this._setSizeManually)
|
||||
return;
|
||||
let size;
|
||||
if (this._setSizeManually) {
|
||||
size = this.iconSize;
|
||||
} else {
|
||||
let [found, len] = node.lookup_length('icon-size', false);
|
||||
size = found ? len : ICON_SIZE;
|
||||
}
|
||||
|
||||
let len = node.get_length('icon-size');
|
||||
if (len > 0)
|
||||
this._setIconSize(len);
|
||||
this._createIconTexture(size);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -272,8 +281,11 @@ IconGrid.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
childrenInRow: function(rowWidth) {
|
||||
return this._computeLayout(rowWidth)[0];
|
||||
},
|
||||
|
||||
_computeLayout: function (forWidth) {
|
||||
let children = this._grid.get_children();
|
||||
let nColumns = 0;
|
||||
let usedWidth = 0;
|
||||
while ((this._colLimit == null || nColumns < this._colLimit) &&
|
||||
|
||||
@@ -5,14 +5,13 @@ const Cogl = imports.gi.Cogl;
|
||||
const GConf = imports.gi.GConf;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const History = imports.misc.history;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
@@ -27,6 +26,7 @@ var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||
'const Mainloop = imports.mainloop; ' +
|
||||
'const Meta = imports.gi.Meta; ' +
|
||||
'const Shell = imports.gi.Shell; ' +
|
||||
'const Tp = imports.gi.TelepathyGLib; ' +
|
||||
'const Main = imports.ui.main; ' +
|
||||
'const Lang = imports.lang; ' +
|
||||
'const Tweener = imports.ui.tweener; ' +
|
||||
@@ -99,12 +99,19 @@ Notebook.prototype = {
|
||||
selectIndex: function(index) {
|
||||
if (index == this._selectedIndex)
|
||||
return;
|
||||
this._unselect();
|
||||
if (index < 0) {
|
||||
this._unselect();
|
||||
this.emit('selection', null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus the new tab before unmapping the old one
|
||||
let tabData = this._tabs[index];
|
||||
if (!tabData.scrollView.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
|
||||
this.actor.grab_key_focus();
|
||||
|
||||
this._unselect();
|
||||
|
||||
tabData.labelBox.add_style_pseudo_class('selected');
|
||||
tabData.scrollView.show();
|
||||
this._selectedIndex = index;
|
||||
@@ -706,6 +713,7 @@ LookingGlass.prototype = {
|
||||
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
|
||||
this.actor.add_actor(toolbar);
|
||||
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: 24 });
|
||||
toolbar.add_actor(inspectIcon);
|
||||
inspectIcon.reactive = true;
|
||||
@@ -743,12 +751,7 @@ LookingGlass.prototype = {
|
||||
let label = new St.Label({ text: 'js>>> ' });
|
||||
entryArea.add(label);
|
||||
|
||||
this._entry = new St.Entry();
|
||||
/* unmapping the edit box will un-focus it, undo that */
|
||||
notebook.connect('selection', Lang.bind(this, function (nb, child) {
|
||||
if (child == this._evalBox)
|
||||
global.stage.set_key_focus(this._entry);
|
||||
}));
|
||||
this._entry = new St.Entry({ can_focus: true });
|
||||
entryArea.add(this._entry, { expand: true });
|
||||
|
||||
this._windowList = new WindowList();
|
||||
@@ -777,23 +780,8 @@ LookingGlass.prototype = {
|
||||
return true;
|
||||
}));
|
||||
|
||||
this._history = new History.HistoryManager(HISTORY_KEY);
|
||||
this._history.connect('changed', Lang.bind(this, function(history, text) {
|
||||
this._entry.text = text;
|
||||
}));
|
||||
|
||||
this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Up) {
|
||||
this._history.prevItem(o.get_text());
|
||||
return true;
|
||||
} else if (symbol == Clutter.Down) {
|
||||
this._history.nextItem(o.get_text());
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
|
||||
entry: this._entry.clutter_text });
|
||||
},
|
||||
|
||||
_updateFont: function() {
|
||||
@@ -922,6 +910,7 @@ LookingGlass.prototype = {
|
||||
if (!Main.pushModal(this._entry))
|
||||
return;
|
||||
|
||||
this._notebook.selectIndex(0);
|
||||
this.actor.show();
|
||||
this.actor.lower(Main.chrome.actor);
|
||||
this._open = true;
|
||||
|
||||
261
js/ui/main.js
@@ -1,11 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
imports.gi.versions.Clutter = '1.0';
|
||||
imports.gi.versions.Gio = '2.0';
|
||||
imports.gi.versions.Gdk = '3.0';
|
||||
imports.gi.versions.GdkPixbuf = '2.0';
|
||||
imports.gi.versions.Gtk = '3.0';
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
@@ -17,8 +11,6 @@ const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Chrome = imports.ui.chrome;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
@@ -37,6 +29,7 @@ const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
||||
const Scripting = imports.ui.scripting;
|
||||
const ShellDBus = imports.ui.shellDBus;
|
||||
const TelepathyClient = imports.ui.telepathyClient;
|
||||
const GoaClient = imports.ui.goaClient;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
const Magnifier = imports.ui.magnifier;
|
||||
const XdndHandler = imports.ui.xdndHandler;
|
||||
@@ -48,6 +41,7 @@ DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
||||
|
||||
let chrome = null;
|
||||
let panel = null;
|
||||
let hotCorners = [];
|
||||
let placesManager = null;
|
||||
let overview = null;
|
||||
let runDialog = null;
|
||||
@@ -57,6 +51,7 @@ let messageTray = null;
|
||||
let notificationDaemon = null;
|
||||
let windowAttentionHandler = null;
|
||||
let telepathyClient = null;
|
||||
let goaClient = null;
|
||||
let ctrlAltTabManager = null;
|
||||
let recorder = null;
|
||||
let shellDBusService = null;
|
||||
@@ -74,20 +69,17 @@ let _cssStylesheet = null;
|
||||
let background = null;
|
||||
|
||||
function start() {
|
||||
// Add a binding for 'global' in the global JS namespace; (gjs
|
||||
// keeps the web browser convention of having that namespace be
|
||||
// called 'window'.)
|
||||
window.global = Shell.Global.get();
|
||||
|
||||
// Now monkey patch utility functions into the global proxy;
|
||||
// Monkey patch utility functions into the global proxy;
|
||||
// This is easier and faster than indirecting down into global
|
||||
// if we want to call back up into JS.
|
||||
global.logError = _logError;
|
||||
global.log = _logDebug;
|
||||
|
||||
// Chain up async errors reported from C
|
||||
global.connect('notify-error', function (global, msg, detail) { notifyError(msg, detail); });
|
||||
|
||||
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
||||
|
||||
global.grab_dbus_service();
|
||||
shellDBusService = new ShellDBus.GnomeShell();
|
||||
// Force a connection now; dbus.js will do this internally
|
||||
// if we use its name acquisition stuff but we aren't right
|
||||
@@ -95,7 +87,9 @@ function start() {
|
||||
// back into sync ones.
|
||||
DBus.session.flush();
|
||||
|
||||
Environment.init();
|
||||
// Load the calendar server. Note that we are careful about
|
||||
// not loading any events until the user presses the clock
|
||||
global.launch_calendar_server();
|
||||
|
||||
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
||||
// also initialize ShellAppSystem first. ShellAppSystem
|
||||
@@ -129,12 +123,14 @@ function start() {
|
||||
|
||||
// Set up stage hierarchy to group all UI actors under one container.
|
||||
uiGroup = new Clutter.Group();
|
||||
St.set_ui_root(global.stage, uiGroup);
|
||||
global.window_group.reparent(uiGroup);
|
||||
global.overlay_group.reparent(uiGroup);
|
||||
global.stage.add_actor(uiGroup);
|
||||
|
||||
placesManager = new PlaceDisplay.PlacesManager();
|
||||
xdndHandler = new XdndHandler.XdndHandler();
|
||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||
overview = new Overview.Overview();
|
||||
chrome = new Chrome.Chrome();
|
||||
magnifier = new Magnifier.Magnifier();
|
||||
@@ -145,13 +141,11 @@ function start() {
|
||||
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
||||
telepathyClient = new TelepathyClient.Client();
|
||||
goaClient = new GoaClient.Client();
|
||||
|
||||
overview.init();
|
||||
statusIconDispatcher.start(messageTray.actor);
|
||||
|
||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||
ctrlAltTabManager.addGroup(panel.actor, _("Panel"), 'gnome-panel');
|
||||
|
||||
_startDate = new Date();
|
||||
|
||||
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
||||
@@ -187,11 +181,14 @@ function start() {
|
||||
// Attempt to become a PolicyKit authentication agent
|
||||
PolkitAuthenticationAgent.init()
|
||||
|
||||
global.gdk_screen.connect('monitors-changed', _relayout);
|
||||
global.screen.connect('monitors-changed', _relayout);
|
||||
|
||||
ExtensionSystem.init();
|
||||
ExtensionSystem.loadExtensions();
|
||||
|
||||
// Perform initial relayout here
|
||||
_relayout();
|
||||
|
||||
panel.startStatusArea();
|
||||
panel.startupAnimation();
|
||||
|
||||
@@ -200,9 +197,6 @@ function start() {
|
||||
|
||||
global.stage.connect('captured-event', _globalKeyPressHandler);
|
||||
|
||||
// Perform initial relayout here
|
||||
_relayout();
|
||||
|
||||
_log('info', 'loaded at ' + _startDate);
|
||||
log('GNOME Shell started at ' + _startDate);
|
||||
|
||||
@@ -214,18 +208,38 @@ function start() {
|
||||
}
|
||||
|
||||
global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
|
||||
Mainloop.idle_add(_nWorkspacesChanged);
|
||||
|
||||
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
|
||||
global.screen.connect('window-left-monitor', _windowLeftMonitor);
|
||||
|
||||
_nWorkspacesChanged();
|
||||
}
|
||||
|
||||
let _workspaces = [];
|
||||
let _checkWorkspacesId = 0;
|
||||
|
||||
/*
|
||||
* When the last window closed on a workspace is a dialog or splash
|
||||
* screen, we assume that it might be an initial window shown before
|
||||
* the main window of an application, and give the app a grace period
|
||||
* where it can map another window before we remove the workspace.
|
||||
*/
|
||||
const LAST_WINDOW_GRACE_TIME = 1000;
|
||||
|
||||
function _checkWorkspaces() {
|
||||
let i;
|
||||
let emptyWorkspaces = [];
|
||||
|
||||
for (i = 0; i < _workspaces.length; i++)
|
||||
emptyWorkspaces[i] = true;
|
||||
for (i = 0; i < _workspaces.length; i++) {
|
||||
let lastRemoved = _workspaces[i]._lastRemovedWindow;
|
||||
if (lastRemoved &&
|
||||
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
|
||||
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
|
||||
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG))
|
||||
emptyWorkspaces[i] = false;
|
||||
else
|
||||
emptyWorkspaces[i] = true;
|
||||
}
|
||||
|
||||
let windows = global.get_window_actors();
|
||||
for (i = 0; i < windows.length; i++) {
|
||||
@@ -244,16 +258,61 @@ function _checkWorkspaces() {
|
||||
emptyWorkspaces.push(false);
|
||||
}
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
|
||||
activeWorkspaceIndex < emptyWorkspaces.length - 1);
|
||||
// Don't enter the overview when removing multiple empty workspaces at startup
|
||||
let showOverview = (removingCurrentWorkspace &&
|
||||
!emptyWorkspaces.every(function(x) { return x; }));
|
||||
|
||||
if (removingCurrentWorkspace) {
|
||||
// "Merge" the empty workspace we are removing with the one at the end
|
||||
wm.blockAnimations();
|
||||
}
|
||||
|
||||
// Delete other empty workspaces; do it from the end to avoid index changes
|
||||
for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
|
||||
if (emptyWorkspaces[i])
|
||||
global.screen.remove_workspace(_workspaces[i], global.get_current_time());
|
||||
}
|
||||
|
||||
if (removingCurrentWorkspace) {
|
||||
global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
|
||||
wm.unblockAnimations();
|
||||
|
||||
if (!overview.visible && showOverview)
|
||||
overview.show();
|
||||
}
|
||||
|
||||
_checkWorkspacesId = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
function _windowRemoved(workspace, window) {
|
||||
workspace._lastRemovedWindow = window;
|
||||
_queueCheckWorkspaces();
|
||||
Mainloop.timeout_add(LAST_WINDOW_GRACE_TIME, function() {
|
||||
if (workspace._lastRemovedWindow == window) {
|
||||
workspace._lastRemovedWindow = null;
|
||||
_queueCheckWorkspaces();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
|
||||
// If the window left the primary monitor, that
|
||||
// might make that workspace empty
|
||||
if (monitorIndex == global.get_primary_monitor_index())
|
||||
_queueCheckWorkspaces();
|
||||
}
|
||||
|
||||
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
|
||||
// If the window entered the primary monitor, that
|
||||
// might make that workspace non-empty
|
||||
if (monitorIndex == global.get_primary_monitor_index())
|
||||
_queueCheckWorkspaces();
|
||||
}
|
||||
|
||||
function _queueCheckWorkspaces() {
|
||||
if (_checkWorkspacesId == 0)
|
||||
_checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
|
||||
@@ -277,7 +336,7 @@ function _nWorkspacesChanged() {
|
||||
for (w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||
let workspace = _workspaces[w];
|
||||
workspace._windowAddedId = workspace.connect('window-added', _queueCheckWorkspaces);
|
||||
workspace._windowRemovedId = workspace.connect('window-removed', _queueCheckWorkspaces);
|
||||
workspace._windowRemovedId = workspace.connect('window-removed', _windowRemoved);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -346,6 +405,27 @@ function loadTheme() {
|
||||
themeContext.set_theme (theme);
|
||||
}
|
||||
|
||||
/**
|
||||
* notifyError:
|
||||
* @msg: An error message
|
||||
* @details: Additional information
|
||||
*
|
||||
* See shell_global_notify_problem().
|
||||
*/
|
||||
function notifyError(msg, details) {
|
||||
// Also print to stderr so it's logged somewhere
|
||||
if (details)
|
||||
log("error: " + msg + ": " + details);
|
||||
else
|
||||
log("error: " + msg)
|
||||
|
||||
let source = new MessageTray.SystemNotificationSource();
|
||||
messageTray.add(source);
|
||||
let notification = new MessageTray.Notification(source, msg, details);
|
||||
notification.setTransient(true);
|
||||
source.notify(notification);
|
||||
}
|
||||
|
||||
/**
|
||||
* _log:
|
||||
* @category: string message type ('info', 'error')
|
||||
@@ -388,9 +468,73 @@ function _getAndClearErrorStack() {
|
||||
}
|
||||
|
||||
function _relayout() {
|
||||
let monitors = global.get_monitors();
|
||||
// destroy old corners
|
||||
for (let i = 0; i < hotCorners.length; i++)
|
||||
hotCorners[i].destroy();
|
||||
hotCorners = [];
|
||||
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
panel.actor.set_position(primary.x, primary.y);
|
||||
panel.actor.set_size(primary.width, Panel.PANEL_HEIGHT);
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let monitor = monitors[i];
|
||||
let isPrimary = (monitor.x == primary.x &&
|
||||
monitor.y == primary.y &&
|
||||
monitor.width == primary.width &&
|
||||
monitor.height == primary.height);
|
||||
|
||||
let cornerX = monitor.x;
|
||||
let cornerY = monitor.y;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
cornerX += monitor.width;
|
||||
|
||||
|
||||
let haveTopLeftCorner = true;
|
||||
|
||||
/* Check if we have a top left (right for RTL) corner.
|
||||
* I.e. if there is no monitor directly above or to the left(right) */
|
||||
let besideX;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
besideX = monitor.x + 1;
|
||||
else
|
||||
besideX = cornerX - 1;
|
||||
let besideY = cornerY;
|
||||
let aboveX = cornerX;
|
||||
let aboveY = cornerY - 1;
|
||||
|
||||
for (let j = 0; j < monitors.length; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
let otherMonitor = monitors[j];
|
||||
if (besideX >= otherMonitor.x &&
|
||||
besideX < otherMonitor.x + otherMonitor.width &&
|
||||
besideY >= otherMonitor.y &&
|
||||
besideY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
if (aboveX >= otherMonitor.x &&
|
||||
aboveX < otherMonitor.x + otherMonitor.width &&
|
||||
aboveY >= otherMonitor.y &&
|
||||
aboveY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We only want hot corners where there is a natural top-left
|
||||
* corner, and on the primary monitor */
|
||||
if (!isPrimary && !haveTopLeftCorner)
|
||||
continue;
|
||||
|
||||
let corner = new Panel.HotCorner(isPrimary ? panel.button : null);
|
||||
hotCorners.push(corner);
|
||||
corner.actor.set_position(cornerX, cornerY);
|
||||
if (isPrimary)
|
||||
panel.setHotCorner(corner);
|
||||
}
|
||||
|
||||
panel.relayout();
|
||||
overview.relayout();
|
||||
|
||||
// To avoid updating the position and size of the workspaces
|
||||
@@ -483,10 +627,8 @@ function _globalKeyPressHandler(actor, event) {
|
||||
|
||||
function _findModal(actor) {
|
||||
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
||||
let [stackActor, stackFocus] = modalActorFocusStack[i];
|
||||
if (stackActor == actor) {
|
||||
if (modalActorFocusStack[i].actor == actor)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -512,7 +654,6 @@ function _findModal(actor) {
|
||||
* Returns: true iff we successfully acquired a grab or already had one
|
||||
*/
|
||||
function pushModal(actor, timestamp) {
|
||||
|
||||
if (timestamp == undefined)
|
||||
timestamp = global.get_current_time();
|
||||
|
||||
@@ -526,20 +667,24 @@ function pushModal(actor, timestamp) {
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
|
||||
modalCount += 1;
|
||||
actor.connect('destroy', function() {
|
||||
let actorDestroyId = actor.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack.splice(index, 1);
|
||||
});
|
||||
let curFocus = global.stage.get_key_focus();
|
||||
let curFocusDestroyId;
|
||||
if (curFocus != null) {
|
||||
curFocus.connect('destroy', function() {
|
||||
curFocusDestroyId = curFocus.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack[index][1] = null;
|
||||
modalActorFocusStack[index].actor = null;
|
||||
});
|
||||
}
|
||||
modalActorFocusStack.push([actor, curFocus]);
|
||||
modalActorFocusStack.push({ actor: actor,
|
||||
focus: curFocus,
|
||||
destroyId: actorDestroyId,
|
||||
focusDestroyId: curFocusDestroyId });
|
||||
|
||||
global.stage.set_key_focus(actor);
|
||||
return true;
|
||||
@@ -559,28 +704,42 @@ function pushModal(actor, timestamp) {
|
||||
* global.get_current_time() is assumed.
|
||||
*/
|
||||
function popModal(actor, timestamp) {
|
||||
|
||||
if (timestamp == undefined)
|
||||
timestamp = global.get_current_time();
|
||||
|
||||
modalCount -= 1;
|
||||
let focusIndex = _findModal(actor);
|
||||
if (focusIndex >= 0) {
|
||||
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||
let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
|
||||
global.stage.set_key_focus(stackFocus);
|
||||
} else {
|
||||
// Remove from the middle, shift the focus chain up
|
||||
for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
|
||||
modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
|
||||
}
|
||||
}
|
||||
modalActorFocusStack.splice(focusIndex, 1);
|
||||
if (focusIndex < 0) {
|
||||
global.stage.set_key_focus(null);
|
||||
global.end_modal(timestamp);
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
|
||||
throw new Error('incorrect pop');
|
||||
}
|
||||
|
||||
modalCount -= 1;
|
||||
|
||||
let record = modalActorFocusStack[focusIndex];
|
||||
record.actor.disconnect(record.destroyId);
|
||||
|
||||
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||
if (record.focus)
|
||||
record.focus.disconnect(record.focusDestroyId);
|
||||
global.stage.set_key_focus(record.focus);
|
||||
} else {
|
||||
let t = modalActorFocusStack[modalActorFocusStack.length - 1];
|
||||
if (t.focus)
|
||||
t.focus.disconnect(t.focusDestroyId);
|
||||
// Remove from the middle, shift the focus chain up
|
||||
for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
|
||||
modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
|
||||
modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
|
||||
}
|
||||
}
|
||||
modalActorFocusStack.splice(focusIndex, 1);
|
||||
|
||||
if (modalCount > 0)
|
||||
return;
|
||||
|
||||
global.stage.set_key_focus(null);
|
||||
global.end_modal(timestamp);
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,6 @@ const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Params = imports.misc.params;
|
||||
|
||||
@@ -39,13 +37,16 @@ ModalDialog.prototype = {
|
||||
params = Params.parse(params, { styleClass: null });
|
||||
|
||||
this.state = State.CLOSED;
|
||||
this._hasModal = false;
|
||||
|
||||
this._group = new St.Group({ visible: false,
|
||||
x: 0,
|
||||
y: 0 });
|
||||
Main.uiGroup.add_actor(this._group);
|
||||
global.focus_manager.add_group(this._group);
|
||||
this._initialKeyFocus = this._group;
|
||||
|
||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||
coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
|
||||
this._group.add_constraint(constraint);
|
||||
|
||||
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
||||
|
||||
@@ -60,12 +61,18 @@ ModalDialog.prototype = {
|
||||
this._group.add_actor(this._backgroundBin);
|
||||
this._lightbox.highlight(this._backgroundBin);
|
||||
|
||||
this._backgroundStack = new Shell.Stack();
|
||||
this._backgroundBin.child = this._backgroundStack;
|
||||
|
||||
this._eventBlocker = new Clutter.Group({ reactive: true });
|
||||
this._backgroundStack.add_actor(this._eventBlocker);
|
||||
|
||||
this._dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog',
|
||||
vertical: true });
|
||||
if (params.styleClass != null) {
|
||||
this._dialogLayout.add_style_class_name(params.styleClass);
|
||||
}
|
||||
this._backgroundBin.child = this._dialogLayout;
|
||||
this._backgroundStack.add_actor(this._dialogLayout);
|
||||
|
||||
this.contentLayout = new St.BoxLayout({ vertical: true });
|
||||
this._dialogLayout.add(this.contentLayout,
|
||||
@@ -74,12 +81,17 @@ ModalDialog.prototype = {
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._buttonLayout = new St.BoxLayout({ opacity: 220,
|
||||
vertical: false });
|
||||
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
||||
opacity: 220,
|
||||
vertical: false });
|
||||
this._dialogLayout.add(this._buttonLayout,
|
||||
{ expand: true,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.END });
|
||||
|
||||
global.focus_manager.add_group(this._dialogLayout);
|
||||
this._initialKeyFocus = this._dialogLayout;
|
||||
this._savedKeyFocus = null;
|
||||
},
|
||||
|
||||
setButtons: function(buttons) {
|
||||
@@ -154,22 +166,23 @@ ModalDialog.prototype = {
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
this._initialKeyFocus.grab_key_focus();
|
||||
this.state = State.OPENED;
|
||||
this.emit('opened');
|
||||
}),
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
setInitialKeyFocus: function(actor) {
|
||||
this._initialKeyFocus = actor;
|
||||
},
|
||||
|
||||
open: function(timestamp) {
|
||||
if (this.state == State.OPENED || this.state == State.OPENING)
|
||||
return true;
|
||||
|
||||
if (!Main.pushModal(this._group, timestamp))
|
||||
if (!this.pushModal(timestamp))
|
||||
return false;
|
||||
|
||||
global.stage.set_key_focus(this._group);
|
||||
|
||||
this._fadeOpen();
|
||||
return true;
|
||||
},
|
||||
@@ -178,14 +191,9 @@ ModalDialog.prototype = {
|
||||
if (this.state == State.CLOSED || this.state == State.CLOSING)
|
||||
return;
|
||||
|
||||
let needsPopModal;
|
||||
|
||||
if (this.state == State.OPENED || this.state == State.OPENING)
|
||||
needsPopModal = true;
|
||||
else
|
||||
needsPopModal = false;
|
||||
|
||||
this.state = State.CLOSING;
|
||||
this.popModal(timestamp);
|
||||
this._savedKeyFocus = null;
|
||||
|
||||
Tweener.addTween(this._group,
|
||||
{ opacity: 0,
|
||||
@@ -195,13 +203,46 @@ ModalDialog.prototype = {
|
||||
function() {
|
||||
this.state = State.CLOSED;
|
||||
this._group.hide();
|
||||
|
||||
if (needsPopModal)
|
||||
Main.popModal(this._group, timestamp);
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
// Drop modal status without closing the dialog; this makes the
|
||||
// dialog insensitive as well, so it needs to be followed shortly
|
||||
// by either a close() or a pushModal()
|
||||
popModal: function(timestamp) {
|
||||
if (!this._hasModal)
|
||||
return;
|
||||
|
||||
let focus = global.stage.key_focus;
|
||||
if (focus && this._group.contains(focus))
|
||||
this._savedKeyFocus = focus;
|
||||
else
|
||||
this._savedKeyFocus = null;
|
||||
Main.popModal(this._group, timestamp);
|
||||
global.gdk_screen.get_display().sync();
|
||||
this._hasModal = false;
|
||||
|
||||
this._eventBlocker.raise_top();
|
||||
},
|
||||
|
||||
pushModal: function (timestamp) {
|
||||
if (this._hasModal)
|
||||
return true;
|
||||
if (!Main.pushModal(this._group, timestamp))
|
||||
return false;
|
||||
|
||||
this._hasModal = true;
|
||||
if (this._savedKeyFocus) {
|
||||
this._savedKeyFocus.grab_key_focus();
|
||||
this._savedKeyFocus = null;
|
||||
} else
|
||||
this._initialKeyFocus.grab_key_focus();
|
||||
|
||||
this._eventBlocker.lower_bottom();
|
||||
return true;
|
||||
},
|
||||
|
||||
// This method is like close, but fades the dialog out much slower,
|
||||
// and leaves the lightbox in place. Once in the faded out state,
|
||||
// the dialog can be brought back by an open call, or the lightbox
|
||||
@@ -220,6 +261,7 @@ ModalDialog.prototype = {
|
||||
if (this.state == State.FADED_OUT)
|
||||
return;
|
||||
|
||||
this.popModal(timestamp);
|
||||
Tweener.addTween(this._dialogLayout,
|
||||
{ opacity: 0,
|
||||
time: FADE_OUT_DIALOG_TIME,
|
||||
@@ -227,7 +269,6 @@ ModalDialog.prototype = {
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
this.state = State.FADED_OUT;
|
||||
Main.popModal(this._group, timestamp);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Mainloop = imports.mainloop;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const Main = imports.ui.main;
|
||||
@@ -93,16 +92,6 @@ NotificationDaemon.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.exportObject('/org/freedesktop/Notifications', this);
|
||||
|
||||
this._everAcquiredName = false;
|
||||
DBus.session.acquire_name('org.freedesktop.Notifications',
|
||||
// We pass MANY_INSTANCES so that if
|
||||
// notification-daemon is running, we'll
|
||||
// get queued behind it and then get the
|
||||
// name after killing it below
|
||||
DBus.MANY_INSTANCES,
|
||||
Lang.bind(this, this._acquiredName),
|
||||
Lang.bind(this, this._lostName));
|
||||
|
||||
this._sources = {};
|
||||
this._senderToPid = {};
|
||||
this._notifications = {};
|
||||
@@ -117,22 +106,6 @@ NotificationDaemon.prototype = {
|
||||
Lang.bind(this, this._onFocusAppChanged));
|
||||
},
|
||||
|
||||
_acquiredName: function() {
|
||||
this._everAcquiredName = true;
|
||||
},
|
||||
|
||||
_lostName: function() {
|
||||
if (this._everAcquiredName)
|
||||
log('Lost name org.freedesktop.Notifications!');
|
||||
else if (GLib.getenv('GNOME_SHELL_NO_REPLACE'))
|
||||
log('Failed to acquire org.freedesktop.Notifications');
|
||||
else {
|
||||
log('Failed to acquire org.freedesktop.Notifications; trying again');
|
||||
Util.killall('notification-daemon');
|
||||
Util.killall('notify-osd');
|
||||
}
|
||||
},
|
||||
|
||||
_iconForNotificationData: function(icon, hints, size) {
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
|
||||
@@ -214,9 +187,11 @@ NotificationDaemon.prototype = {
|
||||
actions, hints, timeout) {
|
||||
let id;
|
||||
|
||||
// Filter out notifications from Empathy, since we
|
||||
// Filter out chat and presence notifications from Empathy, since we
|
||||
// handle that information from telepathyClient.js
|
||||
if (appName == 'Empathy') {
|
||||
if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
|
||||
hints['category'] == 'presence.online' ||
|
||||
hints['category'] == 'presence.offline')) {
|
||||
// Ignore replacesId since we already sent back a
|
||||
// NotificationClosed for that id.
|
||||
id = nextNotificationId++;
|
||||
@@ -371,7 +346,7 @@ NotificationDaemon.prototype = {
|
||||
notification.setTransient(hints['transient'] == true);
|
||||
|
||||
let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
|
||||
source.notify(notification, sourceIconActor);
|
||||
source.processNotification(notification, sourceIconActor);
|
||||
},
|
||||
|
||||
CloseNotification: function(id) {
|
||||
@@ -415,8 +390,7 @@ NotificationDaemon.prototype = {
|
||||
for (let id in this._sources) {
|
||||
let source = this._sources[id];
|
||||
if (source.app == tracker.focus_app) {
|
||||
if (source.notification && !source.notification.resident)
|
||||
source.notification.destroy();
|
||||
source.destroyNonResidentNotifications();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -461,20 +435,57 @@ Source.prototype = {
|
||||
MessageTray.Source.prototype._init.call(this, title);
|
||||
|
||||
this._pid = pid;
|
||||
this._appStateChangedId = 0;
|
||||
this._setApp();
|
||||
if (this.app)
|
||||
this.title = this.app.get_name();
|
||||
else
|
||||
this.useNotificationIcon = true;
|
||||
this._isTrayIcon = false;
|
||||
this._trayIcon = null;
|
||||
},
|
||||
|
||||
notify: function(notification, icon) {
|
||||
processNotification: function(notification, icon) {
|
||||
if (!this.app)
|
||||
this._setApp();
|
||||
if (!this.app && icon)
|
||||
this._setSummaryIcon(icon);
|
||||
MessageTray.Source.prototype.notify.call(this, notification);
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
if (notification.resident && this.app && tracker.focus_app == this.app)
|
||||
this.pushNotification(notification);
|
||||
else
|
||||
this.notify(notification);
|
||||
},
|
||||
|
||||
handleSummaryClick: function() {
|
||||
if (!this._trayIcon)
|
||||
return false;
|
||||
|
||||
let event = Clutter.get_current_event();
|
||||
if (event.type() != Clutter.EventType.BUTTON_RELEASE)
|
||||
return false;
|
||||
|
||||
// Left clicks are passed through only where there aren't unacknowledged
|
||||
// notifications, so it possible to open them in summary mode; right
|
||||
// clicks are always forwarded, as the right click menu is not useful for
|
||||
// tray icons
|
||||
if (event.get_button() == 1 &&
|
||||
this.notifications.length > 0)
|
||||
return false;
|
||||
|
||||
if (Main.overview.visible) {
|
||||
// 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);
|
||||
this._trayIcon.click(event);
|
||||
}));
|
||||
Main.overview.hide();
|
||||
} else {
|
||||
this._trayIcon.click(event);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
_setApp: function() {
|
||||
@@ -485,9 +496,13 @@ Source.prototype = {
|
||||
if (!this.app)
|
||||
return;
|
||||
|
||||
// We only update the app if this.app is null, so we can't disconnect the old this._appStateChangedId
|
||||
// even if it were non-zero for some reason.
|
||||
this._appStateChangedId = this.app.connect('notify::state', Lang.bind(this, this._appStateChanged));
|
||||
|
||||
// Only override the icon if we were previously using
|
||||
// notification-based icons (ie, not a trayicon) or if it was unset before
|
||||
if (!this._isTrayIcon) {
|
||||
if (!this._trayIcon) {
|
||||
this.useNotificationIcon = false;
|
||||
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
|
||||
}
|
||||
@@ -496,15 +511,29 @@ Source.prototype = {
|
||||
setTrayIcon: function(icon) {
|
||||
this._setSummaryIcon(icon);
|
||||
this.useNotificationIcon = false;
|
||||
this._isTrayIcon = true;
|
||||
this._trayIcon = icon;
|
||||
},
|
||||
|
||||
_notificationClicked: function(notification) {
|
||||
open: function(notification) {
|
||||
this.destroyNonResidentNotifications();
|
||||
this.openApp();
|
||||
},
|
||||
|
||||
_notificationRemoved: function() {
|
||||
if (!this._isTrayIcon)
|
||||
_lastNotificationRemoved: function() {
|
||||
if (!this._trayIcon)
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
_appStateChanged: function() {
|
||||
// Destroy notification sources when their apps exit.
|
||||
// The app exiting would normally result in a tray icon being removed,
|
||||
// so the associated source would be destroyed through the code path
|
||||
// that handles the tray icon being removed. We should not destroy
|
||||
// the source associated with a tray icon when the application state
|
||||
// is Shell.AppState.STOPPED because running applications that have
|
||||
// no open windows would also have that state. This is often the case
|
||||
// for applications that use tray icons.
|
||||
if (!this._trayIcon && this.app.get_state() == Shell.AppState.STOPPED)
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
@@ -517,5 +546,13 @@ Source.prototype = {
|
||||
let mostRecentWindow = windows[0];
|
||||
Main.activateWindow(mostRecentWindow);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this.app && this._appStateChangedId) {
|
||||
this.app.disconnect(this._appStateChangedId);
|
||||
this._appStateChangedId = 0;
|
||||
}
|
||||
MessageTray.Source.prototype.destroy.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,8 +8,6 @@ const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
@@ -24,6 +22,7 @@ const PlaceDisplay = imports.ui.placeDisplay;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const ViewSelector = imports.ui.viewSelector;
|
||||
const WorkspacesView = imports.ui.workspacesView;
|
||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
||||
|
||||
// Time for initial animation going into Overview mode
|
||||
const ANIMATION_TIME = 0.25;
|
||||
@@ -74,11 +73,13 @@ ShellInfo.prototype = {
|
||||
Main.messageTray.add(this._source);
|
||||
}
|
||||
|
||||
let notification = this._source.notification;
|
||||
if (notification == null)
|
||||
let notification = null;
|
||||
if (this._source.notifications.length == 0) {
|
||||
notification = new MessageTray.Notification(this._source, text, null);
|
||||
else
|
||||
} else {
|
||||
notification = this._source.notifications[0];
|
||||
notification.update(text, null, { clear: true });
|
||||
}
|
||||
|
||||
notification.setTransient(true);
|
||||
|
||||
@@ -180,10 +181,10 @@ Overview.prototype = {
|
||||
this._group.add_actor(this.viewSelector.actor);
|
||||
|
||||
this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
|
||||
this.viewSelector.addViewTab(_("Windows"), this._workspacesDisplay.actor);
|
||||
this.viewSelector.addViewTab('windows', _("Windows"), this._workspacesDisplay.actor, 'text-x-generic');
|
||||
|
||||
let appView = new AppDisplay.AllAppDisplay();
|
||||
this.viewSelector.addViewTab(_("Applications"), appView.actor);
|
||||
this.viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
|
||||
|
||||
// Default search providers
|
||||
this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||
@@ -197,6 +198,10 @@ Overview.prototype = {
|
||||
this.dash.actor.add_constraint(this.viewSelector.constrainY);
|
||||
this.dash.actor.add_constraint(this.viewSelector.constrainHeight);
|
||||
|
||||
// Translators: this is the name of the dock/favorites area on
|
||||
// the left of the overview
|
||||
Main.ctrlAltTabManager.addGroup(this.dash.actor, _("Dash"), 'user-bookmarks');
|
||||
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
@@ -213,8 +218,18 @@ Overview.prototype = {
|
||||
global.screen.get_workspace_by_index(this._lastActiveWorkspaceIndex).activate(time);
|
||||
this.hideTemporarily();
|
||||
}
|
||||
this._resetWindowSwitchTimeout();
|
||||
this._lastHoveredWindow = null;
|
||||
DND.removeMonitor(this._dragMonitor);
|
||||
this.endItemDrag();
|
||||
},
|
||||
|
||||
_resetWindowSwitchTimeout: function() {
|
||||
if (this._windowSwitchTimeoutId != 0) {
|
||||
Mainloop.source_remove(this._windowSwitchTimeoutId);
|
||||
this._windowSwitchTimeoutId = 0;
|
||||
this._needsFakePointerEvent = false;
|
||||
}
|
||||
},
|
||||
|
||||
_fakePointerEvent: function() {
|
||||
@@ -229,7 +244,10 @@ Overview.prototype = {
|
||||
_onDragMotion: function(dragEvent) {
|
||||
let targetIsWindow = dragEvent.targetActor &&
|
||||
dragEvent.targetActor._delegate &&
|
||||
dragEvent.targetActor._delegate.metaWindow;
|
||||
dragEvent.targetActor._delegate.metaWindow &&
|
||||
!(dragEvent.targetActor._delegate instanceof WorkspaceThumbnail.WindowClone);
|
||||
|
||||
this._windowSwitchTimestamp = global.get_current_time();
|
||||
|
||||
if (targetIsWindow &&
|
||||
dragEvent.targetActor._delegate.metaWindow == this._lastHoveredWindow)
|
||||
@@ -237,15 +255,10 @@ Overview.prototype = {
|
||||
|
||||
this._lastHoveredWindow = null;
|
||||
|
||||
if (this._windowSwitchTimeoutId != 0) {
|
||||
Mainloop.source_remove(this._windowSwitchTimeoutId);
|
||||
this._windowSwitchTimeoutId = 0;
|
||||
this._needsFakePointerEvent = false;
|
||||
}
|
||||
this._resetWindowSwitchTimeout();
|
||||
|
||||
if (targetIsWindow) {
|
||||
this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
|
||||
this._windowSwitchTimestamp = global.get_current_time();
|
||||
this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
|
||||
Lang.bind(this, function() {
|
||||
this._needsFakePointerEvent = true;
|
||||
@@ -428,7 +441,7 @@ Overview.prototype = {
|
||||
let primary = global.get_primary_monitor();
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
|
||||
let contentY = Panel.PANEL_HEIGHT;
|
||||
let contentY = Main.panel.actor.height;
|
||||
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
|
||||
|
||||
this._group.set_position(primary.x, primary.y);
|
||||
@@ -463,6 +476,10 @@ Overview.prototype = {
|
||||
this.emit('item-drag-begin');
|
||||
},
|
||||
|
||||
cancelledItemDrag: function(source) {
|
||||
this.emit('item-drag-cancelled');
|
||||
},
|
||||
|
||||
endItemDrag: function(source) {
|
||||
this.emit('item-drag-end');
|
||||
},
|
||||
@@ -471,35 +488,14 @@ Overview.prototype = {
|
||||
this.emit('window-drag-begin');
|
||||
},
|
||||
|
||||
cancelledWindowDrag: function(source) {
|
||||
this.emit('window-drag-cancelled');
|
||||
},
|
||||
|
||||
endWindowDrag: function(source) {
|
||||
this.emit('window-drag-end');
|
||||
},
|
||||
|
||||
// Returns the scale the Overview has when we just start zooming out
|
||||
// to overview mode. That is, when just the active workspace is showing.
|
||||
getZoomedInScale : function() {
|
||||
return 1 / this.workspaces.getScale();
|
||||
},
|
||||
|
||||
// Returns the position the Overview has when we just start zooming out
|
||||
// to overview mode. That is, when just the active workspace is showing.
|
||||
getZoomedInPosition : function() {
|
||||
let [posX, posY] = this.workspaces.getActiveWorkspacePosition();
|
||||
let scale = this.getZoomedInScale();
|
||||
|
||||
return [- posX * scale, - posY * scale];
|
||||
},
|
||||
|
||||
// Returns the current scale of the Overview.
|
||||
getScale : function() {
|
||||
return this.workspaces.actor.scaleX;
|
||||
},
|
||||
|
||||
// Returns the current position of the Overview.
|
||||
getPosition : function() {
|
||||
return [this.workspaces.actor.x, this.workspaces.actor.y];
|
||||
},
|
||||
|
||||
// show:
|
||||
//
|
||||
// Animates the overview visible and grabs mouse and keyboard input
|
||||
@@ -507,7 +503,7 @@ Overview.prototype = {
|
||||
if (this._shown)
|
||||
return;
|
||||
// Do this manually instead of using _syncInputMode, to handle failure
|
||||
if (!Main.pushModal(this.viewSelector.actor))
|
||||
if (!Main.pushModal(this._group))
|
||||
return;
|
||||
this._modal = true;
|
||||
this._animateVisible();
|
||||
@@ -553,30 +549,13 @@ Overview.prototype = {
|
||||
});
|
||||
}
|
||||
|
||||
// Create a zoom out effect. First scale the workspaces view up and
|
||||
// position it so that the active workspace fills up the whole screen,
|
||||
// then transform it to its normal dimensions and position.
|
||||
// The opposite transition is used in hide().
|
||||
this.workspaces.actor.scaleX = this.workspaces.actor.scaleY = this.getZoomedInScale();
|
||||
[this.workspaces.actor.x, this.workspaces.actor.y] = this.getZoomedInPosition();
|
||||
let primary = global.get_primary_monitor();
|
||||
Tweener.addTween(this.workspaces.actor,
|
||||
{ x: primary.x - this._group.x,
|
||||
y: primary.y - this._group.y,
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._showDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
// Make the other elements fade in.
|
||||
this._group.opacity = 0;
|
||||
Tweener.addTween(this._group,
|
||||
{ opacity: 255,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._showDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
@@ -638,18 +617,6 @@ Overview.prototype = {
|
||||
this.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* getWorkspacesForWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
*
|
||||
* Returns the Workspaces object associated with the given window.
|
||||
* This method is not be accessible if the overview is not open
|
||||
* and will return %null.
|
||||
*/
|
||||
getWorkspacesForWindow: function(metaWindow) {
|
||||
return this.workspaces;
|
||||
},
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
_syncInputMode: function() {
|
||||
@@ -661,20 +628,20 @@ Overview.prototype = {
|
||||
|
||||
if (this._shown) {
|
||||
if (!this._modal) {
|
||||
if (Main.pushModal(this.dash.actor))
|
||||
if (Main.pushModal(this._group))
|
||||
this._modal = true;
|
||||
else
|
||||
this.hide();
|
||||
}
|
||||
} else if (this._shownTemporarily) {
|
||||
if (this._modal) {
|
||||
Main.popModal(this.dash.actor);
|
||||
Main.popModal(this._group);
|
||||
this._modal = false;
|
||||
}
|
||||
global.stage_input_mode = Shell.StageInputMode.FULLSCREEN;
|
||||
} else {
|
||||
if (this._modal) {
|
||||
Main.popModal(this.dash.actor);
|
||||
Main.popModal(this._group);
|
||||
this._modal = false;
|
||||
}
|
||||
else if (global.stage_input_mode == Shell.StageInputMode.FULLSCREEN)
|
||||
@@ -700,27 +667,13 @@ Overview.prototype = {
|
||||
|
||||
this.workspaces.hide();
|
||||
|
||||
// Create a zoom in effect by transforming the workspaces view so that
|
||||
// the active workspace fills up the whole screen. The opposite
|
||||
// transition is used in show().
|
||||
let scale = this.getZoomedInScale();
|
||||
let [posX, posY] = this.getZoomedInPosition();
|
||||
Tweener.addTween(this.workspaces.actor,
|
||||
{ x: posX,
|
||||
y: posY,
|
||||
scaleX: scale,
|
||||
scaleY: scale,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._hideDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
// Make other elements fade out.
|
||||
Tweener.addTween(this._group,
|
||||
{ opacity: 0,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._hideDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
@@ -739,6 +692,7 @@ Overview.prototype = {
|
||||
this._animateNotVisible();
|
||||
|
||||
this._syncInputMode();
|
||||
global.sync_pointer();
|
||||
},
|
||||
|
||||
_hideDone: function() {
|
||||
|
||||
634
js/ui/panel.js
@@ -9,10 +9,9 @@ const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const Overview = imports.ui.overview;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
@@ -21,17 +20,16 @@ const DateMenu = imports.ui.dateMenu;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const PANEL_HEIGHT = 26;
|
||||
|
||||
const PANEL_ICON_SIZE = 24;
|
||||
|
||||
const STARTUP_ANIMATION_TIME = 0.2;
|
||||
|
||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||
|
||||
const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
|
||||
|
||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
|
||||
const SPINNER_UPDATE_TIMEOUT = 130;
|
||||
const SPINNER_SPEED = 0.02;
|
||||
const SPINNER_ANIMATION_TIME = 0.2;
|
||||
|
||||
const STANDARD_TRAY_ICON_ORDER = ['a11y', 'display', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];
|
||||
const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
|
||||
@@ -44,13 +42,11 @@ const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
|
||||
if (Config.HAVE_BLUETOOTH)
|
||||
STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['bluetooth'] = imports.ui.status.bluetooth.Indicator;
|
||||
|
||||
// in org.gnome.desktop.interface
|
||||
const CLOCK_FORMAT_KEY = 'clock-format';
|
||||
|
||||
// in org.gnome.shell.clock
|
||||
const CLOCK_SHOW_DATE_KEY = 'show-date';
|
||||
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
|
||||
|
||||
try {
|
||||
STANDARD_TRAY_ICON_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');
|
||||
}
|
||||
|
||||
// To make sure the panel corners blend nicely with the panel,
|
||||
// we draw background and borders the same way, e.g. drawing
|
||||
@@ -249,6 +245,10 @@ AppMenuButton.prototype = {
|
||||
|
||||
let bin = new St.Bin({ name: 'appMenu' });
|
||||
this.actor.set_child(bin);
|
||||
|
||||
this.actor.reactive = false;
|
||||
this._targetIsCurrent = false;
|
||||
|
||||
this._container = new Shell.GenericContainer();
|
||||
bin.set_child(this._container);
|
||||
this._container.connect('get-preferred-width', Lang.bind(this, this._getContentPreferredWidth));
|
||||
@@ -258,10 +258,14 @@ AppMenuButton.prototype = {
|
||||
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
||||
this._iconBox.connect('style-changed',
|
||||
Lang.bind(this, this._onIconBoxStyleChanged));
|
||||
this._iconBox.connect('notify::allocation',
|
||||
Lang.bind(this, this._updateIconBoxClip));
|
||||
this._container.add_actor(this._iconBox);
|
||||
this._label = new TextShadower();
|
||||
this._container.add_actor(this._label.actor);
|
||||
|
||||
this._iconBottomClip = 0;
|
||||
|
||||
this._quitMenu = new PopupMenu.PopupMenuItem('');
|
||||
this.menu.addMenuItem(this._quitMenu);
|
||||
this._quitMenu.connect('activate', Lang.bind(this, this._onQuit));
|
||||
@@ -276,20 +280,13 @@ AppMenuButton.prototype = {
|
||||
this.hide();
|
||||
}));
|
||||
|
||||
this._updateId = 0;
|
||||
this._animationStep = 0;
|
||||
this._clipWidth = PANEL_ICON_SIZE;
|
||||
this._direction = SPINNER_SPEED;
|
||||
this._stop = true;
|
||||
|
||||
this._spinner = new AnimatedIcon('process-working.png',
|
||||
this._spinner = new AnimatedIcon('process-working.svg',
|
||||
PANEL_ICON_SIZE);
|
||||
this._container.add_actor(this._spinner.actor);
|
||||
this._spinner.actor.lower_bottom();
|
||||
|
||||
this._shadow = new St.Bin({ style_class: 'label-real-shadow' });
|
||||
this._shadow.hide();
|
||||
this._container.add_actor(this._shadow);
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
tracker.connect('notify::focus-app', Lang.bind(this, this._sync));
|
||||
tracker.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
|
||||
@@ -305,6 +302,10 @@ AppMenuButton.prototype = {
|
||||
|
||||
this._visible = true;
|
||||
this.actor.show();
|
||||
|
||||
if (!this._targetIsCurrent)
|
||||
return;
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
@@ -317,6 +318,11 @@ AppMenuButton.prototype = {
|
||||
return;
|
||||
|
||||
this._visible = false;
|
||||
if (!this._targetIsCurrent) {
|
||||
this.actor.hide();
|
||||
return;
|
||||
}
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
@@ -330,71 +336,40 @@ AppMenuButton.prototype = {
|
||||
|
||||
_onIconBoxStyleChanged: function() {
|
||||
let node = this._iconBox.get_theme_node();
|
||||
let bottomClip = node.get_length('app-icon-bottom-clip');
|
||||
if (bottomClip > 0)
|
||||
this._iconBottomClip = node.get_length('app-icon-bottom-clip');
|
||||
this._updateIconBoxClip();
|
||||
},
|
||||
|
||||
_updateIconBoxClip: function() {
|
||||
let allocation = this._iconBox.allocation;
|
||||
if (this._iconBottomClip > 0)
|
||||
this._iconBox.set_clip(0, 0,
|
||||
this._iconBox.width,
|
||||
this._iconBox.height - bottomClip);
|
||||
allocation.x2 - allocation.x1,
|
||||
allocation.y2 - allocation.y1 - this._iconBottomClip);
|
||||
else
|
||||
this._iconBox.remove_clip();
|
||||
},
|
||||
|
||||
_stopAnimation: function(animate) {
|
||||
this._label.actor.remove_clip();
|
||||
if (this._updateId) {
|
||||
this._shadow.hide();
|
||||
if (animate) {
|
||||
Tweener.addTween(this._spinner.actor,
|
||||
{ opacity: 0,
|
||||
time: 0.2,
|
||||
transition: "easeOutQuad",
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
this._spinner.actor.opacity = 255;
|
||||
this._spinner.actor.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
Mainloop.source_remove(this._updateId);
|
||||
this._updateId = 0;
|
||||
}
|
||||
if (!animate)
|
||||
this._spinner.actor.hide();
|
||||
},
|
||||
|
||||
stopAnimation: function() {
|
||||
this._direction = SPINNER_SPEED * 3;
|
||||
this._stop = true;
|
||||
},
|
||||
if (this._stop)
|
||||
return;
|
||||
|
||||
_update: function() {
|
||||
this._animationStep += this._direction;
|
||||
if (this._animationStep > 1 && this._stop) {
|
||||
this._animationStep = 1;
|
||||
this._stopAnimation(true);
|
||||
return false;
|
||||
}
|
||||
if (this._animationStep > 1)
|
||||
this._animationStep = 1;
|
||||
this._clipWidth = this._label.actor.width - (this._label.actor.width - PANEL_ICON_SIZE) * (1 - this._animationStep);
|
||||
if (this.actor.get_direction() == St.TextDirection.LTR) {
|
||||
this._label.actor.set_clip(0, 0, this._clipWidth + this._shadow.width, this.actor.height);
|
||||
} else {
|
||||
this._label.actor.set_clip(this._label.actor.width - this._clipWidth, 0, this._clipWidth, this.actor.height);
|
||||
}
|
||||
this._container.queue_relayout();
|
||||
return true;
|
||||
this._stop = true;
|
||||
Tweener.addTween(this._spinner.actor,
|
||||
{ opacity: 0,
|
||||
time: SPINNER_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
this._spinner.actor.opacity = 255;
|
||||
this._spinner.actor.hide();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
startAnimation: function() {
|
||||
this._direction = SPINNER_SPEED;
|
||||
this._stopAnimation(false);
|
||||
this._animationStep = 0;
|
||||
this._update();
|
||||
this._stop = false;
|
||||
this._updateId = Mainloop.timeout_add(SPINNER_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
||||
this._spinner.actor.show();
|
||||
this._shadow.show();
|
||||
},
|
||||
|
||||
_getContentPreferredWidth: function(actor, forHeight, alloc) {
|
||||
@@ -410,7 +385,7 @@ AppMenuButton.prototype = {
|
||||
let [minSize, naturalSize] = this._iconBox.get_preferred_height(forWidth);
|
||||
alloc.min_size = minSize;
|
||||
alloc.natural_size = naturalSize;
|
||||
[minSizfe, naturalSize] = this._label.actor.get_preferred_height(forWidth);
|
||||
[minSize, naturalSize] = this._label.actor.get_preferred_height(forWidth);
|
||||
if (minSize > alloc.min_size)
|
||||
alloc.min_size = minSize;
|
||||
if (naturalSize > alloc.natural_size)
|
||||
@@ -456,18 +431,13 @@ AppMenuButton.prototype = {
|
||||
this._label.actor.allocate(childBox, flags);
|
||||
|
||||
if (direction == St.TextDirection.LTR) {
|
||||
childBox.x1 = Math.floor(iconWidth / 2) + this._clipWidth + this._shadow.width;
|
||||
childBox.x1 = Math.floor(iconWidth / 2) + this._label.actor.width;
|
||||
childBox.x2 = childBox.x1 + this._spinner.actor.width;
|
||||
childBox.y1 = box.y1;
|
||||
childBox.y2 = box.y2 - 1;
|
||||
this._spinner.actor.allocate(childBox, flags);
|
||||
childBox.x1 = Math.floor(iconWidth / 2) + this._clipWidth + 2;
|
||||
childBox.x2 = childBox.x1 + this._shadow.width;
|
||||
childBox.y1 = box.y1;
|
||||
childBox.y2 = box.y2 - 1;
|
||||
this._shadow.allocate(childBox, flags);
|
||||
} else {
|
||||
childBox.x1 = this._label.actor.width - this._clipWidth - this._spinner.actor.width;
|
||||
childBox.x1 = -this._spinner.actor.width;
|
||||
childBox.x2 = childBox.x1 + this._spinner.actor.width;
|
||||
childBox.y1 = box.y1;
|
||||
childBox.y2 = box.y2 - 1;
|
||||
@@ -506,13 +476,6 @@ AppMenuButton.prototype = {
|
||||
lastStartedApp = this._startingApps[i];
|
||||
|
||||
let focusedApp = tracker.focus_app;
|
||||
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
|
||||
if (targetApp == this._targetApp) {
|
||||
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
|
||||
this.stopAnimation();
|
||||
return;
|
||||
}
|
||||
this._stopAnimation();
|
||||
|
||||
if (!focusedApp) {
|
||||
// If the app has just lost focus to the panel, pretend
|
||||
@@ -522,27 +485,56 @@ AppMenuButton.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
|
||||
|
||||
if (targetApp == null) {
|
||||
if (!this._targetIsCurrent)
|
||||
return;
|
||||
|
||||
this.actor.reactive = false;
|
||||
this._targetIsCurrent = false;
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor, { opacity: 0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._targetIsCurrent) {
|
||||
this.actor.reactive = true;
|
||||
this._targetIsCurrent = true;
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor, { opacity: 255,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
}
|
||||
|
||||
if (targetApp == this._targetApp) {
|
||||
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
|
||||
this.stopAnimation();
|
||||
return;
|
||||
}
|
||||
|
||||
this._spinner.actor.hide();
|
||||
if (this._iconBox.child != null)
|
||||
this._iconBox.child.destroy();
|
||||
this._iconBox.hide();
|
||||
this._label.setText('');
|
||||
this.actor.reactive = false;
|
||||
|
||||
this._targetApp = targetApp;
|
||||
if (targetApp != null) {
|
||||
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
|
||||
let icon = targetApp.get_faded_icon(2 * PANEL_ICON_SIZE);
|
||||
|
||||
this._label.setText(targetApp.get_name());
|
||||
// TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
this._quitMenu.label.set_text(_("Quit %s").format(targetApp.get_name()));
|
||||
this._label.setText(targetApp.get_name());
|
||||
// TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
this._quitMenu.label.set_text(_("Quit %s").format(targetApp.get_name()));
|
||||
|
||||
this.actor.reactive = true;
|
||||
this._iconBox.set_child(icon);
|
||||
this._iconBox.show();
|
||||
this._iconBox.set_child(icon);
|
||||
this._iconBox.show();
|
||||
|
||||
if (targetApp.get_state() == Shell.AppState.STARTING)
|
||||
this.startAnimation();
|
||||
}
|
||||
if (targetApp.get_state() == Shell.AppState.STARTING)
|
||||
this.startAnimation();
|
||||
|
||||
this.emit('changed');
|
||||
}
|
||||
@@ -560,7 +552,7 @@ PanelCorner.prototype = {
|
||||
this._side = side;
|
||||
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
|
||||
this.actor.connect('repaint', Lang.bind(this, this._repaint));
|
||||
this.actor.connect('style-changed', Lang.bind(this, this._reposition));
|
||||
this.actor.connect('style-changed', Lang.bind(this, this.relayout));
|
||||
},
|
||||
|
||||
_repaint: function() {
|
||||
@@ -580,18 +572,19 @@ PanelCorner.prototype = {
|
||||
cr.moveTo(0, 0);
|
||||
if (this._side == St.Side.LEFT)
|
||||
cr.arc(cornerRadius,
|
||||
innerBorderWidth + outerBorderWidth + cornerRadius,
|
||||
innerBorderWidth + cornerRadius,
|
||||
cornerRadius, Math.PI, 3 * Math.PI / 2);
|
||||
else
|
||||
cr.arc(0,
|
||||
innerBorderWidth + outerBorderWidth + cornerRadius,
|
||||
innerBorderWidth + cornerRadius,
|
||||
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
|
||||
cr.lineTo(cornerRadius, 0);
|
||||
cr.closePath();
|
||||
|
||||
let savedPath = cr.copyPath();
|
||||
|
||||
let over = _over(outerBorderColor, backgroundColor);
|
||||
let over = _over(innerBorderColor,
|
||||
_over(outerBorderColor, backgroundColor));
|
||||
Clutter.cairo_set_source_color(cr, over);
|
||||
cr.fill();
|
||||
|
||||
@@ -607,12 +600,12 @@ PanelCorner.prototype = {
|
||||
cr.restore();
|
||||
|
||||
if (this._side == St.Side.LEFT)
|
||||
cr.rectangle(cornerRadius - offset, 0, offset, innerBorderWidth);
|
||||
cr.rectangle(cornerRadius - offset, 0, offset, outerBorderWidth);
|
||||
else
|
||||
cr.rectangle(0, 0, offset, innerBorderWidth);
|
||||
cr.rectangle(0, 0, offset, outerBorderWidth);
|
||||
cr.fill();
|
||||
|
||||
offset = innerBorderWidth + outerBorderWidth;
|
||||
offset = innerBorderWidth;
|
||||
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||
|
||||
cr.save();
|
||||
@@ -622,24 +615,194 @@ PanelCorner.prototype = {
|
||||
cr.restore();
|
||||
},
|
||||
|
||||
_reposition: function() {
|
||||
relayout: function() {
|
||||
let node = this.actor.get_theme_node();
|
||||
|
||||
let cornerRadius = node.get_length("-panel-corner-radius");
|
||||
let innerBorderWidth = node.get_length('-panel-corner-inner-border-width');
|
||||
let outerBorderWidth = node.get_length('-panel-corner-outer-border-width');
|
||||
|
||||
this.actor.set_size(cornerRadius,
|
||||
innerBorderWidth + outerBorderWidth + cornerRadius);
|
||||
innerBorderWidth + cornerRadius);
|
||||
if (this._side == St.Side.LEFT)
|
||||
this.actor.set_position(Main.panel.actor.x,
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth - outerBorderWidth);
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
|
||||
else
|
||||
this.actor.set_position(Main.panel.actor.x + Main.panel.actor.width - cornerRadius,
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth - outerBorderWidth);
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HotCorner:
|
||||
*
|
||||
* This class manages the "hot corner" that can toggle switching to
|
||||
* overview.
|
||||
*/
|
||||
function HotCorner(button) {
|
||||
this._init(button);
|
||||
}
|
||||
|
||||
HotCorner.prototype = {
|
||||
_init : function(button) {
|
||||
// This is the activities button associated with this hot corner,
|
||||
// if this is on the primary monitor (or null with the corner is
|
||||
// on a different monitor)
|
||||
this._button = button;
|
||||
|
||||
// We use this flag to mark the case where the user has entered the
|
||||
// hot corner and has not left both the hot corner and a surrounding
|
||||
// guard area (the "environs"). This avoids triggering the hot corner
|
||||
// multiple times due to an accidental jitter.
|
||||
this._entered = false;
|
||||
|
||||
this.actor = new Clutter.Group({ width: 3,
|
||||
height: 3,
|
||||
reactive: true });
|
||||
|
||||
this._corner = new Clutter.Rectangle({ width: 1,
|
||||
height: 1,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
|
||||
this.actor.add_actor(this._corner);
|
||||
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
||||
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
||||
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||
} else {
|
||||
this._corner.set_position(0, 0);
|
||||
}
|
||||
|
||||
this._activationTime = 0;
|
||||
|
||||
this.actor.connect('enter-event',
|
||||
Lang.bind(this, this._onEnvironsEntered));
|
||||
this.actor.connect('leave-event',
|
||||
Lang.bind(this, this._onEnvironsLeft));
|
||||
// Clicking on the hot corner environs should result in the same bahavior
|
||||
// as clicking on the hot corner.
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this, this._onCornerClicked));
|
||||
|
||||
// In addition to being triggered by the mouse enter event, the hot corner
|
||||
// can be triggered by clicking on it. This is useful if the user wants to
|
||||
// undo the effect of triggering the hot corner once in the hot corner.
|
||||
this._corner.connect('enter-event',
|
||||
Lang.bind(this, this._onCornerEntered));
|
||||
this._corner.connect('button-release-event',
|
||||
Lang.bind(this, this._onCornerClicked));
|
||||
this._corner.connect('leave-event',
|
||||
Lang.bind(this, this._onCornerLeft));
|
||||
|
||||
this._corner._delegate = this._corner;
|
||||
this._corner.handleDragOver = Lang.bind(this,
|
||||
function(source, actor, x, y, time) {
|
||||
if (source == Main.xdndHandler) {
|
||||
if(!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||
this.rippleAnimation();
|
||||
Main.overview.showTemporarily();
|
||||
Main.overview.beginItemDrag(actor);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Main.chrome.addActor(this.actor, { visibleInOverview: true, affectsStruts: false });
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
|
||||
// We draw a ripple by using a source image and animating it scaling
|
||||
// outwards and fading away. We want the ripples to move linearly
|
||||
// or it looks unrealistic, but if the opacity of the ripple goes
|
||||
// linearly to zero it fades away too quickly, so we use Tweener's
|
||||
// 'onUpdate' to give a non-linear curve to the fade-away and make
|
||||
// it more visible in the middle section.
|
||||
|
||||
let [x, y] = this._corner.get_transformed_position();
|
||||
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
|
||||
opacity: 255 * Math.sqrt(startOpacity),
|
||||
scale_x: startScale,
|
||||
scale_y: startScale,
|
||||
x: x,
|
||||
y: y });
|
||||
ripple._opacity = startOpacity;
|
||||
if (ripple.get_direction() == St.TextDirection.RTL)
|
||||
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||
Tweener.addTween(ripple, { _opacity: finalOpacity,
|
||||
scale_x: finalScale,
|
||||
scale_y: finalScale,
|
||||
delay: delay,
|
||||
time: time,
|
||||
transition: 'linear',
|
||||
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
|
||||
onComplete: function() { ripple.destroy(); } });
|
||||
Main.uiGroup.add_actor(ripple);
|
||||
},
|
||||
|
||||
rippleAnimation: function() {
|
||||
// Show three concentric ripples expanding outwards; the exact
|
||||
// parameters were found by trial and error, so don't look
|
||||
// for them to make perfect sense mathematically
|
||||
|
||||
// delay time scale opacity => scale opacity
|
||||
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
|
||||
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
|
||||
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
|
||||
},
|
||||
|
||||
_onEnvironsEntered : function() {
|
||||
if (this._button)
|
||||
this._button.hover = true;
|
||||
},
|
||||
|
||||
_onCornerEntered : function() {
|
||||
if (!this._entered) {
|
||||
this._entered = true;
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._activationTime = Date.now() / 1000;
|
||||
|
||||
this.rippleAnimation();
|
||||
Main.overview.toggle();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCornerClicked : function() {
|
||||
if (!Main.overview.animationInProgress)
|
||||
this.maybeToggleOverviewOnClick();
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCornerLeft : function(actor, event) {
|
||||
if (event.get_related() != this.actor)
|
||||
this._entered = false;
|
||||
// Consume event, otherwise this will confuse onEnvironsLeft
|
||||
return true;
|
||||
},
|
||||
|
||||
_onEnvironsLeft : function(actor, event) {
|
||||
if (this._button)
|
||||
this._button.hover = false;
|
||||
|
||||
if (event.get_related() != this._corner)
|
||||
this._entered = false;
|
||||
return false;
|
||||
},
|
||||
|
||||
// Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
|
||||
// of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
|
||||
// and clicked the Activities button.
|
||||
maybeToggleOverviewOnClick: function() {
|
||||
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
|
||||
Main.overview.toggle();
|
||||
this._activationTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Panel() {
|
||||
this._init();
|
||||
@@ -652,6 +815,8 @@ Panel.prototype = {
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._statusArea = {};
|
||||
|
||||
Main.overview.connect('shown', Lang.bind(this, function () {
|
||||
this.actor.add_style_class_name('in-overview');
|
||||
}));
|
||||
@@ -659,19 +824,14 @@ Panel.prototype = {
|
||||
this.actor.remove_style_class_name('in-overview');
|
||||
}));
|
||||
|
||||
this._leftPointerBarrier = 0;
|
||||
this._rightPointerBarrier = 0;
|
||||
this._menus = new PopupMenu.PopupMenuManager(this);
|
||||
|
||||
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
||||
this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
|
||||
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
||||
|
||||
// This will eventually be automatic, see
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=584662
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
||||
this._leftBox.add_style_pseudo_class('rtl');
|
||||
this._rightBox.add_style_pseudo_class('rtl');
|
||||
}
|
||||
|
||||
this._leftCorner = new PanelCorner(St.Side.LEFT);
|
||||
this._rightCorner = new PanelCorner(St.Side.RIGHT);
|
||||
|
||||
@@ -712,27 +872,6 @@ Panel.prototype = {
|
||||
sideWidth = (allocWidth - centerWidth) / 2;
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = this._hotCornerEnvirons.height;
|
||||
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
||||
childBox.x1 = allocWidth - this._hotCornerEnvirons.width;
|
||||
childBox.x2 = allocWidth;
|
||||
} else {
|
||||
childBox.x1 = 0;
|
||||
childBox.x2 = this._hotCornerEnvirons.width;
|
||||
}
|
||||
this._hotCornerEnvirons.allocate(childBox, flags);
|
||||
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = this._hotCorner.height;
|
||||
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
||||
childBox.x1 = allocWidth - this._hotCorner.width;
|
||||
childBox.x2 = allocWidth;
|
||||
} else {
|
||||
childBox.x1 = 0;
|
||||
childBox.x2 = this._hotCorner.width;
|
||||
}
|
||||
this._hotCorner.allocate(childBox, flags);
|
||||
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = allocHeight;
|
||||
@@ -774,6 +913,7 @@ Panel.prototype = {
|
||||
style_class: 'panel-button',
|
||||
reactive: true,
|
||||
can_focus: true });
|
||||
this._activities = this.button;
|
||||
this.button.set_child(label);
|
||||
this.button._delegate = this.button;
|
||||
this.button._xdndTimeOut = 0;
|
||||
@@ -800,60 +940,12 @@ Panel.prototype = {
|
||||
corner.actor.set_style_pseudo_class(pseudoClass);
|
||||
}));
|
||||
|
||||
// We use this flag to mark the case where the user has entered the
|
||||
// hot corner and has not left both the hot corner and a surrounding
|
||||
// guard area (the "environs"). This avoids triggering the hot corner
|
||||
// multiple times due to an accidental jitter.
|
||||
this._hotCornerEntered = false;
|
||||
this._hotCorner = null;
|
||||
|
||||
this._hotCornerEnvirons = new Clutter.Rectangle({ width: 3,
|
||||
height: 3,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
this._appMenu = new AppMenuButton();
|
||||
this._leftBox.add(this._appMenu.actor);
|
||||
|
||||
this._hotCorner = new Clutter.Rectangle({ width: 1,
|
||||
height: 1,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
|
||||
this._hotCornerActivationTime = 0;
|
||||
|
||||
this._hotCornerEnvirons.connect('leave-event',
|
||||
Lang.bind(this, this._onHotCornerEnvironsLeft));
|
||||
// Clicking on the hot corner environs should result in the same bahavior
|
||||
// as clicking on the hot corner.
|
||||
this._hotCornerEnvirons.connect('button-release-event',
|
||||
Lang.bind(this, this._onHotCornerClicked));
|
||||
|
||||
// In addition to being triggered by the mouse enter event, the hot corner
|
||||
// can be triggered by clicking on it. This is useful if the user wants to
|
||||
// undo the effect of triggering the hot corner once in the hot corner.
|
||||
this._hotCorner.connect('enter-event',
|
||||
Lang.bind(this, this._onHotCornerEntered));
|
||||
this._hotCorner.connect('button-release-event',
|
||||
Lang.bind(this, this._onHotCornerClicked));
|
||||
this._hotCorner.connect('leave-event',
|
||||
Lang.bind(this, this._onHotCornerLeft));
|
||||
|
||||
this._hotCorner._delegate = this._hotCorner;
|
||||
this._hotCorner.handleDragOver = Lang.bind(this,
|
||||
function(source, actor, x, y, time) {
|
||||
if (source == Main.xdndHandler) {
|
||||
if(!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||
this.rippleAnimation();
|
||||
Main.overview.showTemporarily();
|
||||
Main.overview.beginItemDrag(actor);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this._boxContainer.add_actor(this._hotCornerEnvirons);
|
||||
this._boxContainer.add_actor(this._hotCorner);
|
||||
|
||||
let appMenuButton = new AppMenuButton();
|
||||
this._leftBox.add(appMenuButton.actor);
|
||||
|
||||
this._menus.addMenu(appMenuButton.menu);
|
||||
this._menus.addMenu(this._appMenu.menu);
|
||||
|
||||
/* center */
|
||||
this._dateMenu = new DateMenu.DateMenuButton();
|
||||
@@ -872,12 +964,12 @@ Panel.prototype = {
|
||||
this._rightBox.add(this._trayBox);
|
||||
this._rightBox.add(this._statusBox);
|
||||
|
||||
this._statusmenu = new StatusMenu.StatusMenuButton();
|
||||
this._statusmenu.actor.name = 'panelStatus';
|
||||
this._rightBox.add(this._statusmenu.actor);
|
||||
this._userMenu = new StatusMenu.StatusMenuButton();
|
||||
this._userMenu.actor.name = 'panelStatus';
|
||||
this._rightBox.add(this._userMenu.actor);
|
||||
|
||||
// Synchronize the buttons pseudo classes with its corner
|
||||
this._statusmenu.actor.connect('style-changed', Lang.bind(this,
|
||||
this._userMenu.actor.connect('style-changed', Lang.bind(this,
|
||||
function(actor) {
|
||||
let rtl = actor.get_direction() == St.TextDirection.RTL;
|
||||
let corner = rtl ? this._leftCorner : this._rightCorner;
|
||||
@@ -894,7 +986,7 @@ Panel.prototype = {
|
||||
// to switch to.
|
||||
this.button.connect('clicked', Lang.bind(this, function(b) {
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._maybeToggleOverviewOnClick();
|
||||
this._hotCorner.maybeToggleOverviewOnClick();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -917,6 +1009,9 @@ Panel.prototype = {
|
||||
Main.chrome.addActor(this._rightCorner.actor, { visibleInOverview: true,
|
||||
affectsStruts: false,
|
||||
affectsInputRegion: false });
|
||||
|
||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
|
||||
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
||||
},
|
||||
|
||||
_xdndShowOverview: function (actor) {
|
||||
@@ -938,6 +1033,14 @@ Panel.prototype = {
|
||||
this.button._xdndTimeOut = 0;
|
||||
},
|
||||
|
||||
|
||||
// While there can be multiple hotcorners (one per monitor), the hot corner
|
||||
// that is on top of the Activities button is special since it needs special
|
||||
// coordination with clicking on that button
|
||||
setHotCorner: function(corner) {
|
||||
this._hotCorner = corner;
|
||||
},
|
||||
|
||||
startStatusArea: function() {
|
||||
for (let i = 0; i < STANDARD_TRAY_ICON_ORDER.length; i++) {
|
||||
let role = STANDARD_TRAY_ICON_ORDER[i];
|
||||
@@ -949,20 +1052,61 @@ Panel.prototype = {
|
||||
let indicator = new constructor();
|
||||
this._statusBox.add(indicator.actor);
|
||||
this._menus.addMenu(indicator.menu);
|
||||
|
||||
this._statusArea[role] = indicator;
|
||||
}
|
||||
|
||||
// PopupMenuManager depends on menus being added in order for
|
||||
// keyboard navigation
|
||||
this._menus.addMenu(this._statusmenu.menu);
|
||||
this._menus.addMenu(this._userMenu.menu);
|
||||
},
|
||||
|
||||
startupAnimation: function() {
|
||||
this.actor.y = -this.actor.height;
|
||||
let oldY = this.actor.y;
|
||||
this.actor.y = oldY - this.actor.height;
|
||||
Tweener.addTween(this.actor,
|
||||
{ y: 0,
|
||||
time: 0.2,
|
||||
{ y: oldY,
|
||||
time: STARTUP_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
|
||||
let oldCornerY = this._leftCorner.actor.y;
|
||||
this._leftCorner.actor.y = oldCornerY - this.actor.height;
|
||||
this._rightCorner.actor.y = oldCornerY - this.actor.height;
|
||||
Tweener.addTween(this._leftCorner.actor,
|
||||
{ y: oldCornerY,
|
||||
time: STARTUP_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
Tweener.addTween(this._rightCorner.actor,
|
||||
{ y: oldCornerY,
|
||||
time: STARTUP_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
relayout: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
this.actor.set_position(primary.x, primary.y);
|
||||
this.actor.set_size(primary.width, -1);
|
||||
|
||||
if (this._leftPointerBarrier)
|
||||
global.destroy_pointer_barrier(this._leftPointerBarrier);
|
||||
if (this._rightPointerBarrier)
|
||||
global.destroy_pointer_barrier(this._rightPointerBarrier);
|
||||
|
||||
this._leftPointerBarrier =
|
||||
global.create_pointer_barrier(primary.x, primary.y,
|
||||
primary.x, primary.y + this.actor.height,
|
||||
1 /* BarrierPositiveX */);
|
||||
this._rightPointerBarrier =
|
||||
global.create_pointer_barrier(primary.x + primary.width, primary.y,
|
||||
primary.x + primary.width, primary.y + this.actor.height,
|
||||
4 /* BarrierNegativeX */);
|
||||
|
||||
this._leftCorner.relayout();
|
||||
this._rightCorner.relayout();
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon, role) {
|
||||
@@ -1001,88 +1145,4 @@ Panel.prototype = {
|
||||
this._trayBox.remove_actor(icon);
|
||||
},
|
||||
|
||||
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
|
||||
// We draw a ripple by using a source image and animating it scaling
|
||||
// outwards and fading away. We want the ripples to move linearly
|
||||
// or it looks unrealistic, but if the opacity of the ripple goes
|
||||
// linearly to zero it fades away too quickly, so we use Tweener's
|
||||
// 'onUpdate' to give a non-linear curve to the fade-away and make
|
||||
// it more visible in the middle section.
|
||||
|
||||
let [x, y] = this._hotCorner.get_transformed_position();
|
||||
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
|
||||
opacity: 255 * Math.sqrt(startOpacity),
|
||||
scale_x: startScale,
|
||||
scale_y: startScale,
|
||||
x: x,
|
||||
y: y });
|
||||
ripple._opacity = startOpacity;
|
||||
Tweener.addTween(ripple, { _opacity: finalOpacity,
|
||||
scale_x: finalScale,
|
||||
scale_y: finalScale,
|
||||
delay: delay,
|
||||
time: time,
|
||||
transition: 'linear',
|
||||
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
|
||||
onComplete: function() { ripple.destroy(); } });
|
||||
Main.uiGroup.add_actor(ripple);
|
||||
},
|
||||
|
||||
rippleAnimation: function() {
|
||||
// Show three concentric ripples expanding outwards; the exact
|
||||
// parameters were found by trial and error, so don't look
|
||||
// for them to make perfect sense mathematically
|
||||
|
||||
// delay time scale opacity => scale opacity
|
||||
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
|
||||
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
|
||||
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
|
||||
},
|
||||
|
||||
_onHotCornerEntered : function() {
|
||||
if (this._menus.grabbed)
|
||||
return false;
|
||||
if (!this._hotCornerEntered) {
|
||||
this._hotCornerEntered = true;
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._hotCornerActivationTime = Date.now() / 1000;
|
||||
|
||||
this.rippleAnimation();
|
||||
Main.overview.toggle();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerClicked : function() {
|
||||
if (this._menus.grabbed)
|
||||
return false;
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._maybeToggleOverviewOnClick();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerLeft : function(actor, event) {
|
||||
if (event.get_related() != this._hotCornerEnvirons) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerEnvironsLeft : function(actor, event) {
|
||||
if (event.get_related() != this._hotCorner) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
|
||||
// of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
|
||||
// and clicked the Activities button.
|
||||
_maybeToggleOverviewOnClick: function() {
|
||||
if (this._hotCornerActivationTime == 0 || Date.now() / 1000 - this._hotCornerActivationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
|
||||
Main.overview.toggle();
|
||||
this._hotCornerActivationTime = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Lang = imports.lang;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Main = imports.ui.main;
|
||||
@@ -20,32 +22,59 @@ Button.prototype = {
|
||||
track_hover: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPress));
|
||||
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, /* FIXME */ 0);
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
|
||||
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0);
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
||||
Main.chrome.addActor(this.menu.actor, { visibleInOverview: true,
|
||||
affectsStruts: false });
|
||||
this.menu.actor.hide();
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (!this.menu.isOpen) {
|
||||
// Setting the max-height won't do any good if the minimum height of the
|
||||
// menu is higher then the screen; it's useful if part of the menu is
|
||||
// scrollable so the minimum height is smaller than the natural height
|
||||
let monitor = global.get_primary_monitor();
|
||||
this.menu.actor.style = ('max-height: ' +
|
||||
Math.round(monitor.height - Main.panel.actor.height) +
|
||||
'px;');
|
||||
}
|
||||
this.menu.toggle();
|
||||
},
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
_onSourceKeyPress: function(actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||
this.menu.toggle();
|
||||
return true;
|
||||
} else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) {
|
||||
this.menu.close();
|
||||
return true;
|
||||
} else if (symbol == Clutter.KEY_Down) {
|
||||
if (!this.menu.isOpen)
|
||||
this.menu.toggle();
|
||||
this.menu.activateFirst();
|
||||
this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
},
|
||||
|
||||
_onMenuKeyPress: function(actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
|
||||
let focusManager = St.FocusManager.get_for_stage(global.stage);
|
||||
let group = focusManager.get_group(this.actor);
|
||||
if (group) {
|
||||
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
|
||||
group.navigate_focus(this.actor, direction, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onOpenStateChanged: function(menu, open) {
|
||||
if (open)
|
||||
this.actor.add_style_pseudo_class('active');
|
||||
|
||||
@@ -7,8 +7,6 @@ const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
@@ -176,37 +174,8 @@ PlacesManager.prototype = {
|
||||
Util.spawn(['nautilus-connect-server']);
|
||||
});
|
||||
|
||||
let networkApp = null;
|
||||
try {
|
||||
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('gnome-network-scheme.desktop');
|
||||
} catch(e) {
|
||||
try {
|
||||
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('network-scheme.desktop');
|
||||
} catch(e) {
|
||||
log('Cannot create "Network" item, .desktop file not found or corrupt.');
|
||||
}
|
||||
}
|
||||
|
||||
if (networkApp != null) {
|
||||
this._network = new PlaceInfo('special:network', networkApp.get_name(),
|
||||
function(size) {
|
||||
return networkApp.create_icon_texture(size);
|
||||
},
|
||||
function (params) {
|
||||
params = Params.parse(params, { workspace: null,
|
||||
timestamp: 0 });
|
||||
|
||||
networkApp.launch_full(params.timestamp, [],
|
||||
params.workspace ? params.workspace.index() : -1);
|
||||
});
|
||||
}
|
||||
|
||||
this._defaultPlaces.push(this._home);
|
||||
this._defaultPlaces.push(this._desktopMenu);
|
||||
|
||||
if (this._network)
|
||||
this._defaultPlaces.push(this._network);
|
||||
|
||||
this._defaultPlaces.push(this._connect);
|
||||
|
||||
/*
|
||||
@@ -415,7 +384,10 @@ PlaceSearchProvider.prototype = {
|
||||
return null;
|
||||
return { 'id': resultId,
|
||||
'name': placeInfo.name,
|
||||
'icon': placeInfo.iconFactory(Search.RESULT_ICON_SIZE) };
|
||||
'createIcon': function(size) {
|
||||
return placeInfo.iconFactory(size);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
activateResult: function(id, params) {
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const St = imports.gi.St;
|
||||
@@ -36,18 +34,21 @@ const PolkitAgent = imports.gi.PolkitAgent;
|
||||
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
|
||||
function AuthenticationDialog(message, cookie, userNames) {
|
||||
this._init(message, cookie, userNames);
|
||||
function AuthenticationDialog(actionId, message, cookie, userNames) {
|
||||
this._init(actionId, message, cookie, userNames);
|
||||
}
|
||||
|
||||
AuthenticationDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
|
||||
_init: function(message, cookie, userNames) {
|
||||
_init: function(actionId, message, cookie, userNames) {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'polkit-dialog' });
|
||||
|
||||
this.actionId = actionId;
|
||||
this.message = message;
|
||||
this.userNames = userNames;
|
||||
this._wasDismissed = false;
|
||||
this._completed = false;
|
||||
|
||||
let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
|
||||
vertical: false });
|
||||
@@ -68,7 +69,7 @@ AuthenticationDialog.prototype = {
|
||||
{ y_align: St.Align.START });
|
||||
|
||||
this._subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
|
||||
text: _('Authentication Required') });
|
||||
text: _("Authentication Required") });
|
||||
|
||||
messageBox.add(this._subjectLabel,
|
||||
{ y_fill: false,
|
||||
@@ -99,32 +100,35 @@ AuthenticationDialog.prototype = {
|
||||
Lang.bind(this, this._onUserChanged));
|
||||
|
||||
// Special case 'root'
|
||||
if (userName == 'root')
|
||||
userRealName = _('Administrator');
|
||||
let userIsRoot = false;
|
||||
if (userName == 'root') {
|
||||
userIsRoot = true;
|
||||
userRealName = _("Administrator");
|
||||
}
|
||||
|
||||
// Work around Gdm.UserManager returning an empty string for the real name
|
||||
if (userRealName.length == 0)
|
||||
userRealName = userName;
|
||||
|
||||
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
|
||||
vertical: false });
|
||||
messageBox.add(userBox);
|
||||
|
||||
this._userIcon = new St.Icon();
|
||||
this._userIcon.hide();
|
||||
userBox.add(this._userIcon,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label',
|
||||
text: userRealName }));
|
||||
userBox.add(userLabel,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.MIDDLE });
|
||||
if (userIsRoot) {
|
||||
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-root-label',
|
||||
text: userRealName }));
|
||||
messageBox.add(userLabel);
|
||||
} else {
|
||||
let userBox = new St.BoxLayout({ style_class: 'polkit-dialog-user-layout',
|
||||
vertical: false });
|
||||
messageBox.add(userBox);
|
||||
this._userIcon = new St.Icon();
|
||||
this._userIcon.hide();
|
||||
userBox.add(this._userIcon,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label',
|
||||
text: userRealName }));
|
||||
userBox.add(userLabel,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.MIDDLE });
|
||||
}
|
||||
|
||||
this._onUserChanged();
|
||||
|
||||
@@ -133,45 +137,41 @@ AuthenticationDialog.prototype = {
|
||||
this._passwordLabel = new St.Label(({ style_class: 'polkit-dialog-password-label' }));
|
||||
this._passwordBox.add(this._passwordLabel);
|
||||
this._passwordEntry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
|
||||
text: _(''),
|
||||
text: "",
|
||||
can_focus: true});
|
||||
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivate));
|
||||
this._passwordBox.add(this._passwordEntry,
|
||||
{expand: true });
|
||||
this._passwordBox.hide();
|
||||
|
||||
this._errorBox = new St.BoxLayout({ style_class: 'polkit-dialog-error-box' });
|
||||
messageBox.add(this._errorBox);
|
||||
let errorIcon = new St.Icon({ icon_name: 'dialog-error',
|
||||
icon_size: 24,
|
||||
style_class: 'polkit-dialog-error-icon' });
|
||||
this._errorBox.add(errorIcon, { y_align: St.Align.MIDDLE });
|
||||
this._errorMessage = new St.Label({ style_class: 'polkit-dialog-error-label' });
|
||||
this._errorMessage.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._errorMessage.clutter_text.line_wrap = true;
|
||||
this._errorBox.add(this._errorMessage, { expand: true,
|
||||
y_align: St.Align.MIDDLE,
|
||||
y_fill: true });
|
||||
this._errorBox.hide();
|
||||
this._errorMessageLabel = new St.Label({ style_class: 'polkit-dialog-error-label' });
|
||||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||||
messageBox.add(this._errorMessageLabel);
|
||||
this._errorMessageLabel.hide();
|
||||
|
||||
this._infoBox = new St.BoxLayout({ style_class: 'polkit-dialog-info-box' });
|
||||
messageBox.add(this._infoBox);
|
||||
let infoIcon = new St.Icon({ icon_name: 'dialog-information',
|
||||
icon_size: 24,
|
||||
style_class: 'polkit-dialog-info-icon' });
|
||||
this._infoBox.add(infoIcon, { y_align: St.Align.MIDDLE });
|
||||
this._infoMessage = new St.Label({ style_class: 'polkit-dialog-info-label'});
|
||||
this._infoMessage.clutter_text.line_wrap = true;
|
||||
this._infoBox.add(this._infoMessage, { expand: true,
|
||||
y_align: St.Align.MIDDLE,
|
||||
y_fill: true });
|
||||
this._infoBox.hide();
|
||||
this._infoMessageLabel = new St.Label({ style_class: 'polkit-dialog-info-label' });
|
||||
this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._infoMessageLabel.clutter_text.line_wrap = true;
|
||||
messageBox.add(this._infoMessageLabel);
|
||||
this._infoMessageLabel.hide();
|
||||
|
||||
this.setButtons([{ label: _('Cancel'),
|
||||
/* text is intentionally non-blank otherwise the height is not the same as for
|
||||
* infoMessage and errorMessageLabel - but it is still invisible because
|
||||
* gnome-shell.css sets the color to be transparent
|
||||
*/
|
||||
this._nullMessageLabel = new St.Label({ style_class: 'polkit-dialog-null-label',
|
||||
text: 'abc'});
|
||||
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._nullMessageLabel.clutter_text.line_wrap = true;
|
||||
messageBox.add(this._nullMessageLabel);
|
||||
this._nullMessageLabel.show();
|
||||
|
||||
this.setButtons([{ label: _("Cancel"),
|
||||
action: Lang.bind(this, this.cancel),
|
||||
key: Clutter.Escape
|
||||
},
|
||||
{ label: _('Authenticate'),
|
||||
{ label: _("Authenticate"),
|
||||
action: Lang.bind(this, this._onAuthenticateButtonPressed)
|
||||
}]);
|
||||
|
||||
@@ -186,16 +186,45 @@ AuthenticationDialog.prototype = {
|
||||
this._session.connect('request', Lang.bind(this, this._onSessionRequest));
|
||||
this._session.connect('show-error', Lang.bind(this, this._onSessionShowError));
|
||||
this._session.connect('show-info', Lang.bind(this, this._onSessionShowInfo));
|
||||
|
||||
// Delay focus grab to avoid ModalDialog stealing focus with
|
||||
// its buttons
|
||||
this.connect('opened',
|
||||
Lang.bind(this, function() {
|
||||
this._session.initiate();
|
||||
this._passwordEntry.grab_key_focus();
|
||||
}));
|
||||
},
|
||||
|
||||
_emitDone: function(keepVisible) {
|
||||
startAuthentication: function() {
|
||||
this._session.initiate();
|
||||
},
|
||||
|
||||
_ensureOpen: function() {
|
||||
// NOTE: ModalDialog.open() is safe to call if the dialog is
|
||||
// already open - it just returns true without side-effects
|
||||
if (!this.open(global.get_current_time())) {
|
||||
// This can fail if e.g. unable to get input grab
|
||||
//
|
||||
// In an ideal world this wouldn't happen (because the
|
||||
// Shell is in complete control of the session) but that's
|
||||
// just not how things work right now.
|
||||
//
|
||||
// One way to make this happen is by running 'sleep 3;
|
||||
// pkexec bash' and then opening a popup menu.
|
||||
//
|
||||
// We could add retrying if this turns out to be a problem
|
||||
|
||||
log('polkitAuthenticationAgent: Failed to show modal dialog.' +
|
||||
' Dismissing authentication request for action-id ' + this.actionId +
|
||||
' cookie ' + this._cookie);
|
||||
this._emitDone(false, true);
|
||||
}
|
||||
},
|
||||
|
||||
_emitDone: function(keepVisible, dismissed) {
|
||||
if (!this._doneEmitted) {
|
||||
this._doneEmitted = true;
|
||||
this.emit('done', keepVisible);
|
||||
this.emit('done', keepVisible, dismissed);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -204,8 +233,9 @@ AuthenticationDialog.prototype = {
|
||||
this._session.response(response);
|
||||
// When the user responds, dismiss already shown info and
|
||||
// error texts (if any)
|
||||
this._errorBox.hide();
|
||||
this._infoBox.hide();
|
||||
this._errorMessageLabel.hide();
|
||||
this._infoMessageLabel.hide();
|
||||
this._nullMessageLabel.show();
|
||||
},
|
||||
|
||||
_onAuthenticateButtonPressed: function() {
|
||||
@@ -213,14 +243,35 @@ AuthenticationDialog.prototype = {
|
||||
},
|
||||
|
||||
_onSessionCompleted: function(session, gainedAuthorization) {
|
||||
this._passwordBox.hide();
|
||||
this._emitDone(!gainedAuthorization);
|
||||
if (this._completed)
|
||||
return;
|
||||
|
||||
this._completed = true;
|
||||
|
||||
if (!gainedAuthorization) {
|
||||
/* Unless we are showing an existing error message from the PAM
|
||||
* module (the PAM module could be reporting the authentication
|
||||
* error providing authentication-method specific information),
|
||||
* show "Sorry, that didn't work. Please try again."
|
||||
*/
|
||||
if (!this._errorMessageLabel.visible && !this._wasDismissed) {
|
||||
/* Translators: "that didn't work" refers to the fact that the
|
||||
* requested authentication was not gained; this can happen
|
||||
* because of an authentication error (like invalid password),
|
||||
* for instance. */
|
||||
this._errorMessageLabel.set_text(_("Sorry, that didn\'t work. Please try again."));
|
||||
this._errorMessageLabel.show();
|
||||
this._infoMessageLabel.hide();
|
||||
this._nullMessageLabel.hide();
|
||||
}
|
||||
}
|
||||
this._emitDone(!gainedAuthorization, false);
|
||||
},
|
||||
|
||||
_onSessionRequest: function(session, request, echo_on) {
|
||||
// Cheap localization trick
|
||||
if (request == 'Password:')
|
||||
this._passwordLabel.set_text(_('Password:'));
|
||||
this._passwordLabel.set_text(_("Password:"));
|
||||
else
|
||||
this._passwordLabel.set_text(request);
|
||||
|
||||
@@ -232,45 +283,56 @@ AuthenticationDialog.prototype = {
|
||||
this._passwordBox.show();
|
||||
this._passwordEntry.set_text('');
|
||||
this._passwordEntry.grab_key_focus();
|
||||
this._ensureOpen();
|
||||
},
|
||||
|
||||
_onSessionShowError: function(session, text) {
|
||||
this._passwordEntry.set_text('');
|
||||
this._errorMessage.set_text(text);
|
||||
this._errorBox.show();
|
||||
this._errorMessageLabel.set_text(text);
|
||||
this._errorMessageLabel.show();
|
||||
this._infoMessageLabel.hide();
|
||||
this._nullMessageLabel.hide();
|
||||
this._ensureOpen();
|
||||
},
|
||||
|
||||
_onSessionShowInfo: function(session, text) {
|
||||
this._passwordEntry.set_text('');
|
||||
this._infoMessage.set_text(text);
|
||||
this._infoBox.show();
|
||||
this._infoMessageLabel.set_text(text);
|
||||
this._infoMessageLabel.show();
|
||||
this._errorMessageLabel.hide();
|
||||
this._nullMessageLabel.hide();
|
||||
this._ensureOpen();
|
||||
},
|
||||
|
||||
destroySession: function() {
|
||||
if (this._session) {
|
||||
this._session.cancel();
|
||||
if (!this._completed)
|
||||
this._session.cancel();
|
||||
this._session = null;
|
||||
}
|
||||
},
|
||||
|
||||
_onUserChanged: function() {
|
||||
if (this._user.is_loaded) {
|
||||
let iconFileName = this._user.get_icon_file();
|
||||
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'});
|
||||
if (this._userIcon) {
|
||||
let iconFileName = this._user.get_icon_file();
|
||||
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();
|
||||
}
|
||||
this._userIcon.set_gicon (icon);
|
||||
this._userIcon.show();
|
||||
}
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
this._wasDismissed = true;
|
||||
this.close(global.get_current_time());
|
||||
this._emitDone(false);
|
||||
this._emitDone(false, true);
|
||||
},
|
||||
|
||||
};
|
||||
@@ -290,42 +352,40 @@ AuthenticationAgent.prototype = {
|
||||
},
|
||||
|
||||
_onInitiate: function(nativeAgent, actionId, message, iconName, cookie, userNames) {
|
||||
this._currentDialog = new AuthenticationDialog(message, cookie, userNames);
|
||||
if (!this._currentDialog.open(global.get_current_time())) {
|
||||
// This can fail if e.g. unable to get input grab
|
||||
//
|
||||
// In an ideal world this wouldn't happen (because the
|
||||
// Shell is in complete control of the session) but that's
|
||||
// just not how things work right now.
|
||||
//
|
||||
// We could add retrying if this turns out to be a problem
|
||||
log('polkitAuthenticationAgent: Failed to show modal dialog');
|
||||
this._currentDialog.destroySession();
|
||||
this._currentDialog = null;
|
||||
this._native.complete()
|
||||
} else {
|
||||
this._currentDialog.connect('done', Lang.bind(this, this._onDialogDone));
|
||||
}
|
||||
this._currentDialog = new AuthenticationDialog(actionId, message, cookie, userNames);
|
||||
|
||||
// We actually don't want to open the dialog until we know for
|
||||
// sure that we're going to interact with the user. For
|
||||
// example, if the password for the identity to auth is blank
|
||||
// (which it will be on a live CD) then there will be no
|
||||
// conversation at all... of course, we don't *know* that
|
||||
// until we actually try it.
|
||||
//
|
||||
// See https://bugzilla.gnome.org/show_bug.cgi?id=643062 for more
|
||||
// discussion.
|
||||
|
||||
this._currentDialog.connect('done', Lang.bind(this, this._onDialogDone));
|
||||
this._currentDialog.startAuthentication();
|
||||
},
|
||||
|
||||
_onCancel: function(nativeAgent) {
|
||||
this._completeRequest(false);
|
||||
this._completeRequest(false, false);
|
||||
},
|
||||
|
||||
_onDialogDone: function(dialog, keepVisible) {
|
||||
this._completeRequest(keepVisible);
|
||||
_onDialogDone: function(dialog, keepVisible, dismissed) {
|
||||
this._completeRequest(keepVisible, dismissed);
|
||||
},
|
||||
|
||||
_reallyCompleteRequest: function() {
|
||||
_reallyCompleteRequest: function(dismissed) {
|
||||
this._currentDialog.close();
|
||||
this._currentDialog.destroySession();
|
||||
this._currentDialog = null;
|
||||
this._isCompleting = false;
|
||||
|
||||
this._native.complete()
|
||||
this._native.complete(dismissed)
|
||||
},
|
||||
|
||||
_completeRequest: function(keepVisible) {
|
||||
_completeRequest: function(keepVisible, wasDismissed) {
|
||||
if (this._isCompleting)
|
||||
return;
|
||||
|
||||
@@ -337,10 +397,10 @@ AuthenticationAgent.prototype = {
|
||||
Mainloop.timeout_add(2000,
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
this._reallyCompleteRequest();
|
||||
this._reallyCompleteRequest(wasDismissed);
|
||||
}));
|
||||
} else {
|
||||
this._reallyCompleteRequest();
|
||||
this._reallyCompleteRequest(wasDismissed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,9 +13,6 @@ const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
|
||||
|
||||
function PopupBaseMenuItem(params) {
|
||||
@@ -54,12 +51,14 @@ PopupBaseMenuItem.prototype = {
|
||||
}
|
||||
if (params.reactive && params.hover)
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChanged));
|
||||
if (params.reactive)
|
||||
if (params.reactive) {
|
||||
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||
this.actor.connect('key-focus-out', Lang.bind(this, this._onKeyFocusOut));
|
||||
}
|
||||
},
|
||||
|
||||
_onStyleChanged: function (actor) {
|
||||
this._spacing = actor.get_theme_node().get_length('spacing');
|
||||
this._spacing = Math.round(actor.get_theme_node().get_length('spacing'));
|
||||
},
|
||||
|
||||
_onButtonReleaseEvent: function (actor, event) {
|
||||
@@ -81,6 +80,10 @@ PopupBaseMenuItem.prototype = {
|
||||
this.setActive(true);
|
||||
},
|
||||
|
||||
_onKeyFocusOut: function (actor) {
|
||||
this.setActive(false);
|
||||
},
|
||||
|
||||
_onHoverChanged: function (actor) {
|
||||
this.setActive(actor.hover);
|
||||
},
|
||||
@@ -167,6 +170,8 @@ PopupBaseMenuItem.prototype = {
|
||||
cr.fill();
|
||||
},
|
||||
|
||||
// This returns column widths in logical order (i.e. from the dot
|
||||
// to the image), not in visual order (left to right)
|
||||
getColumnWidths: function() {
|
||||
let widths = [];
|
||||
for (let i = 0, col = 0; i < this._children.length; i++) {
|
||||
@@ -218,19 +223,36 @@ PopupBaseMenuItem.prototype = {
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let height = box.y2 - box.y1;
|
||||
let direction = this.actor.get_direction();
|
||||
|
||||
if (this._dot) {
|
||||
// The dot is placed outside box
|
||||
// one quarter of padding from the border of the container
|
||||
// (so 3/4 from the inner border)
|
||||
// (padding is box.x1)
|
||||
let dotBox = new Clutter.ActorBox();
|
||||
let dotWidth = Math.round(box.x1 / 2);
|
||||
|
||||
dotBox.x1 = Math.round(box.x1 / 4);
|
||||
dotBox.x2 = dotBox.x1 + dotWidth;
|
||||
if (direction == St.TextDirection.LTR) {
|
||||
dotBox.x1 = Math.round(box.x1 / 4);
|
||||
dotBox.x2 = dotBox.x1 + dotWidth;
|
||||
} else {
|
||||
dotBox.x2 = box.x2 + 3 * Math.round(box.x1 / 4);
|
||||
dotBox.x1 = dotBox.x2 - dotWidth;
|
||||
}
|
||||
dotBox.y1 = Math.round(box.y1 + (height - dotWidth) / 2);
|
||||
dotBox.y2 = dotBox.y1 + dotWidth;
|
||||
this._dot.allocate(dotBox, flags);
|
||||
}
|
||||
|
||||
let x = box.x1;
|
||||
let x;
|
||||
if (direction == St.TextDirection.LTR)
|
||||
x = box.x1;
|
||||
else
|
||||
x = box.x2;
|
||||
// if direction is ltr, x is the right edge of the last added
|
||||
// actor, and it's constantly increasing, whereas if rtl, x is
|
||||
// the left edge and it decreases
|
||||
for (let i = 0, col = 0; i < this._children.length; i++) {
|
||||
let child = this._children[i];
|
||||
let childBox = new Clutter.ActorBox();
|
||||
@@ -238,9 +260,12 @@ PopupBaseMenuItem.prototype = {
|
||||
let [minWidth, naturalWidth] = child.actor.get_preferred_width(-1);
|
||||
let availWidth, extraWidth;
|
||||
if (this._columnWidths) {
|
||||
if (child.span == -1)
|
||||
availWidth = box.x2 - x;
|
||||
else {
|
||||
if (child.span == -1) {
|
||||
if (direction == St.TextDirection.LTR)
|
||||
availWidth = box.x2 - x;
|
||||
else
|
||||
availWidth = x - box.x1;
|
||||
} else {
|
||||
availWidth = 0;
|
||||
for (let j = 0; j < child.span; j++)
|
||||
availWidth += this._columnWidths[col++];
|
||||
@@ -251,18 +276,36 @@ PopupBaseMenuItem.prototype = {
|
||||
extraWidth = 0;
|
||||
}
|
||||
|
||||
if (child.expand) {
|
||||
childBox.x1 = x;
|
||||
childBox.x2 = x + availWidth;
|
||||
} else if (child.align === St.Align.CENTER) {
|
||||
childBox.x1 = x + Math.round(extraWidth / 2);
|
||||
childBox.x2 = childBox.x1 + naturalWidth;
|
||||
} else if (child.align === St.Align.END) {
|
||||
childBox.x2 = x + availWidth;
|
||||
childBox.x1 = childBox.x2 - naturalWidth;
|
||||
if (direction == St.TextDirection.LTR) {
|
||||
if (child.expand) {
|
||||
childBox.x1 = x;
|
||||
childBox.x2 = x + availWidth;
|
||||
} else if (child.align === St.Align.CENTER) {
|
||||
childBox.x1 = x + Math.round(extraWidth / 2);
|
||||
childBox.x2 = childBox.x1 + naturalWidth;
|
||||
} else if (child.align === St.Align.END) {
|
||||
childBox.x2 = x + availWidth;
|
||||
childBox.x1 = childBox.x2 - naturalWidth;
|
||||
} else {
|
||||
childBox.x1 = x;
|
||||
childBox.x2 = x + naturalWidth;
|
||||
}
|
||||
} else {
|
||||
childBox.x1 = x;
|
||||
childBox.x2 = x + naturalWidth;
|
||||
if (child.expand) {
|
||||
childBox.x1 = x - availWidth;
|
||||
childBox.x2 = x;
|
||||
} else if (child.align === St.Align.CENTER) {
|
||||
childBox.x1 = x - Math.round(extraWidth / 2);
|
||||
childBox.x2 = childBox.x1 + naturalWidth;
|
||||
} else if (child.align === St.Align.END) {
|
||||
// align to the left
|
||||
childBox.x1 = x - availWidth;
|
||||
childBox.x2 = childBox.x1 + naturalWidth;
|
||||
} else {
|
||||
// align to the right
|
||||
childBox.x2 = x;
|
||||
childBox.x1 = x - naturalWidth;
|
||||
}
|
||||
}
|
||||
|
||||
let [minHeight, naturalHeight] = child.actor.get_preferred_height(-1);
|
||||
@@ -271,7 +314,10 @@ PopupBaseMenuItem.prototype = {
|
||||
|
||||
child.actor.allocate(childBox, flags);
|
||||
|
||||
x += availWidth + this._spacing;
|
||||
if (direction == St.TextDirection.LTR)
|
||||
x += availWidth + this._spacing;
|
||||
else
|
||||
x -= availWidth + this._spacing;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -449,7 +495,7 @@ PopupSliderMenuItem.prototype = {
|
||||
this._slider = new St.DrawingArea({ style_class: 'popup-slider-menu-item', reactive: true });
|
||||
this.addActor(this._slider, { span: -1, expand: true });
|
||||
this._slider.connect('repaint', Lang.bind(this, this._sliderRepaint));
|
||||
this._slider.connect('button-press-event', Lang.bind(this, this._startDragging));
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
this._releaseId = this._motionId = 0;
|
||||
@@ -479,12 +525,30 @@ PopupSliderMenuItem.prototype = {
|
||||
let sliderBorderColor = themeNode.get_color('-slider-border-color');
|
||||
let sliderColor = themeNode.get_color('-slider-background-color');
|
||||
|
||||
let sliderActiveBorderColor = themeNode.get_color('-slider-active-border-color');
|
||||
let sliderActiveColor = themeNode.get_color('-slider-active-background-color');
|
||||
|
||||
cr.setSourceRGBA (
|
||||
sliderActiveColor.red / 255,
|
||||
sliderActiveColor.green / 255,
|
||||
sliderActiveColor.blue / 255,
|
||||
sliderActiveColor.alpha / 255);
|
||||
cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth * this._value, sliderHeight);
|
||||
cr.fillPreserve();
|
||||
cr.setSourceRGBA (
|
||||
sliderActiveBorderColor.red / 255,
|
||||
sliderActiveBorderColor.green / 255,
|
||||
sliderActiveBorderColor.blue / 255,
|
||||
sliderActiveBorderColor.alpha / 255);
|
||||
cr.setLineWidth(sliderBorderWidth);
|
||||
cr.stroke();
|
||||
|
||||
cr.setSourceRGBA (
|
||||
sliderColor.red / 255,
|
||||
sliderColor.green / 255,
|
||||
sliderColor.blue / 255,
|
||||
sliderColor.alpha / 255);
|
||||
cr.rectangle(handleRadius, (height - sliderHeight) / 2, sliderWidth, sliderHeight);
|
||||
cr.rectangle(handleRadius + sliderWidth * this._value, (height - sliderHeight) / 2, sliderWidth * (1 - this._value), sliderHeight);
|
||||
cr.fillPreserve();
|
||||
cr.setSourceRGBA (
|
||||
sliderBorderColor.red / 255,
|
||||
@@ -684,28 +748,6 @@ PopupImageMenuItem.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function mod(a, b) {
|
||||
return (a + b) % b;
|
||||
}
|
||||
|
||||
function findNextInCycle(items, current, direction) {
|
||||
let cur;
|
||||
|
||||
if (items.length == 0)
|
||||
return current;
|
||||
else if (items.length == 1)
|
||||
return items[0];
|
||||
|
||||
if (current)
|
||||
cur = items.indexOf(current);
|
||||
else if (direction == 1)
|
||||
cur = items.length - 1;
|
||||
else
|
||||
cur = 0;
|
||||
|
||||
return items[mod(cur + direction, items.length)];
|
||||
}
|
||||
|
||||
function PopupMenuBase() {
|
||||
throw new TypeError('Trying to instantiate abstract class PopupMenuBase');
|
||||
}
|
||||
@@ -720,8 +762,19 @@ PopupMenuBase.prototype = {
|
||||
} else {
|
||||
this.box = new St.BoxLayout({ vertical: true });
|
||||
}
|
||||
this.box.connect_after('queue-relayout', Lang.bind(this, this._menuQueueRelayout));
|
||||
this.length = 0;
|
||||
|
||||
this.isOpen = false;
|
||||
|
||||
// If set, we don't send events (including crossing events) to the source actor
|
||||
// for the menu which causes its prelight state to freeze
|
||||
this.blockSourceEvents = false;
|
||||
|
||||
// Can be set while a menu is up to let all events through without special
|
||||
// menu handling useful for scrollbars in menus, and probably not otherwise.
|
||||
this.passEvents = false;
|
||||
|
||||
this._activeMenuItem = null;
|
||||
},
|
||||
|
||||
@@ -800,6 +853,8 @@ PopupMenuBase.prototype = {
|
||||
menuItem.connect('destroy', Lang.bind(this, function() {
|
||||
menuItem.disconnect(menuItem._subMenuActivateId);
|
||||
menuItem.disconnect(menuItem._subMenuActiveChangeId);
|
||||
|
||||
this.length--;
|
||||
}));
|
||||
} else if (menuItem instanceof PopupSubMenuMenuItem) {
|
||||
if (before_item == null)
|
||||
@@ -816,12 +871,16 @@ PopupMenuBase.prototype = {
|
||||
this._connectItemSignals(menuItem);
|
||||
else
|
||||
throw TypeError("Invalid argument to PopupMenuBase.addMenuItem()");
|
||||
|
||||
this.length++;
|
||||
},
|
||||
|
||||
getColumnWidths: function() {
|
||||
let columnWidths = [];
|
||||
let items = this.box.get_children();
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
if (!items[i].visible)
|
||||
continue;
|
||||
if (items[i]._delegate instanceof PopupBaseMenuItem || items[i]._delegate instanceof PopupMenuBase) {
|
||||
let itemColumnWidths = items[i]._delegate.getColumnWidths();
|
||||
for (let j = 0; j < itemColumnWidths.length; j++) {
|
||||
@@ -841,6 +900,16 @@ PopupMenuBase.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// Because of the above column-width funniness, we need to do a
|
||||
// queue-relayout on every item whenever the menu itself changes
|
||||
// size, to force clutter to drop its cached size requests. (The
|
||||
// menuitems will in turn call queue_relayout on their parent, the
|
||||
// menu, but that call will be a no-op since the menu already
|
||||
// has a relayout queued, so we won't get stuck in a loop.
|
||||
_menuQueueRelayout: function() {
|
||||
this.box.get_children().map(function (actor) { actor.queue_relayout(); });
|
||||
},
|
||||
|
||||
addActor: function(actor) {
|
||||
this.box.add(actor);
|
||||
},
|
||||
@@ -861,17 +930,6 @@ PopupMenuBase.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
activateFirst: function() {
|
||||
let children = this.box.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let actor = children[i];
|
||||
if (actor._delegate && actor._delegate instanceof PopupBaseMenuItem && actor.visible && actor.reactive) {
|
||||
actor._delegate.setActive(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if (this.isOpen)
|
||||
this.close(true);
|
||||
@@ -909,6 +967,8 @@ PopupMenu.prototype = {
|
||||
this.actor = this._boxPointer.actor;
|
||||
this.actor._delegate = this;
|
||||
this.actor.style_class = 'popup-menu-boxpointer';
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
|
||||
this._boxWrapper = new Shell.GenericContainer();
|
||||
this._boxWrapper.connect('get-preferred-width', Lang.bind(this, this._boxGetPreferredWidth));
|
||||
this._boxWrapper.connect('get-preferred-height', Lang.bind(this, this._boxGetPreferredHeight));
|
||||
@@ -937,6 +997,15 @@ PopupMenu.prototype = {
|
||||
this.box.allocate(box, flags);
|
||||
},
|
||||
|
||||
_onKeyPressEvent: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.Escape) {
|
||||
this.close(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
setArrowOrigin: function(origin) {
|
||||
this._boxPointer.setArrowOrigin(origin);
|
||||
},
|
||||
@@ -975,45 +1044,109 @@ PopupSubMenu.prototype = {
|
||||
__proto__: PopupMenuBase.prototype,
|
||||
|
||||
_init: function(sourceActor, sourceArrow) {
|
||||
PopupMenuBase.prototype._init.call(this, sourceActor, 'popup-sub-menu');
|
||||
PopupMenuBase.prototype._init.call(this, sourceActor);
|
||||
|
||||
this._arrow = sourceArrow;
|
||||
this._arrow.rotation_center_z_gravity = Clutter.Gravity.CENTER;
|
||||
|
||||
this.actor = this.box;
|
||||
// Since a function of a submenu might be to provide a "More.." expander
|
||||
// with long content, we make it scrollable - the scrollbar will only take
|
||||
// effect if a CSS max-height is set on the top menu.
|
||||
this.actor = new St.ScrollView({ style_class: 'popup-sub-menu',
|
||||
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||
vscrollbar_policy: Gtk.PolicyType.NEVER });
|
||||
|
||||
// StScrollbar plays dirty tricks with events, calling
|
||||
// clutter_set_motion_events_enabled (FALSE) during the scroll; this
|
||||
// confuses our event tracking, so we just turn it off during the
|
||||
// scroll.
|
||||
let vscroll = this.actor.get_vscroll_bar();
|
||||
vscroll.connect('scroll-start',
|
||||
Lang.bind(this, function() {
|
||||
let topMenu = this._getTopMenu();
|
||||
if (topMenu)
|
||||
topMenu.passEvents = true;
|
||||
}));
|
||||
vscroll.connect('scroll-stop',
|
||||
Lang.bind(this, function() {
|
||||
let topMenu = this._getTopMenu();
|
||||
if (topMenu)
|
||||
topMenu.passEvents = false;
|
||||
}));
|
||||
|
||||
this.actor.add_actor(this.box);
|
||||
this.actor._delegate = this;
|
||||
this.actor.clip_to_allocation = true;
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
_getTopMenu: function() {
|
||||
let actor = this.actor.get_parent();
|
||||
while (actor) {
|
||||
if (actor._delegate && actor._delegate instanceof PopupMenu)
|
||||
return actor._delegate;
|
||||
|
||||
actor = actor.get_parent();
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_needsScrollbar: function() {
|
||||
let topMenu = this._getTopMenu();
|
||||
let [topMinHeight, topNaturalHeight] = topMenu.actor.get_preferred_height(-1);
|
||||
let topThemeNode = topMenu.actor.get_theme_node();
|
||||
|
||||
let topMaxHeight = topThemeNode.get_max_height();
|
||||
return topMaxHeight >= 0 && topNaturalHeight >= topMaxHeight;
|
||||
},
|
||||
|
||||
open: function(animate) {
|
||||
if (this.isOpen)
|
||||
return;
|
||||
|
||||
this.isOpen = true;
|
||||
|
||||
// we don't implement the !animate case because that doesn't
|
||||
// currently get used...
|
||||
|
||||
let [naturalHeight, minHeight] = this.actor.get_preferred_height(-1);
|
||||
this.actor.height = 0;
|
||||
this.actor.show();
|
||||
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
|
||||
Tweener.addTween(this.actor,
|
||||
{ _arrow_rotation: 90,
|
||||
height: naturalHeight,
|
||||
time: 0.25,
|
||||
onUpdateScope: this,
|
||||
onUpdate: function() {
|
||||
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
|
||||
},
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
this.actor.set_height(-1);
|
||||
this.emit('open-state-changed', true);
|
||||
}
|
||||
});
|
||||
|
||||
let needsScrollbar = this._needsScrollbar();
|
||||
|
||||
// St.ScrollView always requests space horizontally for a possible vertical
|
||||
// scrollbar if in AUTOMATIC mode. Doing better would require implementation
|
||||
// of width-for-height in St.BoxLayout and St.ScrollView. This looks bad
|
||||
// when we *don't* need it, so turn off the scrollbar when that's true.
|
||||
// Dynamic changes in whether we need it aren't handled properly.
|
||||
this.actor.vscrollbar_policy =
|
||||
needsScrollbar ? Gtk.PolicyType.AUTOMATIC : Gtk.PolicyType.NEVER;
|
||||
|
||||
// It looks funny if we animate with a scrollbar (at what point is
|
||||
// the scrollbar added?) so just skip that case
|
||||
if (animate && needsScrollbar)
|
||||
animate = false;
|
||||
|
||||
if (animate) {
|
||||
let [minHeight, naturalHeight] = this.actor.get_preferred_height(-1);
|
||||
this.actor.height = 0;
|
||||
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
|
||||
Tweener.addTween(this.actor,
|
||||
{ _arrow_rotation: 90,
|
||||
height: naturalHeight,
|
||||
time: 0.25,
|
||||
onUpdateScope: this,
|
||||
onUpdate: function() {
|
||||
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
|
||||
},
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
this.actor.set_height(-1);
|
||||
this.emit('open-state-changed', true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._arrow.rotation_angle_z = 90;
|
||||
this.emit('open-state-changed', true);
|
||||
}
|
||||
},
|
||||
|
||||
close: function(animate) {
|
||||
@@ -1025,6 +1158,9 @@ PopupSubMenu.prototype = {
|
||||
if (this._activeMenuItem)
|
||||
this._activeMenuItem.setActive(false);
|
||||
|
||||
if (animate && this._needsScrollbar())
|
||||
animate = false;
|
||||
|
||||
if (animate) {
|
||||
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
|
||||
Tweener.addTween(this.actor,
|
||||
@@ -1127,11 +1263,17 @@ PopupSubMenuMenuItem.prototype = {
|
||||
},
|
||||
|
||||
_onKeyPressEvent: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.KEY_Right) {
|
||||
let symbol = event.get_key_symbol();
|
||||
|
||||
if (symbol == Clutter.KEY_Right) {
|
||||
this.menu.open(true);
|
||||
this.menu.activateFirst();
|
||||
this.menu.actor.navigate_focus(null, Gtk.DirectionType.DOWN, false);
|
||||
return true;
|
||||
} else if (symbol == Clutter.KEY_Left && this.menu.isOpen) {
|
||||
this.menu.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return PopupBaseMenuItem.prototype._onKeyPressEvent.call(this, actor, event);
|
||||
},
|
||||
|
||||
@@ -1158,12 +1300,13 @@ PopupMenuManager.prototype = {
|
||||
this.grabbed = false;
|
||||
|
||||
this._eventCaptureId = 0;
|
||||
this._keyPressEventId = 0;
|
||||
this._enterEventId = 0;
|
||||
this._leaveEventId = 0;
|
||||
this._keyFocusNotifyId = 0;
|
||||
this._activeMenu = null;
|
||||
this._menus = [];
|
||||
this._preGrabInputMode = null;
|
||||
this._grabbedFromKeynav = false;
|
||||
},
|
||||
|
||||
addMenu: function(menu, position) {
|
||||
@@ -1172,15 +1315,13 @@ PopupMenuManager.prototype = {
|
||||
openStateChangeId: menu.connect('open-state-changed', Lang.bind(this, this._onMenuOpenState)),
|
||||
destroyId: menu.connect('destroy', Lang.bind(this, this._onMenuDestroy)),
|
||||
enterId: 0,
|
||||
focusInId: 0,
|
||||
focusOutId: 0
|
||||
focusInId: 0
|
||||
};
|
||||
|
||||
let source = menu.sourceActor;
|
||||
if (source) {
|
||||
menudata.enterId = source.connect('enter-event', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
|
||||
menudata.focusInId = source.connect('key-focus-in', Lang.bind(this, function() { this._onMenuSourceEnter(menu); }));
|
||||
menudata.focusOutId = source.connect('key-focus-out', Lang.bind(this, function() { this._onKeyFocusOut(menu); }));
|
||||
}
|
||||
|
||||
if (position == undefined)
|
||||
@@ -1205,8 +1346,6 @@ PopupMenuManager.prototype = {
|
||||
menu.sourceActor.disconnect(menudata.enterId);
|
||||
if (menudata.focusInId)
|
||||
menu.sourceActor.disconnect(menudata.focusInId);
|
||||
if (menudata.focusOutId)
|
||||
menu.sourceActor.disconnect(menudata.focusOutId);
|
||||
|
||||
this._menus.splice(position, 1);
|
||||
},
|
||||
@@ -1215,10 +1354,10 @@ PopupMenuManager.prototype = {
|
||||
Main.pushModal(this._owner.actor);
|
||||
|
||||
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
|
||||
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
// captured-event doesn't see enter/leave events
|
||||
this._enterEventId = global.stage.connect('enter-event', Lang.bind(this, this._onEventCapture));
|
||||
this._leaveEventId = global.stage.connect('leave-event', Lang.bind(this, this._onEventCapture));
|
||||
this._keyFocusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
||||
|
||||
this.grabbed = true;
|
||||
},
|
||||
@@ -1226,49 +1365,47 @@ PopupMenuManager.prototype = {
|
||||
_ungrab: function() {
|
||||
global.stage.disconnect(this._eventCaptureId);
|
||||
this._eventCaptureId = 0;
|
||||
global.stage.disconnect(this._keyPressEventId);
|
||||
this._keyPressEventId = 0;
|
||||
global.stage.disconnect(this._enterEventId);
|
||||
this._enterEventId = 0;
|
||||
global.stage.disconnect(this._leaveEventId);
|
||||
this._leaveEventId = 0;
|
||||
global.stage.disconnect(this._keyFocusNotifyId);
|
||||
this._keyFocusNotifyId = 0;
|
||||
|
||||
this.grabbed = false;
|
||||
Main.popModal(this._owner.actor);
|
||||
},
|
||||
|
||||
_onMenuOpenState: function(menu, open) {
|
||||
if (open)
|
||||
this._activeMenu = menu;
|
||||
|
||||
// Check what the focus was before calling pushModal/popModal
|
||||
let focus = global.stage.key_focus;
|
||||
let hadFocus = focus && this._activeMenuContains(focus);
|
||||
|
||||
if (open) {
|
||||
if (!this.grabbed) {
|
||||
this._preGrabInputMode = global.stage_input_mode;
|
||||
this._grabbedFromKeynav = hadFocus;
|
||||
this._grab();
|
||||
}
|
||||
this._activeMenu = menu;
|
||||
|
||||
// if the focus is not already associated with the menu,
|
||||
// then focus the menu
|
||||
let focus = global.stage.key_focus;
|
||||
if (!this._activeMenuContains(focus))
|
||||
menu.sourceActor.grab_key_focus();
|
||||
if (hadFocus)
|
||||
focus.grab_key_focus();
|
||||
else
|
||||
menu.actor.grab_key_focus();
|
||||
} else if (menu == this._activeMenu) {
|
||||
let focus = global.stage.key_focus;
|
||||
let fromActive = this._activeMenuContains(focus);
|
||||
|
||||
if (this.grabbed)
|
||||
this._ungrab();
|
||||
this._activeMenu = null;
|
||||
|
||||
// If keynav was in effect before we grabbed, then we need
|
||||
// to properly re-establish it after we ungrab. (popModal
|
||||
// will have unset the focus.) If some part of the menu
|
||||
// was focused at the time of the ungrab then focus its
|
||||
// sourceActor. Otherwise just reset the focus to where it
|
||||
// was right before the ungrab.
|
||||
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED) {
|
||||
global.stage_input_mode = Shell.StageInputMode.FOCUSED;
|
||||
if (fromActive)
|
||||
if (this._grabbedFromKeynav) {
|
||||
if (this._preGrabInputMode == Shell.StageInputMode.FOCUSED)
|
||||
global.stage_input_mode = Shell.StageInputMode.FOCUSED;
|
||||
if (hadFocus && menu.sourceActor)
|
||||
menu.sourceActor.grab_key_focus();
|
||||
else
|
||||
else if (focus)
|
||||
focus.grab_key_focus();
|
||||
}
|
||||
}
|
||||
@@ -1296,29 +1433,20 @@ PopupMenuManager.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
_onKeyFocusOut: function(menu) {
|
||||
if (!this.grabbed || menu != this._activeMenu)
|
||||
_onKeyFocusChanged: function() {
|
||||
if (!this.grabbed || !this._activeMenu)
|
||||
return;
|
||||
|
||||
// We want to close the menu if the focus has moved somewhere
|
||||
// other than inside the menu or to another menu's sourceActor.
|
||||
// Unfortunately, when key-focus-out is emitted,
|
||||
// stage.key_focus will be null. So we have to wait until
|
||||
// after it emits the key-focus-in as well.
|
||||
let id = global.stage.connect('notify::key-focus', Lang.bind(this,
|
||||
function () {
|
||||
global.stage.disconnect(id);
|
||||
let focus = global.stage.key_focus;
|
||||
if (focus) {
|
||||
if (this._activeMenuContains(focus))
|
||||
return;
|
||||
if (focus._delegate && focus._delegate.menu &&
|
||||
this._findMenu(focus._delegate.menu) != -1)
|
||||
return;
|
||||
}
|
||||
|
||||
if (menu != this._activeMenu)
|
||||
return;
|
||||
|
||||
let focus = global.stage.key_focus;
|
||||
if (!focus || this._activeMenuContains(focus))
|
||||
return;
|
||||
if (focus._delegate && this._findMenu(focus._delegate.menu) != -1)
|
||||
return;
|
||||
menu.close(true);
|
||||
}));
|
||||
this._closeMenu();
|
||||
},
|
||||
|
||||
_onMenuDestroy: function(menu) {
|
||||
@@ -1335,14 +1463,20 @@ PopupMenuManager.prototype = {
|
||||
return this._activeMenuContains(event.get_source());
|
||||
},
|
||||
|
||||
_eventIsOnAnyMenuSource: function(event) {
|
||||
_shouldBlockEvent: function(event) {
|
||||
let src = event.get_source();
|
||||
|
||||
if (this._activeMenu != null && this._activeMenu.actor.contains(src))
|
||||
return false;
|
||||
|
||||
for (let i = 0; i < this._menus.length; i++) {
|
||||
let menu = this._menus[i].menu;
|
||||
if (menu.sourceActor && menu.sourceActor.contains(src))
|
||||
return true;
|
||||
if (menu.sourceActor && !menu.blockSourceEvents && menu.sourceActor.contains(src)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_findMenu: function(item) {
|
||||
@@ -1354,18 +1488,6 @@ PopupMenuManager.prototype = {
|
||||
return -1;
|
||||
},
|
||||
|
||||
_nextMenu: function(pos, direction) {
|
||||
for (let i = 1; i < this._menus.length; i++) {
|
||||
let candidate = mod(pos + i * direction, this._menus.length);
|
||||
let menu = this._menus[candidate].menu;
|
||||
if (!menu.sourceActor || menu.sourceActor.visible)
|
||||
return menu;
|
||||
}
|
||||
// no menu is found? this should not happen
|
||||
// anyway stay on current menu
|
||||
return this._menus[pos];
|
||||
},
|
||||
|
||||
_onEventCapture: function(actor, event) {
|
||||
if (!this.grabbed)
|
||||
return false;
|
||||
@@ -1374,8 +1496,12 @@ PopupMenuManager.prototype = {
|
||||
this._owner.menuEventFilter(event))
|
||||
return true;
|
||||
|
||||
if (this._activeMenu != null && this._activeMenu.passEvents)
|
||||
return false;
|
||||
|
||||
let activeMenuContains = this._eventIsOnActiveMenu(event);
|
||||
let eventType = event.type();
|
||||
|
||||
if (eventType == Clutter.EventType.BUTTON_RELEASE) {
|
||||
if (activeMenuContains) {
|
||||
return false;
|
||||
@@ -1383,38 +1509,16 @@ PopupMenuManager.prototype = {
|
||||
this._closeMenu();
|
||||
return true;
|
||||
}
|
||||
} else if ((eventType == Clutter.EventType.BUTTON_PRESS && !activeMenuContains)
|
||||
|| (eventType == Clutter.EventType.KEY_PRESS && event.get_key_symbol() == Clutter.Escape)) {
|
||||
} else if (eventType == Clutter.EventType.BUTTON_PRESS && !activeMenuContains) {
|
||||
this._closeMenu();
|
||||
return true;
|
||||
} else if (activeMenuContains || this._eventIsOnAnyMenuSource(event)) {
|
||||
} else if (!this._shouldBlockEvent(event)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_onKeyPressEvent: function(actor, event) {
|
||||
if (!this.grabbed || !this._activeMenu)
|
||||
return false;
|
||||
if (!this._eventIsOnActiveMenu(event))
|
||||
return false;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Left || symbol == Clutter.Right) {
|
||||
let direction = symbol == Clutter.Right ? 1 : -1;
|
||||
let pos = this._findMenu(this._activeMenu);
|
||||
let next = this._nextMenu(pos, direction);
|
||||
if (next != this._activeMenu) {
|
||||
this._changeMenu(next);
|
||||
next.activateFirst();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_closeMenu: function() {
|
||||
if (this._activeMenu != null)
|
||||
this._activeMenu.close(true);
|
||||
|
||||
@@ -8,8 +8,6 @@ const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
@@ -22,6 +20,9 @@ const MAX_FILE_DELETED_BEFORE_INVALID = 10;
|
||||
|
||||
const HISTORY_KEY = 'command-history';
|
||||
|
||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
const DISABLE_COMMAND_LINE_KEY = 'disable-command-line';
|
||||
|
||||
const DIALOG_GROW_TIME = 0.1;
|
||||
|
||||
function CommandCompleter() {
|
||||
@@ -167,6 +168,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
_init : function() {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' });
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||
global.settings.connect('changed::development-tools', Lang.bind(this, function () {
|
||||
this._enableInternalCommands = global.settings.get_boolean('development-tools');
|
||||
}));
|
||||
@@ -206,10 +208,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
|
||||
this._entryText = entry.clutter_text;
|
||||
this.contentLayout.add(entry, { y_align: St.Align.START });
|
||||
this.connect('opened',
|
||||
Lang.bind(this, function() {
|
||||
this._entryText.grab_key_focus();
|
||||
}));
|
||||
this.setInitialKeyFocus(this._entryText);
|
||||
|
||||
this._errorBox = new St.BoxLayout({ style_class: 'run-dialog-error-box' });
|
||||
|
||||
@@ -234,31 +233,26 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
this._commandCompleter = new CommandCompleter();
|
||||
this._group.connect('notify::visible', Lang.bind(this._commandCompleter, this._commandCompleter.update));
|
||||
|
||||
this._history = new History.HistoryManager(HISTORY_KEY);
|
||||
this._history.connect('changed', Lang.bind(this, function(history, text) {
|
||||
this._entryText.set_text(text);
|
||||
}));
|
||||
|
||||
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
|
||||
entry: this._entryText });
|
||||
this._entryText.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Down) {
|
||||
this._history.nextItem(o.get_text());
|
||||
return true;
|
||||
}
|
||||
if (symbol == Clutter.Up) {
|
||||
this._history.prevItem(o.get_text());
|
||||
return true;
|
||||
}
|
||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||
this.popModal();
|
||||
if (Shell.get_event_state(e) & Clutter.ModifierType.CONTROL_MASK)
|
||||
this._run(o.get_text(), true);
|
||||
else
|
||||
this._run(o.get_text(), false);
|
||||
if (!this._commandError)
|
||||
this.close(global.get_current_time());
|
||||
this.close();
|
||||
else {
|
||||
if (!this.pushModal())
|
||||
this.close();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (symbol == Clutter.Escape) {
|
||||
this.close(global.get_current_time());
|
||||
this.close();
|
||||
return true;
|
||||
}
|
||||
if (symbol == Clutter.slash) {
|
||||
@@ -364,6 +358,9 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
this._entryText.set_text('');
|
||||
this._commandError = false;
|
||||
|
||||
if (this._lockdownSettings.get_boolean(DISABLE_COMMAND_LINE_KEY))
|
||||
return;
|
||||
|
||||
ModalDialog.ModalDialog.prototype.open.call(this);
|
||||
},
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
@@ -68,6 +69,104 @@ function waitLeisure() {
|
||||
};
|
||||
}
|
||||
|
||||
const PerfHelperIface = {
|
||||
name: 'org.gnome.Shell.PerfHelper',
|
||||
methods: [{ name: 'CreateWindow', inSignature: 'iibb', outSignature: '' },
|
||||
{ name: 'WaitWindows', inSignature: '', outSignature: '' },
|
||||
{ name: 'DestroyWindows', inSignature: '', outSignature: ''}]
|
||||
};
|
||||
|
||||
const PerfHelper = function () {
|
||||
this._init();
|
||||
};
|
||||
|
||||
PerfHelper.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this, 'org.gnome.Shell.PerfHelper', '/org/gnome/Shell/PerfHelper');
|
||||
}
|
||||
};
|
||||
|
||||
DBus.proxifyPrototype(PerfHelper.prototype, PerfHelperIface);
|
||||
|
||||
let _perfHelper = null;
|
||||
function _getPerfHelper() {
|
||||
if (_perfHelper == null)
|
||||
_perfHelper = new PerfHelper();
|
||||
|
||||
return _perfHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* createTestWindow:
|
||||
* @width: width of window, in pixels
|
||||
* @height: height of window, in pixels
|
||||
* @alpha: whether the window should be alpha transparent
|
||||
* @maximized: whethe the window should be created maximized
|
||||
*
|
||||
* Creates a window using gnome-shell-perf-helper for testing purposes.
|
||||
* While this function can be used with yield in an automation
|
||||
* script to pause until the D-Bus call to the helper process returns,
|
||||
* because of the normal X asynchronous mapping process, to actually wait
|
||||
* until the window has been mapped and exposed, use waitTestWindows().
|
||||
*/
|
||||
function createTestWindow(width, height, alpha, maximized) {
|
||||
let cb;
|
||||
let perfHelper = _getPerfHelper();
|
||||
|
||||
perfHelper.CreateWindowRemote(width, height, alpha, maximized,
|
||||
function(result, excp) {
|
||||
if (cb)
|
||||
cb();
|
||||
});
|
||||
|
||||
return function(callback) {
|
||||
cb = callback;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* waitTestWindows:
|
||||
*
|
||||
* Used within an automation script to pause until all windows previously
|
||||
* created with createTestWindow have been mapped and exposed.
|
||||
*/
|
||||
function waitTestWindows() {
|
||||
let cb;
|
||||
let perfHelper = _getPerfHelper();
|
||||
|
||||
perfHelper.WaitWindowsRemote(function(result, excp) {
|
||||
if (cb)
|
||||
cb();
|
||||
});
|
||||
|
||||
return function(callback) {
|
||||
cb = callback;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* destroyTestWindows:
|
||||
*
|
||||
* Destroys all windows previously created with createTestWindow().
|
||||
* While this function can be used with yield in an automation
|
||||
* script to pause until the D-Bus call to the helper process returns,
|
||||
* this doesn't guarantee that Mutter has actually finished the destroy
|
||||
* process because of normal X asynchronicity.
|
||||
*/
|
||||
function destroyTestWindows() {
|
||||
let cb;
|
||||
let perfHelper = _getPerfHelper();
|
||||
|
||||
perfHelper.DestroyWindowsRemote(function(result, excp) {
|
||||
if (cb)
|
||||
cb();
|
||||
});
|
||||
|
||||
return function(callback) {
|
||||
cb = callback;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* defineScriptEvent
|
||||
* @name: The event will be called script.<name>
|
||||
@@ -147,8 +246,8 @@ function _collect(scriptModule, outputFile) {
|
||||
Shell.write_string_to_stream(out, '"events":\n');
|
||||
Shell.PerfLog.get_default().dump_events(out);
|
||||
|
||||
let monitors = global.get_monitors()
|
||||
let primary = global.get_primary_monitor()
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
Shell.write_string_to_stream(out, ',\n"monitors":\n[');
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let monitor = monitors[i];
|
||||
@@ -167,7 +266,21 @@ function _collect(scriptModule, outputFile) {
|
||||
Shell.write_string_to_stream(out, ',\n"metrics":\n[ ');
|
||||
let first = true;
|
||||
for (let name in scriptModule.METRICS) {
|
||||
let metric = scriptModule.METRICS[name];
|
||||
let metric = scriptModule.METRICS[name];
|
||||
// Extra checks here because JSON.stringify generates
|
||||
// invalid JSON for undefined values
|
||||
if (metric.description == null) {
|
||||
log("Error: No description found for metric " + name);
|
||||
continue;
|
||||
}
|
||||
if (metric.units == null) {
|
||||
log("Error: No units found for metric " + name);
|
||||
continue;
|
||||
}
|
||||
if (metric.value == null) {
|
||||
log("Error: No value found for metric " + name);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!first)
|
||||
Shell.write_string_to_stream(out, ',\n ');
|
||||
|
||||
@@ -7,16 +7,11 @@ const Signals = imports.signals;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const DISABLED_OPEN_SEARCH_PROVIDERS_KEY = 'disabled-open-search-providers';
|
||||
|
||||
const RESULT_ICON_SIZE = 48;
|
||||
|
||||
// Not currently referenced by the search API, but
|
||||
// this enumeration can be useful for provider
|
||||
// implementations.
|
||||
@@ -165,8 +160,9 @@ SearchProvider.prototype = {
|
||||
* getResultInfo:
|
||||
* @id: Result identifier string
|
||||
*
|
||||
* Return an object with 'id', 'name', (both strings) and 'icon' (Clutter.Texture)
|
||||
* properties which describe the given search result.
|
||||
* Return an object with 'id', 'name', (both strings) and 'createIcon'
|
||||
* (function(size) returning a Clutter.Texture) properties which describe
|
||||
* the given search result.
|
||||
*/
|
||||
getResultMeta: function(id) {
|
||||
throw new Error('Not implemented');
|
||||
@@ -209,17 +205,6 @@ SearchProvider.prototype = {
|
||||
*/
|
||||
activateResult: function(id) {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
/**
|
||||
* expandSearch:
|
||||
*
|
||||
* Called when the user clicks on the header for this
|
||||
* search section. Should typically launch an external program
|
||||
* displaying search results for that item type.
|
||||
*/
|
||||
expandSearch: function(terms) {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(SearchProvider.prototype);
|
||||
@@ -286,24 +271,18 @@ OpenSearchSystem.prototype = {
|
||||
},
|
||||
|
||||
_addProvider: function(fileName) {
|
||||
let file = Gio.file_new_for_path(global.datadir + '/search_providers/' + fileName);
|
||||
let source = '';
|
||||
|
||||
file.load_contents_async(null, Lang.bind(this, function (obj, res) {
|
||||
let [success, source] = file.load_contents_finish(res);
|
||||
if (source) {
|
||||
let [success, name, url, langs, icon_uri] = global.parse_search_provider(source);
|
||||
let provider ={ name: name,
|
||||
url: url,
|
||||
id: this._providers.length,
|
||||
icon_uri: icon_uri,
|
||||
langs: langs };
|
||||
if (this._checkSupportedProviderLanguage(provider)) {
|
||||
this._providers.push(provider);
|
||||
this.emit('changed');
|
||||
}
|
||||
}
|
||||
}));
|
||||
let path = global.datadir + '/search_providers/' + fileName;
|
||||
let source = Shell.get_file_contents_utf8_sync(path);
|
||||
let [success, name, url, langs, icon_uri] = Shell.parse_search_provider(source);
|
||||
let provider ={ name: name,
|
||||
url: url,
|
||||
id: this._providers.length,
|
||||
icon_uri: icon_uri,
|
||||
langs: langs };
|
||||
if (this._checkSupportedProviderLanguage(provider)) {
|
||||
this._providers.push(provider);
|
||||
this.emit('changed');
|
||||
}
|
||||
},
|
||||
|
||||
_refresh: function() {
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
@@ -13,7 +12,7 @@ const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const Search = imports.ui.search;
|
||||
|
||||
const MAX_SEARCH_RESULTS_ROWS = 2;
|
||||
const MAX_SEARCH_RESULTS_ROWS = 1;
|
||||
|
||||
|
||||
function SearchResult(provider, metaInfo, terms) {
|
||||
@@ -36,10 +35,9 @@ SearchResult.prototype = {
|
||||
reactive: true,
|
||||
track_hover: true });
|
||||
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||
{ createIcon: Lang.bind(this, function(size) {
|
||||
return this.metaInfo['icon'];
|
||||
})});
|
||||
{ createIcon: this.metaInfo['createIcon'] });
|
||||
content.set_child(icon.actor);
|
||||
this.actor.label_actor = icon.label;
|
||||
}
|
||||
this._content = content;
|
||||
this.actor.set_child(content);
|
||||
@@ -51,6 +49,10 @@ SearchResult.prototype = {
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endItemDrag(this);
|
||||
@@ -74,11 +76,12 @@ SearchResult.prototype = {
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
return this.metaInfo['icon'];
|
||||
// not exactly right, but alignment problems are hard to notice
|
||||
return this._content;
|
||||
},
|
||||
|
||||
getDragActor: function(stageX, stageY) {
|
||||
return new Clutter.Clone({ source: this.metaInfo['icon'] });
|
||||
return this.metaInfo['createIcon'](Main.overview.dash.iconSize);
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch: function(params) {
|
||||
@@ -102,8 +105,30 @@ GridSearchResults.prototype = {
|
||||
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
|
||||
xAlign: St.Align.START });
|
||||
this.actor = new St.Bin({ x_align: St.Align.START });
|
||||
|
||||
this.actor.set_child(this._grid.actor);
|
||||
this.selectionIndex = -1;
|
||||
this._width = 0;
|
||||
this.actor.connect('notify::width', Lang.bind(this, function() {
|
||||
this._width = this.actor.width;
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||
this._tryAddResults();
|
||||
}));
|
||||
}));
|
||||
this._notDisplayedResult = [];
|
||||
this._terms = [];
|
||||
},
|
||||
|
||||
_tryAddResults: function() {
|
||||
let canDisplay = this._grid.childrenInRow(this._width) * MAX_SEARCH_RESULTS_ROWS
|
||||
- this._grid.visibleItemsCount();
|
||||
|
||||
for (let i = Math.min(this._notDisplayedResult.length, canDisplay); i > 0; i--) {
|
||||
let result = this._notDisplayedResult.shift();
|
||||
let meta = this.provider.getResultMeta(result);
|
||||
let display = new SearchResult(this.provider, meta, this._terms);
|
||||
this._grid.addItem(display.actor);
|
||||
}
|
||||
},
|
||||
|
||||
getVisibleResultCount: function() {
|
||||
@@ -111,15 +136,15 @@ GridSearchResults.prototype = {
|
||||
},
|
||||
|
||||
renderResults: function(results, terms) {
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let result = results[i];
|
||||
let meta = this.provider.getResultMeta(result);
|
||||
let display = new SearchResult(this.provider, meta, terms);
|
||||
this._grid.addItem(display.actor);
|
||||
}
|
||||
// copy the lists
|
||||
this._notDisplayedResult = results.slice(0);
|
||||
this._terms = terms.slice(0);
|
||||
this._tryAddResults();
|
||||
},
|
||||
|
||||
clear: function () {
|
||||
this._terms = [];
|
||||
this._notDisplayedResult = [];
|
||||
this._grid.removeAll();
|
||||
this.selectionIndex = -1;
|
||||
},
|
||||
@@ -233,6 +258,7 @@ SearchResults.prototype = {
|
||||
let title = new St.Label({ text: provider.name,
|
||||
style_class: 'dash-search-button-label' });
|
||||
|
||||
button.label_actor = title;
|
||||
bin.set_child(title);
|
||||
button.set_child(bin);
|
||||
provider.actor = button;
|
||||
@@ -243,18 +269,9 @@ SearchResults.prototype = {
|
||||
createProviderMeta: function(provider) {
|
||||
let providerBox = new St.BoxLayout({ style_class: 'search-section',
|
||||
vertical: true });
|
||||
let titleButton = new St.Button({ style_class: 'search-section-header',
|
||||
reactive: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
titleButton.connect('clicked', Lang.bind(this, function () { this._onHeaderClicked(provider); }));
|
||||
providerBox.add(titleButton);
|
||||
let titleBox = new St.BoxLayout();
|
||||
titleButton.set_child(titleBox);
|
||||
let title = new St.Label({ text: provider.title });
|
||||
let count = new St.Label();
|
||||
titleBox.add(title, { expand: true });
|
||||
titleBox.add(count);
|
||||
let title = new St.Label({ style_class: 'search-section-header',
|
||||
text: provider.title });
|
||||
providerBox.add(title);
|
||||
|
||||
let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
|
||||
x_fill: true,
|
||||
@@ -267,8 +284,7 @@ SearchResults.prototype = {
|
||||
resultDisplayBin.set_child(resultDisplay.actor);
|
||||
|
||||
this._providerMeta.push({ actor: providerBox,
|
||||
resultDisplay: resultDisplay,
|
||||
count: count });
|
||||
resultDisplay: resultDisplay });
|
||||
this._content.add(providerBox);
|
||||
},
|
||||
|
||||
@@ -317,22 +333,26 @@ SearchResults.prototype = {
|
||||
let terms = this._searchSystem.getTerms();
|
||||
this._openSearchSystem.setSearchTerms(terms);
|
||||
|
||||
// To avoid CSS transitions causing flickering
|
||||
// of the selection when the first search result
|
||||
// stays the same, we hide the content while
|
||||
// filling in the results and setting the initial
|
||||
// selection.
|
||||
this._content.hide();
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let [provider, providerResults] = results[i];
|
||||
let meta = this._metaForProvider(provider);
|
||||
meta.actor.show();
|
||||
meta.resultDisplay.renderResults(providerResults, terms);
|
||||
meta.count.set_text('' + providerResults.length);
|
||||
}
|
||||
|
||||
if (this._selectedOpenSearchButton == -1)
|
||||
this.selectDown(false);
|
||||
|
||||
return true;
|
||||
},
|
||||
this._content.show();
|
||||
|
||||
_onHeaderClicked: function(provider) {
|
||||
provider.expandSearch(this._searchSystem.getTerms());
|
||||
return true;
|
||||
},
|
||||
|
||||
_modifyActorSelection: function(resultDisplay, up) {
|
||||
|
||||
@@ -14,9 +14,6 @@ const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
|
||||
const KEY_STICKY_KEYS_ENABLED = 'stickykeys-enable';
|
||||
const KEY_BOUNCE_KEYS_ENABLED = 'bouncekeys-enable';
|
||||
@@ -25,16 +22,12 @@ const KEY_MOUSE_KEYS_ENABLED = 'mousekeys-enable';
|
||||
|
||||
const APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||
|
||||
const XSETTINGS_SCHEMA = 'org.gnome.settings-daemon.plugins.xsettings';
|
||||
const KEY_DPI = 'dpi';
|
||||
|
||||
const DPI_LOW_REASONABLE_VALUE = 50;
|
||||
const DPI_HIGH_REASONABLE_VALUE = 500;
|
||||
|
||||
const DPI_FACTOR_LARGE = 1.25;
|
||||
const DPI_FACTOR_LARGER = 1.5;
|
||||
const DPI_FACTOR_LARGEST = 2.0;
|
||||
const DPI_DEFAULT = 96;
|
||||
|
||||
const KEY_META_DIR = '/apps/metacity/general';
|
||||
const KEY_VISUAL_BELL = KEY_META_DIR + '/visual_bell';
|
||||
@@ -42,25 +35,10 @@ const KEY_VISUAL_BELL = KEY_META_DIR + '/visual_bell';
|
||||
const DESKTOP_INTERFACE_SCHEMA = 'org.gnome.desktop.interface';
|
||||
const KEY_GTK_THEME = 'gtk-theme';
|
||||
const KEY_ICON_THEME = 'icon-theme';
|
||||
const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
|
||||
|
||||
const HIGH_CONTRAST_THEME = 'HighContrast';
|
||||
|
||||
function getDPIFromX() {
|
||||
let screen = global.get_gdk_screen();
|
||||
if (screen) {
|
||||
let width_dpi = (screen.get_width() / (screen.get_width_mm() / 25.4));
|
||||
let height_dpi = (screen.get_height() / (screen.get_height_mm() / 25.4));
|
||||
if (width_dpi < DPI_LOW_REASONABLE_VALUE
|
||||
|| width_dpi > DPI_HIGH_REASONABLE_VALUE
|
||||
|| height_dpi < DPI_LOW_REASONABLE_VALUE
|
||||
|| height_dpi > DPI_HIGH_REASONABLE_VALUE)
|
||||
return DPI_DEFAULT;
|
||||
else
|
||||
return (width_dpi + height_dpi) / 2;
|
||||
}
|
||||
return DPI_DEFAULT;
|
||||
}
|
||||
|
||||
function ATIndicator() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
@@ -85,13 +63,13 @@ ATIndicator.prototype = {
|
||||
let textZoom = this._buildFontItem();
|
||||
this.menu.addMenuItem(textZoom);
|
||||
|
||||
let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
|
||||
'screen-reader-enabled');
|
||||
this.menu.addMenuItem(screenReader);
|
||||
// let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
|
||||
// 'screen-reader-enabled');
|
||||
// this.menu.addMenuItem(screenReader);
|
||||
|
||||
let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
'screen-keyboard-enabled');
|
||||
this.menu.addMenuItem(screenKeyboard);
|
||||
// let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
// 'screen-keyboard-enabled');
|
||||
// this.menu.addMenuItem(screenKeyboard);
|
||||
|
||||
let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL);
|
||||
this.menu.addMenuItem(visualBell);
|
||||
@@ -110,7 +88,8 @@ ATIndicator.prototype = {
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Universal Access Settings"), function() {
|
||||
Util.spawnDesktop('gnome-universal-access-panel');
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-universal-access-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
},
|
||||
|
||||
@@ -194,30 +173,23 @@ ATIndicator.prototype = {
|
||||
},
|
||||
|
||||
_buildFontItem: function() {
|
||||
let settings = new Gio.Settings({ schema: XSETTINGS_SCHEMA });
|
||||
let settings = new Gio.Settings({ schema: DESKTOP_INTERFACE_SCHEMA });
|
||||
|
||||
// we assume this never changes (which is not true if resolution
|
||||
// is changed, but we would need XRandR events for that)
|
||||
let x_value = getDPIFromX();
|
||||
let user_value;
|
||||
function on_get() {
|
||||
user_value = settings.get_double(KEY_DPI);
|
||||
return (user_value - (DPI_FACTOR_LARGE * x_value) > -1);
|
||||
}
|
||||
let initial_setting = on_get();
|
||||
let default_value = initial_setting ? x_value : user_value;
|
||||
let factor = settings.get_double(KEY_TEXT_SCALING_FACTOR);
|
||||
let initial_setting = (factor > 1.0);
|
||||
let widget = this._buildItemExtended(_("Large Text"),
|
||||
initial_setting,
|
||||
settings.is_writable(KEY_DPI),
|
||||
settings.is_writable(KEY_TEXT_SCALING_FACTOR),
|
||||
function (enabled) {
|
||||
if (enabled)
|
||||
settings.set_double(KEY_DPI, DPI_FACTOR_LARGE * default_value);
|
||||
settings.set_double(KEY_TEXT_SCALING_FACTOR,
|
||||
DPI_FACTOR_LARGE);
|
||||
else
|
||||
settings.set_double(KEY_DPI, default_value);
|
||||
settings.reset(KEY_TEXT_SCALING_FACTOR);
|
||||
});
|
||||
settings.connect('changed::' + KEY_DPI, function() {
|
||||
let active = on_get();
|
||||
default_value = active ? x_value : user_value;
|
||||
settings.connect('changed::' + KEY_TEXT_SCALING_FACTOR, function() {
|
||||
let factor = settings.get_double(KEY_TEXT_SCALING_FACTOR);
|
||||
let active = (factor > 1.0);
|
||||
widget.setToggleState(active);
|
||||
});
|
||||
return widget;
|
||||
|
||||
@@ -16,9 +16,6 @@ const MessageTray = imports.ui.messageTray;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const ConnectionState = {
|
||||
DISCONNECTED: 0,
|
||||
CONNECTED: 1,
|
||||
@@ -67,7 +64,7 @@ Indicator.prototype = {
|
||||
|
||||
this._fullMenuItems = [new PopupMenu.PopupSeparatorMenuItem(),
|
||||
new PopupMenu.PopupMenuItem(_("Send Files to Device...")),
|
||||
new PopupMenu.PopupMenuItem(_("Setup a New Device...")),
|
||||
new PopupMenu.PopupMenuItem(_("Set up a New Device...")),
|
||||
new PopupMenu.PopupSeparatorMenuItem()];
|
||||
this._hasDevices = false;
|
||||
this._deviceSep = this._fullMenuItems[0]; // hidden if no device exists
|
||||
@@ -93,7 +90,8 @@ Indicator.prototype = {
|
||||
this._updateFullMenu();
|
||||
|
||||
this.menu.addAction(_("Bluetooth Settings"), function() {
|
||||
GLib.spawn_command_line_async('gnome-control-center bluetooth');
|
||||
let app = Shell.AppSystem.get_default().get_app('bluetooth-properties.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
|
||||
this._applet.connect('pincode-request', Lang.bind(this, this._pinRequest));
|
||||
@@ -126,47 +124,31 @@ Indicator.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_deviceCompare: function(d1, d2) {
|
||||
return d1.device_path == d2.device_path &&
|
||||
d1.bdaddr == d2.bdaddr &&
|
||||
d1.can_connect == d2.can_connect &&
|
||||
d1.capabilities == d2.capabilities;
|
||||
},
|
||||
|
||||
_updateDevices: function() {
|
||||
let devices = this._applet.get_devices();
|
||||
|
||||
for (let i = 0; i < this._deviceItems.length; i++) {
|
||||
let item = this._deviceItems[i];
|
||||
let destroy = true;
|
||||
for (let j = 0; j < devices.length; j++) {
|
||||
// we need to deep compare because BluetoothSimpleDevice is a boxed type
|
||||
// (but we take advantage of that, because _skip will disappear the next
|
||||
// time get_devices() is called)
|
||||
if (this._deviceCompare(item._device, devices[i])) {
|
||||
item.label.text = devices[i].alias;
|
||||
devices[i]._skip = true;
|
||||
destroy = false;
|
||||
}
|
||||
}
|
||||
if (destroy) {
|
||||
item.destroy();
|
||||
item._destroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
let newlist = [ ];
|
||||
for (let i = 0; i < this._deviceItems.length; i++) {
|
||||
let item = this._deviceItems[i];
|
||||
if (!item._destroyed)
|
||||
let destroy = true;
|
||||
for (let j = 0; j < devices.length; j++) {
|
||||
if (item._device.device_path == devices[j].device_path) {
|
||||
this._updateDeviceItem(item, devices[j]);
|
||||
destroy = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (destroy)
|
||||
item.destroy();
|
||||
else
|
||||
newlist.push(item);
|
||||
}
|
||||
this._deviceItems = newlist;
|
||||
|
||||
this._deviceItems = newlist;
|
||||
this._hasDevices = newlist.length > 0;
|
||||
for (let i = 0; i < devices.length; i++) {
|
||||
let d = devices[i];
|
||||
if (d._skip)
|
||||
if (d._item)
|
||||
continue;
|
||||
let item = this._createDeviceItem(d);
|
||||
if (item) {
|
||||
@@ -181,17 +163,55 @@ Indicator.prototype = {
|
||||
this._deviceSep.actor.hide();
|
||||
},
|
||||
|
||||
_updateDeviceItem: function(item, device) {
|
||||
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE) {
|
||||
item.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
let prevDevice = item._device;
|
||||
let prevCapabilities = prevDevice.capabilities;
|
||||
let prevCanConnect = prevDevice.can_connect;
|
||||
|
||||
// adopt the new device object
|
||||
item._device = device;
|
||||
device._item = item;
|
||||
|
||||
// update properties
|
||||
item.label.text = device.alias;
|
||||
|
||||
if (prevCapabilities != device.capabilities ||
|
||||
prevCanConnect != device.can_connect) {
|
||||
// need to rebuild the submenu
|
||||
item.menu.removeAll();
|
||||
this._buildDeviceSubMenu(item, device);
|
||||
}
|
||||
|
||||
// update connected property
|
||||
if (device.can_connect)
|
||||
item._connectedMenuitem.setToggleState(device.connected);
|
||||
},
|
||||
|
||||
_createDeviceItem: function(device) {
|
||||
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE)
|
||||
return null;
|
||||
let item = new PopupMenu.PopupSubMenuMenuItem(device.alias);
|
||||
item._device = device;
|
||||
|
||||
// adopt the device object, and add a back link
|
||||
item._device = device;
|
||||
device._item = item;
|
||||
|
||||
this._buildDeviceSubMenu(item, device);
|
||||
|
||||
return item;
|
||||
},
|
||||
|
||||
_buildDeviceSubMenu: function(item, device) {
|
||||
if (device.can_connect) {
|
||||
item._connected = device.connected;
|
||||
let menuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
|
||||
item._connectedMenuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
|
||||
|
||||
menuitem.connect('toggled', Lang.bind(this, function() {
|
||||
item._connectedMenuitem.connect('toggled', Lang.bind(this, function() {
|
||||
if (item._connected > ConnectionState.CONNECTED) {
|
||||
// operation already in progress, revert
|
||||
menuitem.setToggleState(menuitem.state);
|
||||
@@ -221,7 +241,7 @@ Indicator.prototype = {
|
||||
}
|
||||
}));
|
||||
|
||||
item.menu.addMenuItem(menuitem);
|
||||
item.menu.addMenuItem(item._connectedMenuitem);
|
||||
}
|
||||
|
||||
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
|
||||
@@ -267,8 +287,6 @@ Indicator.prototype = {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return item;
|
||||
},
|
||||
|
||||
_updateFullMenu: function() {
|
||||
@@ -471,9 +489,15 @@ PinNotification.prototype = {
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
if (action == 'ok') {
|
||||
if (this._numeric)
|
||||
this._applet.agent_reply_passkey(this._devicePath, parseInt(this._entry.text));
|
||||
else
|
||||
if (this._numeric) {
|
||||
let num = parseInt(this._entry.text);
|
||||
if (isNaN(num)) {
|
||||
// user reply was empty, or was invalid
|
||||
// cancel the operation
|
||||
num = -1;
|
||||
}
|
||||
this._applet.agent_reply_passkey(this._devicePath, num);
|
||||
} else
|
||||
this._applet.agent_reply_pincode(this._devicePath, this._entry.text);
|
||||
} else {
|
||||
if (this._numeric)
|
||||
|
||||
@@ -13,9 +13,6 @@ const PopupMenu = imports.ui.popupMenu;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
function LayoutMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
@@ -71,10 +68,11 @@ XKBIndicator.prototype = {
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Show Keyboard Layout..."), Lang.bind(this, function() {
|
||||
Util.spawn(['gkbd-keyboard-display', '-g', this._config.get_current_group() + 1]);
|
||||
Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
|
||||
}));
|
||||
this.menu.addAction(_("Localization Settings"), function() {
|
||||
Util.spawn(['gnome-control-center', 'region']);
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-region-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
2193
js/ui/status/network.js
Normal file
@@ -11,9 +11,6 @@ const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const BUS_NAME = 'org.gnome.PowerManager';
|
||||
const OBJECT_PATH = '/org/gnome/PowerManager';
|
||||
|
||||
@@ -49,7 +46,7 @@ const PowerManagerInterface = {
|
||||
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
|
||||
],
|
||||
signals: [
|
||||
{ name: 'Changed', outSignature: '' },
|
||||
{ name: 'Changed', inSignature: '' },
|
||||
],
|
||||
properties: [
|
||||
{ name: 'Icon', signature: 's', access: 'read' },
|
||||
@@ -72,7 +69,7 @@ Indicator.prototype = {
|
||||
this._hasPrimary = false;
|
||||
this._primaryDeviceId = null;
|
||||
|
||||
this._batteryItem = new PopupMenu.PopupMenuItem('');
|
||||
this._batteryItem = new PopupMenu.PopupMenuItem('', { reactive: false });
|
||||
this._primaryPercentage = new St.Label();
|
||||
this._batteryItem.addActor(this._primaryPercentage, { align: St.Align.END });
|
||||
this.menu.addMenuItem(this._batteryItem);
|
||||
@@ -83,7 +80,8 @@ Indicator.prototype = {
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this.menu.addAction(_("Power Settings"),function() {
|
||||
Util.spawnDesktop('gnome-power-panel');
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-power-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
|
||||
this._proxy.connect('Changed', Lang.bind(this, this._devicesChanged));
|
||||
@@ -104,21 +102,27 @@ Indicator.prototype = {
|
||||
if (device_type == UPDeviceType.BATTERY) {
|
||||
this._hasPrimary = true;
|
||||
let time = Math.round(seconds / 60);
|
||||
let minutes = time % 60;
|
||||
let hours = Math.floor(time / 60);
|
||||
let timestring;
|
||||
if (time > 60) {
|
||||
if (minutes == 0) {
|
||||
timestring = Gettext.ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
|
||||
} else {
|
||||
/* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
|
||||
let template = _("%d %s %d %s remaining");
|
||||
if (time == 0) {
|
||||
// 0 is reported when UPower does not have enough data
|
||||
// to estimate battery life
|
||||
this._batteryItem.label.text = _("Estimating...");
|
||||
} else {
|
||||
let minutes = time % 60;
|
||||
let hours = Math.floor(time / 60);
|
||||
let timestring;
|
||||
if (time > 60) {
|
||||
if (minutes == 0) {
|
||||
timestring = ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
|
||||
} else {
|
||||
/* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
|
||||
let template = _("%d %s %d %s remaining");
|
||||
|
||||
timestring = template.format (hours, Gettext.ngettext("hour", "hours", hours), minutes, Gettext.ngettext("minute", "minutes", minutes));
|
||||
}
|
||||
} else
|
||||
timestring = Gettext.ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
|
||||
this._batteryItem.label.text = timestring;
|
||||
timestring = template.format (hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes));
|
||||
}
|
||||
} else
|
||||
timestring = ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
|
||||
this._batteryItem.label.text = timestring;
|
||||
}
|
||||
this._primaryPercentage.text = Math.round(percentage) + '%';
|
||||
this._batteryItem.actor.show();
|
||||
if (this._deviceItems.length > 0)
|
||||
@@ -130,17 +134,6 @@ Indicator.prototype = {
|
||||
}
|
||||
|
||||
this._primaryDeviceId = device_id;
|
||||
if (this._primaryDeviceId) {
|
||||
this._batteryItem.actor.reactive = true;
|
||||
this._batteryItem.actor.can_focus = true;
|
||||
this._batteryItem.connect('activate', function(item) {
|
||||
Util.spawn(['gnome-power-statistics', '--device', device_id]);
|
||||
});
|
||||
} else {
|
||||
// virtual device
|
||||
this._batteryItem.actor.reactive = false;
|
||||
this._batteryItem.actor.can_focus = false;
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -162,9 +155,6 @@ Indicator.prototype = {
|
||||
continue;
|
||||
|
||||
let item = new DeviceItem (devices[i]);
|
||||
item.connect('activate', function() {
|
||||
Util.spawn(['gnome-power-statistics', '--device', device_id]);
|
||||
});
|
||||
this._deviceItems.push(item);
|
||||
this.menu.addMenuItem(item, this._otherDevicePosition + position);
|
||||
position++;
|
||||
@@ -210,7 +200,7 @@ DeviceItem.prototype = {
|
||||
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
||||
|
||||
_init: function(device) {
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
|
||||
PopupMenu.PopupBaseMenuItem.prototype._init.call(this, { reactive: false });
|
||||
|
||||
let [device_id, device_type, icon, percentage, state, time] = device;
|
||||
|
||||
|
||||
@@ -13,10 +13,6 @@ const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const VOLUME_MAX = 65536.0; /* PA_VOLUME_NORM */
|
||||
const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
|
||||
|
||||
const VOLUME_NOTIFY_ID = 1;
|
||||
@@ -37,6 +33,8 @@ Indicator.prototype = {
|
||||
this._control.connect('default-source-changed', Lang.bind(this, this._readInput));
|
||||
this._control.connect('stream-added', Lang.bind(this, this._maybeShowInput));
|
||||
this._control.connect('stream-removed', Lang.bind(this, this._maybeShowInput));
|
||||
this._volumeMax = this._control.get_vol_max_norm();
|
||||
this._volumeMaxAmplified = this._control.get_vol_max_amplified();
|
||||
|
||||
this._output = null;
|
||||
this._outputVolumeId = 0;
|
||||
@@ -63,7 +61,8 @@ Indicator.prototype = {
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Sound Settings"), function() {
|
||||
Util.spawnDesktop('gnome-sound-panel');
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-sound-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
@@ -72,9 +71,9 @@ Indicator.prototype = {
|
||||
|
||||
_getMaxVolume: function(property) {
|
||||
if (this[property].get_can_decibel())
|
||||
return (VOLUME_MAX * 1.5);
|
||||
return this._volumeMaxAmplified;
|
||||
else
|
||||
return VOLUME_MAX;
|
||||
return this._volumeMax;
|
||||
},
|
||||
|
||||
_onScrollEvent: function(actor, event) {
|
||||
|
||||
@@ -19,7 +19,8 @@ const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
|
||||
'a11y-keyboard': 'a11y',
|
||||
'kbd-scrolllock': 'keyboard',
|
||||
'kbd-numlock': 'keyboard',
|
||||
'kbd-capslock': 'keyboard'
|
||||
'kbd-capslock': 'keyboard',
|
||||
'ibus-ui-gtk': 'input-method'
|
||||
};
|
||||
|
||||
function StatusIconDispatcher() {
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Gdm = imports.gi.Gdm;
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
const UPowerGlib = imports.gi.UPowerGlib;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Main = imports.ui.main;
|
||||
@@ -15,6 +16,21 @@ const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const BUS_NAME = 'org.gnome.ScreenSaver';
|
||||
const OBJECT_PATH = '/org/gnome/ScreenSaver';
|
||||
|
||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
|
||||
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
||||
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
||||
|
||||
const ScreenSaverInterface = {
|
||||
name: BUS_NAME,
|
||||
methods: [ { name: 'Lock', inSignature: '' } ]
|
||||
};
|
||||
|
||||
let ScreenSaverProxy = DBus.makeProxyClass(ScreenSaverInterface);
|
||||
|
||||
// Adapted from gdm/gui/user-switch-applet/applet.c
|
||||
//
|
||||
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
|
||||
@@ -32,15 +48,20 @@ StatusMenuButton.prototype = {
|
||||
let box = new St.BoxLayout({ name: 'panelStatusMenu' });
|
||||
this.actor.set_child(box);
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||
|
||||
this._gdm = Gdm.UserManager.ref_default();
|
||||
this._gdm.queue_load();
|
||||
|
||||
this._user = this._gdm.get_user(GLib.get_user_name());
|
||||
this._presence = new GnomeSession.Presence();
|
||||
this._presenceItems = {};
|
||||
this._session = new GnomeSession.SessionManager();
|
||||
|
||||
this._account_mgr = Tp.AccountManager.dup()
|
||||
|
||||
this._upClient = new UPowerGlib.Client();
|
||||
|
||||
this._screenSaverProxy = new ScreenSaverProxy(DBus.session, BUS_NAME, OBJECT_PATH);
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._iconBox = new St.Bin();
|
||||
@@ -64,6 +85,15 @@ StatusMenuButton.prototype = {
|
||||
this._gdm.connect('notify::is-loaded', Lang.bind(this, this._updateSwitchUser));
|
||||
this._gdm.connect('user-added', Lang.bind(this, this._updateSwitchUser));
|
||||
this._gdm.connect('user-removed', Lang.bind(this, this._updateSwitchUser));
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_USER_SWITCH_KEY,
|
||||
Lang.bind(this, this._updateSwitchUser));
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
||||
Lang.bind(this, this._updateLogout));
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
|
||||
Lang.bind(this, this._updateLockScreen));
|
||||
this._updateSwitchUser();
|
||||
this._updateLogout();
|
||||
this._updateLockScreen();
|
||||
|
||||
this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
|
||||
},
|
||||
@@ -80,11 +110,41 @@ StatusMenuButton.prototype = {
|
||||
this._name.set_text("");
|
||||
},
|
||||
|
||||
_updateSessionSeparator: function() {
|
||||
let showSeparator = this._loginScreenItem.actor.visible ||
|
||||
this._logoutItem.actor.visible ||
|
||||
this._lockScreenItem.actor.visible;
|
||||
if (showSeparator)
|
||||
this._sessionSeparator.actor.show();
|
||||
else
|
||||
this._sessionSeparator.actor.hide();
|
||||
},
|
||||
|
||||
_updateSwitchUser: function() {
|
||||
if (this._gdm.can_switch ())
|
||||
let allowSwitch = !this._lockdownSettings.get_boolean(DISABLE_USER_SWITCH_KEY);
|
||||
if (allowSwitch && this._gdm.can_switch ())
|
||||
this._loginScreenItem.actor.show();
|
||||
else
|
||||
this._loginScreenItem.actor.hide();
|
||||
this._updateSessionSeparator();
|
||||
},
|
||||
|
||||
_updateLogout: function() {
|
||||
let allowLogout = !this._lockdownSettings.get_boolean(DISABLE_LOG_OUT_KEY);
|
||||
if (allowLogout)
|
||||
this._logoutItem.actor.show();
|
||||
else
|
||||
this._logoutItem.actor.hide();
|
||||
this._updateSessionSeparator();
|
||||
},
|
||||
|
||||
_updateLockScreen: function() {
|
||||
let allowLockScreen = !this._lockdownSettings.get_boolean(DISABLE_LOCK_SCREEN_KEY);
|
||||
if (allowLockScreen)
|
||||
this._lockScreenItem.actor.show();
|
||||
else
|
||||
this._lockScreenItem.actor.hide();
|
||||
this._updateSessionSeparator();
|
||||
},
|
||||
|
||||
_updateSuspendOrPowerOff: function() {
|
||||
@@ -98,7 +158,7 @@ StatusMenuButton.prototype = {
|
||||
if (!this._haveSuspend) {
|
||||
this._suspendOrPowerOffItem.updateText(_("Power Off..."), null);
|
||||
} else {
|
||||
this._suspendOrPowerOffItem.updateText(_("Suspend"), ("Power Off..."));
|
||||
this._suspendOrPowerOffItem.updateText(_("Suspend"), _("Power Off..."));
|
||||
}
|
||||
},
|
||||
|
||||
@@ -146,6 +206,7 @@ StatusMenuButton.prototype = {
|
||||
item = new PopupMenu.PopupMenuItem(_("Lock Screen"));
|
||||
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
this._lockScreenItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Switch User"));
|
||||
item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
|
||||
@@ -155,9 +216,11 @@ StatusMenuButton.prototype = {
|
||||
item = new PopupMenu.PopupMenuItem(_("Log Out..."));
|
||||
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
this._logoutItem = item;
|
||||
|
||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||
this.menu.addMenuItem(item);
|
||||
this._sessionSeparator = item;
|
||||
|
||||
item = new PopupMenu.PopupAlternatingMenuItem(_("Suspend"),
|
||||
_("Power Off..."));
|
||||
@@ -169,21 +232,25 @@ StatusMenuButton.prototype = {
|
||||
|
||||
_setPresenceStatus: function(item, event, status) {
|
||||
this._presence.setStatus(status);
|
||||
|
||||
this._setIMStatus(status);
|
||||
},
|
||||
|
||||
_onMyAccountActivate: function() {
|
||||
Main.overview.hide();
|
||||
Util.spawnDesktop('gnome-user-accounts-panel');
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-user-accounts-panel.desktop');
|
||||
app.activate(-1);
|
||||
},
|
||||
|
||||
_onPreferencesActivate: function() {
|
||||
Main.overview.hide();
|
||||
Util.spawnDesktop('gnome-control-center');
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-control-center.desktop');
|
||||
app.activate(-1);
|
||||
},
|
||||
|
||||
_onLockScreenActivate: function() {
|
||||
Main.overview.hide();
|
||||
Util.spawn(['gnome-screensaver-command', '--lock']);
|
||||
this._screenSaverProxy.LockRemote();
|
||||
},
|
||||
|
||||
_onLoginScreenActivate: function() {
|
||||
@@ -194,7 +261,7 @@ StatusMenuButton.prototype = {
|
||||
|
||||
_onQuitSessionActivate: function() {
|
||||
Main.overview.hide();
|
||||
Util.spawn(['gnome-session-save', '--logout-dialog']);
|
||||
this._session.LogoutRemote(0);
|
||||
},
|
||||
|
||||
_onSuspendOrPowerOffActivate: function() {
|
||||
@@ -202,9 +269,37 @@ StatusMenuButton.prototype = {
|
||||
|
||||
if (this._haveSuspend &&
|
||||
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
||||
this._upClient.suspend_sync(null);
|
||||
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
|
||||
this._upClient.suspend_sync(null);
|
||||
}));
|
||||
} else {
|
||||
Util.spawn(['gnome-session-save', '--shutdown-dialog']);
|
||||
this._session.ShutdownRemote();
|
||||
}
|
||||
},
|
||||
|
||||
_setIMStatus: function(session_status) {
|
||||
let [presence_type, presence_status, msg] = this._account_mgr.get_most_available_presence();
|
||||
let type, status;
|
||||
|
||||
// We change the IM presence only if there are connected accounts
|
||||
if (presence_type == Tp.ConnectionPresenceType.UNSET ||
|
||||
presence_type == Tp.ConnectionPresenceType.OFFLINE ||
|
||||
presence_type == Tp.ConnectionPresenceType.UNKNOWN ||
|
||||
presence_type == Tp.ConnectionPresenceType.ERROR)
|
||||
return;
|
||||
|
||||
if (session_status == GnomeSession.PresenceStatus.AVAILABLE) {
|
||||
type = Tp.ConnectionPresenceType.AVAILABLE;
|
||||
status = "available";
|
||||
}
|
||||
else if (session_status == GnomeSession.PresenceStatus.BUSY) {
|
||||
type = Tp.ConnectionPresenceType.BUSY;
|
||||
status = "busy";
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
this._account_mgr.set_all_requested_presences(type, status, msg);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,10 +7,10 @@ const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Tpl = imports.gi.TelepathyLogger;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const History = imports.misc.history;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
@@ -21,6 +21,9 @@ const SCROLLBACK_RECENT_TIME = 15 * 60; // 15 minutes
|
||||
const SCROLLBACK_RECENT_LENGTH = 20;
|
||||
const SCROLLBACK_IDLE_LENGTH = 5;
|
||||
|
||||
// See Source._displayPendingMessages
|
||||
const SCROLLBACK_HISTORY_LINES = 10;
|
||||
|
||||
const NotificationDirection = {
|
||||
SENT: 'chat-sent',
|
||||
RECEIVED: 'chat-received'
|
||||
@@ -35,13 +38,37 @@ let contactFeatures = [Tp.ContactFeature.ALIAS,
|
||||
// lets us see messages even if they belong to another app (eg,
|
||||
// Empathy).
|
||||
|
||||
function makeMessageFromTpMessage(tpMessage, direction) {
|
||||
let [text, flags] = tpMessage.to_text();
|
||||
return {
|
||||
messageType: tpMessage.get_message_type(),
|
||||
text: text,
|
||||
sender: tpMessage.sender.alias,
|
||||
timestamp: tpMessage.get_received_timestamp(),
|
||||
direction: direction
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function makeMessageFromTplEvent(event) {
|
||||
let sent = event.get_sender().get_entity_type() == Tpl.EntityType.SELF;
|
||||
let direction = sent ? NotificationDirection.SENT : NotificationDirection.RECEIVED;
|
||||
|
||||
return {
|
||||
messageType: event.get_message_type(),
|
||||
text: event.get_message(),
|
||||
sender: event.get_sender().get_alias(),
|
||||
timestamp: event.get_timestamp(),
|
||||
direction: direction
|
||||
};
|
||||
}
|
||||
|
||||
function Client() {
|
||||
this._init();
|
||||
};
|
||||
|
||||
Client.prototype = {
|
||||
_init : function() {
|
||||
this._accounts = {};
|
||||
// channel path -> Source
|
||||
this._sources = {};
|
||||
|
||||
@@ -50,14 +77,9 @@ Client.prototype = {
|
||||
// The second argument, recover, means _observeChannels will be run
|
||||
// for any existing channel as well.
|
||||
let dbus = Tp.DBusDaemon.dup();
|
||||
this._observer = Tp.SimpleObserver.new(dbus, true, 'GnomeShell', true,
|
||||
Lang.bind(this, this._observeChannels));
|
||||
|
||||
// We only care about single-user text-based chats
|
||||
let props = {};
|
||||
props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
|
||||
props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
|
||||
this._observer.add_observer_filter(props);
|
||||
this._observer = Shell.TpClient.new(dbus);
|
||||
this._observer.set_observe_channels_func(
|
||||
Lang.bind(this, this._observeChannels));
|
||||
|
||||
try {
|
||||
this._observer.register();
|
||||
@@ -68,7 +90,22 @@ Client.prototype = {
|
||||
|
||||
_observeChannels: function(observer, account, conn, channels,
|
||||
dispatchOp, requests, context) {
|
||||
let connPath = conn.get_object_path();
|
||||
// If the self_contact doesn't have the ALIAS, make sure
|
||||
// to fetch it before trying to grab the channels.
|
||||
let self_contact = conn.get_self_contact();
|
||||
if (self_contact.has_feature(Tp.ContactFeature.ALIAS)) {
|
||||
this._finishObserveChannels(account, conn, channels, context);
|
||||
} else {
|
||||
Shell.get_self_contact_features(conn,
|
||||
contactFeatures.length, contactFeatures,
|
||||
Lang.bind(this, function() {
|
||||
this._finishObserveChannels(account, conn, channels, context);
|
||||
}));
|
||||
context.delay();
|
||||
}
|
||||
},
|
||||
|
||||
_finishObserveChannels: function(account, conn, channels, context) {
|
||||
let len = channels.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let channel = channels[i];
|
||||
@@ -91,7 +128,6 @@ Client.prototype = {
|
||||
}), null);
|
||||
}
|
||||
|
||||
// Allow dbus method to return
|
||||
context.accept();
|
||||
},
|
||||
|
||||
@@ -117,7 +153,7 @@ Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(account, conn, channel, contact) {
|
||||
MessageTray.Source.prototype._init.call(this, channel.get_identifier());
|
||||
MessageTray.Source.prototype._init.call(this, contact.get_alias());
|
||||
|
||||
this.isChat = true;
|
||||
|
||||
@@ -128,8 +164,6 @@ Source.prototype = {
|
||||
this._channel = channel;
|
||||
this._closedId = this._channel.connect('invalidated', Lang.bind(this, this._channelClosed));
|
||||
|
||||
this._updateAlias();
|
||||
|
||||
this._notification = new Notification(this);
|
||||
this._notification.setUrgency(MessageTray.Urgency.HIGH);
|
||||
|
||||
@@ -144,11 +178,18 @@ Source.prototype = {
|
||||
this._notifyAvatarId = this._contact.connect('notify::avatar-file', Lang.bind(this, this._updateAvatarIcon));
|
||||
this._presenceChangedId = this._contact.connect('presence-changed', Lang.bind(this, this._presenceChanged));
|
||||
|
||||
this._displayPendingMessages();
|
||||
// Add ourselves as a source.
|
||||
Main.messageTray.add(this);
|
||||
this.pushNotification(this._notification);
|
||||
|
||||
this._getLogMessages();
|
||||
},
|
||||
|
||||
_updateAlias: function() {
|
||||
let oldAlias = this.title;
|
||||
this.title = this._contact.get_alias();
|
||||
this._notification.appendAliasChange(oldAlias, this.title);
|
||||
this.pushNotification(this._notification);
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
@@ -174,7 +215,7 @@ Source.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_notificationClicked: function(notification) {
|
||||
open: function(notification) {
|
||||
let props = {};
|
||||
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
|
||||
[props[Tp.PROP_CHANNEL_TARGET_HANDLE], props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE]] = this._channel.get_handle();
|
||||
@@ -184,13 +225,52 @@ Source.prototype = {
|
||||
req.ensure_channel_async('', null, null);
|
||||
},
|
||||
|
||||
_displayPendingMessages: function() {
|
||||
let msgs = this._channel.get_pending_messages();
|
||||
_getLogMessages: function() {
|
||||
let logManager = Tpl.LogManager.dup_singleton();
|
||||
let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
|
||||
Shell.get_contact_events(logManager,
|
||||
this._account, entity,
|
||||
SCROLLBACK_HISTORY_LINES,
|
||||
Lang.bind(this, this._displayPendingMessages));
|
||||
},
|
||||
|
||||
for (let i = 0; i < msgs.length; i++) {
|
||||
let msg = msgs[i];
|
||||
this._messageReceived(this._channel, msg);
|
||||
_displayPendingMessages: function(logManager, result) {
|
||||
let [success, events] = logManager.get_filtered_events_finish(result);
|
||||
|
||||
let logMessages = events.map(makeMessageFromTplEvent);
|
||||
|
||||
let pendingTpMessages = this._channel.get_pending_messages();
|
||||
let pendingMessages = pendingTpMessages.map(function (tpMessage) { return makeMessageFromTpMessage(tpMessage, NotificationDirection.RECEIVED); });
|
||||
|
||||
let showTimestamp = false;
|
||||
|
||||
for (let i = 0; i < logMessages.length; i++) {
|
||||
let logMessage = logMessages[i];
|
||||
let isPending = false;
|
||||
|
||||
// Skip any log messages that are also in pendingMessages
|
||||
for (let j = 0; j < pendingMessages.length; j++) {
|
||||
let pending = pendingMessages[j];
|
||||
if (logMessage.timestamp == pending.timestamp && logMessage.text == pending.text) {
|
||||
isPending = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isPending) {
|
||||
showTimestamp = true;
|
||||
this._notification.appendMessage(logMessage, true, ['chat-log-message']);
|
||||
}
|
||||
}
|
||||
|
||||
if (showTimestamp)
|
||||
this._notification.appendTimestamp();
|
||||
|
||||
for (let i = 0; i < pendingMessages.length; i++)
|
||||
this._notification.appendMessage(pendingMessages[i], true);
|
||||
|
||||
if (pendingMessages.length > 0)
|
||||
this.notify();
|
||||
},
|
||||
|
||||
_channelClosed: function() {
|
||||
@@ -206,25 +286,35 @@ Source.prototype = {
|
||||
},
|
||||
|
||||
_messageReceived: function(channel, message) {
|
||||
this._notification.appendMessage(message, NotificationDirection.RECEIVED);
|
||||
if (message.get_message_type() == Tp.ChannelTextMessageType.DELIVERY_REPORT)
|
||||
return;
|
||||
|
||||
message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
|
||||
this._notification.appendMessage(message);
|
||||
this.notify();
|
||||
},
|
||||
|
||||
// This is called for both messages we send from
|
||||
// our client and other clients as well.
|
||||
_messageSent: function(channel, message, flags, token) {
|
||||
this._notification.appendMessage(message, NotificationDirection.SENT);
|
||||
message = makeMessageFromTpMessage(message, NotificationDirection.SENT);
|
||||
this._notification.appendMessage(message);
|
||||
},
|
||||
|
||||
notify: function() {
|
||||
if (!Main.messageTray.contains(this))
|
||||
Main.messageTray.add(this);
|
||||
|
||||
MessageTray.Source.prototype.notify.call(this, this._notification);
|
||||
},
|
||||
|
||||
respond: function(text) {
|
||||
let msg = Tp.ClientMessage.new_text(Tp.ChannelTextMessageType.NORMAL, text);
|
||||
let type;
|
||||
if (text.slice(0, 4) == '/me ') {
|
||||
type = Tp.ChannelTextMessageType.ACTION;
|
||||
text = text.slice(4);
|
||||
} else {
|
||||
type = Tp.ChannelTextMessageType.NORMAL;
|
||||
}
|
||||
|
||||
let msg = Tp.ClientMessage.new_text(type, text);
|
||||
this._channel.send_message_async(msg, 0, null);
|
||||
},
|
||||
|
||||
@@ -280,19 +370,52 @@ Notification.prototype = {
|
||||
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
|
||||
this.setActionArea(this._responseEntry);
|
||||
|
||||
this._oldMaxScrollAdjustment = 0;
|
||||
this._createScrollArea();
|
||||
|
||||
this._scrollArea.vscroll.adjustment.connect('changed', Lang.bind(this, function(adjustment) {
|
||||
let currentValue = adjustment.value + adjustment.page_size;
|
||||
if (currentValue == this._oldMaxScrollAdjustment)
|
||||
this.scrollTo(St.Side.BOTTOM);
|
||||
this._oldMaxScrollAdjustment = adjustment.upper;
|
||||
}));
|
||||
|
||||
this._inputHistory = new History.HistoryManager({ entry: this._responseEntry.clutter_text });
|
||||
|
||||
this._history = [];
|
||||
this._timestampTimeoutId = 0;
|
||||
},
|
||||
|
||||
appendMessage: function(message, direction) {
|
||||
let [text, flags] = message.to_text();
|
||||
let timestamp = message.get_received_timestamp();
|
||||
/**
|
||||
* appendMessage:
|
||||
* @message: An object with the properties:
|
||||
* text: the body of the message,
|
||||
* messageType: a #Tp.ChannelTextMessageType,
|
||||
* sender: the name of the sender,
|
||||
* timestamp: the time the message was sent
|
||||
* direction: a #NotificationDirection
|
||||
*
|
||||
* @noTimestamp: Whether to add a timestamp. If %true, no timestamp
|
||||
* will be added, regardless of the difference since the
|
||||
* last timestamp
|
||||
* @styles: A list of CSS class names.
|
||||
*/
|
||||
appendMessage: function(message, noTimestamp, styles) {
|
||||
let messageBody = GLib.markup_escape_text(message.text, -1);
|
||||
styles = styles || [];
|
||||
styles.push(message.direction);
|
||||
|
||||
this.update(this.source.title, text, { customContent: true });
|
||||
this._append(text, direction, timestamp);
|
||||
if (message.messageType == Tp.ChannelTextMessageType.ACTION) {
|
||||
let senderAlias = GLib.markup_escape_text(message.sender, -1);
|
||||
messageBody = '<i>%s</i> %s'.format(senderAlias, messageBody);
|
||||
styles.push('chat-action');
|
||||
}
|
||||
|
||||
this.update(this.source.title, messageBody, { customContent: true, bannerMarkup: true });
|
||||
this._append(messageBody, styles, message.timestamp, noTimestamp);
|
||||
},
|
||||
|
||||
_append: function(text, style, timestamp) {
|
||||
_append: function(text, styles, timestamp, noTimestamp) {
|
||||
let currentTime = (Date.now() / 1000);
|
||||
if (!timestamp)
|
||||
timestamp = currentTime;
|
||||
@@ -304,20 +427,22 @@ Notification.prototype = {
|
||||
if (this._timestampTimeoutId)
|
||||
Mainloop.source_remove(this._timestampTimeoutId);
|
||||
|
||||
let body = this.addBody(text);
|
||||
body.add_style_class_name(style);
|
||||
this.scrollTo(St.Side.BOTTOM);
|
||||
let body = this.addBody(text, true);
|
||||
for (let i = 0; i < styles.length; i ++)
|
||||
body.add_style_class_name(styles[i]);
|
||||
|
||||
this._history.unshift({ actor: body, time: timestamp, realMessage: true });
|
||||
|
||||
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME)
|
||||
this._appendTimestamp();
|
||||
else
|
||||
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
|
||||
// from the timestamp of the message.
|
||||
this._timestampTimeoutId = Mainloop.timeout_add_seconds(
|
||||
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
|
||||
Lang.bind(this, this._appendTimestamp));
|
||||
if (!noTimestamp) {
|
||||
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME)
|
||||
this.appendTimestamp();
|
||||
else
|
||||
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
|
||||
// from the timestamp of the message.
|
||||
this._timestampTimeoutId = Mainloop.timeout_add_seconds(
|
||||
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
|
||||
Lang.bind(this, this.appendTimestamp));
|
||||
}
|
||||
|
||||
if (this._history.length > 1) {
|
||||
// Keep the scrollback from growing too long. If the most
|
||||
@@ -338,15 +463,41 @@ Notification.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_appendTimestamp: function() {
|
||||
_formatTimestamp: function(date) {
|
||||
let now = new Date();
|
||||
|
||||
var daysAgo = (now.getTime() - date.getTime()) / (24 * 60 * 60 * 1000);
|
||||
|
||||
let format;
|
||||
|
||||
// Show a week day and time if date is in the last week
|
||||
if (daysAgo < 1 || (daysAgo < 7 && now.getDay() != date.getDay())) {
|
||||
/* Translators: this is a time format string followed by a date.
|
||||
If applicable, replace %X with a strftime format valid for your
|
||||
locale, without seconds. */
|
||||
// xgettext:no-c-format
|
||||
format = _("Sent at %X on %A");
|
||||
|
||||
// FIXME: The next two are stolen from calendar.js with the comment to avoid
|
||||
// a string-freeze break. They should be replaced with better strings
|
||||
// with 'Sent at', appropriate context and appropriate translator comment.
|
||||
|
||||
} else if (date.getYear() == now.getYear()) {
|
||||
/* Translators: Shown on calendar heading when selected day occurs on current year */
|
||||
format = C_("calendar heading", "%A, %B %d");
|
||||
} else {
|
||||
/* Translators: Shown on calendar heading when selected day occurs on different year */
|
||||
format = C_("calendar heading", "%A, %B %d, %Y");
|
||||
}
|
||||
|
||||
return date.toLocaleFormat(format);
|
||||
},
|
||||
|
||||
appendTimestamp: function() {
|
||||
let lastMessageTime = this._history[0].time;
|
||||
let lastMessageDate = new Date(lastMessageTime * 1000);
|
||||
|
||||
/* Translators: this is a time format string followed by a date.
|
||||
If applicable, replace %X with a strftime format valid for your
|
||||
locale, without seconds. */
|
||||
// xgettext:no-c-format
|
||||
let timeLabel = this.addBody(lastMessageDate.toLocaleFormat(_("Sent at %X on %A")), false, { expand: true, x_fill: false, x_align: St.Align.END });
|
||||
let timeLabel = this.addBody(this._formatTimestamp(lastMessageDate), false, { expand: true, x_fill: false, x_align: St.Align.END });
|
||||
timeLabel.add_style_class_name('chat-meta-message');
|
||||
this._history.unshift({ actor: timeLabel, time: lastMessageTime, realMessage: false });
|
||||
|
||||
@@ -364,11 +515,26 @@ Notification.prototype = {
|
||||
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false});
|
||||
},
|
||||
|
||||
appendAliasChange: function(oldAlias, newAlias) {
|
||||
oldAlias = GLib.markup_escape_text(oldAlias, -1);
|
||||
newAlias = GLib.markup_escape_text(newAlias, -1);
|
||||
|
||||
/* Translators: this is the other person changing their old IM name to their new
|
||||
IM name. */
|
||||
let message = '<i>' + _("%s is now known as %s").format(oldAlias, newAlias) + '</i>';
|
||||
let label = this.addBody(message, true);
|
||||
label.add_style_class_name('chat-meta-message');
|
||||
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false });
|
||||
this.update(newAlias, null, { customContent: true });
|
||||
},
|
||||
|
||||
_onEntryActivated: function() {
|
||||
let text = this._responseEntry.get_text();
|
||||
if (text == '')
|
||||
return;
|
||||
|
||||
this._inputHistory.addItem(text);
|
||||
|
||||
// Telepathy sends out the Sent signal for us.
|
||||
// see Source._messageSent
|
||||
this._responseEntry.set_text('');
|
||||
|
||||
@@ -1,199 +1,25 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Search = imports.ui.search;
|
||||
const SearchDisplay = imports.ui.searchDisplay;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
|
||||
function SearchEntry(focusBase) {
|
||||
this._init(focusBase);
|
||||
}
|
||||
|
||||
SearchEntry.prototype = {
|
||||
_init : function(focusBase) {
|
||||
this.actor = new St.Entry({ name: 'searchEntry',
|
||||
/* Translators: this is the text displayed
|
||||
in the search entry when no search is
|
||||
active; it should not exceed ~30
|
||||
characters */
|
||||
hint_text: _("Type to search..."),
|
||||
track_hover: true });
|
||||
this.entry = this.actor.clutter_text;
|
||||
|
||||
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-find',
|
||||
icon_type: St.IconType.SYMBOLIC });
|
||||
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-clear',
|
||||
icon_type: St.IconType.SYMBOLIC });
|
||||
this.actor.set_secondary_icon(this._inactiveIcon);
|
||||
|
||||
this._iconClickedId = 0;
|
||||
|
||||
this.actor.clutter_text.connect('text-changed',
|
||||
Lang.bind(this, this._onTextChanged));
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||
|
||||
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
|
||||
|
||||
this.pane = null;
|
||||
|
||||
this._capturedEventId = 0;
|
||||
this._focusBase = focusBase;
|
||||
},
|
||||
|
||||
_updateCursorVisibility: function() {
|
||||
let focus = global.stage.get_key_focus();
|
||||
if (focus == this._focusBase || focus == this.entry)
|
||||
this.entry.set_cursor_visible(true);
|
||||
else
|
||||
this.entry.set_cursor_visible(false);
|
||||
},
|
||||
|
||||
_onMapped: function() {
|
||||
if (this.actor.mapped) {
|
||||
// Enable 'find-as-you-type'
|
||||
this._capturedEventId = global.stage.connect('captured-event',
|
||||
Lang.bind(this, this._onCapturedEvent));
|
||||
this.entry.set_cursor_visible(true);
|
||||
this.entry.set_selection(0, 0);
|
||||
} else {
|
||||
// Disable 'find-as-you-type'
|
||||
if (this._capturedEventId > 0)
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
this.actor.sync_hover();
|
||||
|
||||
this.entry.text = '';
|
||||
|
||||
// Return focus to the viewSelector
|
||||
global.stage.set_key_focus(this._focusBase);
|
||||
|
||||
this.entry.set_cursor_visible(true);
|
||||
this.entry.set_selection(0, 0);
|
||||
},
|
||||
|
||||
getText: function () {
|
||||
return this.entry.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||
},
|
||||
|
||||
// some search term has been entered
|
||||
isActive: function() {
|
||||
return this.actor.get_text() != '';
|
||||
},
|
||||
|
||||
// the entry does not show the hint
|
||||
_isActivated: function() {
|
||||
return this.entry.text == this.actor.get_text();
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
let source = event.get_source();
|
||||
let panelEvent = source && Main.panel.actor.contains(source);
|
||||
|
||||
switch (event.type()) {
|
||||
case Clutter.EventType.BUTTON_PRESS:
|
||||
// the user clicked outside after activating the entry, but
|
||||
// with no search term entered - cancel the search
|
||||
if (source != this.entry && this.entry.text == '') {
|
||||
this.reset();
|
||||
// allow only panel events to continue
|
||||
return !panelEvent;
|
||||
}
|
||||
return false;
|
||||
case Clutter.EventType.KEY_PRESS:
|
||||
// If some "special" actor grabbed the focus (run
|
||||
// dialog, looking glass); we don't want to interfere
|
||||
// with that
|
||||
let focus = global.stage.get_key_focus();
|
||||
if (focus != this._focusBase && focus != this.entry)
|
||||
return false;
|
||||
|
||||
let sym = event.get_key_symbol();
|
||||
|
||||
// If we have an active search, Escape cancels it - if we
|
||||
// haven't, the key is ignored
|
||||
if (sym == Clutter.Escape)
|
||||
if (this._isActivated()) {
|
||||
this.reset();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore non-printable keys
|
||||
if (!Clutter.keysym_to_unicode(sym))
|
||||
return false;
|
||||
|
||||
// Search started - move the key focus to the entry and
|
||||
// "repeat" the event
|
||||
if (!this._isActivated()) {
|
||||
global.stage.set_key_focus(this.entry);
|
||||
this.entry.event(event, false);
|
||||
}
|
||||
|
||||
return false;
|
||||
default:
|
||||
// Suppress all other events outside the panel while the entry
|
||||
// is activated and no search has been entered - any click
|
||||
// outside the entry will cancel the search
|
||||
return (this.entry.text == '' && !panelEvent);
|
||||
}
|
||||
},
|
||||
|
||||
_onTextChanged: function() {
|
||||
if (this.isActive()) {
|
||||
this.actor.set_secondary_icon(this._activeIcon);
|
||||
|
||||
if (this._iconClickedId == 0)
|
||||
this._iconClickedId = this.actor.connect('secondary-icon-clicked',
|
||||
Lang.bind(this, function() {
|
||||
this.reset();
|
||||
}));
|
||||
} else {
|
||||
if (this._iconClickedId > 0)
|
||||
this.actor.disconnect(this._iconClickedId);
|
||||
this._iconClickedId = 0;
|
||||
|
||||
this.actor.set_secondary_icon(this._inactiveIcon);
|
||||
}
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
if (this._capturedEventId > 0) {
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
|
||||
this._activeIcon = null;
|
||||
this._inactiveIcon = null;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(SearchEntry.prototype);
|
||||
|
||||
|
||||
function BaseTab(titleActor, pageActor) {
|
||||
this._init(titleActor, pageActor);
|
||||
function BaseTab(titleActor, pageActor, name, a11yIcon) {
|
||||
this._init(titleActor, pageActor, name, a11yIcon);
|
||||
}
|
||||
|
||||
BaseTab.prototype = {
|
||||
_init: function(titleActor, pageActor) {
|
||||
_init: function(titleActor, pageActor, name, a11yIcon) {
|
||||
this.title = titleActor;
|
||||
this.page = new St.Bin({ child: pageActor,
|
||||
x_align: St.Align.START,
|
||||
@@ -202,14 +28,25 @@ BaseTab.prototype = {
|
||||
y_fill: true,
|
||||
style_class: 'view-tab-page' });
|
||||
|
||||
if (this.title.can_focus) {
|
||||
Main.ctrlAltTabManager.addGroup(this.title, name, a11yIcon);
|
||||
} else {
|
||||
Main.ctrlAltTabManager.addGroup(this.page, name, a11yIcon,
|
||||
{ proxy: this.title,
|
||||
focusCallback: Lang.bind(this, this._a11yFocus) });
|
||||
}
|
||||
|
||||
this.visible = false;
|
||||
},
|
||||
|
||||
show: function() {
|
||||
show: function(animate) {
|
||||
this.visible = true;
|
||||
this.page.opacity = 0;
|
||||
this.page.show();
|
||||
|
||||
if (!animate)
|
||||
return;
|
||||
|
||||
this.page.opacity = 0;
|
||||
Tweener.addTween(this.page,
|
||||
{ opacity: 255,
|
||||
time: 0.1,
|
||||
@@ -229,6 +66,11 @@ BaseTab.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
_a11yFocus: function() {
|
||||
this._activate();
|
||||
this.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
},
|
||||
|
||||
_activate: function() {
|
||||
this.emit('activated');
|
||||
}
|
||||
@@ -236,48 +78,70 @@ BaseTab.prototype = {
|
||||
Signals.addSignalMethods(BaseTab.prototype);
|
||||
|
||||
|
||||
function ViewTab(label, pageActor) {
|
||||
this._init(label, pageActor);
|
||||
function ViewTab(id, label, pageActor, a11yIcon) {
|
||||
this._init(id, label, pageActor, a11yIcon);
|
||||
}
|
||||
|
||||
ViewTab.prototype = {
|
||||
__proto__: BaseTab.prototype,
|
||||
|
||||
_init: function(label, pageActor) {
|
||||
_init: function(id, label, pageActor, a11yIcon) {
|
||||
this.id = id;
|
||||
|
||||
let titleActor = new St.Button({ label: label,
|
||||
style_class: 'view-tab-title' });
|
||||
titleActor.connect('clicked', Lang.bind(this, this._activate));
|
||||
|
||||
BaseTab.prototype._init.call(this, titleActor, pageActor);
|
||||
BaseTab.prototype._init.call(this, titleActor, pageActor, label, a11yIcon);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function SearchTab(focusBase) {
|
||||
this._init(focusBase);
|
||||
function SearchTab() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
SearchTab.prototype = {
|
||||
__proto__: BaseTab.prototype,
|
||||
|
||||
_init: function(focusBase) {
|
||||
this._searchActive = false;
|
||||
_init: function() {
|
||||
this.active = false;
|
||||
this._searchPending = false;
|
||||
this._keyPressId = 0;
|
||||
this._searchTimeoutId = 0;
|
||||
this._focusBase = focusBase;
|
||||
|
||||
this._searchSystem = new Search.SearchSystem();
|
||||
this._openSearchSystem = new Search.OpenSearchSystem();
|
||||
|
||||
this._searchEntry = new SearchEntry(focusBase);
|
||||
this._entry = new St.Entry({ name: 'searchEntry',
|
||||
/* Translators: this is the text displayed
|
||||
in the search entry when no search is
|
||||
active; it should not exceed ~30
|
||||
characters. */
|
||||
hint_text: _("Type to search..."),
|
||||
track_hover: true,
|
||||
can_focus: true });
|
||||
this._text = this._entry.clutter_text;
|
||||
this._text.connect('key-press-event', Lang.bind(this, this._onKeyPress));
|
||||
|
||||
this._inactiveIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-find',
|
||||
icon_type: St.IconType.SYMBOLIC });
|
||||
this._activeIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-clear',
|
||||
icon_type: St.IconType.SYMBOLIC });
|
||||
this._entry.set_secondary_icon(this._inactiveIcon);
|
||||
|
||||
this._iconClickedId = 0;
|
||||
|
||||
this._searchResults = new SearchDisplay.SearchResults(this._searchSystem, this._openSearchSystem);
|
||||
BaseTab.prototype._init.call(this,
|
||||
this._searchEntry.actor,
|
||||
this._searchResults.actor);
|
||||
this._searchEntry.entry.connect('text-changed',
|
||||
Lang.bind(this, this._onTextChanged));
|
||||
this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) {
|
||||
this._entry,
|
||||
this._searchResults.actor,
|
||||
_("Search"),
|
||||
'edit-find');
|
||||
|
||||
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
|
||||
this._text.connect('activate', Lang.bind(this, function (se) {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._doSearch();
|
||||
@@ -285,24 +149,54 @@ SearchTab.prototype = {
|
||||
this._searchResults.activateSelected();
|
||||
return true;
|
||||
}));
|
||||
},
|
||||
|
||||
show: function() {
|
||||
BaseTab.prototype.show.call(this);
|
||||
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||
|
||||
if (this._keyPressId == 0)
|
||||
this._keyPressId = this._searchEntry.entry.connect('key-press-event',
|
||||
Lang.bind(this, this._onKeyPress));
|
||||
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
|
||||
|
||||
this._capturedEventId = 0;
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
BaseTab.prototype.hide.call(this);
|
||||
|
||||
if (this._keyPressId > 0) {
|
||||
this._searchEntry.entry.disconnect(this._keyPressId);
|
||||
this._keyPressId = 0;
|
||||
// Leave the entry focused when it doesn't have any text;
|
||||
// when replacing a selected search term, Clutter emits
|
||||
// two 'text-changed' signals, one for deleting the previous
|
||||
// text and one for the new one - the second one is handled
|
||||
// incorrectly when we remove focus
|
||||
// (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
|
||||
if (this._text.text != '')
|
||||
this._reset();
|
||||
},
|
||||
|
||||
_reset: function () {
|
||||
this._text.text = '';
|
||||
|
||||
global.stage.set_key_focus(null);
|
||||
|
||||
this._text.set_cursor_visible(true);
|
||||
this._text.set_selection(0, 0);
|
||||
},
|
||||
|
||||
_updateCursorVisibility: function() {
|
||||
let focus = global.stage.get_key_focus();
|
||||
this._text.set_cursor_visible(focus == this._text);
|
||||
},
|
||||
|
||||
_onMapped: function() {
|
||||
if (this._entry.mapped) {
|
||||
// Enable 'find-as-you-type'
|
||||
this._capturedEventId = global.stage.connect('captured-event',
|
||||
Lang.bind(this, this._onCapturedEvent));
|
||||
this._text.set_cursor_visible(true);
|
||||
this._text.set_selection(0, 0);
|
||||
} else {
|
||||
// Disable 'find-as-you-type'
|
||||
if (this._capturedEventId > 0)
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
this._searchEntry.reset();
|
||||
},
|
||||
|
||||
addSearchProvider: function(provider) {
|
||||
@@ -310,19 +204,42 @@ SearchTab.prototype = {
|
||||
this._searchResults.createProviderMeta(provider);
|
||||
},
|
||||
|
||||
startSearch: function(event) {
|
||||
global.stage.set_key_focus(this._text);
|
||||
this._text.event(event, false);
|
||||
},
|
||||
|
||||
// the entry does not show the hint
|
||||
_isActivated: function() {
|
||||
return this._text.text == this._entry.get_text();
|
||||
},
|
||||
|
||||
_onTextChanged: function (se, prop) {
|
||||
let searchPreviouslyActive = this._searchActive;
|
||||
this._searchActive = this._searchEntry.isActive();
|
||||
this._searchPending = this._searchActive && !searchPreviouslyActive;
|
||||
let searchPreviouslyActive = this.active;
|
||||
this.active = this._entry.get_text() != '';
|
||||
this._searchPending = this.active && !searchPreviouslyActive;
|
||||
if (this._searchPending) {
|
||||
this._searchResults.startingSearch();
|
||||
}
|
||||
if (this._searchActive) {
|
||||
if (this.active) {
|
||||
this._entry.set_secondary_icon(this._activeIcon);
|
||||
|
||||
if (this._iconClickedId == 0) {
|
||||
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
|
||||
Lang.bind(this, function() {
|
||||
this._reset();
|
||||
}));
|
||||
}
|
||||
this._activate();
|
||||
} else {
|
||||
if (this._iconClickedId > 0)
|
||||
this._entry.disconnect(this._iconClickedId);
|
||||
this._iconClickedId = 0;
|
||||
|
||||
this._entry.set_secondary_icon(this._inactiveIcon);
|
||||
this.emit('search-cancelled');
|
||||
}
|
||||
if (!this._searchActive) {
|
||||
if (!this.active) {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._searchTimeoutId = 0;
|
||||
@@ -337,24 +254,43 @@ SearchTab.prototype = {
|
||||
_onKeyPress: function(entry, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Up) {
|
||||
if (!this._searchActive)
|
||||
if (!this.active)
|
||||
return true;
|
||||
this._searchResults.selectUp(false);
|
||||
|
||||
return true;
|
||||
} else if (symbol == Clutter.Down) {
|
||||
if (!this._searchActive)
|
||||
if (!this.active)
|
||||
return true;
|
||||
|
||||
this._searchResults.selectDown(false);
|
||||
return true;
|
||||
} else if (symbol == Clutter.Escape) {
|
||||
if (this._isActivated()) {
|
||||
this._reset();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
let source = event.get_source();
|
||||
if (source != this._text && this._text.text == '') {
|
||||
// the user clicked outside after activating the entry, but
|
||||
// with no search term entered - cancel the search
|
||||
this._reset();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_doSearch: function () {
|
||||
this._searchTimeoutId = 0;
|
||||
let text = this._searchEntry.getText();
|
||||
let text = this._text.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
|
||||
this._searchResults.updateSearch(text);
|
||||
|
||||
return false;
|
||||
@@ -370,8 +306,6 @@ ViewSelector.prototype = {
|
||||
_init : function() {
|
||||
this.actor = new St.BoxLayout({ name: 'viewSelector',
|
||||
vertical: true });
|
||||
this.actor.connect('key-press-event',
|
||||
Lang.bind(this, this._onKeyPress));
|
||||
|
||||
// The tab bar is located at the top of the view selector and
|
||||
// holds both "normal" tab labels and the search entry. The former
|
||||
@@ -405,7 +339,7 @@ ViewSelector.prototype = {
|
||||
this._tabs = [];
|
||||
this._activeTab = null;
|
||||
|
||||
this._searchTab = new SearchTab(this.actor);
|
||||
this._searchTab = new SearchTab();
|
||||
this._searchArea.set_child(this._searchTab.title);
|
||||
this._addTab(this._searchTab);
|
||||
|
||||
@@ -416,10 +350,22 @@ ViewSelector.prototype = {
|
||||
|
||||
Main.overview.connect('item-drag-begin',
|
||||
Lang.bind(this, this._switchDefaultTab));
|
||||
Main.overview.connect('showing',
|
||||
Lang.bind(this, this._switchDefaultTab));
|
||||
Main.overview.connect('hiding',
|
||||
Lang.bind(this, this._switchDefaultTab));
|
||||
|
||||
this._stageKeyPressId = 0;
|
||||
Main.overview.connect('showing', Lang.bind(this,
|
||||
function () {
|
||||
this._switchDefaultTab();
|
||||
this._stageKeyPressId = global.stage.connect('key-press-event',
|
||||
Lang.bind(this, this._onStageKeyPress));
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this,
|
||||
function () {
|
||||
this._switchDefaultTab();
|
||||
if (this._stageKeyPressId != 0) {
|
||||
global.stage.disconnect(this._stageKeyPressId);
|
||||
this._stageKeyPressId = 0;
|
||||
}
|
||||
}));
|
||||
|
||||
// Public constraints which may be used to tie actors' height or
|
||||
// vertical position to the current tab's content; as the content's
|
||||
@@ -443,14 +389,16 @@ ViewSelector.prototype = {
|
||||
}));
|
||||
},
|
||||
|
||||
addViewTab: function(title, pageActor) {
|
||||
let viewTab = new ViewTab(title, pageActor);
|
||||
addViewTab: function(id, title, pageActor, a11yIcon) {
|
||||
let viewTab = new ViewTab(id, title, pageActor, a11yIcon);
|
||||
this._tabs.push(viewTab);
|
||||
this._tabBox.add(viewTab.title);
|
||||
this._addTab(viewTab);
|
||||
},
|
||||
|
||||
_switchTab: function(tab) {
|
||||
let firstSwitch = this._activeTab == null;
|
||||
|
||||
if (this._activeTab && this._activeTab.visible) {
|
||||
if (this._activeTab == tab)
|
||||
return;
|
||||
@@ -466,11 +414,13 @@ ViewSelector.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
// Only fade when switching between tabs,
|
||||
// not when setting the initially selected one.
|
||||
if (!tab.visible)
|
||||
tab.show();
|
||||
tab.show(!firstSwitch);
|
||||
|
||||
// Pull a Meg Ryan:
|
||||
if (Main.overview && Main.overview.workspaces) {
|
||||
if (!firstSwitch && Main.overview.workspaces) {
|
||||
if (tab != this._tabs[0]) {
|
||||
Tweener.addTween(Main.overview.workspaces.actor,
|
||||
{ opacity: 0,
|
||||
@@ -493,6 +443,14 @@ ViewSelector.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
switchTab: function(id) {
|
||||
for (let i = 0; i < this._tabs.length; i++)
|
||||
if (this._tabs[i].id == id) {
|
||||
this._switchTab(this._tabs[i]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_switchDefaultTab: function() {
|
||||
if (this._tabs.length > 0)
|
||||
this._switchTab(this._tabs[0]);
|
||||
@@ -574,22 +532,25 @@ ViewSelector.prototype = {
|
||||
}));
|
||||
},
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
_onStageKeyPress: function(actor, event) {
|
||||
let modifiers = Shell.get_event_state(event);
|
||||
let symbol = event.get_key_symbol();
|
||||
|
||||
if (symbol == Clutter.Escape) {
|
||||
Main.overview.hide();
|
||||
return true;
|
||||
} else if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
|
||||
if (symbol == Clutter.Page_Up) {
|
||||
if (!this._searchActive)
|
||||
if (!this._searchTab.active)
|
||||
this._prevTab();
|
||||
return true;
|
||||
} else if (symbol == Clutter.Page_Down) {
|
||||
if (!this._searchActive)
|
||||
if (!this._searchTab.active)
|
||||
this._nextTab();
|
||||
return true;
|
||||
}
|
||||
} else if (Clutter.keysym_to_unicode(symbol)) {
|
||||
this._searchTab.startSearch(event);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
@@ -15,12 +13,11 @@ function WindowAttentionHandler() {
|
||||
WindowAttentionHandler.prototype = {
|
||||
_init : function() {
|
||||
this._startupIds = {};
|
||||
this._sources = {};
|
||||
this._tracker = Shell.WindowTracker.get_default();
|
||||
this._tracker.connect('startup-sequence-changed', Lang.bind(this, this._onStartupSequenceChanged));
|
||||
|
||||
let display = global.screen.get_display();
|
||||
display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
tracker.connect('startup-sequence-changed', Lang.bind(this, this._onStartupSequenceChanged));
|
||||
},
|
||||
|
||||
_onStartupSequenceChanged : function(tracker) {
|
||||
@@ -57,28 +54,16 @@ WindowAttentionHandler.prototype = {
|
||||
if (!window || window.has_focus() || window.is_skip_taskbar())
|
||||
return;
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let app = tracker.get_window_app(window);
|
||||
let appId = app.get_id();
|
||||
|
||||
let source = this._sources[appId];
|
||||
if (source == null) {
|
||||
source = new Source(app, window);
|
||||
this._sources[appId] = source;
|
||||
Main.messageTray.add(source);
|
||||
source.connect('destroy', Lang.bind(this, function() { delete this._sources[appId]; }));
|
||||
}
|
||||
let app = this._tracker.get_window_app(window);
|
||||
let source = new Source(app, window);
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notification = new MessageTray.Notification(source, this._getTitle(app, window), this._getBanner(app, window));
|
||||
source.notify(notification);
|
||||
|
||||
window.connect('notify::title', Lang.bind(this, function(win) {
|
||||
notification.update(this._getTitle(app, win), this._getBanner(app, win));
|
||||
}));
|
||||
window.connect('notify::demands-attention', Lang.bind(this, function() { source.destroy(); }));
|
||||
window.connect('focus', Lang.bind(this, function() { source.destroy(); }));
|
||||
window.connect('unmanaged', Lang.bind(this, function() { source.destroy(); }));
|
||||
|
||||
source.signalIDs.push(window.connect('notify::title', Lang.bind(this, function(win) {
|
||||
notification.update(this._getTitle(app, win), this._getBanner(app, win));
|
||||
})));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -94,13 +79,27 @@ Source.prototype = {
|
||||
this._window = window;
|
||||
this._app = app;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
|
||||
this.signalIDs = [];
|
||||
this.signalIDs.push(this._window.connect('notify::demands-attention', Lang.bind(this, function() { this.destroy(); })));
|
||||
this.signalIDs.push(this._window.connect('focus', Lang.bind(this, function() { this.destroy(); })));
|
||||
this.signalIDs.push(this._window.connect('unmanaged', Lang.bind(this, function() { this.destroy(); })));
|
||||
|
||||
this.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
},
|
||||
|
||||
_onDestroy : function() {
|
||||
for(let i = 0; i < this.signalIDs.length; i++) {
|
||||
this._window.disconnect(this.signalIDs[i]);
|
||||
}
|
||||
this.signalIDs = [];
|
||||
},
|
||||
|
||||
createNotificationIcon : function() {
|
||||
return this._app.create_icon_texture(this.ICON_SIZE);
|
||||
},
|
||||
|
||||
_notificationClicked : function(notification) {
|
||||
open : function(notification) {
|
||||
Main.activateWindow(this._window);
|
||||
this.destroy();
|
||||
}
|
||||
|
||||
@@ -93,6 +93,8 @@ WindowManager.prototype = {
|
||||
|
||||
this._dimmedWindows = [];
|
||||
|
||||
this._animationBlockCount = 0;
|
||||
|
||||
this._switchData = null;
|
||||
this._shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
|
||||
this._shellwm.connect('kill-window-effects', Lang.bind(this, function (shellwm, actor) {
|
||||
@@ -117,14 +119,15 @@ WindowManager.prototype = {
|
||||
this.setKeybindingHandler('switch_to_workspace_down', Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setKeybindingHandler('switch_windows', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_group', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_panels', Lang.bind(this, this._startA11ySwitcher));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
this._undimParentWindow(this._dimmedWindows[i], true);
|
||||
this._undimWindow(this._dimmedWindows[i], true);
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||
this._dimParentWindow(this._dimmedWindows[i], true);
|
||||
this._dimWindow(this._dimmedWindows[i], true);
|
||||
}));
|
||||
},
|
||||
|
||||
@@ -138,8 +141,16 @@ WindowManager.prototype = {
|
||||
this._shellwm.connect('keybinding::' + keybinding, handler);
|
||||
},
|
||||
|
||||
blockAnimations: function() {
|
||||
this._animationBlockCount++;
|
||||
},
|
||||
|
||||
unblockAnimations: function() {
|
||||
this._animationBlockCount = Math.max(0, this._animationBlockCount - 1);
|
||||
},
|
||||
|
||||
_shouldAnimate : function(actor) {
|
||||
if (Main.overview.visible)
|
||||
if (Main.overview.visible || this._animationsBlocked > 0)
|
||||
return false;
|
||||
if (actor && (actor.meta_window.get_window_type() != Meta.WindowType.NORMAL))
|
||||
return false;
|
||||
@@ -223,41 +234,39 @@ WindowManager.prototype = {
|
||||
_unmaximizeWindowDone : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_parentHasOtherAttachedDialog: function(parent, self) {
|
||||
_hasAttachedDialogs: function(window, ignoreWindow) {
|
||||
var count = 0;
|
||||
parent.foreach_transient(function(win) {
|
||||
if (win.get_window_type() == Meta.WindowType.MODAL_DIALOG && win != self)
|
||||
window.foreach_transient(function(win) {
|
||||
if (win != ignoreWindow && win.get_window_type() == Meta.WindowType.MODAL_DIALOG)
|
||||
count++;
|
||||
return false;
|
||||
});
|
||||
return count != 0;
|
||||
},
|
||||
|
||||
_markParentWindowAsDimmable: function(actor, animate) {
|
||||
if (Meta.prefs_get_attach_modal_dialogs()) {
|
||||
this._dimmedWindows.push(actor);
|
||||
if (this._shouldAnimate())
|
||||
this._dimParentWindow(actor, animate);
|
||||
_checkDimming: function(window, ignoreWindow) {
|
||||
let shouldDim = Meta.prefs_get_attach_modal_dialogs() && this._hasAttachedDialogs(window, ignoreWindow);
|
||||
|
||||
if (shouldDim && !window._dimmed) {
|
||||
window._dimmed = true;
|
||||
this._dimmedWindows.push(window);
|
||||
if (!Main.overview.visible)
|
||||
this._dimWindow(window, true);
|
||||
} else if (!shouldDim && window._dimmed) {
|
||||
window._dimmed = false;
|
||||
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
|
||||
return win != window;
|
||||
});
|
||||
if (!Main.overview.visible)
|
||||
this._undimWindow(window, true);
|
||||
}
|
||||
},
|
||||
|
||||
_unmarkParentWindowAsDimmable: function(actor, animate) {
|
||||
if (!Main.overview.visible)
|
||||
this._undimParentWindow(actor, true);
|
||||
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
|
||||
return win != actor;
|
||||
});
|
||||
},
|
||||
|
||||
_dimParentWindow: function(actor, animate) {
|
||||
let meta = actor.get_meta_window();
|
||||
let parent = meta.get_transient_for();
|
||||
if (!parent)
|
||||
_dimWindow: function(window, animate) {
|
||||
let actor = window.get_compositor_private();
|
||||
if (!actor)
|
||||
return;
|
||||
let parentActor = parent.get_compositor_private();
|
||||
if (!parentActor || this._parentHasOtherAttachedDialog(parent, meta))
|
||||
return;
|
||||
let texture = parentActor.get_texture();
|
||||
let texture = actor.get_texture();
|
||||
if (animate)
|
||||
Tweener.addTween(getWindowDimmer(texture),
|
||||
{ dimFraction: 1.0,
|
||||
@@ -268,15 +277,11 @@ WindowManager.prototype = {
|
||||
getWindowDimmer(texture).dimFraction = 1.0;
|
||||
},
|
||||
|
||||
_undimParentWindow: function(actor, animate) {
|
||||
let meta = actor.get_meta_window();
|
||||
let parent = meta.get_transient_for();
|
||||
if (!parent)
|
||||
_undimWindow: function(window, animate) {
|
||||
let actor = window.get_compositor_private();
|
||||
if (!actor)
|
||||
return;
|
||||
let parentActor = parent.get_compositor_private();
|
||||
if (!parentActor || this._parentHasOtherAttachedDialog(parent, meta))
|
||||
return;
|
||||
let texture = parentActor.get_texture();
|
||||
let texture = actor.get_texture();
|
||||
if (animate)
|
||||
Tweener.addTween(getWindowDimmer(texture),
|
||||
{ dimFraction: 0.0,
|
||||
@@ -293,17 +298,19 @@ WindowManager.prototype = {
|
||||
let type = actor.meta_window.get_window_type();
|
||||
if (type == actor._windowType)
|
||||
return;
|
||||
if (type == Meta.WindowType.MODAL_DIALOG)
|
||||
this._markParentWindowAsDimmable(actor, true);
|
||||
else if (actor._windowType == Meta.WindowType.MODAL_DIALOG)
|
||||
this._unmarkParentWindowAsDimmable(actor, true);
|
||||
if (type == Meta.WindowType.MODAL_DIALOG ||
|
||||
actor._windowType == Meta.WindowType.MODAL_DIALOG) {
|
||||
let parent = actor.get_meta_window().get_transient_for();
|
||||
if (parent)
|
||||
this._checkDimming(parent);
|
||||
}
|
||||
|
||||
actor._windowType = type;
|
||||
}));
|
||||
if (actor.meta_window.get_window_type() == Meta.WindowType.MODAL_DIALOG
|
||||
&& Meta.prefs_get_attach_modal_dialogs()
|
||||
&& actor.get_meta_window().get_transient_for()) {
|
||||
this._markParentWindowAsDimmable(actor, true);
|
||||
this._checkDimming(actor.get_meta_window().get_transient_for());
|
||||
if (this._shouldAnimate()) {
|
||||
actor.set_scale(1.0, 0.0);
|
||||
actor.show();
|
||||
@@ -363,14 +370,20 @@ WindowManager.prototype = {
|
||||
},
|
||||
|
||||
_destroyWindow : function(shellwm, actor) {
|
||||
let parent = actor.meta_window.get_transient_for();
|
||||
let window = actor.meta_window;
|
||||
let parent = window.get_transient_for();
|
||||
if (actor._notifyWindowTypeSignalId) {
|
||||
actor.meta_window.disconnect(actor._notifyWindowTypeSignalId);
|
||||
window.disconnect(actor._notifyWindowTypeSignalId);
|
||||
actor._notifyWindowTypeSignalId = 0;
|
||||
}
|
||||
while (actor.meta_window.get_window_type() == Meta.WindowType.MODAL_DIALOG
|
||||
if (window._dimmed) {
|
||||
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
|
||||
return win != window;
|
||||
});
|
||||
}
|
||||
while (window.get_window_type() == Meta.WindowType.MODAL_DIALOG
|
||||
&& parent) {
|
||||
this._unmarkParentWindowAsDimmable(actor, true);
|
||||
this._checkDimming(parent, window);
|
||||
if (!Meta.prefs_get_attach_modal_dialogs()
|
||||
|| !this._shouldAnimate())
|
||||
break;
|
||||
@@ -525,6 +538,10 @@ WindowManager.prototype = {
|
||||
tabPopup.destroy();
|
||||
},
|
||||
|
||||
_startA11ySwitcher : function(shellwm, binding, window, backwards) {
|
||||
Main.ctrlAltTabManager.popup(backwards);
|
||||
},
|
||||
|
||||
_showWorkspaceSwitcher : function(shellwm, binding, window, backwards) {
|
||||
if (global.screen.n_workspaces == 1)
|
||||
return;
|
||||
|
||||
@@ -125,6 +125,7 @@ WindowClone.prototype = {
|
||||
dragActorMaxSize: WINDOW_DND_SIZE,
|
||||
dragActorOpacity: DRAGGING_WINDOW_OPACITY });
|
||||
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled));
|
||||
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||
this.inDrag = false;
|
||||
|
||||
@@ -220,8 +221,15 @@ WindowClone.prototype = {
|
||||
|
||||
let [width, height] = this.actor.get_transformed_size();
|
||||
|
||||
this.actor.x = _clamp(this.actor.x, 0, global.screen_width - width);
|
||||
this.actor.y = _clamp(this.actor.y, Panel.PANEL_HEIGHT, global.screen_height - height);
|
||||
let monitorIndex = this.metaWindow.get_monitor();
|
||||
let availArea = global.get_monitors()[monitorIndex];
|
||||
if (monitorIndex == global.get_primary_monitor_index()) {
|
||||
availArea.y += Main.panel.actor.height;
|
||||
availArea.height -= Main.panel.actor.height;
|
||||
}
|
||||
|
||||
this.actor.x = _clamp(this.actor.x, availArea.x, availArea.x + availArea.width - width);
|
||||
this.actor.y = _clamp(this.actor.y, availArea.y, availArea.y + availArea.height - height);
|
||||
},
|
||||
|
||||
_zoomStart : function () {
|
||||
@@ -229,7 +237,7 @@ WindowClone.prototype = {
|
||||
this.emit('zoom-start');
|
||||
|
||||
if (!this._zoomLightbox)
|
||||
this._zoomLightbox = new Lightbox.Lightbox(global.stage,
|
||||
this._zoomLightbox = new Lightbox.Lightbox(Main.uiGroup,
|
||||
{ fadeTime: LIGHTBOX_FADE_TIME });
|
||||
this._zoomLightbox.show();
|
||||
|
||||
@@ -240,7 +248,7 @@ WindowClone.prototype = {
|
||||
this._zoomGlobalOrig.setPosition.apply(this._zoomGlobalOrig, this.actor.get_transformed_position());
|
||||
this._zoomGlobalOrig.setScale(width / this.actor.width, height / this.actor.height);
|
||||
|
||||
this.actor.reparent(global.stage);
|
||||
this.actor.reparent(Main.uiGroup);
|
||||
this._zoomLightbox.highlight(this.actor);
|
||||
|
||||
[this.actor.x, this.actor.y] = this._zoomGlobalOrig.getPosition();
|
||||
@@ -288,10 +296,19 @@ WindowClone.prototype = {
|
||||
},
|
||||
|
||||
_onDragBegin : function (draggable, time) {
|
||||
if (this._zooming)
|
||||
this._zoomEnd();
|
||||
|
||||
[this.dragOrigX, this.dragOrigY] = this.actor.get_position();
|
||||
this.dragOrigScale = this.actor.scale_x;
|
||||
this.inDrag = true;
|
||||
this.emit('drag-begin');
|
||||
},
|
||||
|
||||
_onDragCancelled : function (draggable, time) {
|
||||
this.emit('drag-cancelled');
|
||||
},
|
||||
|
||||
_onDragEnd : function (draggable, time, snapback) {
|
||||
this.inDrag = false;
|
||||
|
||||
@@ -327,6 +344,7 @@ WindowOverlay.prototype = {
|
||||
|
||||
this._windowClone = windowClone;
|
||||
this._parentActor = parentActor;
|
||||
this._hidden = false;
|
||||
|
||||
let title = new St.Label({ style_class: 'window-caption',
|
||||
text: metaWindow.title });
|
||||
@@ -372,23 +390,21 @@ WindowOverlay.prototype = {
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this._hidden = true;
|
||||
this.closeButton.hide();
|
||||
this.title.hide();
|
||||
},
|
||||
|
||||
show: function() {
|
||||
let [x, y, mask] = global.get_pointer();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor == this._windowClone.actor) {
|
||||
this._hidden = false;
|
||||
if (this._windowClone.actor.has_pointer)
|
||||
this.closeButton.show();
|
||||
}
|
||||
this.title.show();
|
||||
},
|
||||
|
||||
fadeIn: function() {
|
||||
this.show();
|
||||
this.title.opacity = 0;
|
||||
this.title.show();
|
||||
this._parentActor.raise_top();
|
||||
Tweener.addTween(this.title,
|
||||
{ opacity: 255,
|
||||
@@ -419,8 +435,13 @@ WindowOverlay.prototype = {
|
||||
let button = this.closeButton;
|
||||
let title = this.title;
|
||||
|
||||
let buttonX = cloneX + cloneWidth - button._overlap;
|
||||
let buttonY = cloneY - button.height + button._overlap;
|
||||
let buttonX;
|
||||
let buttonY = cloneY - (button.height - button._overlap);
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
buttonX = cloneX - (button.width - button._overlap);
|
||||
else
|
||||
buttonX = cloneX + (cloneWidth - button._overlap);
|
||||
|
||||
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
||||
|
||||
if (!title.fullWidth)
|
||||
@@ -475,6 +496,12 @@ WindowOverlay.prototype = {
|
||||
},
|
||||
|
||||
_onEnter: function() {
|
||||
// We might get enter events on the clone while the overlay is
|
||||
// hidden, e.g. during animations, we ignore these events,
|
||||
// as the close button will be shown as needed when the overlays
|
||||
// are shown again
|
||||
if (this._hidden)
|
||||
return;
|
||||
this._parentActor.raise_top();
|
||||
this.closeButton.show();
|
||||
this.emit('show-close-button');
|
||||
@@ -515,44 +542,45 @@ WindowOverlay.prototype = {
|
||||
Signals.addSignalMethods(WindowOverlay.prototype);
|
||||
|
||||
const WindowPositionFlags = {
|
||||
ZOOM: 1 << 0,
|
||||
INITIAL: 1 << 0,
|
||||
ANIMATE: 1 << 1
|
||||
};
|
||||
|
||||
/**
|
||||
* @metaWorkspace: a #Meta.Workspace
|
||||
* @metaWorkspace: a #Meta.Workspace, or null
|
||||
*/
|
||||
function Workspace(metaWorkspace) {
|
||||
this._init(metaWorkspace);
|
||||
function Workspace(metaWorkspace, monitorIndex) {
|
||||
this._init(metaWorkspace, monitorIndex);
|
||||
}
|
||||
|
||||
Workspace.prototype = {
|
||||
_init : function(metaWorkspace) {
|
||||
_init : function(metaWorkspace, monitorIndex) {
|
||||
// When dragging a window, we use this slot for reserve space.
|
||||
this._reservedSlot = null;
|
||||
this.metaWorkspace = metaWorkspace;
|
||||
this._x = 0;
|
||||
this._y = 0;
|
||||
this._width = 0;
|
||||
this._height = 0;
|
||||
|
||||
this.monitorIndex = monitorIndex;
|
||||
this._monitor = global.get_monitors()[this.monitorIndex];
|
||||
this._windowOverlaysGroup = new Clutter.Group();
|
||||
// Without this the drop area will be overlapped.
|
||||
this._windowOverlaysGroup.set_size(0, 0);
|
||||
|
||||
this.actor = new Clutter.Group();
|
||||
this.actor._delegate = this;
|
||||
this.actor.set_size(0, 0);
|
||||
|
||||
this._dropRect = new Clutter.Rectangle({ opacity: 0 });
|
||||
this._dropRect._delegate = this;
|
||||
|
||||
this.actor.add_actor(this._dropRect);
|
||||
this.actor.add_actor(this._windowOverlaysGroup);
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
// Items in _windowOverlaysGroup should not be scaled, so we don't
|
||||
// add them to this.actor, but to its parent whenever it changes
|
||||
this.actor.connect('parent-set', Lang.bind(this, this._onParentSet));
|
||||
|
||||
// Auto-sizing is unreliable in the presence of ClutterClone, so rather than
|
||||
// implicitly counting on the workspace actor to be sized to the size of the
|
||||
// included desktop actor clone, set the size explicitly to the screen size.
|
||||
// See http://bugzilla.openedhand.com/show_bug.cgi?id=1755
|
||||
this.actor.width = global.screen_width;
|
||||
this.actor.height = global.screen_height;
|
||||
this.scale = 1.0;
|
||||
|
||||
let windows = Main.getWindowActorsForWorkspace(this.metaWorkspace.index());
|
||||
let windows = global.get_window_actors().filter(this._isMyWindow, this);
|
||||
|
||||
// Create clones for windows that should be
|
||||
// visible in the Overview
|
||||
@@ -565,15 +593,37 @@ Workspace.prototype = {
|
||||
}
|
||||
|
||||
// Track window changes
|
||||
this._windowAddedId = this.metaWorkspace.connect('window-added',
|
||||
Lang.bind(this, this._windowAdded));
|
||||
this._windowRemovedId = this.metaWorkspace.connect('window-removed',
|
||||
Lang.bind(this, this._windowRemoved));
|
||||
if (this.metaWorkspace) {
|
||||
this._windowAddedId = this.metaWorkspace.connect('window-added',
|
||||
Lang.bind(this, this._windowAdded));
|
||||
this._windowRemovedId = this.metaWorkspace.connect('window-removed',
|
||||
Lang.bind(this, this._windowRemoved));
|
||||
}
|
||||
this._windowEnteredMonitorId = global.screen.connect('window-entered-monitor',
|
||||
Lang.bind(this, this._windowEnteredMonitor));
|
||||
this._windowLeftMonitorId = global.screen.connect('window-left-monitor',
|
||||
Lang.bind(this, this._windowLeftMonitor));
|
||||
this._repositionWindowsId = 0;
|
||||
|
||||
this.leavingOverview = false;
|
||||
},
|
||||
|
||||
setGeometry: function(x, y, width, height) {
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
|
||||
// This is sometimes called during allocation, so we do this later
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||
function () {
|
||||
this._dropRect.set_position(x, y);
|
||||
this._dropRect.set_size(width, height);
|
||||
return false;
|
||||
}));
|
||||
|
||||
},
|
||||
|
||||
_lookupIndex: function (metaWindow) {
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
if (this._windows[i].metaWindow == metaWindow) {
|
||||
@@ -583,17 +633,6 @@ Workspace.prototype = {
|
||||
return -1;
|
||||
},
|
||||
|
||||
_onParentSet: function(actor, old_parent) {
|
||||
let new_parent = this.actor.get_parent();
|
||||
if (new_parent == null)
|
||||
return;
|
||||
|
||||
if (old_parent)
|
||||
this._windowOverlaysGroup.reparent(new_parent);
|
||||
else
|
||||
new_parent.add_actor(this._windowOverlaysGroup);
|
||||
},
|
||||
|
||||
containsMetaWindow: function (metaWindow) {
|
||||
return this._lookupIndex(metaWindow) >= 0;
|
||||
},
|
||||
@@ -672,10 +711,20 @@ Workspace.prototype = {
|
||||
let xDelta, yDelta, distanceSquared;
|
||||
let actorWidth, actorHeight;
|
||||
|
||||
actorWidth = actor.width * actor.scale_x;
|
||||
actorHeight = actor.height * actor.scale_y;
|
||||
xDelta = actor.x + actorWidth / 2.0 - xCenter * global.screen_width;
|
||||
yDelta = actor.y + actorHeight / 2.0 - yCenter * global.screen_height;
|
||||
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;
|
||||
@@ -700,6 +749,12 @@ Workspace.prototype = {
|
||||
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) {
|
||||
@@ -760,38 +815,35 @@ Workspace.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* _getSlotRelativeGeometry:
|
||||
* _getSlotGeometry:
|
||||
* @slot: A layout slot
|
||||
*
|
||||
* Returns: the workspace-relative [x, y, width, height]
|
||||
* Returns: the screen-relative [x, y, width, height]
|
||||
* of a given window layout slot.
|
||||
*/
|
||||
_getSlotRelativeGeometry: function(slot) {
|
||||
_getSlotGeometry: function(slot) {
|
||||
let [xCenter, yCenter, fraction] = slot;
|
||||
|
||||
let width = global.screen_width * fraction;
|
||||
let height = global.screen_height * fraction;
|
||||
let width = this._width * fraction;
|
||||
let height = this._height * fraction;
|
||||
|
||||
let x = xCenter * global.screen_width - width / 2;
|
||||
let y = yCenter * global.screen_height - height / 2;
|
||||
let x = this._x + xCenter * this._width - width / 2 ;
|
||||
let y = this._y + yCenter * this._height - height / 2;
|
||||
|
||||
return [x, y, width, height];
|
||||
},
|
||||
|
||||
/**
|
||||
* _computeWindowRelativeLayout:
|
||||
* _computeWindowLayout:
|
||||
* @metaWindow: A #MetaWindow
|
||||
* @slot: A layout slot
|
||||
*
|
||||
* Given a window and slot to fit it in, compute its
|
||||
* workspace-relative [x, y, scale] where scale applies
|
||||
* screen-relative [x, y, scale] where scale applies
|
||||
* to both X and Y directions.
|
||||
*/
|
||||
_computeWindowRelativeLayout: function(metaWindow, slot) {
|
||||
let [xCenter, yCenter, fraction] = slot;
|
||||
let [x, y, width, height] = this._getSlotRelativeGeometry(slot);
|
||||
|
||||
xCenter = xCenter * global.screen_width;
|
||||
_computeWindowLayout: function(metaWindow, slot) {
|
||||
let [x, y, width, height] = this._getSlotGeometry(slot);
|
||||
|
||||
let rect = metaWindow.get_outer_rect();
|
||||
let buttonOuterHeight, captionHeight;
|
||||
@@ -799,23 +851,19 @@ Workspace.prototype = {
|
||||
|
||||
if (this._windowOverlays[0]) {
|
||||
[buttonOuterHeight, captionHeight] = this._windowOverlays[0].chromeHeights();
|
||||
buttonOuterWidth = this._windowOverlays[0].chromeWidth() / this.scale;
|
||||
buttonOuterWidth = this._windowOverlays[0].chromeWidth();
|
||||
} else
|
||||
[buttonOuterHeight, captionHeight] = [0, 0];
|
||||
buttonOuterHeight /= this.scale;
|
||||
captionHeight /= this.scale;
|
||||
|
||||
let desiredWidth = global.screen_width * fraction;
|
||||
let desiredHeight = global.screen_height * fraction;
|
||||
let scale = Math.min((desiredWidth - buttonOuterWidth) / rect.width,
|
||||
(desiredHeight - buttonOuterHeight - captionHeight) / rect.height,
|
||||
1.0 / this.scale);
|
||||
let scale = Math.min((width - buttonOuterWidth) / rect.width,
|
||||
(height - buttonOuterHeight - captionHeight) / rect.height,
|
||||
1.0);
|
||||
|
||||
x = Math.floor(xCenter - 0.5 * scale * rect.width);
|
||||
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(yCenter * global.screen_height - 0.5 * scale * rect.height);
|
||||
y = Math.floor(y + (height - scale * rect.height) / 2);
|
||||
else
|
||||
y = Math.floor(y + height - rect.height * scale - captionHeight);
|
||||
|
||||
@@ -841,7 +889,7 @@ Workspace.prototype = {
|
||||
/**
|
||||
* positionWindows:
|
||||
* @flags:
|
||||
* ZOOM - workspace is moving at the same time and we need to take that into account.
|
||||
* INITIAL - this is the initial positioning of the windows.
|
||||
* ANIMATE - Indicates that we need animate changing position.
|
||||
*/
|
||||
positionWindows : function(flags) {
|
||||
@@ -854,7 +902,7 @@ Workspace.prototype = {
|
||||
if (this._reservedSlot)
|
||||
clones.push(this._reservedSlot);
|
||||
|
||||
let workspaceZooming = flags & WindowPositionFlags.ZOOM;
|
||||
let initialPositioning = flags & WindowPositionFlags.INITIAL;
|
||||
let animate = flags & WindowPositionFlags.ANIMATE;
|
||||
|
||||
// Start the animations
|
||||
@@ -862,7 +910,7 @@ Workspace.prototype = {
|
||||
clones = this._orderWindowsByMotionAndStartup(clones, slots);
|
||||
|
||||
let currentWorkspace = global.screen.get_active_workspace();
|
||||
let isOnCurrentWorkspace = this.metaWorkspace == currentWorkspace;
|
||||
let isOnCurrentWorkspace = this.metaWorkspace == null || this.metaWorkspace == currentWorkspace;
|
||||
|
||||
for (let i = 0; i < clones.length; i++) {
|
||||
let slot = slots[i];
|
||||
@@ -876,7 +924,7 @@ Workspace.prototype = {
|
||||
if (clone.inDrag)
|
||||
continue;
|
||||
|
||||
let [x, y, scale] = this._computeWindowRelativeLayout(metaWindow, slot);
|
||||
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
|
||||
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
@@ -885,7 +933,7 @@ Workspace.prototype = {
|
||||
/* Hidden windows should fade in and grow
|
||||
* therefore we need to resize them now so they
|
||||
* can be scaled up later */
|
||||
if (workspaceZooming) {
|
||||
if (initialPositioning) {
|
||||
clone.actor.opacity = 0;
|
||||
clone.actor.scale_x = 0;
|
||||
clone.actor.scale_y = 0;
|
||||
@@ -906,7 +954,6 @@ Workspace.prototype = {
|
||||
y: y,
|
||||
scale_x: scale,
|
||||
scale_y: scale,
|
||||
workspace_relative: workspaceZooming ? this : null,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
@@ -929,7 +976,7 @@ Workspace.prototype = {
|
||||
let clone = clones[i];
|
||||
let metaWindow = clone.metaWindow;
|
||||
if (i == 0) {
|
||||
clone.setStackAbove(null);
|
||||
clone.setStackAbove(this._dropRect);
|
||||
} else {
|
||||
let previousClone = clones[i - 1];
|
||||
clone.setStackAbove(previousClone.actor);
|
||||
@@ -949,10 +996,8 @@ Workspace.prototype = {
|
||||
// be after the workspace animation finishes.
|
||||
let [cloneX, cloneY] = clone.actor.get_position();
|
||||
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
||||
cloneX = this.x + this.scale * cloneX;
|
||||
cloneY = this.y + this.scale * cloneY;
|
||||
cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
|
||||
cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
|
||||
cloneWidth = clone.actor.scale_x * cloneWidth;
|
||||
cloneHeight = clone.actor.scale_y * cloneHeight;
|
||||
|
||||
if (overlay) {
|
||||
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
|
||||
@@ -968,7 +1013,8 @@ Workspace.prototype = {
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let overlay = this._windowOverlays[i];
|
||||
this._showWindowOverlay(clone, overlay, this.metaWorkspace == currentWorkspace);
|
||||
this._showWindowOverlay(clone, overlay,
|
||||
this.metaWorkspace == null || this.metaWorkspace == currentWorkspace);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -977,12 +1023,10 @@ Workspace.prototype = {
|
||||
return true;
|
||||
|
||||
let [x, y, mask] = global.get_pointer();
|
||||
let wsWidth = this.actor.width * this.scale;
|
||||
let wsHeight = this.actor.height * this.scale;
|
||||
|
||||
let pointerHasMoved = (this._cursorX != x && this._cursorY != y);
|
||||
let inWorkspace = (this.x < x && x < this.x + wsWidth &&
|
||||
this.y < y && y < this.y + wsHeight);
|
||||
let inWorkspace = (this._x < x && x < this._x + this._width &&
|
||||
this._y < y && y < this._y + this._height);
|
||||
|
||||
if (pointerHasMoved && inWorkspace) {
|
||||
// store current cursor position
|
||||
@@ -1007,7 +1051,7 @@ Workspace.prototype = {
|
||||
this._windowOverlaysGroup.hide();
|
||||
},
|
||||
|
||||
_windowRemoved : function(metaWorkspace, metaWin) {
|
||||
_doRemoveWindow : function(metaWin) {
|
||||
let win = metaWin.get_compositor_private();
|
||||
|
||||
// find the position of the window in our list
|
||||
@@ -1016,6 +1060,10 @@ Workspace.prototype = {
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
// Check if window still should be here
|
||||
if (win && this._isMyWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._windows[index];
|
||||
|
||||
this._windows.splice(index, 1);
|
||||
@@ -1059,7 +1107,7 @@ Workspace.prototype = {
|
||||
Lang.bind(this, this._delayedWindowRepositioning));
|
||||
},
|
||||
|
||||
_windowAdded : function(metaWorkspace, metaWin) {
|
||||
_doAddWindow : function(metaWin) {
|
||||
if (this.leavingOverview)
|
||||
return;
|
||||
|
||||
@@ -1070,31 +1118,65 @@ Workspace.prototype = {
|
||||
// the compositor finds out about them...
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function () {
|
||||
if (this.actor && metaWin.get_compositor_private())
|
||||
this._windowAdded(metaWorkspace, metaWin);
|
||||
if (this.actor &&
|
||||
metaWin.get_compositor_private() &&
|
||||
metaWin.get_workspace() == this.metaWorkspace)
|
||||
this._doAddWindow(metaWin);
|
||||
return false;
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._isOverviewWindow(win))
|
||||
// We might have the window in our list already if it was on all workspaces and
|
||||
// now was moved to this workspace
|
||||
if (this._lookupIndex (metaWin) != -1)
|
||||
return;
|
||||
|
||||
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._addWindowClone(win);
|
||||
|
||||
if (win._overviewHint) {
|
||||
let x = (win._overviewHint.x - this.actor.x) / this.scale;
|
||||
let y = (win._overviewHint.y - this.actor.y) / this.scale;
|
||||
let scale = win._overviewHint.scale / this.scale;
|
||||
let x = win._overviewHint.x - this.actor.x;
|
||||
let y = win._overviewHint.y - this.actor.y;
|
||||
let scale = win._overviewHint.scale;
|
||||
delete win._overviewHint;
|
||||
|
||||
clone.actor.set_position (x, y);
|
||||
clone.actor.set_scale (scale, scale);
|
||||
} else {
|
||||
// Position new windows at the top corner of the workspace rather
|
||||
// than where they were placed for real to avoid the window
|
||||
// being clipped to the workspaceView. Its not really more
|
||||
// natural for the window to suddenly appear in the overview
|
||||
// on some seemingly random location anyway.
|
||||
clone.actor.set_position (this._x, this._y);
|
||||
}
|
||||
|
||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||
},
|
||||
|
||||
_windowAdded : function(metaWorkspace, metaWin) {
|
||||
this._doAddWindow(metaWin);
|
||||
},
|
||||
|
||||
_windowRemoved : function(metaWorkspace, metaWin) {
|
||||
this._doRemoveWindow(metaWin);
|
||||
},
|
||||
|
||||
_windowEnteredMonitor : function(metaScreen, monitorIndex, metaWin) {
|
||||
if (monitorIndex == this.monitorIndex) {
|
||||
this._doAddWindow(metaWin);
|
||||
}
|
||||
},
|
||||
|
||||
_windowLeftMonitor : function(metaScreen, monitorIndex, metaWin) {
|
||||
if (monitorIndex == this.monitorIndex) {
|
||||
this._doRemoveWindow(metaWin);
|
||||
}
|
||||
},
|
||||
|
||||
// check for maximized windows on the workspace
|
||||
hasMaximizedWindows: function() {
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
@@ -1109,14 +1191,11 @@ Workspace.prototype = {
|
||||
|
||||
// Animate the full-screen to Overview transition.
|
||||
zoomToOverview : function() {
|
||||
this.actor.set_position(this.x, this.y);
|
||||
this.actor.set_scale(this.scale, this.scale);
|
||||
|
||||
// Position and scale the windows.
|
||||
if (Main.overview.animationInProgress)
|
||||
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.ZOOM);
|
||||
this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
|
||||
else
|
||||
this.positionWindows(WindowPositionFlags.ZOOM);
|
||||
this.positionWindows(WindowPositionFlags.INITIAL);
|
||||
},
|
||||
|
||||
// Animates the return from Overview mode
|
||||
@@ -1134,7 +1213,7 @@ Workspace.prototype = {
|
||||
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
|
||||
this._doneLeavingOverview));
|
||||
|
||||
if (this._metaWorkspace == currentWorkspace)
|
||||
if (this.metaWorkspace != null && this.metaWorkspace != currentWorkspace)
|
||||
return;
|
||||
|
||||
// Position and scale the windows.
|
||||
@@ -1149,7 +1228,6 @@ Workspace.prototype = {
|
||||
y: clone.origY,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
workspace_relative: this,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
opacity: 255,
|
||||
transition: 'easeOutQuad'
|
||||
@@ -1160,7 +1238,6 @@ Workspace.prototype = {
|
||||
{ scale_x: 0,
|
||||
scale_y: 0,
|
||||
opacity: 0,
|
||||
workspace_relative: this,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
@@ -1180,8 +1257,12 @@ Workspace.prototype = {
|
||||
}
|
||||
Tweener.removeTweens(actor);
|
||||
|
||||
this.metaWorkspace.disconnect(this._windowAddedId);
|
||||
this.metaWorkspace.disconnect(this._windowRemovedId);
|
||||
if (this.metaWorkspace) {
|
||||
this.metaWorkspace.disconnect(this._windowAddedId);
|
||||
this.metaWorkspace.disconnect(this._windowRemovedId);
|
||||
}
|
||||
global.screen.disconnect(this._windowEnteredMonitorId);
|
||||
global.screen.disconnect(this._windowLeftMonitorId);
|
||||
|
||||
if (this._repositionWindowsId > 0)
|
||||
Mainloop.source_remove(this._repositionWindowsId);
|
||||
@@ -1200,9 +1281,10 @@ Workspace.prototype = {
|
||||
this.leavingOverview = false;
|
||||
},
|
||||
|
||||
// Tests if @win belongs to this workspaces
|
||||
// Tests if @win belongs to this workspaces and monitor
|
||||
_isMyWindow : function (win) {
|
||||
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index());
|
||||
return (this.metaWorkspace == null || Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index())) &&
|
||||
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
|
||||
},
|
||||
|
||||
// Tests if @win should be shown in the Overview
|
||||
@@ -1223,6 +1305,10 @@ Workspace.prototype = {
|
||||
Main.overview.beginWindowDrag();
|
||||
overlay.hide();
|
||||
}));
|
||||
clone.connect('drag-cancelled',
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.cancelledWindowDrag();
|
||||
}));
|
||||
clone.connect('drag-end',
|
||||
Lang.bind(this, function(clone) {
|
||||
Main.overview.endWindowDrag();
|
||||
@@ -1286,8 +1372,10 @@ Workspace.prototype = {
|
||||
},
|
||||
|
||||
_onCloneSelected : function (clone, time) {
|
||||
Main.activateWindow(clone.metaWindow, time,
|
||||
this.metaWorkspace.index());
|
||||
let wsIndex = undefined;
|
||||
if (this.metaWorkspace)
|
||||
wsIndex = this.metaWorkspace.index();
|
||||
Main.activateWindow(clone.metaWindow, time, wsIndex);
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
@@ -1315,7 +1403,15 @@ Workspace.prototype = {
|
||||
};
|
||||
|
||||
let metaWindow = win.get_meta_window();
|
||||
metaWindow.change_workspace_by_index(this.metaWorkspace.index(),
|
||||
|
||||
// We need to move the window before changing the workspace, because
|
||||
// the move itself could cause a workspace change if the window enters
|
||||
// the primary monitor
|
||||
if (metaWindow.get_monitor() != this.monitorIndex)
|
||||
metaWindow.move_to_monitor(this.monitorIndex);
|
||||
|
||||
let index = this.metaWorkspace ? this.metaWorkspace.index() : global.screen.get_active_workspace_index();
|
||||
metaWindow.change_workspace_by_index(index,
|
||||
false, // don't create workspace
|
||||
time);
|
||||
return true;
|
||||
@@ -1330,56 +1426,3 @@ Workspace.prototype = {
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Workspace.prototype);
|
||||
|
||||
// Create a SpecialPropertyModifier to let us move windows in a
|
||||
// straight line on the screen even though their containing workspace
|
||||
// is also moving.
|
||||
Tweener.registerSpecialPropertyModifier('workspace_relative', _workspaceRelativeModifier, _workspaceRelativeGet);
|
||||
|
||||
function _workspaceRelativeModifier(workspace) {
|
||||
let [startX, startY] = Main.overview.getPosition();
|
||||
let overviewPosX, overviewPosY, overviewScale;
|
||||
|
||||
if (!workspace)
|
||||
return [];
|
||||
|
||||
if (workspace.leavingOverview) {
|
||||
let [zoomedInX, zoomedInY] = Main.overview.getZoomedInPosition();
|
||||
overviewPosX = { begin: startX, end: zoomedInX };
|
||||
overviewPosY = { begin: startY, end: zoomedInY };
|
||||
overviewScale = { begin: Main.overview.getScale(),
|
||||
end: Main.overview.getZoomedInScale() };
|
||||
} else {
|
||||
overviewPosX = { begin: startX, end: 0 };
|
||||
overviewPosY = { begin: startY, end: 0 };
|
||||
overviewScale = { begin: Main.overview.getScale(), end: 1 };
|
||||
}
|
||||
|
||||
return [ { name: 'x',
|
||||
parameters: { workspacePos: workspace.x,
|
||||
overviewPos: overviewPosX,
|
||||
overviewScale: overviewScale } },
|
||||
{ name: 'y',
|
||||
parameters: { workspacePos: workspace.y,
|
||||
overviewPos: overviewPosY,
|
||||
overviewScale: overviewScale } }
|
||||
];
|
||||
}
|
||||
|
||||
function _workspaceRelativeGet(begin, end, time, params) {
|
||||
let curOverviewPos = (1 - time) * params.overviewPos.begin +
|
||||
time * params.overviewPos.end;
|
||||
let curOverviewScale = (1 - time) * params.overviewScale.begin +
|
||||
time * params.overviewScale.end;
|
||||
|
||||
// Calculate the screen position of the window.
|
||||
let screen = (1 - time) *
|
||||
((begin + params.workspacePos) * params.overviewScale.begin +
|
||||
params.overviewPos.begin) +
|
||||
time *
|
||||
((end + params.workspacePos) * params.overviewScale.end +
|
||||
params.overviewPos.end);
|
||||
|
||||
// Return the workspace coordinates.
|
||||
return (screen - curOverviewPos) / curOverviewScale - params.workspacePos;
|
||||
}
|
||||
|
||||
@@ -146,6 +146,7 @@ function WorkspaceThumbnail(metaWorkspace) {
|
||||
WorkspaceThumbnail.prototype = {
|
||||
_init : function(metaWorkspace) {
|
||||
this.metaWorkspace = metaWorkspace;
|
||||
this.monitorIndex = global.get_primary_monitor_index();
|
||||
|
||||
this.actor = new St.Group({ reactive: true,
|
||||
clip_to_allocation: true,
|
||||
@@ -169,7 +170,8 @@ WorkspaceThumbnail.prototype = {
|
||||
this._background = new Clutter.Clone({ source: global.background_actor });
|
||||
this._contents.add_actor(this._background);
|
||||
|
||||
this.setPorthole(0, 0, global.screen_width, global.screen_height);
|
||||
let monitor = global.get_primary_monitor();
|
||||
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
|
||||
|
||||
let windows = global.get_window_actors().filter(this._isMyWindow, this);
|
||||
|
||||
@@ -186,6 +188,10 @@ WorkspaceThumbnail.prototype = {
|
||||
Lang.bind(this, this._windowAdded));
|
||||
this._windowRemovedId = this.metaWorkspace.connect('window-removed',
|
||||
Lang.bind(this, this._windowRemoved));
|
||||
this._windowEnteredMonitorId = global.screen.connect('window-entered-monitor',
|
||||
Lang.bind(this, this._windowEnteredMonitor));
|
||||
this._windowLeftMonitorId = global.screen.connect('window-left-monitor',
|
||||
Lang.bind(this, this._windowLeftMonitor));
|
||||
|
||||
this.state = ThumbnailState.NORMAL;
|
||||
this._slidePosition = 0; // Fully slid in
|
||||
@@ -193,6 +199,8 @@ WorkspaceThumbnail.prototype = {
|
||||
},
|
||||
|
||||
setPorthole: function(x, y, width, height) {
|
||||
this._portholeX = x;
|
||||
this._portholeY = y;
|
||||
this.actor.set_size(width, height);
|
||||
this._contents.set_position(-x, -y);
|
||||
},
|
||||
@@ -239,7 +247,7 @@ WorkspaceThumbnail.prototype = {
|
||||
return this._collapseFraction;
|
||||
},
|
||||
|
||||
_windowRemoved : function(metaWorkspace, metaWin) {
|
||||
_doRemoveWindow : function(metaWin) {
|
||||
let win = metaWin.get_compositor_private();
|
||||
|
||||
// find the position of the window in our list
|
||||
@@ -248,12 +256,16 @@ WorkspaceThumbnail.prototype = {
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
// Check if window still should be here
|
||||
if (win && this._isMyWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._windows[index];
|
||||
this._windows.splice(index, 1);
|
||||
clone.destroy();
|
||||
},
|
||||
|
||||
_windowAdded : function(metaWorkspace, metaWin) {
|
||||
_doAddWindow : function(metaWin) {
|
||||
if (this.leavingOverview)
|
||||
return;
|
||||
|
||||
@@ -264,19 +276,46 @@ WorkspaceThumbnail.prototype = {
|
||||
// the compositor finds out about them...
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function () {
|
||||
if (this.actor && metaWin.get_compositor_private())
|
||||
this._windowAdded(metaWorkspace, metaWin);
|
||||
if (this.actor &&
|
||||
metaWin.get_compositor_private() &&
|
||||
metaWin.get_workspace() == this.metaWorkspace)
|
||||
this._doAddWindow(metaWin);
|
||||
return false;
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._isOverviewWindow(win))
|
||||
// We might have the window in our list already if it was on all workspaces and
|
||||
// now was moved to this workspace
|
||||
if (this._lookupIndex (metaWin) != -1)
|
||||
return;
|
||||
|
||||
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._addWindowClone(win);
|
||||
},
|
||||
|
||||
_windowAdded : function(metaWorkspace, metaWin) {
|
||||
this._doAddWindow(metaWin);
|
||||
},
|
||||
|
||||
_windowRemoved : function(metaWorkspace, metaWin) {
|
||||
this._doRemoveWindow(metaWin);
|
||||
},
|
||||
|
||||
_windowEnteredMonitor : function(metaScreen, monitorIndex, metaWin) {
|
||||
if (monitorIndex == this.monitorIndex) {
|
||||
this._doAddWindow(metaWin);
|
||||
}
|
||||
},
|
||||
|
||||
_windowLeftMonitor : function(metaScreen, monitorIndex, metaWin) {
|
||||
if (monitorIndex == this.monitorIndex) {
|
||||
this._doRemoveWindow(metaWin);
|
||||
}
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
@@ -284,15 +323,17 @@ WorkspaceThumbnail.prototype = {
|
||||
_onDestroy: function(actor) {
|
||||
this.metaWorkspace.disconnect(this._windowAddedId);
|
||||
this.metaWorkspace.disconnect(this._windowRemovedId);
|
||||
global.screen.disconnect(this._windowEnteredMonitorId);
|
||||
global.screen.disconnect(this._windowLeftMonitorId);
|
||||
|
||||
this._windows = [];
|
||||
this.actor = null;
|
||||
},
|
||||
|
||||
// Tests if @win belongs to this workspaces
|
||||
// Tests if @win belongs to this workspace and monitor
|
||||
_isMyWindow : function (win) {
|
||||
return win.get_workspace() == this.metaWorkspace.index() ||
|
||||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
|
||||
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index()) &&
|
||||
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
|
||||
},
|
||||
|
||||
// Tests if @win should be shown in the Overview
|
||||
@@ -340,6 +381,11 @@ WorkspaceThumbnail.prototype = {
|
||||
|
||||
// Draggable target interface
|
||||
handleDragOver : function(source, actor, x, y, time) {
|
||||
if (source == Main.xdndHandler) {
|
||||
this.metaWorkspace.activate(time);
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
}
|
||||
|
||||
if (this.state > ThumbnailState.NORMAL)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
@@ -361,6 +407,13 @@ WorkspaceThumbnail.prototype = {
|
||||
return false;
|
||||
|
||||
let metaWindow = win.get_meta_window();
|
||||
|
||||
// We need to move the window before changing the workspace, because
|
||||
// the move itself could cause a workspace change if the window enters
|
||||
// the primary monitor
|
||||
if (metaWindow.get_monitor() != this.monitorIndex)
|
||||
metaWindow.move_to_monitor(this.monitorIndex);
|
||||
|
||||
metaWindow.change_workspace_by_index(this.metaWorkspace.index(),
|
||||
false, // don't create workspace
|
||||
time);
|
||||
@@ -402,10 +455,6 @@ ThumbnailsBox.prototype = {
|
||||
// for the border and padding of the background actor.
|
||||
this._background = new St.Bin({ style_class: 'workspace-thumbnails-background' });
|
||||
|
||||
// This will eventually be automatic, see https://bugzilla.gnome.org/show_bug.cgi?id=584662
|
||||
if (St.Widget.get_default_direction () == St.TextDirection.RTL)
|
||||
this._background.add_style_pseudo_class('rtl');
|
||||
|
||||
this.actor.add_actor(this._background);
|
||||
|
||||
let indicator = new St.Bin({ style_class: 'workspace-thumbnail-indicator' });
|
||||
@@ -424,7 +473,7 @@ ThumbnailsBox.prototype = {
|
||||
this._indicatorY = 0; // only used when _animatingIndicator is true
|
||||
|
||||
this._stateCounts = {};
|
||||
for (key in ThumbnailState)
|
||||
for (let key in ThumbnailState)
|
||||
this._stateCounts[ThumbnailState[key]] = 0;
|
||||
|
||||
this._thumbnails = [];
|
||||
@@ -441,16 +490,17 @@ ThumbnailsBox.prototype = {
|
||||
this._stateUpdateQueued = false;
|
||||
|
||||
this._stateCounts = {};
|
||||
for (key in ThumbnailState)
|
||||
for (let key in ThumbnailState)
|
||||
this._stateCounts[ThumbnailState[key]] = 0;
|
||||
|
||||
// The "porthole" is the portion of the screen that we show in the workspaces
|
||||
let panelHeight = Main.panel.actor.height;
|
||||
let monitor = global.get_primary_monitor();
|
||||
this._porthole = {
|
||||
x: 0,
|
||||
y: panelHeight,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height - panelHeight
|
||||
x: monitor.x,
|
||||
y: monitor.y + panelHeight,
|
||||
width: monitor.width,
|
||||
height: monitor.height - panelHeight
|
||||
};
|
||||
|
||||
this.addThumbnails(0, global.screen.n_workspaces);
|
||||
|
||||
@@ -7,8 +7,6 @@ const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
@@ -25,14 +23,13 @@ const MAX_WORKSPACES = 16;
|
||||
const CONTROLS_POP_IN_TIME = 0.1;
|
||||
|
||||
|
||||
function WorkspacesView(width, height, x, y, workspaces) {
|
||||
this._init(width, height, x, y, workspaces);
|
||||
function WorkspacesView(workspaces) {
|
||||
this._init(workspaces);
|
||||
}
|
||||
|
||||
WorkspacesView.prototype = {
|
||||
_init: function(width, height, x, y, workspaces) {
|
||||
_init: function(workspaces) {
|
||||
this.actor = new St.Group({ style_class: 'workspaces-view' });
|
||||
this.actor.set_clip(x, y, width, height);
|
||||
|
||||
// The actor itself isn't a drop target, so we don't want to pick on its area
|
||||
this.actor.set_size(0, 0);
|
||||
@@ -43,19 +40,17 @@ WorkspacesView.prototype = {
|
||||
function() {
|
||||
let node = this.actor.get_theme_node();
|
||||
this._spacing = node.get_length('spacing');
|
||||
this._computeWorkspacePositions();
|
||||
this._updateWorkspaceActors(false);
|
||||
}));
|
||||
this.actor.connect('notify::mapped',
|
||||
Lang.bind(this, this._onMappedChanged));
|
||||
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._zoomScale = 1.0;
|
||||
this._width = 0;
|
||||
this._height = 0;
|
||||
this._x = 0;
|
||||
this._y = 0;
|
||||
this._workspaceRatioSpacing = 0;
|
||||
this._spacing = 0;
|
||||
this._activeWorkspaceX = 0; // x offset of active ws while dragging
|
||||
this._activeWorkspaceY = 0; // y offset of active ws while dragging
|
||||
this._lostWorkspaces = [];
|
||||
this._animating = false; // tweening
|
||||
this._scrolling = false; // swipe-scrolling
|
||||
@@ -71,6 +66,18 @@ WorkspacesView.prototype = {
|
||||
this._workspaces[w].actor.reparent(this.actor);
|
||||
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
||||
|
||||
this._extraWorkspaces = [];
|
||||
let monitors = global.get_monitors();
|
||||
let m = 0;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (i == global.get_primary_monitor_index())
|
||||
continue;
|
||||
let ws = new Workspace.Workspace(null, i);
|
||||
this._extraWorkspaces[m++] = ws;
|
||||
ws.setGeometry(monitors[i].x, monitors[i].y, monitors[i].width, monitors[i].height);
|
||||
global.overlay_group.add_actor(ws.actor);
|
||||
}
|
||||
|
||||
// Position/scale the desktop windows and their children after the
|
||||
// workspaces have been created. This cannot be done first because
|
||||
// window movement depends on the Workspaces object being accessible
|
||||
@@ -80,6 +87,13 @@ WorkspacesView.prototype = {
|
||||
Lang.bind(this, function() {
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomToOverview();
|
||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||
this._extraWorkspaces[w].zoomToOverview();
|
||||
}));
|
||||
this._overviewShownId =
|
||||
Main.overview.connect('shown',
|
||||
Lang.bind(this, function() {
|
||||
this.actor.set_clip(this._x, this._y, this._width, this._height);
|
||||
}));
|
||||
|
||||
this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
||||
@@ -109,30 +123,18 @@ WorkspacesView.prototype = {
|
||||
this._swipeScrollEndId = 0;
|
||||
},
|
||||
|
||||
setZoomScale: function(zoomScale) {
|
||||
if (zoomScale == this._zoomScale)
|
||||
return;
|
||||
setGeometry: function(x, y, width, height, spacing) {
|
||||
if (this._x == x && this._y == y &&
|
||||
this._width == width && this._height == height)
|
||||
return;
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._x = x;
|
||||
this._y = y;
|
||||
this._workspaceRatioSpacing = spacing;
|
||||
|
||||
this._zoomScale = zoomScale;
|
||||
if (this._zoomOut) {
|
||||
// If we are already zoomed out, then we have to reposition.
|
||||
// Note that when shown initially zoomOut is false, so we
|
||||
// won't trigger this.
|
||||
|
||||
// setZoomScale can be invoked when the workspaces view is
|
||||
// reallocated. Since we just want to animate things to the
|
||||
// new position it seems OK to call updateWorkspaceActors
|
||||
// immediately - adding a tween doesn't immediately cause
|
||||
// a new allocation. But hide/show of the window overlays we
|
||||
// do around animation does, so we need to do it later.
|
||||
// This can be removed when we fix things to not hide/show
|
||||
// the window overlay.
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this, function() {
|
||||
this._computeWorkspacePositions();
|
||||
this._updateWorkspaceActors(true);
|
||||
}));
|
||||
}
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setGeometry(x, y, width, height);
|
||||
},
|
||||
|
||||
_lookupWorkspaceForMetaWindow: function (metaWindow) {
|
||||
@@ -154,101 +156,41 @@ WorkspacesView.prototype = {
|
||||
|
||||
activeWorkspace.actor.raise_top();
|
||||
|
||||
this.actor.remove_clip(this._x, this._y, this._width, this._height);
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomFromOverview();
|
||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||
this._extraWorkspaces[w].zoomFromOverview();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
getScale: function() {
|
||||
return this._workspaces[0].scale;
|
||||
},
|
||||
|
||||
syncStacking: function(stackIndices) {
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].syncStacking(stackIndices);
|
||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||
this._extraWorkspaces[i].syncStacking(stackIndices);
|
||||
},
|
||||
|
||||
// Get the grid position of the active workspace.
|
||||
getActiveWorkspacePosition: function() {
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||
|
||||
return [activeWorkspace.x, activeWorkspace.y];
|
||||
},
|
||||
|
||||
zoomOut: function() {
|
||||
if (this._zoomOut)
|
||||
return;
|
||||
|
||||
this._zoomOut = true;
|
||||
this._computeWorkspacePositions();
|
||||
this._updateWorkspaceActors(true);
|
||||
},
|
||||
|
||||
zoomIn: function() {
|
||||
if (!this._zoomOut)
|
||||
return;
|
||||
|
||||
this._zoomOut = false;
|
||||
this._computeWorkspacePositions();
|
||||
this._updateWorkspaceActors(true);
|
||||
},
|
||||
|
||||
// Compute the position, scale and opacity of the workspaces, but don't
|
||||
// actually change the actors to match
|
||||
_computeWorkspacePositions: function() {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
let zoomScale = this._zoomOut ? this._zoomScale : 1;
|
||||
let scale = zoomScale * this._width / global.screen_width;
|
||||
|
||||
let _width = this._workspaces[0].actor.width * scale;
|
||||
let _height = this._workspaces[0].actor.height * scale;
|
||||
|
||||
this._activeWorkspaceX = (this._width - _width) / 2;
|
||||
this._activeWorkspaceY = (this._height - _height) / 2;
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++) {
|
||||
let workspace = this._workspaces[w];
|
||||
|
||||
workspace.opacity = (this._inDrag && w != active) ? 200 : 255;
|
||||
|
||||
workspace.scale = scale;
|
||||
workspace.x = this._x + this._activeWorkspaceX;
|
||||
|
||||
// We adjust the center because the zoomScale is to leave space for
|
||||
// the expanded workspace control so we want to zoom to either the
|
||||
// left part of the area or the right part of the area
|
||||
let offset = 0.5 * (1 - this._zoomScale) * this._width;
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
if (this._zoomOut)
|
||||
workspace.x += rtl ? offset : - offset;
|
||||
|
||||
// We divide by zoomScale so that adjacent workspaces are always offscreen
|
||||
// except when we are switching between workspaces
|
||||
workspace.y = this._y + this._activeWorkspaceY
|
||||
+ (w - active) * (_height + this._spacing) / zoomScale;
|
||||
}
|
||||
updateWindowPositions: function() {
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].positionWindows(Workspace.WindowPositionFlags.ANIMATE);
|
||||
},
|
||||
|
||||
_scrollToActive: function(showAnimation) {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
|
||||
this._computeWorkspacePositions();
|
||||
this._updateWorkspaceActors(showAnimation);
|
||||
this._updateScrollAdjustment(active, showAnimation);
|
||||
},
|
||||
|
||||
// Update workspace actors parameters to the values calculated in
|
||||
// _computeWorkspacePositions()
|
||||
// Update workspace actors parameters
|
||||
// @showAnimation: iff %true, transition between states
|
||||
_updateWorkspaceActors: function(showAnimation) {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
let targetWorkspaceNewY = this._y + this._activeWorkspaceY;
|
||||
let targetWorkspaceCurrentY = this._workspaces[active].y;
|
||||
let dy = targetWorkspaceNewY - targetWorkspaceCurrentY;
|
||||
|
||||
this._animating = showAnimation;
|
||||
|
||||
@@ -257,14 +199,10 @@ WorkspacesView.prototype = {
|
||||
|
||||
Tweener.removeTweens(workspace.actor);
|
||||
|
||||
workspace.y += dy;
|
||||
let y = (w - active) * (this._height + this._spacing + this._workspaceRatioSpacing);
|
||||
|
||||
if (showAnimation) {
|
||||
let params = { x: workspace.x,
|
||||
y: workspace.y,
|
||||
scale_x: workspace.scale,
|
||||
scale_y: workspace.scale,
|
||||
opacity: workspace.opacity,
|
||||
let params = { y: y,
|
||||
time: WORKSPACE_SWITCH_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
};
|
||||
@@ -281,9 +219,7 @@ WorkspacesView.prototype = {
|
||||
}
|
||||
Tweener.addTween(workspace.actor, params);
|
||||
} else {
|
||||
workspace.actor.set_scale(workspace.scale, workspace.scale);
|
||||
workspace.actor.set_position(workspace.x, workspace.y);
|
||||
workspace.actor.opacity = workspace.opacity;
|
||||
workspace.actor.set_position(0, y);
|
||||
if (w == 0)
|
||||
this._updateVisibility();
|
||||
}
|
||||
@@ -294,7 +230,6 @@ WorkspacesView.prototype = {
|
||||
|
||||
Tweener.removeTweens(workspace.actor);
|
||||
|
||||
workspace.y += dy;
|
||||
workspace.actor.show();
|
||||
workspace.hideWindowsOverlays();
|
||||
|
||||
@@ -338,7 +273,6 @@ WorkspacesView.prototype = {
|
||||
this._lostWorkspaces[l].destroy();
|
||||
this._lostWorkspaces = [];
|
||||
|
||||
this._computeWorkspacePositions();
|
||||
this._updateWorkspaceActors(false);
|
||||
},
|
||||
|
||||
@@ -380,7 +314,6 @@ WorkspacesView.prototype = {
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++)
|
||||
this.actor.add_actor(this._workspaces[w].actor);
|
||||
|
||||
this._computeWorkspacePositions();
|
||||
this._updateWorkspaceActors(false);
|
||||
} else {
|
||||
this._lostWorkspaces = lostWorkspaces;
|
||||
@@ -397,10 +330,16 @@ WorkspacesView.prototype = {
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||
this._extraWorkspaces[i].destroy();
|
||||
this._scrollAdjustment.run_dispose();
|
||||
Main.overview.disconnect(this._overviewShowingId);
|
||||
Main.overview.disconnect(this._overviewShownId);
|
||||
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
||||
|
||||
if (this._inDrag)
|
||||
this._dragEnd();
|
||||
|
||||
if (this._timeoutId) {
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
@@ -443,6 +382,7 @@ WorkspacesView.prototype = {
|
||||
return;
|
||||
|
||||
this._inDrag = true;
|
||||
this._firstDragMotion = true;
|
||||
|
||||
this._dragMonitor = {
|
||||
dragMotion: Lang.bind(this, this._onDragMotion)
|
||||
@@ -454,6 +394,14 @@ WorkspacesView.prototype = {
|
||||
if (Main.overview.animationInProgress)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
if (this._firstDragMotion) {
|
||||
this._firstDragMotion = false;
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||
}
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
@@ -467,7 +415,6 @@ WorkspacesView.prototype = {
|
||||
let switchTop = (dragEvent.y <= topEdge && topWorkspace);
|
||||
if (switchTop && this._dragOverLastY != topEdge) {
|
||||
topWorkspace.metaWorkspace.activate(global.get_current_time());
|
||||
topWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
|
||||
this._dragOverLastY = topEdge;
|
||||
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
@@ -476,7 +423,6 @@ WorkspacesView.prototype = {
|
||||
let switchBottom = (dragEvent.y >= bottomEdge && bottomWorkspace);
|
||||
if (switchBottom && this._dragOverLastY != bottomEdge) {
|
||||
bottomWorkspace.metaWorkspace.activate(global.get_current_time());
|
||||
bottomWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
|
||||
this._dragOverLastY = bottomEdge;
|
||||
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
@@ -488,20 +434,14 @@ WorkspacesView.prototype = {
|
||||
if (topWorkspace) {
|
||||
if (topWorkspace.actor.contains(dragEvent.targetActor)) {
|
||||
hoverWorkspace = topWorkspace;
|
||||
topWorkspace.opacity = topWorkspace.actor.opacity = 255;
|
||||
result = topWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
||||
} else {
|
||||
topWorkspace.opacity = topWorkspace.actor.opacity = 200;
|
||||
}
|
||||
}
|
||||
|
||||
if (bottomWorkspace) {
|
||||
if (bottomWorkspace.actor.contains(dragEvent.targetActor)) {
|
||||
hoverWorkspace = bottomWorkspace;
|
||||
bottomWorkspace.opacity = bottomWorkspace.actor.opacity = 255;
|
||||
result = bottomWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
||||
} else {
|
||||
bottomWorkspace.opacity = bottomWorkspace.actor.opacity = 200;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -511,7 +451,6 @@ WorkspacesView.prototype = {
|
||||
this._timeoutId = Mainloop.timeout_add_seconds(1,
|
||||
Lang.bind(this, function() {
|
||||
hoverWorkspace.metaWorkspace.activate(global.get_current_time());
|
||||
hoverWorkspace.setReservedSlot(dragEvent.dragActor._delegate);
|
||||
return false;
|
||||
}));
|
||||
} else {
|
||||
@@ -534,6 +473,8 @@ WorkspacesView.prototype = {
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setReservedSlot(null);
|
||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||
this._extraWorkspaces[i].setReservedSlot(null);
|
||||
},
|
||||
|
||||
_swipeScrollBegin: function() {
|
||||
@@ -557,12 +498,6 @@ WorkspacesView.prototype = {
|
||||
Main.overview.hide();
|
||||
}
|
||||
|
||||
if (result == Overview.SwipeScrollResult.SWIPE)
|
||||
// The active workspace has changed; while swipe-scrolling
|
||||
// has already taken care of the positioning, the cached
|
||||
// positions need to be updated
|
||||
this._computeWorkspacePositions();
|
||||
|
||||
// Make sure title captions etc are shown as necessary
|
||||
this._updateVisibility();
|
||||
},
|
||||
@@ -590,7 +525,7 @@ WorkspacesView.prototype = {
|
||||
return;
|
||||
|
||||
let currentY = firstWorkspaceY;
|
||||
let newY = this._y - adj.value / (adj.upper - 1) * workspacesHeight;
|
||||
let newY = - adj.value / (adj.upper - 1) * workspacesHeight;
|
||||
|
||||
let dy = newY - currentY;
|
||||
|
||||
@@ -618,6 +553,7 @@ WorkspacesDisplay.prototype = {
|
||||
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('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor.set_clip_to_allocation(true);
|
||||
|
||||
let controls = new St.Bin({ style_class: 'workspace-controls',
|
||||
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT,
|
||||
@@ -633,6 +569,8 @@ WorkspacesDisplay.prototype = {
|
||||
controls.connect('scroll-event',
|
||||
Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
this._monitorIndex = global.get_primary_monitor_index();
|
||||
this._monitor = global.get_monitors()[this._monitorIndex];
|
||||
|
||||
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
|
||||
controls.add_actor(this._thumbnailsBox.actor);
|
||||
@@ -640,65 +578,53 @@ WorkspacesDisplay.prototype = {
|
||||
this.workspacesView = null;
|
||||
|
||||
this._inDrag = false;
|
||||
this._cancelledDrag = false;
|
||||
|
||||
this._alwaysZoomOut = false;
|
||||
this._zoomOut = false;
|
||||
this._zoomFraction = 0;
|
||||
|
||||
this._updateAlwaysZoom();
|
||||
|
||||
global.screen.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
||||
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
|
||||
this._alwaysZoomOut = true;
|
||||
}));
|
||||
|
||||
Main.xdndHandler.connect('drag-end', Lang.bind(this, function(){
|
||||
this._alwaysZoomOut = false;
|
||||
this._updateAlwaysZoom();
|
||||
}));
|
||||
|
||||
this._nWorkspacesNotifyId = 0;
|
||||
this._switchWorkspaceNotifyId = 0;
|
||||
|
||||
this._itemDragBeginId = 0;
|
||||
this._itemDragCancelledId = 0;
|
||||
this._itemDragEndId = 0;
|
||||
this._windowDragBeginId = 0;
|
||||
this._windowDragCancelledId = 0;
|
||||
this._windowDragEndId = 0;
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this._zoomOut = this._alwaysZoomOut;
|
||||
this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
|
||||
this._updateZoom();
|
||||
|
||||
this._controls.show();
|
||||
this._thumbnailsBox.show();
|
||||
|
||||
this._workspaces = [];
|
||||
for (let i = 0; i < global.screen.n_workspaces; i++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(i);
|
||||
this._workspaces[i] = new Workspace.Workspace(metaWorkspace);
|
||||
this._workspaces[i] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
|
||||
}
|
||||
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
|
||||
let totalAllocation = this.actor.allocation;
|
||||
let totalWidth = totalAllocation.x2 - totalAllocation.x1;
|
||||
let totalHeight = totalAllocation.y2 - totalAllocation.y1;
|
||||
|
||||
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
|
||||
|
||||
totalWidth -= controlsVisible;
|
||||
|
||||
// Workspaces expect to have the same ratio as the screen, so take
|
||||
// this into account when fitting the workspace into the available space
|
||||
let width, height;
|
||||
let totalRatio = totalWidth / totalHeight;
|
||||
let wsRatio = global.screen_width / global.screen_height;
|
||||
if (wsRatio > totalRatio) {
|
||||
width = totalWidth;
|
||||
height = Math.floor(totalWidth / wsRatio);
|
||||
} else {
|
||||
width = Math.floor(totalHeight * wsRatio);
|
||||
height = totalHeight;
|
||||
}
|
||||
|
||||
// Position workspaces in the available space
|
||||
let [x, y] = this.actor.get_transformed_position();
|
||||
x = Math.floor(x + Math.abs(totalWidth - width) / 2);
|
||||
y = Math.floor(y + Math.abs(totalHeight - height) / 2);
|
||||
|
||||
if (rtl)
|
||||
x += controlsVisible;
|
||||
|
||||
let newView = new WorkspacesView(width, height, x, y, this._workspaces);
|
||||
this._updateZoomScale();
|
||||
|
||||
if (this.workspacesView)
|
||||
this.workspacesView.destroy();
|
||||
this.workspacesView = newView;
|
||||
this.workspacesView = new WorkspacesView(this._workspaces);
|
||||
this._updateWorkspacesGeometry();
|
||||
|
||||
this._nWorkspacesNotifyId =
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
@@ -711,20 +637,23 @@ WorkspacesDisplay.prototype = {
|
||||
if (this._itemDragBeginId == 0)
|
||||
this._itemDragBeginId = Main.overview.connect('item-drag-begin',
|
||||
Lang.bind(this, this._dragBegin));
|
||||
if (this._itemDragCancelledId == 0)
|
||||
this._itemDragCancelledId = Main.overview.connect('item-drag-cancelled',
|
||||
Lang.bind(this, this._dragCancelled));
|
||||
if (this._itemDragEndId == 0)
|
||||
this._itemDragEndId = Main.overview.connect('item-drag-end',
|
||||
Lang.bind(this, this._dragEnd));
|
||||
if (this._windowDragBeginId == 0)
|
||||
this._windowDragBeginId = Main.overview.connect('window-drag-begin',
|
||||
Lang.bind(this, this._dragBegin));
|
||||
if (this._windowDragCancelledId == 0)
|
||||
this._windowDragCancelledId = Main.overview.connect('window-drag-cancelled',
|
||||
Lang.bind(this, this._dragCancelled));
|
||||
if (this._windowDragEndId == 0)
|
||||
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
||||
Lang.bind(this, this._dragEnd));
|
||||
|
||||
this._onRestacked();
|
||||
this._zoomOut = false;
|
||||
this._zoomFraction = 0;
|
||||
this._updateZoom();
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
@@ -743,7 +672,11 @@ WorkspacesDisplay.prototype = {
|
||||
Main.overview.disconnect(this._itemDragBeginId);
|
||||
this._itemDragBeginId = 0;
|
||||
}
|
||||
if (this._itemEndBeginId > 0) {
|
||||
if (this._itemDragCancelledId > 0) {
|
||||
Main.overview.disconnect(this._itemDragCancelledId);
|
||||
this._itemDragCancelledId = 0;
|
||||
}
|
||||
if (this._itemDragEndId > 0) {
|
||||
Main.overview.disconnect(this._itemDragEndId);
|
||||
this._itemDragEndId = 0;
|
||||
}
|
||||
@@ -751,6 +684,10 @@ WorkspacesDisplay.prototype = {
|
||||
Main.overview.disconnect(this._windowDragBeginId);
|
||||
this._windowDragBeginId = 0;
|
||||
}
|
||||
if (this._windowDragCancelledId > 0) {
|
||||
Main.overview.disconnect(this._windowDragCancelledId);
|
||||
this._windowDragCancelledId = 0;
|
||||
}
|
||||
if (this._windowDragEndId > 0) {
|
||||
Main.overview.disconnect(this._windowDragEndId);
|
||||
this._windowDragEndId = 0;
|
||||
@@ -774,6 +711,23 @@ WorkspacesDisplay.prototype = {
|
||||
return this._zoomFraction;
|
||||
},
|
||||
|
||||
_updateAlwaysZoom: function() {
|
||||
this._alwaysZoomOut = false;
|
||||
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
/* Look for any monitor to the right of the primary, if there is
|
||||
* one, we always keep zoom out, otherwise its hard to reach
|
||||
* the thumbnail area without passing into the next monitor. */
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (monitors[i].x >= primary.x + primary.width) {
|
||||
this._alwaysZoomOut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
// pass through the call in case the child needs it, but report 0x0
|
||||
this._controls.get_preferred_width(forHeight);
|
||||
@@ -809,22 +763,41 @@ WorkspacesDisplay.prototype = {
|
||||
childBox.y2 = box.y2- box.y1;
|
||||
this._controls.allocate(childBox, flags);
|
||||
|
||||
this._updateZoomScale();
|
||||
this._updateWorkspacesGeometry();
|
||||
},
|
||||
|
||||
_updateZoomScale: function() {
|
||||
_updateWorkspacesGeometry: function() {
|
||||
if (!this.workspacesView)
|
||||
return;
|
||||
|
||||
let totalAllocation = this.actor.allocation;
|
||||
let totalWidth = totalAllocation.x2 - totalAllocation.x1;
|
||||
let totalHeight = totalAllocation.y2 - totalAllocation.y1;
|
||||
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
|
||||
let fullHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
|
||||
|
||||
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(totalHeight);
|
||||
let width = fullWidth;
|
||||
let height = fullHeight;
|
||||
|
||||
let [controlsMin, controlsNatural] = this._controls.get_preferred_width(height);
|
||||
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
|
||||
|
||||
let zoomScale = (totalWidth - controlsNatural) / (totalWidth - controlsVisible);
|
||||
this.workspacesView.setZoomScale(zoomScale);
|
||||
let [x, y] = this.actor.get_transformed_position();
|
||||
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
|
||||
if (this._zoomOut) {
|
||||
width -= controlsNatural;
|
||||
if (rtl)
|
||||
x += controlsNatural;
|
||||
} else {
|
||||
width -= controlsVisible;
|
||||
if (rtl)
|
||||
x += controlsVisible;
|
||||
}
|
||||
|
||||
height = (fullHeight / fullWidth) * width;
|
||||
let difference = fullHeight - height;
|
||||
y += difference / 2;
|
||||
|
||||
this.workspacesView.setGeometry(x, y, width, height, difference);
|
||||
},
|
||||
|
||||
_onRestacked: function() {
|
||||
@@ -853,7 +826,7 @@ WorkspacesDisplay.prototype = {
|
||||
// Assume workspaces are only added at the end
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||
this._workspaces[w] = new Workspace.Workspace(metaWorkspace);
|
||||
this._workspaces[w] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
|
||||
}
|
||||
|
||||
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
|
||||
@@ -890,9 +863,10 @@ WorkspacesDisplay.prototype = {
|
||||
if (Main.overview.animationInProgress)
|
||||
return;
|
||||
|
||||
let shouldZoom = this._controls.hover || this._inDrag;
|
||||
let shouldZoom = this._alwaysZoomOut || this._controls.hover || (this._inDrag && !this._cancelledDrag);
|
||||
if (shouldZoom != this._zoomOut) {
|
||||
this._zoomOut = shouldZoom;
|
||||
this._updateWorkspacesGeometry();
|
||||
|
||||
if (!this.workspacesView)
|
||||
return;
|
||||
@@ -902,10 +876,7 @@ WorkspacesDisplay.prototype = {
|
||||
time: WORKSPACE_SWITCH_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
|
||||
if (shouldZoom)
|
||||
this.workspacesView.zoomOut();
|
||||
else
|
||||
this.workspacesView.zoomIn();
|
||||
this.workspacesView.updateWindowPositions();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -915,6 +886,12 @@ WorkspacesDisplay.prototype = {
|
||||
|
||||
_dragBegin: function() {
|
||||
this._inDrag = true;
|
||||
this._cancelledDrag = false;
|
||||
this._updateZoom();
|
||||
},
|
||||
|
||||
_dragCancelled: function() {
|
||||
this._cancelledDrag = true;
|
||||
this._updateZoom();
|
||||
},
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Mainloop = imports.mainloop;
|
||||
const DND = imports.ui.dnd;
|
||||
|
||||
function XdndHandler() {
|
||||
@@ -41,9 +40,14 @@ XdndHandler.prototype = {
|
||||
// Called when the user cancels the drag (i.e release the button)
|
||||
_onLeave: function() {
|
||||
if (this._windowGroupVisibilityHandlerId != 0) {
|
||||
Mainloop.source_remove(this._windowGroupVisibilityHandlerId);
|
||||
global.window_group.disconnect(this._windowGroupVisibilityHandlerId);
|
||||
this._windowGroupVisibilityHandlerId = 0;
|
||||
}
|
||||
if (this._cursorWindowClone) {
|
||||
this._cursorWindowClone.destroy();
|
||||
this._cursorWindowClone = null;
|
||||
}
|
||||
|
||||
this.emit('drag-end');
|
||||
},
|
||||
|
||||
@@ -77,8 +81,7 @@ XdndHandler.prototype = {
|
||||
// Make sure that the clone has the same position as the source
|
||||
this._cursorWindowClone.add_constraint(constraint_position);
|
||||
} else {
|
||||
if (this._cursorWindowClone)
|
||||
{
|
||||
if (this._cursorWindowClone) {
|
||||
this._cursorWindowClone.destroy();
|
||||
this._cursorWindowClone = null;
|
||||
}
|
||||
|
||||
10
po/LINGUAS
@@ -1,13 +1,19 @@
|
||||
af
|
||||
an
|
||||
ar
|
||||
bg
|
||||
bn
|
||||
bn_IN
|
||||
ca
|
||||
cs
|
||||
da
|
||||
de
|
||||
el
|
||||
en_GB
|
||||
eo
|
||||
es
|
||||
et
|
||||
eu
|
||||
fa
|
||||
fi
|
||||
fr
|
||||
@@ -15,6 +21,7 @@ ga
|
||||
gl
|
||||
gu
|
||||
he
|
||||
hi
|
||||
hu
|
||||
id
|
||||
it
|
||||
@@ -22,6 +29,8 @@ ja
|
||||
ko
|
||||
kn
|
||||
lt
|
||||
lv
|
||||
mr
|
||||
nb
|
||||
nl
|
||||
nn
|
||||
@@ -31,6 +40,7 @@ pt
|
||||
pt_BR
|
||||
ro
|
||||
ru
|
||||
sk
|
||||
sl
|
||||
sr
|
||||
sr@latin
|
||||
|
||||
@@ -13,6 +13,7 @@ js/ui/messageTray.js
|
||||
js/ui/overview.js
|
||||
js/ui/panel.js
|
||||
js/ui/placeDisplay.js
|
||||
js/ui/polkitAuthenticationAgent.js
|
||||
js/ui/popupMenu.js
|
||||
js/ui/runDialog.js
|
||||
js/ui/searchDisplay.js
|
||||
@@ -20,6 +21,7 @@ js/ui/statusMenu.js
|
||||
js/ui/status/accessibility.js
|
||||
js/ui/status/bluetooth.js
|
||||
js/ui/status/keyboard.js
|
||||
js/ui/status/network.js
|
||||
js/ui/status/power.js
|
||||
js/ui/status/volume.js
|
||||
js/ui/telepathyClient.js
|
||||
@@ -28,7 +30,11 @@ js/ui/windowAttentionHandler.js
|
||||
js/ui/workspacesView.js
|
||||
src/gvc/gvc-mixer-control.c
|
||||
src/gdmuser/gdm-user.c
|
||||
src/main.c
|
||||
src/shell-app.c
|
||||
src/shell-app-system.c
|
||||
src/shell-global.c
|
||||
src/shell-mobile-providers.c
|
||||
src/shell-polkit-authentication-agent.c
|
||||
src/shell-util.c
|
||||
|
||||
|
||||
1189
po/bn_IN.po
Normal file
1314
po/en_GB.po
552
po/et.po
@@ -12,21 +12,21 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell MASTER\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2011-02-04 22:28+0000\n"
|
||||
"PO-Revision-Date: 2011-02-06 08:43+0200\n"
|
||||
"Last-Translator: Ivar Smolin <okul@linux.ee>\n"
|
||||
"shell&keywords=I18N+L10N&component=general\n"
|
||||
"POT-Creation-Date: 2011-03-30 17:13+0000\n"
|
||||
"PO-Revision-Date: 2011-03-30 23:56+0300\n"
|
||||
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
|
||||
"Language-Team: Estonian <gnome-et@linux.ee>\n"
|
||||
"Language: et\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: et\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Poedit-Language: Estonian\n"
|
||||
"X-Poedit-Country: Estonia\n"
|
||||
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME kest"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Aknahaldur ja rakenduste käivitaja"
|
||||
@@ -58,6 +58,10 @@ msgstr ""
|
||||
msgid "History for command (Alt-F2) dialog"
|
||||
msgstr "Käsudialoogi (Alt-F2) ajalugu"
|
||||
|
||||
# suurendusklaasidialoog? miks ka mitte :)
|
||||
msgid "History for the looking glass dialog"
|
||||
msgstr "Otsingudialoogi ajalugu"
|
||||
|
||||
msgid "If true, display date in the clock, in addition to time."
|
||||
msgstr "Kui määratud, siis kuvatakse kellaaja kõrval ka kuupäeva."
|
||||
|
||||
@@ -83,6 +87,16 @@ msgid ""
|
||||
"records to WEBM using the VP8 codec. %T is used as a placeholder for a guess "
|
||||
"at the optimal thread count on the system."
|
||||
msgstr ""
|
||||
"Määrab GStreameri toru, mida kasutatakse lindistuste kodeerimiseks. See peab "
|
||||
"vastama gst-launch'i süntaksile. Torul peaks olema vaba plokk (pad), kuhu "
|
||||
"lindistatav video salvestatakse. Tavaliselt on vaba plokk olemas; selle "
|
||||
"ploki väljund kirjutatakse väljundfaili. Toru võib hoolitseda ka enda "
|
||||
"väljundi eest - seda võib kasutada väljundi saatmiseks icecast serverisse "
|
||||
"shout2send või sarnase tehnoloogia abil. Kui see on määramata või väärtus on "
|
||||
"tühi, kasutatakse vaikimisi toru. See on praegu 'videorate ! vp8enc "
|
||||
"quality=10 speed=2 threads=%T ! queue ! webmmux' ning lindistab WEBM "
|
||||
"vormingusse VP8 koodekiga. %T asendatakse süsteemi oletatava optimaalseima "
|
||||
"lõimede (thread) arvuga."
|
||||
|
||||
msgid "Show date in clock"
|
||||
msgstr "Kell näitab kuupäeva"
|
||||
@@ -96,7 +110,7 @@ msgstr "Kellaaega näidatakse sekunditega"
|
||||
msgid ""
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
msgstr ""
|
||||
msgstr "Nendele tunnustele vastavaid rakendusi kuvatakse lemmikutes."
|
||||
|
||||
msgid ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
@@ -112,9 +126,10 @@ msgid ""
|
||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
|
||||
"screencast recorder in frames-per-second."
|
||||
msgstr ""
|
||||
"GNOME Shelli lindistatava ekraanivideo kaadrisagedus (kaadrit sekundis)."
|
||||
|
||||
msgid "The gstreamer pipeline used to encode the screencast"
|
||||
msgstr ""
|
||||
msgstr "GStreameri toru, mida ekraanivideo kodeerimiseks kasutatakse"
|
||||
|
||||
msgid ""
|
||||
"The shell normally monitors active applications in order to present the most "
|
||||
@@ -122,125 +137,19 @@ msgid ""
|
||||
"want to disable this for privacy reasons. Please note that doing so won't "
|
||||
"remove already saved data."
|
||||
msgstr ""
|
||||
"Shell tavaliselt seirab aktiivseid rakendusi, et näidata enamkasutatavaid "
|
||||
"(näiteks käivitajaid). Kuigi neid andmeid hoitakse privaatselt, võid "
|
||||
"privaatsuse suurendamiseks selle keelata. Selle keelamine siiski ei eemalda "
|
||||
"juba salvestatud andmeid."
|
||||
|
||||
msgid "Uuids of extensions to disable"
|
||||
msgstr "Keelatavate laienduste UUID-d"
|
||||
|
||||
msgid "Whether to collect stats about applications usage"
|
||||
msgstr ""
|
||||
msgstr "Kas rakenduste kasutuse kohta kogutakse andmeid"
|
||||
|
||||
msgid "disabled OpenSearch providers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Clip the crosshairs at the center"
|
||||
msgstr "Niitristi keskel on auk"
|
||||
|
||||
msgid "Color of the crosshairs"
|
||||
msgstr "Niitristi värvus"
|
||||
|
||||
msgid ""
|
||||
"Determines the length of the vertical and horizontal lines that make up the "
|
||||
"crosshairs."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Determines the position of the magnified mouse image within the magnified "
|
||||
"view and how it reacts to system mouse movement. The values are - none: no "
|
||||
"mouse tracking; - centered: the mouse image is displayed at the center of "
|
||||
"the zoom region (which also represents the point under the system mouse) and "
|
||||
"the magnified contents are scrolled as the system mouse moves; - "
|
||||
"proportional: the position of the magnified mouse in the zoom region is "
|
||||
"proportionally the same as the position of the system mouse on screen; - "
|
||||
"push: when the magnified mouse intersects a boundary of the zoom region, the "
|
||||
"contents are scrolled into view."
|
||||
msgstr ""
|
||||
|
||||
msgid ""
|
||||
"Determines the transparency of the crosshairs, from fully opaque to fully "
|
||||
"transparent."
|
||||
msgstr ""
|
||||
"Määrab niitristi läbipaistvuse, alates täiesti läbipaistmatust kuni täiesti "
|
||||
"läbipaistvani."
|
||||
|
||||
msgid ""
|
||||
"Determines whether the crosshairs intersect the magnified mouse sprite, or "
|
||||
"are clipped such that the ends of the horizontal and vertical lines surround "
|
||||
"the mouse image."
|
||||
msgstr ""
|
||||
"Määrab, kas niitrist kattub suurendatud hiire pildiga või on keskelt ära "
|
||||
"lõigatud nii, et jooned ümbritsevad hiirekursori pilti."
|
||||
|
||||
msgid "Enable lens mode"
|
||||
msgstr "Läätsede režiimi lubamine"
|
||||
|
||||
msgid ""
|
||||
"Enables/disables display of crosshairs centered on the magnified mouse "
|
||||
"sprite."
|
||||
msgstr "Lubab/keelab niitristi kuvamise suurendatud hiirekursori kohal."
|
||||
|
||||
msgid ""
|
||||
"For centered mouse tracking, when the system pointer is at or near the edge "
|
||||
"of the screen, the magnified contents continue to scroll such that the "
|
||||
"screen edge moves into the magnified view."
|
||||
msgstr ""
|
||||
|
||||
msgid "Length of the crosshairs"
|
||||
msgstr "Niitristi pikkus"
|
||||
|
||||
msgid "Magnification factor"
|
||||
msgstr "Suurendustegur"
|
||||
|
||||
msgid "Mouse Tracking Mode"
|
||||
msgstr "Hiire jälitamise režiim"
|
||||
|
||||
msgid "Opacity of the crosshairs"
|
||||
msgstr "Niitristi läbipaistvus"
|
||||
|
||||
msgid "Screen position"
|
||||
msgstr "Ekraani asukoht"
|
||||
|
||||
msgid "Scroll magnified contents beyond the edges of the desktop"
|
||||
msgstr "Suurendusklaas võib liikuda töölauapiiridest väljapoole"
|
||||
|
||||
msgid "Show or hide crosshairs"
|
||||
msgstr "Niitristi kuvamine või peitmine"
|
||||
|
||||
msgid "Show or hide the magnifier"
|
||||
msgstr "Suurendusklaasi kuvamine või peitmine"
|
||||
|
||||
msgid "Show or hide the magnifier and all of its zoom regions."
|
||||
msgstr ""
|
||||
"Suurendusklaasi ja selle kõigi suurenduspiirkondade kuvamine või peitmine."
|
||||
|
||||
msgid ""
|
||||
"The color of the the vertical and horizontal lines that make up the "
|
||||
"crosshairs."
|
||||
msgstr "Niitristi püst- ja rõhtjoone värvus."
|
||||
|
||||
msgid ""
|
||||
"The magnified view either fills the entire screen, or occupies the top-half, "
|
||||
"bottom-half, left-half, or right-half of the screen."
|
||||
msgstr ""
|
||||
"Suurendatud vaade täidab kas kogu ekraani või täidab ülemise, alumise, "
|
||||
"vasaku või parema ekraanipoole."
|
||||
|
||||
msgid ""
|
||||
"The power of the magnification. A value of 1.0 means no magnification. A "
|
||||
"value of 2.0 doubles the size."
|
||||
msgstr "Suurendustegur. 1,0 tähendab originaalsuurust. 2,0 muudab kaks korda."
|
||||
|
||||
msgid "Thickness of the crosshairs"
|
||||
msgstr "Niitristi paksus"
|
||||
|
||||
msgid ""
|
||||
"Whether the magnified view should be centered over the location of the "
|
||||
"system mouse and move with it."
|
||||
msgstr ""
|
||||
"Kas suurendatud vaate keskkoht peaks asetsema süsteemi hiire kohal ning "
|
||||
"liikuma sellega kaasa."
|
||||
|
||||
msgid "Width of the vertical and horizontal lines that make up the crosshairs."
|
||||
msgstr "Niitristi moodustavate püst- ja rõhtjoone laius"
|
||||
msgstr "keelatud OpenSearch pakkujad"
|
||||
|
||||
msgid "Command not found"
|
||||
msgstr "Käsku ei leitud"
|
||||
@@ -250,9 +159,6 @@ msgstr "Käsku ei leitud"
|
||||
msgid "Could not parse command:"
|
||||
msgstr "Käsku pole võimalik analüüsida:"
|
||||
|
||||
msgid "No such application"
|
||||
msgstr "Sellist rakendust ei ole"
|
||||
|
||||
#, c-format
|
||||
msgid "Execution of '%s' failed:"
|
||||
msgstr "'%s' käivitamine nurjus:"
|
||||
@@ -264,8 +170,8 @@ msgstr "Kõik"
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Rakendused"
|
||||
|
||||
msgid "PREFERENCES"
|
||||
msgstr "Eelistused"
|
||||
msgid "SETTINGS"
|
||||
msgstr "Seaded"
|
||||
|
||||
msgid "New Window"
|
||||
msgstr "Uus aken"
|
||||
@@ -289,7 +195,7 @@ msgstr "%s eemaldati lemmikutest."
|
||||
#.
|
||||
msgctxt "event list time"
|
||||
msgid "All Day"
|
||||
msgstr "Kogu päeva"
|
||||
msgstr "Kogu päev"
|
||||
|
||||
#. Translators: Shown in calendar event list, if 24h format
|
||||
msgctxt "event list time"
|
||||
@@ -382,7 +288,7 @@ msgstr "L"
|
||||
|
||||
#. Translators: Text to show if there are no events
|
||||
msgid "Nothing Scheduled"
|
||||
msgstr ""
|
||||
msgstr "Ühtegi sündmust pole plaanitud"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
msgctxt "calendar heading"
|
||||
@@ -465,6 +371,8 @@ msgstr "Logi välja"
|
||||
|
||||
msgid "Click Log Out to quit these applications and log out of the system."
|
||||
msgstr ""
|
||||
"Nende rakenduste sulgemiseks ja süsteemist väljalogimiseks klõpsa nupule "
|
||||
"Logi välja."
|
||||
|
||||
#, c-format
|
||||
msgid "%s will be logged out automatically in %d seconds."
|
||||
@@ -477,17 +385,19 @@ msgstr "Sind logitakse %d sekundi pärast automaatselt välja."
|
||||
msgid "Logging out of the system."
|
||||
msgstr "Süsteemist väljalogimine"
|
||||
|
||||
msgid "Shut Down"
|
||||
msgid "Power Off"
|
||||
msgstr "Lülita välja"
|
||||
|
||||
msgid "Click Shut Down to quit these applications and shut down the system."
|
||||
msgid "Click Power Off to quit these applications and power off the system."
|
||||
msgstr ""
|
||||
"Nende rakenduste sulgemiseks ja süsteemi väljalülitamiseks klõpsa nupule "
|
||||
"Lülita välja."
|
||||
|
||||
#, c-format
|
||||
msgid "The system will shut down automatically in %d seconds."
|
||||
msgid "The system will power off automatically in %d seconds."
|
||||
msgstr "%d sekundi pärast lülitub süsteem automaatselt välja."
|
||||
|
||||
msgid "Shutting down the system."
|
||||
msgid "Powering off the system."
|
||||
msgstr "Süsteemi väljalülitamine."
|
||||
|
||||
msgid "Restart"
|
||||
@@ -505,9 +415,6 @@ msgstr "Süsteem taaskäivitatakse automaatselt %d sekundi pärast."
|
||||
msgid "Restarting the system."
|
||||
msgstr "Süsteemi taaskäivitamine."
|
||||
|
||||
msgid "Confirm"
|
||||
msgstr "Kinnita"
|
||||
|
||||
msgid "Cancel"
|
||||
msgstr "Katkesta"
|
||||
|
||||
@@ -534,6 +441,9 @@ msgstr "Kuva lähtekoodi"
|
||||
msgid "Web Page"
|
||||
msgstr "Veebileht"
|
||||
|
||||
msgid "Open"
|
||||
msgstr "Ava"
|
||||
|
||||
msgid "System Information"
|
||||
msgstr "Süsteemi andmed"
|
||||
|
||||
@@ -546,6 +456,11 @@ msgstr "Aknad"
|
||||
msgid "Applications"
|
||||
msgstr "Rakendused"
|
||||
|
||||
#. Translators: this is the name of the dock/favorites area on
|
||||
#. the left of the overview
|
||||
msgid "Dash"
|
||||
msgstr "Dokk"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
@@ -556,6 +471,9 @@ msgstr "Lõpeta %s"
|
||||
msgid "Activities"
|
||||
msgstr "Tegevused"
|
||||
|
||||
msgid "Top Bar"
|
||||
msgstr "Ülemine riba"
|
||||
|
||||
#, c-format
|
||||
msgid "Failed to unmount '%s'"
|
||||
msgstr "'%s' lahtihaakimine nurjus"
|
||||
@@ -569,6 +487,25 @@ msgstr "Ühendumine..."
|
||||
msgid "PLACES & DEVICES"
|
||||
msgstr "Asukohad ja seadmed"
|
||||
|
||||
msgid "Authentication Required"
|
||||
msgstr "Vajalik on autentimine"
|
||||
|
||||
msgid "Administrator"
|
||||
msgstr "Administraator"
|
||||
|
||||
msgid "Authenticate"
|
||||
msgstr "Autendi"
|
||||
|
||||
#. Translators: "that didn't work" refers to the fact that the
|
||||
#. * requested authentication was not gained; this can happen
|
||||
#. * because of an authentication error (like invalid password),
|
||||
#. * for instance.
|
||||
msgid "Sorry, that didn't work. Please try again."
|
||||
msgstr "Kahjuks see ei sobinud. Palun proovi uuesti."
|
||||
|
||||
msgid "Password:"
|
||||
msgstr "Parool:"
|
||||
|
||||
#. Translators: this MUST be either "toggle-switch-us"
|
||||
#. (for toggle switches containing the English words
|
||||
#. "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
||||
@@ -580,6 +517,18 @@ msgstr "toggle-switch-intl"
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Palun sisesta käsk:"
|
||||
|
||||
msgid "Searching..."
|
||||
msgstr "Otsimine..."
|
||||
|
||||
msgid "No matching results."
|
||||
msgstr "Tulemused puuduvad."
|
||||
|
||||
msgid "Power Off..."
|
||||
msgstr "Lülita välja..."
|
||||
|
||||
msgid "Suspend"
|
||||
msgstr "Uinak"
|
||||
|
||||
msgid "Available"
|
||||
msgstr "Saadaval"
|
||||
|
||||
@@ -601,24 +550,15 @@ msgstr "Vaheta kasutajat"
|
||||
msgid "Log Out..."
|
||||
msgstr "Logi välja..."
|
||||
|
||||
#. This is temporarily removed, see
|
||||
#. http://bugzilla.gnome.org/show_bug.cgi?id=636680
|
||||
#. for details.
|
||||
#. item = new PopupMenu.PopupMenuItem(_("Suspend..."));
|
||||
#. item.connect('activate', Lang.bind(this, this._onShutDownActivate));
|
||||
#. this.menu.addMenuItem(item);
|
||||
msgid "Shut Down..."
|
||||
msgstr "Lülita välja..."
|
||||
|
||||
msgid "Zoom"
|
||||
msgstr ""
|
||||
|
||||
msgid "Screen Reader"
|
||||
msgstr "Ekraanilugeja"
|
||||
|
||||
msgid "Screen Keyboard"
|
||||
msgstr "Ekraaniklaviatuur"
|
||||
msgstr "Suurendus"
|
||||
|
||||
#. let screenReader = this._buildItem(_("Screen Reader"), APPLICATIONS_SCHEMA,
|
||||
#. 'screen-reader-enabled');
|
||||
#. this.menu.addMenuItem(screenReader);
|
||||
#. let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
#. 'screen-keyboard-enabled');
|
||||
#. this.menu.addMenuItem(screenKeyboard);
|
||||
msgid "Visual Alerts"
|
||||
msgstr "Visuaalsed märguanded"
|
||||
|
||||
@@ -638,10 +578,10 @@ msgid "Universal Access Settings"
|
||||
msgstr "Universaalse ligipääsu sätted"
|
||||
|
||||
msgid "High Contrast"
|
||||
msgstr ""
|
||||
msgstr "Kõrgkontrastne"
|
||||
|
||||
msgid "Large Text"
|
||||
msgstr ""
|
||||
msgstr "Suur tekst"
|
||||
|
||||
msgid "Bluetooth"
|
||||
msgstr "Bluetooth"
|
||||
@@ -653,7 +593,7 @@ msgid "Send Files to Device..."
|
||||
msgstr "Failide saatmine seadmesse..."
|
||||
|
||||
msgid "Setup a New Device..."
|
||||
msgstr ""
|
||||
msgstr "Uue seadme häälestamine..."
|
||||
|
||||
msgid "Bluetooth Settings"
|
||||
msgstr "Bluetoothi sätted"
|
||||
@@ -672,7 +612,7 @@ msgstr "Viga seadme sirvimisel"
|
||||
|
||||
#, c-format
|
||||
msgid "The requested device cannot be browsed, error is '%s'"
|
||||
msgstr ""
|
||||
msgstr "Küsitud seadet pole võimalik sirvida, viga on '%s'"
|
||||
|
||||
msgid "Keyboard Settings"
|
||||
msgstr "Klaviatuurisätted"
|
||||
@@ -683,9 +623,6 @@ msgstr "Hiiresätted"
|
||||
msgid "Sound Settings"
|
||||
msgstr "Helisätted"
|
||||
|
||||
msgid "Bluetooth Agent"
|
||||
msgstr "Bluetoothi agent"
|
||||
|
||||
#, c-format
|
||||
msgid "Authorization request from %s"
|
||||
msgstr "Autoriseerimise päring seadmelt %s"
|
||||
@@ -731,12 +668,126 @@ msgstr "Palun sisesta seadme poolt öeldav PIN-kood."
|
||||
msgid "OK"
|
||||
msgstr "Olgu"
|
||||
|
||||
msgid "Show Keyboard Layout..."
|
||||
msgstr "Klaviatuuripaigutuse kuvamine..."
|
||||
|
||||
msgid "Localization Settings"
|
||||
msgstr "Lokaliseerimissätted"
|
||||
|
||||
msgid "<unknown>"
|
||||
msgstr "<tundmatu>"
|
||||
|
||||
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
|
||||
msgid "disabled"
|
||||
msgstr "keelatud"
|
||||
|
||||
msgid "connecting..."
|
||||
msgstr "ühendumine..."
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
msgid "authentication required"
|
||||
msgstr "vajalik on autentimine"
|
||||
|
||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||
#. module, which is missing
|
||||
msgid "firmware missing"
|
||||
msgstr "püsivara puudub"
|
||||
|
||||
#. Translators: this is for wired network devices that are physically disconnected
|
||||
msgid "cable unplugged"
|
||||
msgstr "juhe eemaldatud"
|
||||
|
||||
#. Translators: this is for a network device that cannot be activated (for example it
|
||||
#. is disabled by rfkill, or it has no coverage
|
||||
msgid "unavailable"
|
||||
msgstr "pole saadaval"
|
||||
|
||||
msgid "connection failed"
|
||||
msgstr "ühendumine nurjus"
|
||||
|
||||
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
|
||||
#. and we cannot access its settings (including the name)
|
||||
msgid "Connected (private)"
|
||||
msgstr "Ühendatud (privaatne)"
|
||||
|
||||
msgid "Auto Ethernet"
|
||||
msgstr "Automaatne ethernet"
|
||||
|
||||
msgid "Auto broadband"
|
||||
msgstr "Automaatne lairibaühendus"
|
||||
|
||||
msgid "Auto dial-up"
|
||||
msgstr "Automaatne sissehelistamine"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "Automaatne %s"
|
||||
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Automaatne bluetooth"
|
||||
|
||||
msgid "Auto wireless"
|
||||
msgstr "Automaatne juhtmeta ühendus"
|
||||
|
||||
msgid "More..."
|
||||
msgstr "Veel..."
|
||||
|
||||
msgid "Enable networking"
|
||||
msgstr "Luba võrguühendused"
|
||||
|
||||
msgid "Wired"
|
||||
msgstr "Juhtmega"
|
||||
|
||||
msgid "Wireless"
|
||||
msgstr "Juhtmeta"
|
||||
|
||||
msgid "Mobile broadband"
|
||||
msgstr "Mobiiliühendus"
|
||||
|
||||
msgid "VPN Connections"
|
||||
msgstr "VPN-ühendused"
|
||||
|
||||
msgid "Network Settings"
|
||||
msgstr "Võrgusätted"
|
||||
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "Loodi mobiiliühendus '%s'"
|
||||
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "Loodi ühendus juhtmeta võrguga '%s'"
|
||||
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "Loodi ühendus juhtmega võrguga '%s'"
|
||||
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "Loodi ühendus VPN-võrguga '%s'"
|
||||
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "Loodi võrguühendus '%s' kaudu"
|
||||
|
||||
msgid "Connection established"
|
||||
msgstr "Ühendus loodud"
|
||||
|
||||
msgid "Networking is disabled"
|
||||
msgstr "Võrguühendused on keelatud"
|
||||
|
||||
msgid "Network Manager"
|
||||
msgstr "Võrguhaldur"
|
||||
|
||||
msgid "Power Settings"
|
||||
msgstr "Toitesätted..."
|
||||
|
||||
#. 0 is reported when UPower does not have enough data
|
||||
#. to estimate battery life
|
||||
msgid "Estimating..."
|
||||
msgstr "Andmete kogumine..."
|
||||
|
||||
#, c-format
|
||||
msgid "%d hour remaining"
|
||||
msgid_plural "%d hours remaining"
|
||||
@@ -829,8 +880,15 @@ msgstr "%s on hõivatud."
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "Saadetud: %a, kell %X"
|
||||
|
||||
msgid "Search your computer"
|
||||
msgstr ""
|
||||
#. Translators: this is the text displayed
|
||||
#. in the search entry when no search is
|
||||
#. active; it should not exceed ~30
|
||||
#. characters.
|
||||
msgid "Type to search..."
|
||||
msgstr "Otsing..."
|
||||
|
||||
msgid "Search"
|
||||
msgstr "Otsing"
|
||||
|
||||
#, c-format
|
||||
msgid "%s has finished starting"
|
||||
@@ -840,32 +898,32 @@ msgstr "%s läks käima"
|
||||
msgid "'%s' is ready"
|
||||
msgstr "'%s' on valmis"
|
||||
|
||||
msgid ""
|
||||
"Can't add a new workspace because maximum workspaces limit has been reached."
|
||||
msgstr "Pole võimalik uut tööala lisada, kuna tööalade piir on saavutatud."
|
||||
|
||||
msgid "Can't remove the first workspace."
|
||||
msgstr "Esimest tööala pole võimalik eemaldada."
|
||||
|
||||
#. translators:
|
||||
#. * The number of sound outputs on a particular device
|
||||
#, c-format
|
||||
msgid "%u Output"
|
||||
msgid_plural "%u Outputs"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%u väljund"
|
||||
msgstr[1] "%u väljundit"
|
||||
|
||||
#. translators:
|
||||
#. * The number of sound inputs on a particular device
|
||||
#, c-format
|
||||
msgid "%u Input"
|
||||
msgid_plural "%u Inputs"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
msgstr[0] "%u sisend"
|
||||
msgstr[1] "%u sisendit"
|
||||
|
||||
msgid "System Sounds"
|
||||
msgstr "Süsteemi helid"
|
||||
|
||||
msgid "Print version"
|
||||
msgstr "Printimise versioon"
|
||||
|
||||
#, c-format
|
||||
msgid "Failed to launch '%s'"
|
||||
msgstr "'%s' käivitamine nurjus"
|
||||
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Vähem kui minuti eest"
|
||||
|
||||
@@ -893,6 +951,15 @@ msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d nädal tagasi"
|
||||
msgstr[1] "%d nädalat tagasi"
|
||||
|
||||
msgid "United Kingdom"
|
||||
msgstr "Suurbritannia"
|
||||
|
||||
msgid "Default"
|
||||
msgstr "Vaikimisi"
|
||||
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "Kasutaja katkestas autentimisdialoogi"
|
||||
|
||||
msgid "Home Folder"
|
||||
msgstr "Kodukaust"
|
||||
|
||||
@@ -901,9 +968,6 @@ msgstr "Kodukaust"
|
||||
msgid "File System"
|
||||
msgstr "Failisüsteem"
|
||||
|
||||
msgid "Search"
|
||||
msgstr "Otsing"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
@@ -913,8 +977,140 @@ msgstr "Otsing"
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Suspend..."
|
||||
#~ msgstr "Peata..."
|
||||
#~ msgid "Shut Down"
|
||||
#~ msgstr "Lülita välja"
|
||||
|
||||
#~ msgid "Click Shut Down to quit these applications and shut down the system."
|
||||
#~ msgstr ""
|
||||
#~ "Nende rakenduste sulgemiseks ja süsteemi väljalülitamiseks klõpsa nupule "
|
||||
#~ "Logi välja."
|
||||
|
||||
#~ msgid "The system will shut down automatically in %d seconds."
|
||||
#~ msgstr "%d sekundi pärast lülitub süsteem automaatselt välja."
|
||||
|
||||
#~ msgid "Shutting down the system."
|
||||
#~ msgstr "Süsteemi väljalülitamine."
|
||||
|
||||
#~ msgid "Confirm"
|
||||
#~ msgstr "Kinnita"
|
||||
|
||||
#~ msgid "Panel"
|
||||
#~ msgstr "Paneel"
|
||||
|
||||
#~ msgid "No such application"
|
||||
#~ msgstr "Sellist rakendust ei ole"
|
||||
|
||||
#~ msgid "Screen Reader"
|
||||
#~ msgstr "Ekraanilugeja"
|
||||
|
||||
#~ msgid "Screen Keyboard"
|
||||
#~ msgstr "Ekraaniklaviatuur"
|
||||
|
||||
#~ msgid "Clip the crosshairs at the center"
|
||||
#~ msgstr "Niitristi keskel on auk"
|
||||
|
||||
#~ msgid "Color of the crosshairs"
|
||||
#~ msgstr "Niitristi värvus"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Determines the transparency of the crosshairs, from fully opaque to fully "
|
||||
#~ "transparent."
|
||||
#~ msgstr ""
|
||||
#~ "Määrab niitristi läbipaistvuse, alates täiesti läbipaistmatust kuni "
|
||||
#~ "täiesti läbipaistvani."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Determines whether the crosshairs intersect the magnified mouse sprite, "
|
||||
#~ "or are clipped such that the ends of the horizontal and vertical lines "
|
||||
#~ "surround the mouse image."
|
||||
#~ msgstr ""
|
||||
#~ "Määrab, kas niitrist kattub suurendatud hiire pildiga või on keskelt ära "
|
||||
#~ "lõigatud nii, et jooned ümbritsevad hiirekursori pilti."
|
||||
|
||||
#~ msgid "Enable lens mode"
|
||||
#~ msgstr "Läätsede režiimi lubamine"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Enables/disables display of crosshairs centered on the magnified mouse "
|
||||
#~ "sprite."
|
||||
#~ msgstr "Lubab/keelab niitristi kuvamise suurendatud hiirekursori kohal."
|
||||
|
||||
#~ msgid "Length of the crosshairs"
|
||||
#~ msgstr "Niitristi pikkus"
|
||||
|
||||
#~ msgid "Magnification factor"
|
||||
#~ msgstr "Suurendustegur"
|
||||
|
||||
#~ msgid "Mouse Tracking Mode"
|
||||
#~ msgstr "Hiire jälitamise režiim"
|
||||
|
||||
#~ msgid "Opacity of the crosshairs"
|
||||
#~ msgstr "Niitristi läbipaistvus"
|
||||
|
||||
#~ msgid "Screen position"
|
||||
#~ msgstr "Ekraani asukoht"
|
||||
|
||||
#~ msgid "Scroll magnified contents beyond the edges of the desktop"
|
||||
#~ msgstr "Suurendusklaas võib liikuda töölauapiiridest väljapoole"
|
||||
|
||||
#~ msgid "Show or hide crosshairs"
|
||||
#~ msgstr "Niitristi kuvamine või peitmine"
|
||||
|
||||
#~ msgid "Show or hide the magnifier"
|
||||
#~ msgstr "Suurendusklaasi kuvamine või peitmine"
|
||||
|
||||
#~ msgid "Show or hide the magnifier and all of its zoom regions."
|
||||
#~ msgstr ""
|
||||
#~ "Suurendusklaasi ja selle kõigi suurenduspiirkondade kuvamine või peitmine."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The color of the the vertical and horizontal lines that make up the "
|
||||
#~ "crosshairs."
|
||||
#~ msgstr "Niitristi püst- ja rõhtjoone värvus."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The magnified view either fills the entire screen, or occupies the top-"
|
||||
#~ "half, bottom-half, left-half, or right-half of the screen."
|
||||
#~ msgstr ""
|
||||
#~ "Suurendatud vaade täidab kas kogu ekraani või täidab ülemise, alumise, "
|
||||
#~ "vasaku või parema ekraanipoole."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "The power of the magnification. A value of 1.0 means no magnification. A "
|
||||
#~ "value of 2.0 doubles the size."
|
||||
#~ msgstr ""
|
||||
#~ "Suurendustegur. 1,0 tähendab originaalsuurust. 2,0 muudab kaks korda."
|
||||
|
||||
#~ msgid "Thickness of the crosshairs"
|
||||
#~ msgstr "Niitristi paksus"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Whether the magnified view should be centered over the location of the "
|
||||
#~ "system mouse and move with it."
|
||||
#~ msgstr ""
|
||||
#~ "Kas suurendatud vaate keskkoht peaks asetsema süsteemi hiire kohal ning "
|
||||
#~ "liikuma sellega kaasa."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Width of the vertical and horizontal lines that make up the crosshairs."
|
||||
#~ msgstr "Niitristi moodustavate püst- ja rõhtjoone laius"
|
||||
|
||||
#~ msgid "PREFERENCES"
|
||||
#~ msgstr "Eelistused"
|
||||
|
||||
#~ msgid "Shut Down..."
|
||||
#~ msgstr "Lülita välja..."
|
||||
|
||||
#~ msgid "Bluetooth Agent"
|
||||
#~ msgstr "Bluetoothi agent"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Can't add a new workspace because maximum workspaces limit has been "
|
||||
#~ "reached."
|
||||
#~ msgstr "Pole võimalik uut tööala lisada, kuna tööalade piir on saavutatud."
|
||||
|
||||
#~ msgid "Can't remove the first workspace."
|
||||
#~ msgstr "Esimest tööala pole võimalik eemaldada."
|
||||
|
||||
#~ msgid "Clock"
|
||||
#~ msgstr "Kell"
|
||||
@@ -958,11 +1154,5 @@ msgstr "%1$s: %2$s"
|
||||
#~ msgid "Find"
|
||||
#~ msgstr "Otsi"
|
||||
|
||||
#~ msgid "Searching..."
|
||||
#~ msgstr "Otsimine..."
|
||||
|
||||
#~ msgid "No matching results."
|
||||
#~ msgstr "Tulemused puuduvad."
|
||||
|
||||
#~ msgid "Invisible"
|
||||
#~ msgstr "Nähtamatu"
|
||||
|
||||