Compare commits
617 Commits
wip/menus-
...
3.4.1
Author | SHA1 | Date | |
---|---|---|---|
bdfff20ec2 | |||
bdd05aba3b | |||
89c2538ff1 | |||
7680819108 | |||
d79e8b84c9 | |||
731317230a | |||
5046938913 | |||
0e8fd45559 | |||
6099a5dbc3 | |||
2daa98a694 | |||
5d2c6496fa | |||
817dbbe73f | |||
29c89c82f8 | |||
0b714bd479 | |||
8c94a5afb9 | |||
aeb117c9d1 | |||
a2d4f133b7 | |||
b833aff3c8 | |||
6601e4ddba | |||
815da2d0ec | |||
ddd35b3653 | |||
8a32894c83 | |||
49d8e6da40 | |||
8089f24c81 | |||
b6aab53d10 | |||
55a4517cd1 | |||
b095319a16 | |||
5ea5806730 | |||
bfbf812148 | |||
168e9eeac1 | |||
dd79c1a79a | |||
fe3402589b | |||
74dcaff21c | |||
0a7968a2e5 | |||
00091a2acb | |||
c5aa834b6a | |||
b1bde46694 | |||
49e4fa494e | |||
4622c52b71 | |||
e9ac5dd5f4 | |||
7570c43d11 | |||
4332e7ec49 | |||
9f26f1e225 | |||
0c0319c415 | |||
c16dbd7607 | |||
7b1f10a5fe | |||
dce74749b7 | |||
1ba88b8c42 | |||
9c50b57d46 | |||
900bd3ee97 | |||
b4affe00a7 | |||
ca49c84bc1 | |||
2cddf60226 | |||
d9c3951f02 | |||
aa5997d975 | |||
c51acf7c2a | |||
348044bc8a | |||
7dbdf2aa07 | |||
c933731ead | |||
e7da715994 | |||
6d82aefad4 | |||
8a11ab7d96 | |||
f465086405 | |||
70313a8b79 | |||
71679c38be | |||
addd943074 | |||
0b8470421c | |||
bcf7c0f006 | |||
2b87bb015c | |||
07e10fa03e | |||
bf992989c7 | |||
00400e354d | |||
19a49d34ce | |||
e8badac282 | |||
282a60fcab | |||
e76a28ded5 | |||
b22543ab66 | |||
d5165cdc08 | |||
1c0549f468 | |||
a7316b0594 | |||
634eeaf74c | |||
1299e196be | |||
92c325230d | |||
827a466a5c | |||
89b38b1361 | |||
140de6dd60 | |||
e64ff5832e | |||
17b1543d44 | |||
043e79a570 | |||
5d036e3d54 | |||
9d2a638988 | |||
7943993fcb | |||
026ddc2d9b | |||
384c7e2c17 | |||
700f706428 | |||
0a4deb2a9b | |||
5b8abe6809 | |||
2c5005c1ea | |||
c2b3022163 | |||
644abb2dc9 | |||
48b53c30f7 | |||
bf3818eb22 | |||
b3358aeed7 | |||
a7d4c7d8de | |||
369c1b0a41 | |||
21636f3f29 | |||
bf428312d7 | |||
6218209dcb | |||
1b7ead3455 | |||
3a252a1b41 | |||
fc7e6470b5 | |||
3813a03117 | |||
e59c29993c | |||
92d2ebc3f9 | |||
67ef448471 | |||
207abe9a2c | |||
05863227a6 | |||
ac05cb323c | |||
066d44636a | |||
3dbf06420d | |||
1983097d3a | |||
1c60aa58ae | |||
1626d9f9a4 | |||
c7182589d2 | |||
ceb17dc713 | |||
46c0360b03 | |||
0ebddfcf50 | |||
36d20eb1b8 | |||
db4b266874 | |||
63cf470e07 | |||
1f87eb4157 | |||
9bb9999b46 | |||
60e6349963 | |||
581d1c5db1 | |||
cf0b6dda25 | |||
8a5faa3d2e | |||
09607787cc | |||
0aad74a670 | |||
985f28bbea | |||
22e1abbaff | |||
21e8097b9c | |||
14d267c246 | |||
9420174477 | |||
fb4878bb7c | |||
c856cbb523 | |||
2e42eb6bad | |||
4f87e86603 | |||
3c6737f738 | |||
b2bc73c3fe | |||
30ca25e978 | |||
ecdd0875df | |||
d05d748fe2 | |||
8db193a172 | |||
c064973c9d | |||
01c66eaf0c | |||
c2fdec188e | |||
d7e2b0a771 | |||
06354a8c9a | |||
7c25dead17 | |||
f4d3153e91 | |||
7030d59b2f | |||
6eae036ac3 | |||
b6b6ed0e2f | |||
51b5825665 | |||
1c2629595e | |||
e91f4e88b5 | |||
bdb7dbdd00 | |||
7092521253 | |||
47f7fcd4fe | |||
93a004b016 | |||
2fad9d73d4 | |||
252eb24522 | |||
b7964e9efb | |||
23e7a9e710 | |||
36804a60c9 | |||
73270345f5 | |||
e1ffe06709 | |||
3dd240bdbb | |||
b58425d7d7 | |||
a197ce6f53 | |||
9dcdaf05b5 | |||
c827cccdf3 | |||
6805f2d71e | |||
0ea690a2f2 | |||
d68ff69c7a | |||
f1f2bc28a2 | |||
5f0389c07c | |||
c2f304f3bc | |||
ce9c1a1f7a | |||
203382e007 | |||
d2ba9eb967 | |||
59ebec25f3 | |||
b864b03a65 | |||
c7a37660ce | |||
02aae631d8 | |||
d542f63d3f | |||
74694a6e23 | |||
a5baeac428 | |||
e23e04953c | |||
fa9f923697 | |||
797e201946 | |||
156a642d28 | |||
96379b7517 | |||
9b5bb62aa7 | |||
895745ac14 | |||
6cde2d8db4 | |||
a277f8e0e1 | |||
cf5c5d06e1 | |||
722f45fa58 | |||
c97390b9c6 | |||
124c461a56 | |||
4ac352637c | |||
00cf62acfb | |||
ee0c2a1152 | |||
f32ab20267 | |||
1316f93b21 | |||
52d72fe8a1 | |||
0406aaa591 | |||
8f56660cfc | |||
402cc6b90c | |||
b8c14ad64e | |||
1f9c83d88b | |||
319667a25c | |||
b047a37a80 | |||
31af220483 | |||
40d51ea59f | |||
284cf83935 | |||
5ba04a7478 | |||
2b87051022 | |||
a901f2dc5d | |||
bd6f1f2c6d | |||
ca612872a6 | |||
feb33a6a28 | |||
ff92d962f3 | |||
79ca0d579c | |||
c61ac862ba | |||
64ce622f83 | |||
772638c78e | |||
24badb46fe | |||
87d54b37e4 | |||
98aa61e2a4 | |||
bea5c6f4e6 | |||
7d29e691a4 | |||
b0d161faad | |||
4c74fa81d1 | |||
556a3e08db | |||
e3fb77c051 | |||
3ee07d0e82 | |||
72c486cb3e | |||
e37574510e | |||
f4b58f35ba | |||
01696f19e8 | |||
1f5a27d5c5 | |||
81476dedcb | |||
90b08acbf1 | |||
f967fd21f8 | |||
8d854d5f1a | |||
fde5932b45 | |||
eb84227f78 | |||
550d595034 | |||
24cc4b49d6 | |||
5f130d1925 | |||
4f05787338 | |||
a98db33c18 | |||
a5d78f2943 | |||
46ebe9ffc5 | |||
e2b80658ca | |||
0a586c5c92 | |||
aa5d352a06 | |||
760da64a4c | |||
714ffc5ef1 | |||
fd4d645687 | |||
24ad59ea37 | |||
15f881f967 | |||
d5285674ae | |||
bb862e20c0 | |||
be3eb308b9 | |||
e7f0b1dc59 | |||
336cec8b2a | |||
fad0b96f24 | |||
d2aab9d6a6 | |||
4005863e3d | |||
70cdb67f31 | |||
a9aec6956d | |||
d871eda6be | |||
49d620a414 | |||
2e2e3281da | |||
37cbfe29cf | |||
a1f88fc17f | |||
0065da61bd | |||
d2b0706c40 | |||
a95e585e39 | |||
7d39fa76dd | |||
ddf27c1a84 | |||
87e46f3ff1 | |||
33a6fda6c3 | |||
7cc1bdb35d | |||
60557f4e0f | |||
914441218a | |||
e322d98886 | |||
ba1e5f8f71 | |||
517075c605 | |||
540e970170 | |||
d0fd5641c1 | |||
caaa21dec0 | |||
22c606326f | |||
00ed2973b2 | |||
3837fc0a87 | |||
07b95d3436 | |||
1f5dd9c397 | |||
007736a234 | |||
c2a9f7fbb2 | |||
b18cc8de86 | |||
30e4f80894 | |||
dd8a53d5e0 | |||
0f01928402 | |||
a8b081661c | |||
c892610f27 | |||
72dad591fa | |||
ea19790828 | |||
cc2f5d19c8 | |||
64b2c5d1b4 | |||
a9f728d2a7 | |||
3736d81d8f | |||
fbcea03ab3 | |||
f19ee78fb2 | |||
b47fd6df31 | |||
786beccca5 | |||
916c62a702 | |||
11234c7cfc | |||
80eac7370e | |||
ac78a1e1c0 | |||
34c6ff9645 | |||
f6749fb204 | |||
89fe43f70c | |||
e2c66ce48a | |||
eb0d803617 | |||
53d9ea7a2c | |||
0fbdd0b67f | |||
f248aa69dc | |||
9f1ed13a38 | |||
9400d8f6db | |||
c7a4b307af | |||
0bac3a5dd7 | |||
14b92a4897 | |||
66bd8b553f | |||
e80462a2c3 | |||
b990ed2c23 | |||
097e56f4ab | |||
7a4b6138c1 | |||
bc918d0d18 | |||
8b08d8bf2d | |||
d92c97f755 | |||
6a367917f7 | |||
b67138b5ae | |||
0e5177c329 | |||
c6ed3cdb61 | |||
fd99d13f04 | |||
36c3ce9333 | |||
aee28616a9 | |||
70830560ae | |||
df6cd46bd6 | |||
dce797f4d9 | |||
f3232901d8 | |||
d3e4f44d37 | |||
d81958a074 | |||
92ee17493c | |||
f9e456bb47 | |||
740388c778 | |||
1c0c42e8e7 | |||
e2726f3e38 | |||
ed465a6ffe | |||
fd8f3df2cd | |||
0c2037875a | |||
fbf6e032d0 | |||
c8020e6559 | |||
68b7e8437b | |||
6528f8366f | |||
88eb246b60 | |||
bed50688d2 | |||
44686bac3e | |||
ca575ef0ae | |||
c20503028a | |||
4516e4cc3b | |||
b2ec340f9e | |||
570a029f27 | |||
ebe72e197d | |||
ce629b09b2 | |||
97c2db1cfd | |||
c5804c1929 | |||
92276c5e70 | |||
62c0088dd8 | |||
e8498adaf1 | |||
c7fa719cc3 | |||
41f0e133a9 | |||
7705a65beb | |||
604e8f4f8a | |||
de0116d8c8 | |||
8d968e5c9b | |||
758e573483 | |||
eab4f4c963 | |||
245c58842b | |||
e508635c6e | |||
138b8cf874 | |||
d446b657f3 | |||
019dd2e1b0 | |||
602da771f6 | |||
5de8a0a84b | |||
d2198925e1 | |||
44e02003ad | |||
e8bfd990e4 | |||
d1fc87577a | |||
8b4c1a80d0 | |||
6ca0d4a5ef | |||
d0cd6ba47d | |||
aa2a63bd84 | |||
daa380fb0e | |||
61e2e04f13 | |||
db7e4ddc04 | |||
c4aa277b19 | |||
ab29ce872a | |||
57beb0ade1 | |||
e3d0b6f90f | |||
e2aa954cb5 | |||
05c285a945 | |||
27b34992c6 | |||
4886238761 | |||
42d46aed90 | |||
a622aba7eb | |||
831099cca5 | |||
b8a54faf94 | |||
80ff6ff797 | |||
2f27b94757 | |||
b2f33e2895 | |||
d1d4142052 | |||
46caf6d673 | |||
2864c360bc | |||
e5dfc6323a | |||
5bc042ba6f | |||
c63fe5ee24 | |||
ee6bc33cea | |||
5c730dc53d | |||
5a3de8d663 | |||
fad88dd517 | |||
39dd24310d | |||
b13809d0c7 | |||
87559414a3 | |||
b5b5759829 | |||
d254e2e1f2 | |||
458b0b22fc | |||
cd30128af8 | |||
d61cdd8cea | |||
0d0e545979 | |||
6c5e96c33a | |||
bae2359b54 | |||
8cbbb456f0 | |||
dfd39461cf | |||
60d8683ae7 | |||
f2cc5cf152 | |||
d4a26fbf4b | |||
025784fd83 | |||
4e89a5edde | |||
b3936ecadf | |||
2c9e6bb589 | |||
73261a4a66 | |||
3d0dd38045 | |||
8bcbf3030f | |||
1bc7edc5d8 | |||
0673720db9 | |||
730a0d4c5a | |||
9147dee0de | |||
12746a1949 | |||
bdd65fe755 | |||
21e2280825 | |||
e9d2a429eb | |||
b67dfb9edf | |||
55308917f9 | |||
1b64b09532 | |||
74dd298891 | |||
5a85fc0e55 | |||
26991988cb | |||
15563444cf | |||
3bcdba6e1d | |||
ef56a78544 | |||
049a561466 | |||
b40b19997a | |||
46505a8314 | |||
78fb102002 | |||
c6e924f788 | |||
f6508b51a2 | |||
b0ae596de8 | |||
1d311e7916 | |||
0c19f71c96 | |||
8d6ab32b9a | |||
6c1a2d531f | |||
c6e9f9742b | |||
d23aaf3cea | |||
017fde91ad | |||
31ffc5a85d | |||
62b65a25d8 | |||
882fe48d80 | |||
90a691ed25 | |||
eadb41b3bb | |||
6829590c8f | |||
29da720e6a | |||
c5932c0f07 | |||
6195386a06 | |||
0080440118 | |||
b5be62cd1b | |||
1bac40fbe3 | |||
11637bae43 | |||
301bacec9f | |||
8943b3b0e9 | |||
f59018f2d7 | |||
235cb9c505 | |||
3f328463a8 | |||
e58c82fc04 | |||
91ca86ffe4 | |||
33d4518e50 | |||
b087191d2b | |||
64baea1693 | |||
b88b743428 | |||
c606cf076d | |||
d205d7e7c2 | |||
efdd3375d0 | |||
abcca3d3bc | |||
f4d13b9801 | |||
7da39031e1 | |||
6cdb1bd60c | |||
7c108e267c | |||
5cf06fe9a7 | |||
41f6956197 | |||
417cbea79c | |||
225c807550 | |||
ff78d2655b | |||
bde15f7c61 | |||
30300f1aeb | |||
d42c3a15d6 | |||
14a65559af | |||
ba1e7bd095 | |||
951705a4b2 | |||
36bf63a5de | |||
66c4881fd2 | |||
c6b169cb33 | |||
0e753ed5a6 | |||
785969feb5 | |||
56036476a4 | |||
936b1b5638 | |||
bf3b94d654 | |||
90b4a0856f | |||
686190ce80 | |||
45495c2474 | |||
9caa88fecb | |||
25948f214e | |||
bea4faacd4 | |||
a7bd9f811b | |||
2b9561fcbb | |||
7b9c9b2f7d | |||
b47b82ed42 | |||
c4c2c11dca | |||
ce38293a0f | |||
6c4e9d23f2 | |||
4aa1fe9ca2 | |||
951fff5aa0 | |||
5ad8080cb9 | |||
e53e3cbb09 | |||
8a029f333f | |||
4debedb275 | |||
8764253861 | |||
bbdce159fa | |||
087d8e602e | |||
50aa15dec9 | |||
26580f8f2c | |||
875b6d131b | |||
77afd6782f | |||
09ab13cf04 | |||
56f312dc03 | |||
f2cbddc196 | |||
c7846e172f | |||
54afb7b25e | |||
f3cb9d0443 | |||
fcee7f2f3a | |||
faff0738eb | |||
69e26c6dee | |||
1acec65c5e | |||
8a6a3968c3 | |||
58e4870cb8 | |||
102099cadd | |||
efe6d06ddd | |||
f0d0e025dd | |||
fc2d0215f5 | |||
02af8eb824 | |||
102f2a91f9 | |||
2c649d5da5 | |||
7fa7d04ed0 | |||
aad9179373 | |||
d5b4e30eb7 | |||
34ba6f2f71 | |||
d845f40b98 | |||
80c16aa8f7 | |||
0cbaeaefed | |||
ab6a7773ce | |||
85e243982b | |||
6eb168bc68 | |||
47b55e29d4 | |||
2c243b678f | |||
a634f25d30 | |||
26df6cf35c | |||
84dde8e9bb | |||
f2c79be11a | |||
10df80b96a | |||
bbb83656bf | |||
ef49670ae4 | |||
e4df00c77d | |||
3d70662716 | |||
8d0638a187 | |||
06143396b7 |
3
.gitignore
vendored
@ -18,6 +18,8 @@ config
|
|||||||
configure
|
configure
|
||||||
data/gnome-shell.desktop
|
data/gnome-shell.desktop
|
||||||
data/gnome-shell.desktop.in
|
data/gnome-shell.desktop.in
|
||||||
|
data/gnome-shell-extension-prefs.desktop
|
||||||
|
data/gnome-shell-extension-prefs.desktop.in
|
||||||
data/gschemas.compiled
|
data/gschemas.compiled
|
||||||
data/org.gnome.shell.gschema.xml
|
data/org.gnome.shell.gschema.xml
|
||||||
data/org.gnome.shell.gschema.valid
|
data/org.gnome.shell.gschema.valid
|
||||||
@ -62,6 +64,7 @@ src/calendar-server/org.gnome.Shell.CalendarServer.service
|
|||||||
src/gnome-shell
|
src/gnome-shell
|
||||||
src/gnome-shell-calendar-server
|
src/gnome-shell-calendar-server
|
||||||
src/gnome-shell-extension-tool
|
src/gnome-shell-extension-tool
|
||||||
|
src/gnome-shell-extension-prefs
|
||||||
src/gnome-shell-hotplug-sniffer
|
src/gnome-shell-hotplug-sniffer
|
||||||
src/gnome-shell-jhbuild
|
src/gnome-shell-jhbuild
|
||||||
src/gnome-shell-perf-helper
|
src/gnome-shell-perf-helper
|
||||||
|
311
NEWS
@ -1,3 +1,312 @@
|
|||||||
|
3.4.1
|
||||||
|
=====
|
||||||
|
* Fix crash that occurred when an icon theme change caused unexpected
|
||||||
|
reentrancy in the icon loading code [Jasper; #673512]
|
||||||
|
* Don't show system and other disabled users in the GDM user list
|
||||||
|
[Adel; #673784]
|
||||||
|
* Make gnome-shell-calendar-server initialize GTK+ so it can display
|
||||||
|
password prompts if needed [#673608; Owen, Rico]
|
||||||
|
* Adapt to Mutter API change for keybinding addition [Florian; #673014]
|
||||||
|
* Fix crash when an extension was installed as both a user extension
|
||||||
|
and a system extension [#673613; Jasper]
|
||||||
|
* Fix bug where chat entry could end up partially offscreen [Joost, 661944]
|
||||||
|
* Fix problem where icons weren't updating when theme was changed
|
||||||
|
[#672941; Florian]
|
||||||
|
* Look for Evolution calendar settings in GSettings, not GConf [#673610; Owen]
|
||||||
|
* Add <super>F10 for the application menu [#672909; Florian]
|
||||||
|
* Fix %Id format characters to work in translations [#673106; Cosimo]
|
||||||
|
(were already used in fa translation)
|
||||||
|
* Fix error when NetworkManager restarts [#673043; Giovanni]
|
||||||
|
* Improve efficiency of overview redraws by working around Clutter issue
|
||||||
|
[Stefano; #670636]
|
||||||
|
* Misc bug fixes [Florian, Giovanni, Jasper, Rui, Stefano;
|
||||||
|
#672592, #672641, #672719, #673187, #673233, #673656]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Giovanni Campagna, Cosimo Cecchi, Stefano Facchini, Adel Gadllah, Rui Matos,
|
||||||
|
Florian Müllner, Jasper St. Pierre, Owen Taylor, Rico Tzschichholz,
|
||||||
|
Joost Verdoorn
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Khaled Hosny [ar], Ihar Hrachyshka [be], Alexander Shopov [bg], Gil Forcada,
|
||||||
|
Jordi Serratosa [ca], Petr Kovar [cs], Bruce Cowan [en_GB],
|
||||||
|
Carles Ferrando [ca@valencia], Wolfgang Stöggl [de], Daniel Mustieles [es],
|
||||||
|
Arash Mousavi [fa], Bruno Brouard [fr], Fran Diéguez [gl],
|
||||||
|
Sweta Kothari [gu], Yaron Shahrabani [he], Gabor Kelemen [hu],
|
||||||
|
Shankar Prasad [kn], Žygimantas Beručka [lt], Rudolfs Mazurs [lv],
|
||||||
|
Sandeep Sheshrao Shedmake [mr], Kjartan Maraas [nb], Piotr Drąg [pl],
|
||||||
|
Yuri Myasoedov [ru], Daniel Nylander [se], Matej Urbančič [sl],
|
||||||
|
Miroslav Nikolić [sr], Sasi Bhushan, Praveen Illa [te], Yinghua Wang [zh_CN]
|
||||||
|
|
||||||
|
3.4.0
|
||||||
|
=====
|
||||||
|
* Don't crash when taking screenshots [Jasper; #672775]
|
||||||
|
* Fix dialog-resizing problem [Florian; #672543]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Florian Müllner, Jasper St. Pierre
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Khaled Hosny, Abderrahim Kitouni [ar], Ihar Hrachyshka [be],
|
||||||
|
Alexander Shopov [bg], Marek Černocký [cs], Jiri Grönroos, Timo Jyrinki [fi],
|
||||||
|
Bruno Brouard [fr], Fran Diéguez [gl], Yaron Shahrabani [he],
|
||||||
|
Gabor Kelemen [hu], Jiro Matsuzawa [ja], Kenneth Nielsen [dk],
|
||||||
|
Mattias Põldaru [et], Changwoo Ryu [ko], Rudolfs Mazurs [lv],
|
||||||
|
Jonh Wendell [pt_BR], Yuri Myasoedov[ru], Daniel Korostil [uk],
|
||||||
|
Nguyễn Thái Ngọc Duy [vi], Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||||
|
|
||||||
|
3.3.92
|
||||||
|
======
|
||||||
|
* Add shell-dialogs for GNOME Keyring prompts [Stef; #652459, #652460, #671034]
|
||||||
|
* When the user returns from idle, bring up the message tray if there were
|
||||||
|
messages while they were away [Marina; #643014]
|
||||||
|
* https://live.gnome.org/EveryDetailMatters
|
||||||
|
- Make the workspace thumbnails clickable all the way to the edge of the
|
||||||
|
screen [Stefano; #643319]
|
||||||
|
- Don't slide out the workspace thumbnails if the mouse is over them when
|
||||||
|
entering the overview [Joost, #651092]
|
||||||
|
- Fix placeholder jumps while dragging a dash item [Joost; #651842]
|
||||||
|
- Don't favorite apps if they are dropped back at the same position
|
||||||
|
[Jean-Philippe; #656333]
|
||||||
|
- To avoid confusion, don't allow removing running apps from favorites
|
||||||
|
[Florian; #644853]
|
||||||
|
- Fix creation of new workspaces by dragging application launchers
|
||||||
|
[Stefano; #664202]
|
||||||
|
- Make it easier to drag dash items without triggering the menu
|
||||||
|
[Florian; #637103]
|
||||||
|
* Accessibility [Alejandro]
|
||||||
|
- Add StWidget API for easily adding accessible states and setting roles,
|
||||||
|
names [#668366, #667432, #671378]
|
||||||
|
- Set accessibility information on UI elements
|
||||||
|
[#644255, #667432, #668361, #672047, #670308, #670312, #670719, #671404]
|
||||||
|
* Improve key-navigation in the overview [Rui, Florian; #663901]
|
||||||
|
* Key navigation bug fixes [Rui, Florian; #662493, #663437, #665215, #671998]
|
||||||
|
* Honor a 'org.gnome.shell.overrides.dynamic-workspaces' setting that
|
||||||
|
determines whether the workspace count is dynamic and unsaved in GSettings
|
||||||
|
or static and saved. [Florian; #671568]
|
||||||
|
* Avoid saving user presence to GSettings when not necessary
|
||||||
|
[Florian; #665701, #668214]
|
||||||
|
* Save screencasts in the users Videos/ directory [Adel; #670749]
|
||||||
|
Use a "human readable" filename [Florian, Adel, Ray; #670753]
|
||||||
|
* Allow dragging from the empty part of the top panel to unmaximize a window
|
||||||
|
[Florian; #666359]
|
||||||
|
* Fix hangs that could occur when switching away to a VT [Ray; #653833]
|
||||||
|
* Fix problems with installing from extensions.gnome.org [Giovanni; #671134]
|
||||||
|
* Fix locking the screen when suspending via menu [David, Gert; #670820]
|
||||||
|
* Fix browser plugin with Konqueror and Opera [Jasper]
|
||||||
|
* Fix shell restart not to bring up failure screen [Giovanni; #648384]
|
||||||
|
* Reorganize and clean up CSS theming [Allan; #668209]
|
||||||
|
* Improve appearance of modal dialogs [Allan, Florian; #670227, #668209]
|
||||||
|
* Update the calendar code to use ECalClient [Giovanni; #671177]
|
||||||
|
* Update jhbuild script to use the main moduleset [Owen, Will; #668440]
|
||||||
|
* StTextureCache: code cleanup, evict unused icons, merge together
|
||||||
|
simulataneous requests for the same icon [Jasper; #670771, #671656, #672273]
|
||||||
|
* Clean up St for recent Clutter changes and fix bugs. StContainer and
|
||||||
|
StGroup are removed [Jasper, Florian; #670034, #670640, #670904]
|
||||||
|
* Code cleanup [Adel, Jasper, Rui; #613194, #671086, #671103]
|
||||||
|
* Misc bug fixes
|
||||||
|
[Adel, Colin G, Cosimo, Florian, Giovanni, Jasper, Marius, Rui, Stefano;
|
||||||
|
#651130, #658946, #667552, #670076, #671001, #670979, #671410, #671411,
|
||||||
|
#671556, #671656, #671657, #672011, #672024, #672240, #672265, #672270,
|
||||||
|
#672321, #672326, #672413, #672471]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jean-Philippe Braun, Giovanni Campagna, Cosimo Cecchi, Allan Day,
|
||||||
|
Stefano Facchini, David Foerster, Adel Gadllah, Marius Gedminas,
|
||||||
|
Colin Guthrie, Gert Michael Kulyk, William Lachance, Rui Matos,
|
||||||
|
Florian Müllner, Alejandro Piñeiro, Jan Alexander Steffens,
|
||||||
|
Jasper St. Pierre, Ray Strode, Owen Taylor, Joost Verdoorn, Stef Walter,
|
||||||
|
Marina Zhurakhinskaya
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Nilamdyuti Goswami [as], Ihar Hrachyshka, Kasia Bondarava [be],
|
||||||
|
Alexander Shopov, Ivaylo Valkov [bg], Gil Forcada [ca], Marek Černocký [cs],
|
||||||
|
Mario Blättermann [de], Kris Thomsen [dk], Bruce Cowan [en_GB],
|
||||||
|
Kristjan Schmidt [eo], Daniel Mustieles [es], Mattias Põldaru [et],
|
||||||
|
Inaki Larranaga Murgoitio [eu], Arash Mousavi [fa], Timo Jyrinki [fi],
|
||||||
|
Bruno Brouard [fr], Fran Diéguez [gl], Sweta Kothari [gu],
|
||||||
|
Yaron Shahrabani [he], Gabor Kelemen [hu], Jiro Matsuzawa [ja],
|
||||||
|
Baurzhan Muftakhidinov [kk], Seong-ho Cho [ko], Žygimantas Beručka [lt],
|
||||||
|
Anita Reitere [lv], Anish A, Praveen Arimbrathodiyil, Mohammed Sadiq [ml],
|
||||||
|
fKjartan Maraas [nb], Wouter Bolsterlee [nl], A S Alam [pa], Piotr Drąg [pl],
|
||||||
|
Duarte Loreto [pt], Jonh Wendell [pt_BR], Yuri Myasoedov [ru],
|
||||||
|
Matej Urbančič [sl], Miroslav Nikolić [sr], Tirumurti Vasudevan [ta],
|
||||||
|
Sasi Bhushan, Krishnababu Krothapalli [te], Daniel Korostil [uk],
|
||||||
|
Nguyễn Thái Ngọc Duy [vi], YunQiang Su, Yinghua Wang [zh_CN],
|
||||||
|
Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||||
|
|
||||||
|
3.3.90
|
||||||
|
======
|
||||||
|
|
||||||
|
* Allow other applications to implement search providers via D-Bus
|
||||||
|
[Florian; #663125, #670148]
|
||||||
|
* Remove "Recent Items" search, as replaced by Documents search
|
||||||
|
[Florian; #663125]
|
||||||
|
* Allow NetworkManager VPN plugins to use a shell-themed dialog
|
||||||
|
[Giovanni; #658484]
|
||||||
|
* Port away from deprecated Clutter API [Jasper, Florian, Adel; #670034]
|
||||||
|
- StTooltip is removed
|
||||||
|
- StWidget is now a concrete class and can be instantiated
|
||||||
|
- st_container_destroy_children(), st_box_layout_insert_actor(),
|
||||||
|
and other functions removed in favor of new replacements in Clutter.
|
||||||
|
* Use systemd for console/session handling when available [Lennart]
|
||||||
|
* Visual improvements to contact search, padding, top panel, checkboxes
|
||||||
|
[Allan, Florian, Jakub; #669489, #669811, #669993]
|
||||||
|
* Add a include_cursor parameter to Screenshot and ScreenshotWindow
|
||||||
|
D-Bus methods [Adel; #670086]
|
||||||
|
* Add a "FlashArea" D-Bus method to do the screenshot flash without a
|
||||||
|
screenshot [Adel; #669660]
|
||||||
|
* Build fixes [Adel, Giovanni, Jasper; #658484, #669637]
|
||||||
|
* Misc bug fixes [Adel, Florian, Giovanni, Guillaume, Jasper, Jeff,
|
||||||
|
Marc-Antoine, Stef, Stefano, Will; #642135, #658484, #658908, #667694,
|
||||||
|
#669098, #669921, #669662, #669694, #669776, #669887, #669921, #670005,
|
||||||
|
#670006, #670319, #670418, #670489]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Giovanni Campagna, Cosimo Cecchi, Allan Day, Guillaume Desmottes, Jeff Epler,
|
||||||
|
Stefano Facchini, Adel Gadllah, Florian Müllner, Marc-Antoine Perennou,
|
||||||
|
Jasper St. Pierre, Lennart Poettering, Jakub Steiner, Jasper St. Pierre,
|
||||||
|
Will Thompson, Stef Walter
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Ihar Hrachyshka [be], Marek Černocký, Adam Matoušek [cs],
|
||||||
|
Kenneth Nielsen [dk], Daniel Mustieles [es], Mattias Põldaru [et],
|
||||||
|
Fran Diéguez [gl], Yaron Shahrabani [he], Luca Ferretti [it],
|
||||||
|
Baurzhan Muftakhidinov [kk], Aurimas Černius [lt], Kjartan Maraas [nb],
|
||||||
|
A S Alam [pa], Matej Urbančič [sl], Miroslav Nikolić [sr],
|
||||||
|
Praveen Illa [te], Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||||
|
|
||||||
|
3.3.5
|
||||||
|
=====
|
||||||
|
|
||||||
|
* Extension system: [Jasper; #668429]
|
||||||
|
http://blog.mecheye.net/2012/02/more-extension-api-breaks/
|
||||||
|
- Add a 'gnome-shell-extension-prefs' application for displaying extension
|
||||||
|
preferences as provided by the extension in a prefs.js file.
|
||||||
|
- Allow launching gnome-shell-extension-prefs from extensions.gnome.org
|
||||||
|
throuhg the browser plugin.
|
||||||
|
- Add ExtensionUtils.getCurrentExtension() for an extension to get a
|
||||||
|
handle to an extension object, to get local imports or paths.
|
||||||
|
- Add an onshellrestart callback to the browser plugin [Jasper; #668517]
|
||||||
|
* Screenshots:
|
||||||
|
- Move the screenshot "flash" to the shell [Cosimo; #668618]
|
||||||
|
- Move saving screenshots to a thread [Adel; #652952]
|
||||||
|
- Correctly screenshot rounded decorations [Jasper; #662486]
|
||||||
|
* Screen recorder:
|
||||||
|
- Change the default pipeline to favor speed over quality [Owen; #669066]
|
||||||
|
- Drop frames to keep from running the user out of memory [Owen; #669066]
|
||||||
|
* Work around a slow implementation of glReadPixels() in the Intel drivers,
|
||||||
|
improving performance for screenshots and the screen recorder.
|
||||||
|
[Owen; #669065]
|
||||||
|
* Use Keywords: field in desktop files when search for applications
|
||||||
|
[Florian; #609702]
|
||||||
|
* Strip debian- when matching desktop file names [Jasper; #665647]
|
||||||
|
* Fix up various problems from CSS background size-addition
|
||||||
|
[Florian, Jasper; #668430, #633462]
|
||||||
|
* UI tweaks and behavior fixes
|
||||||
|
[Florian, Giovanni, Stefano; #643867, #666197, #664622]
|
||||||
|
* Some improvements to exported accessibility information [Alejando; #667376]
|
||||||
|
* Don't show contacts without IM information as offline [Florian; #662685]
|
||||||
|
* Don't change status from hidden to extended_away when going idle
|
||||||
|
[Florian; #642408]
|
||||||
|
* Cleanups [Emmanuele, Jasper; #662152, #669239]
|
||||||
|
* Misc bug fixes [Cosimo, Dan, Florian, Jasper, Rui, Stefano;
|
||||||
|
#633462, #643867, #662213, #662386, #662747, #665000, #665017, #665322,
|
||||||
|
#667371, #667860, #668020, #668517, #668541, #669236]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Stefano Facchini,
|
||||||
|
Adel Gadllah, Rui Matos, Florian Müllner, Alejandro Piñeiro,
|
||||||
|
Jasper St. Pierre, Owen Taylor, Dan Winship
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Daniel Mustieles [es], Timo Jyrinki [fi], Seán de Búrca [ga],
|
||||||
|
Fran Diéguez [gl], Kjartan Maraas [nb], Wouter Bolsterlee [nl],
|
||||||
|
Danishka Navin [si], Yaron Shahrabani [he], Matej Urbančič [sl],
|
||||||
|
Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||||
|
|
||||||
|
3.3.4
|
||||||
|
=====
|
||||||
|
* https://live.gnome.org/EveryDetailMatters
|
||||||
|
- Add "browse" for labels for dash items - once a tooltip is
|
||||||
|
showing, switch to other items without a delay [Seif; #666170]
|
||||||
|
- Always scale down windows in the overview at least to 70% [Vit; #646704]
|
||||||
|
- Fix the new-workspace drop indicator sometimes getting stuck
|
||||||
|
[Stefano; #664201]
|
||||||
|
- Delay rearranging windows in the overview as long as the pointer
|
||||||
|
is over a window [Vit; #645325]
|
||||||
|
* Add a GConf => DConf migration file for overriden Mutter settings
|
||||||
|
[Florian; #667636]
|
||||||
|
* When a VPN connection is active, show that as the network icon
|
||||||
|
[Giovanni; #665115]
|
||||||
|
* Handle the "ExtendedAway" IM status as away, not offline [Guillaume; #667813]
|
||||||
|
* Improve the appearance of the labels in "Applications" [Alex; #642392]
|
||||||
|
* Adjust for GTK+ and Mutter API changes for application menu [Ryan; #668118]
|
||||||
|
* Add section label support to the application menu [Giovanni; #666681]
|
||||||
|
* Fix screenshot methods to work again [Cosimo; #667662]
|
||||||
|
* Fix several crashers related to updating workspace thumbnails [Owen; #667652]
|
||||||
|
* Fix memory management error causing gnome-shell-hotplug-sniffer to crash
|
||||||
|
[Owen; #667378]
|
||||||
|
* Build fixes [Emmanuele, Rico; #667864]
|
||||||
|
* Code cleanups [Adel; #668087]
|
||||||
|
* Misc bug fixes [Colin, Florian, Giovanni, Owen, Xavier; #633028, #658817,
|
||||||
|
#664138, #667881, #668048, #668050]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Emmanuele Bassi, Giovanni Campagna, Cosimo Cecchi, Xavier Claessens,
|
||||||
|
Guillaume Desmottes, Stefano Facchini, Adel Gadllah, Alex Hultman,
|
||||||
|
Ryan Lortie, Seif Lotfy, Florian Müllner, Vit Stanislav, Owen Taylor,
|
||||||
|
Rico Tzschichholz, Colin Walters
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Ihar Hrachyshka [be], Alexander Shopov [bg], Arash Mousavi [fa],
|
||||||
|
Jiri Grönroos, Timo Jyrinki [fi], Fran Diéguez [gl], Kjartan Maraas [nb],
|
||||||
|
Yuri Myasoedov [ru], Matej Urbančič [sl], Nguyễn Thái Ngọc Duy [vi]
|
||||||
|
|
||||||
|
3.3.3
|
||||||
|
=====
|
||||||
|
* https://live.gnome.org/EveryDetailMatters
|
||||||
|
- Stop flashing the window labels on actions in overview [Zan; #644861]
|
||||||
|
- Improve the look of window captions in the overview [Marc; #664487]
|
||||||
|
- Move dash tooltips beside the icon [Seif, Stefano; #666166]
|
||||||
|
* Support application menus exported from applications via new GLib API
|
||||||
|
and D-Bus protocol. [Giovanni, Colin, Matthias, Cosimo]
|
||||||
|
* For removable device prompts, show "Open with Rhythmbox], rather
|
||||||
|
than "Open with Rhythmbox Music Player' [Florian; #664561]
|
||||||
|
* Switch to activating the message tray only with a hot corner rather
|
||||||
|
than a full row of pixels, allowing mouse events to apps [Rui; #663366]
|
||||||
|
* Fully handle the case where the workspaces-only-on-primary
|
||||||
|
GSetting is set to false [Florian; #652580]
|
||||||
|
* Add support for background-size CSS property to St [Quentin; #633462]
|
||||||
|
* Port to new GJS Lang.Class framework [Giovanni; #664436]
|
||||||
|
* Finish port to GDBus [Giovanni; #664436]
|
||||||
|
* Stop using the deprecated Clutter default stage [Florian, Jasper; #664052]
|
||||||
|
* Fix bugs that kept browser plugin from working in WebKit-based browser
|
||||||
|
[Jasper; #666444]
|
||||||
|
* Fix typo that made uninstalling extensions not work [Jasper]
|
||||||
|
* Fix crash in browser plugin if shell is not run [Jürg]
|
||||||
|
* Reintroduce piscine paschal ovum [Giovanni; #666606]
|
||||||
|
* Network menu bug fixes
|
||||||
|
Giovanni; #664124, #665194, #665680, #666429, #666614]
|
||||||
|
* Misc bug fixes [Florian, Jasper, Jonny, Marina, Ron; #647587, #659272,
|
||||||
|
#664138, #665261, #666020, #666243]
|
||||||
|
* Build fixes [Owen]
|
||||||
|
|
||||||
|
Contributors:
|
||||||
|
Jürg Billeter, Giovanni Campagna, Stefano Candori, Cosimo Cecchi,
|
||||||
|
Matthias Clasen, Zan Dobersek, Quentin Glidic, Jonny Lamb, Ryan Lortie,
|
||||||
|
Seif Lotfy, Rui Matos, Florian Müllner, Bastien Nocera, Jasper St. Pierre,
|
||||||
|
Marc Plano-Lesay, Owen Taylor, Colin Walters, Ron Yorsten,
|
||||||
|
Marina Zhurakhinskaya
|
||||||
|
|
||||||
|
Translations:
|
||||||
|
Petr Kovar [cs], Kris Thomsen [dk], Daniel Mustieles [es],
|
||||||
|
Ville-Pekka Vainio [fi], Yaron Shahrabani [he], Luca Ferretti [it],
|
||||||
|
Hideki Yamane [ja], Žygimantas Beručka [lt], Jovan Naumovski [mk],
|
||||||
|
Kjartan Maraas [nb], "Andreas N" [nn], Lucian Adrian Grijincu [ro],
|
||||||
|
Matej Urbančič [sl], Praveen Illa [te], Muhammet Kara [tr],
|
||||||
|
Daniel Korostil [uk], Aron Xu [zh_CN]
|
||||||
|
|
||||||
3.3.2
|
3.3.2
|
||||||
=====
|
=====
|
||||||
* Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian,
|
* Port D-Bus usage in the shell to GDBus [Giovanni, Marc-Antoine, Florian,
|
||||||
@ -154,7 +463,7 @@ Contributors:
|
|||||||
Translations:
|
Translations:
|
||||||
Friedel Wolff [af], Nilamdyuti Goswami [as], Ihar Hrachyshka [be],
|
Friedel Wolff [af], Nilamdyuti Goswami [as], Ihar Hrachyshka [be],
|
||||||
Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
|
Ivaylo Valkov [bg], Gil Forcada [ca], Carles Ferrando [ca@valencia],
|
||||||
Petr Kovar [cz], Mario Blättermann [de], Kris Thomsen [dk],
|
Petr Kovar [cs], Mario Blättermann [de], Kris Thomsen [dk],
|
||||||
Tiffany Antopolski, Kristjan Schmidt [eo], Daniel Mustieles [es],
|
Tiffany Antopolski, Kristjan Schmidt [eo], Daniel Mustieles [es],
|
||||||
Inaki Larranaga Murgoitio [eu], Tommi Vainikainen [fi], Bruno Brouard [fr],
|
Inaki Larranaga Murgoitio [eu], Tommi Vainikainen [fi], Bruno Brouard [fr],
|
||||||
Fran Dieguez [gl], Yaron Shahrabani [he], Gabor Kelemen [hu],
|
Fran Dieguez [gl], Yaron Shahrabani [he], Gabor Kelemen [hu],
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
"It can be used only by extensions.gnome.org"
|
"It can be used only by extensions.gnome.org"
|
||||||
#define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type";
|
#define PLUGIN_MIME_STRING "application/x-gnome-shell-integration::Gnome Shell Integration Dummy Content-Type";
|
||||||
|
|
||||||
#define PLUGIN_API_VERSION 1
|
#define PLUGIN_API_VERSION 3
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GDBusProxy *proxy;
|
GDBusProxy *proxy;
|
||||||
@ -104,7 +104,7 @@ check_origin_and_protocol (NPP instance)
|
|||||||
&location))
|
&location))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!NPVARIANT_IS_OBJECT (document))
|
if (!NPVARIANT_IS_OBJECT (location))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
hostname = get_string_property (instance,
|
hostname = get_string_property (instance,
|
||||||
@ -153,6 +153,8 @@ NP_Initialize(NPNetscapeFuncs *pfuncs, NPPluginFuncs *plugin)
|
|||||||
/* global initialization routine, called once when plugin
|
/* global initialization routine, called once when plugin
|
||||||
is loaded */
|
is loaded */
|
||||||
|
|
||||||
|
g_type_init ();
|
||||||
|
|
||||||
g_debug ("plugin loaded");
|
g_debug ("plugin loaded");
|
||||||
|
|
||||||
memcpy (&funcs, pfuncs, sizeof (funcs));
|
memcpy (&funcs, pfuncs, sizeof (funcs));
|
||||||
@ -262,11 +264,13 @@ NPP_Destroy(NPP instance,
|
|||||||
/* =================== scripting interface =================== */
|
/* =================== scripting interface =================== */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NPObject parent;
|
NPObject parent;
|
||||||
NPP instance;
|
NPP instance;
|
||||||
GDBusProxy *proxy;
|
GDBusProxy *proxy;
|
||||||
NPObject *listener;
|
NPObject *listener;
|
||||||
gint signal_id;
|
NPObject *restart_listener;
|
||||||
|
gint signal_id;
|
||||||
|
guint watch_name_id;
|
||||||
} PluginObject;
|
} PluginObject;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -284,7 +288,7 @@ on_shell_signal (GDBusProxy *proxy,
|
|||||||
gint32 status;
|
gint32 status;
|
||||||
gchar *error;
|
gchar *error;
|
||||||
NPVariant args[3];
|
NPVariant args[3];
|
||||||
NPVariant result;
|
NPVariant result = { NPVariantType_Void };
|
||||||
|
|
||||||
g_variant_get (parameters, "(sis)", &uuid, &status, &error);
|
g_variant_get (parameters, "(sis)", &uuid, &status, &error);
|
||||||
STRINGZ_TO_NPVARIANT (uuid, args[0]);
|
STRINGZ_TO_NPVARIANT (uuid, args[0]);
|
||||||
@ -300,6 +304,25 @@ on_shell_signal (GDBusProxy *proxy,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_shell_appeared (GDBusConnection *connection,
|
||||||
|
const gchar *name,
|
||||||
|
const gchar *name_owner,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
PluginObject *obj = (PluginObject*) user_data;
|
||||||
|
|
||||||
|
if (obj->restart_listener)
|
||||||
|
{
|
||||||
|
NPVariant result = { NPVariantType_Void };
|
||||||
|
|
||||||
|
funcs.invokeDefault (obj->instance, obj->restart_listener,
|
||||||
|
NULL, 0, &result);
|
||||||
|
|
||||||
|
funcs.releasevariantvalue (&result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static NPObject *
|
static NPObject *
|
||||||
plugin_object_allocate (NPP instance,
|
plugin_object_allocate (NPP instance,
|
||||||
NPClass *klass)
|
NPClass *klass)
|
||||||
@ -312,6 +335,14 @@ plugin_object_allocate (NPP instance,
|
|||||||
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
|
obj->signal_id = g_signal_connect (obj->proxy, "g-signal",
|
||||||
G_CALLBACK (on_shell_signal), obj);
|
G_CALLBACK (on_shell_signal), obj);
|
||||||
|
|
||||||
|
obj->watch_name_id = g_bus_watch_name (G_BUS_TYPE_SESSION,
|
||||||
|
"org.gnome.Shell",
|
||||||
|
G_BUS_NAME_WATCHER_FLAGS_NONE,
|
||||||
|
on_shell_appeared,
|
||||||
|
NULL,
|
||||||
|
obj,
|
||||||
|
NULL);
|
||||||
|
|
||||||
g_debug ("plugin object created");
|
g_debug ("plugin object created");
|
||||||
|
|
||||||
return (NPObject*)obj;
|
return (NPObject*)obj;
|
||||||
@ -328,6 +359,9 @@ plugin_object_deallocate (NPObject *npobj)
|
|||||||
if (obj->listener)
|
if (obj->listener)
|
||||||
funcs.releaseobject (obj->listener);
|
funcs.releaseobject (obj->listener);
|
||||||
|
|
||||||
|
if (obj->watch_name_id)
|
||||||
|
g_bus_unwatch_name (obj->watch_name_id);
|
||||||
|
|
||||||
g_debug ("plugin object destroyed");
|
g_debug ("plugin object destroyed");
|
||||||
|
|
||||||
g_slice_free (PluginObject, obj);
|
g_slice_free (PluginObject, obj);
|
||||||
@ -341,7 +375,9 @@ static NPIdentifier enable_extension_id;
|
|||||||
static NPIdentifier install_extension_id;
|
static NPIdentifier install_extension_id;
|
||||||
static NPIdentifier uninstall_extension_id;
|
static NPIdentifier uninstall_extension_id;
|
||||||
static NPIdentifier onextension_changed_id;
|
static NPIdentifier onextension_changed_id;
|
||||||
|
static NPIdentifier onrestart_id;
|
||||||
static NPIdentifier get_errors_id;
|
static NPIdentifier get_errors_id;
|
||||||
|
static NPIdentifier launch_extension_prefs_id;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
plugin_object_has_method (NPObject *npobj,
|
plugin_object_has_method (NPObject *npobj,
|
||||||
@ -352,7 +388,8 @@ plugin_object_has_method (NPObject *npobj,
|
|||||||
name == enable_extension_id ||
|
name == enable_extension_id ||
|
||||||
name == install_extension_id ||
|
name == install_extension_id ||
|
||||||
name == uninstall_extension_id ||
|
name == uninstall_extension_id ||
|
||||||
name == get_errors_id);
|
name == get_errors_id ||
|
||||||
|
name == launch_extension_prefs_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline gboolean
|
static inline gboolean
|
||||||
@ -455,9 +492,12 @@ plugin_enable_extension (PluginObject *obj,
|
|||||||
NPString uuid,
|
NPString uuid,
|
||||||
gboolean enabled)
|
gboolean enabled)
|
||||||
{
|
{
|
||||||
const gchar *uuid_str = uuid.UTF8Characters;
|
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
||||||
if (!uuid_is_valid (uuid_str))
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
{
|
||||||
|
g_free (uuid_str);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
g_dbus_proxy_call (obj->proxy,
|
g_dbus_proxy_call (obj->proxy,
|
||||||
(enabled ? "EnableExtension" : "DisableExtension"),
|
(enabled ? "EnableExtension" : "DisableExtension"),
|
||||||
@ -468,6 +508,8 @@ plugin_enable_extension (PluginObject *obj,
|
|||||||
NULL, /* callback */
|
NULL, /* callback */
|
||||||
NULL /* user_data */);
|
NULL /* user_data */);
|
||||||
|
|
||||||
|
g_free (uuid_str);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,21 +518,32 @@ plugin_install_extension (PluginObject *obj,
|
|||||||
NPString uuid,
|
NPString uuid,
|
||||||
NPString version_tag)
|
NPString version_tag)
|
||||||
{
|
{
|
||||||
const gchar *uuid_str = uuid.UTF8Characters;
|
gchar *uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
||||||
|
gchar *version_tag_str;
|
||||||
|
|
||||||
if (!uuid_is_valid (uuid_str))
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
{
|
||||||
|
g_free (uuid_str);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
version_tag_str = g_strndup (version_tag.UTF8Characters,
|
||||||
|
version_tag.UTF8Length);
|
||||||
|
|
||||||
g_dbus_proxy_call (obj->proxy,
|
g_dbus_proxy_call (obj->proxy,
|
||||||
"InstallRemoteExtension",
|
"InstallRemoteExtension",
|
||||||
g_variant_new ("(ss)",
|
g_variant_new ("(ss)",
|
||||||
uuid_str,
|
uuid_str,
|
||||||
version_tag.UTF8Characters),
|
version_tag_str),
|
||||||
G_DBUS_CALL_FLAGS_NONE,
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
-1, /* timeout */
|
-1, /* timeout */
|
||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
NULL, /* callback */
|
NULL, /* callback */
|
||||||
NULL /* user_data */);
|
NULL /* user_data */);
|
||||||
|
|
||||||
|
g_free (uuid_str);
|
||||||
|
g_free (version_tag_str);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -501,11 +554,14 @@ plugin_uninstall_extension (PluginObject *obj,
|
|||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GVariant *res;
|
GVariant *res;
|
||||||
const gchar *uuid_str;
|
gchar *uuid_str;
|
||||||
|
|
||||||
uuid_str = uuid.UTF8Characters;
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
||||||
if (!uuid_is_valid (uuid_str))
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
{
|
||||||
|
g_free (uuid_str);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||||
"UninstallExtension",
|
"UninstallExtension",
|
||||||
@ -516,6 +572,8 @@ plugin_uninstall_extension (PluginObject *obj,
|
|||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
|
g_free (uuid_str);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
g_warning ("Failed to uninstall extension: %s", error->message);
|
g_warning ("Failed to uninstall extension: %s", error->message);
|
||||||
@ -533,11 +591,14 @@ plugin_get_info (PluginObject *obj,
|
|||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GVariant *res;
|
GVariant *res;
|
||||||
const gchar *uuid_str;
|
gchar *uuid_str;
|
||||||
|
|
||||||
uuid_str = uuid.UTF8Characters;
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
||||||
if (!uuid_is_valid (uuid_str))
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
{
|
||||||
|
g_free (uuid_str);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||||
"GetExtensionInfo",
|
"GetExtensionInfo",
|
||||||
@ -547,6 +608,8 @@ plugin_get_info (PluginObject *obj,
|
|||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
|
g_free (uuid_str);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
g_warning ("Failed to retrieve extension metadata: %s", error->message);
|
g_warning ("Failed to retrieve extension metadata: %s", error->message);
|
||||||
@ -564,11 +627,14 @@ plugin_get_errors (PluginObject *obj,
|
|||||||
{
|
{
|
||||||
GError *error = NULL;
|
GError *error = NULL;
|
||||||
GVariant *res;
|
GVariant *res;
|
||||||
const gchar *uuid_str;
|
gchar *uuid_str;
|
||||||
|
|
||||||
uuid_str = uuid.UTF8Characters;
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
||||||
if (!uuid_is_valid (uuid_str))
|
if (!uuid_is_valid (uuid_str))
|
||||||
return FALSE;
|
{
|
||||||
|
g_free (uuid_str);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
res = g_dbus_proxy_call_sync (obj->proxy,
|
res = g_dbus_proxy_call_sync (obj->proxy,
|
||||||
"GetExtensionErrors",
|
"GetExtensionErrors",
|
||||||
@ -578,6 +644,8 @@ plugin_get_errors (PluginObject *obj,
|
|||||||
NULL, /* cancellable */
|
NULL, /* cancellable */
|
||||||
&error);
|
&error);
|
||||||
|
|
||||||
|
g_free (uuid_str);
|
||||||
|
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
g_warning ("Failed to retrieve errors: %s", error->message);
|
g_warning ("Failed to retrieve errors: %s", error->message);
|
||||||
@ -588,6 +656,33 @@ plugin_get_errors (PluginObject *obj,
|
|||||||
return jsonify_variant (res, result);
|
return jsonify_variant (res, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
plugin_launch_extension_prefs (PluginObject *obj,
|
||||||
|
NPString uuid,
|
||||||
|
NPVariant *result)
|
||||||
|
{
|
||||||
|
gchar *uuid_str;
|
||||||
|
|
||||||
|
uuid_str = g_strndup (uuid.UTF8Characters, uuid.UTF8Length);
|
||||||
|
if (!uuid_is_valid (uuid_str))
|
||||||
|
{
|
||||||
|
g_free (uuid_str);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_dbus_proxy_call (obj->proxy,
|
||||||
|
"LaunchExtensionPrefs",
|
||||||
|
g_variant_new ("(s)", uuid_str),
|
||||||
|
G_DBUS_CALL_FLAGS_NONE,
|
||||||
|
-1, /* timeout */
|
||||||
|
NULL, /* cancellable */
|
||||||
|
NULL, /* callback */
|
||||||
|
NULL /* user_data */);
|
||||||
|
|
||||||
|
g_free (uuid_str);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
plugin_get_api_version (PluginObject *obj,
|
plugin_get_api_version (PluginObject *obj,
|
||||||
NPVariant *result)
|
NPVariant *result)
|
||||||
@ -633,7 +728,8 @@ plugin_get_shell_version (PluginObject *obj,
|
|||||||
STRINGN_TO_NPVARIANT (buffer, length, *result);
|
STRINGN_TO_NPVARIANT (buffer, length, *result);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
g_variant_unref (res);
|
if (res)
|
||||||
|
g_variant_unref (res);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -697,6 +793,14 @@ plugin_object_invoke (NPObject *npobj,
|
|||||||
NPVARIANT_TO_STRING(args[0]),
|
NPVARIANT_TO_STRING(args[0]),
|
||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
|
else if (name == launch_extension_prefs_id)
|
||||||
|
{
|
||||||
|
if (!NPVARIANT_IS_STRING(args[0])) return FALSE;
|
||||||
|
|
||||||
|
return plugin_launch_extension_prefs (obj,
|
||||||
|
NPVARIANT_TO_STRING(args[0]),
|
||||||
|
result);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -706,6 +810,7 @@ plugin_object_has_property (NPObject *npobj,
|
|||||||
NPIdentifier name)
|
NPIdentifier name)
|
||||||
{
|
{
|
||||||
return (name == onextension_changed_id ||
|
return (name == onextension_changed_id ||
|
||||||
|
name == onrestart_id ||
|
||||||
name == api_version_id ||
|
name == api_version_id ||
|
||||||
name == shell_version_id);
|
name == shell_version_id);
|
||||||
}
|
}
|
||||||
@ -732,6 +837,33 @@ plugin_object_get_property (NPObject *npobj,
|
|||||||
else
|
else
|
||||||
NULL_TO_NPVARIANT (*result);
|
NULL_TO_NPVARIANT (*result);
|
||||||
}
|
}
|
||||||
|
else if (name == onrestart_id)
|
||||||
|
{
|
||||||
|
if (obj->restart_listener)
|
||||||
|
OBJECT_TO_NPVARIANT (obj->restart_listener, *result);
|
||||||
|
else
|
||||||
|
NULL_TO_NPVARIANT (*result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
plugin_object_set_callback (NPObject **listener,
|
||||||
|
const NPVariant *value)
|
||||||
|
{
|
||||||
|
if (!NPVARIANT_IS_OBJECT (*value) && !NPVARIANT_IS_NULL (*value))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (*listener)
|
||||||
|
funcs.releaseobject (*listener);
|
||||||
|
*listener = NULL;
|
||||||
|
|
||||||
|
if (NPVARIANT_IS_OBJECT (*value))
|
||||||
|
{
|
||||||
|
*listener = NPVARIANT_TO_OBJECT (*value);
|
||||||
|
funcs.retainobject (*listener);
|
||||||
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@ -743,25 +875,13 @@ plugin_object_set_property (NPObject *npobj,
|
|||||||
{
|
{
|
||||||
PluginObject *obj;
|
PluginObject *obj;
|
||||||
|
|
||||||
if (!plugin_object_has_property (npobj, name))
|
obj = (PluginObject *)npobj;
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if (name == onextension_changed_id)
|
if (name == onextension_changed_id)
|
||||||
{
|
return plugin_object_set_callback (&obj->listener, value);
|
||||||
obj = (PluginObject*) npobj;
|
|
||||||
if (obj->listener)
|
|
||||||
funcs.releaseobject (obj->listener);
|
|
||||||
|
|
||||||
obj->listener = NULL;
|
if (name == onrestart_id)
|
||||||
if (NPVARIANT_IS_OBJECT (*value))
|
return plugin_object_set_callback (&obj->restart_listener, value);
|
||||||
{
|
|
||||||
obj->listener = NPVARIANT_TO_OBJECT (*value);
|
|
||||||
funcs.retainobject (obj->listener);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
else if (NPVARIANT_IS_NULL (*value))
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -795,7 +915,9 @@ init_methods_and_properties (void)
|
|||||||
install_extension_id = funcs.getstringidentifier ("installExtension");
|
install_extension_id = funcs.getstringidentifier ("installExtension");
|
||||||
uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
|
uninstall_extension_id = funcs.getstringidentifier ("uninstallExtension");
|
||||||
get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
|
get_errors_id = funcs.getstringidentifier ("getExtensionErrors");
|
||||||
|
launch_extension_prefs_id = funcs.getstringidentifier ("launchExtensionPrefs");
|
||||||
|
|
||||||
|
onrestart_id = funcs.getstringidentifier ("onshellrestart");
|
||||||
onextension_changed_id = funcs.getstringidentifier ("onchange");
|
onextension_changed_id = funcs.getstringidentifier ("onchange");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
56
configure.ac
@ -1,5 +1,5 @@
|
|||||||
AC_PREREQ(2.63)
|
AC_PREREQ(2.63)
|
||||||
AC_INIT([gnome-shell],[3.3.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
AC_INIT([gnome-shell],[3.4.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||||
@ -53,27 +53,28 @@ if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
|
|||||||
AC_MSG_RESULT(yes)
|
AC_MSG_RESULT(yes)
|
||||||
build_recorder=true
|
build_recorder=true
|
||||||
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11"
|
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 x11"
|
||||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes)
|
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0 xfixes gl)
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT(no)
|
AC_MSG_RESULT(no)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||||
|
|
||||||
CLUTTER_MIN_VERSION=1.7.5
|
CLUTTER_MIN_VERSION=1.9.16
|
||||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||||
GJS_MIN_VERSION=1.29.18
|
GJS_MIN_VERSION=1.29.18
|
||||||
MUTTER_MIN_VERSION=3.3.2
|
MUTTER_MIN_VERSION=3.4.1
|
||||||
FOLKS_MIN_VERSION=0.5.2
|
FOLKS_MIN_VERSION=0.5.2
|
||||||
GTK_MIN_VERSION=3.0.0
|
GTK_MIN_VERSION=3.3.9
|
||||||
GIO_MIN_VERSION=2.31.0
|
GIO_MIN_VERSION=2.31.6
|
||||||
LIBECAL_MIN_VERSION=2.32.0
|
LIBECAL_MIN_VERSION=2.32.0
|
||||||
LIBEDATASERVER_MIN_VERSION=1.2.0
|
LIBEDATASERVER_MIN_VERSION=1.2.0
|
||||||
LIBEDATASERVERUI_MIN_VERSION=2.91.6
|
LIBEDATASERVERUI_MIN_VERSION=2.91.6
|
||||||
TELEPATHY_GLIB_MIN_VERSION=0.15.5
|
TELEPATHY_GLIB_MIN_VERSION=0.17.5
|
||||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||||
POLKIT_MIN_VERSION=0.100
|
POLKIT_MIN_VERSION=0.100
|
||||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||||
|
GCR_MIN_VERSION=3.3.90
|
||||||
|
|
||||||
# Collect more than 20 libraries for a prize!
|
# Collect more than 20 libraries for a prize!
|
||||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||||
@ -84,6 +85,7 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
|||||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
||||||
libgnome-menu-3.0 $recorder_modules
|
libgnome-menu-3.0 $recorder_modules
|
||||||
gdk-x11-3.0 libsoup-2.4
|
gdk-x11-3.0 libsoup-2.4
|
||||||
|
gl
|
||||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||||
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
||||||
@ -92,7 +94,8 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-unix-2.0 >= $GIO_MIN_VERSION
|
|||||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||||
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
telepathy-logger-0.2 >= $TELEPATHY_LOGGER_MIN_VERSION
|
||||||
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
polkit-agent-1 >= $POLKIT_MIN_VERSION xfixes
|
||||||
libnm-glib libnm-util gnome-keyring-1)
|
libnm-glib libnm-util gnome-keyring-1
|
||||||
|
gcr-3 >= $GCR_MIN_VERSION)
|
||||||
|
|
||||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||||
|
|
||||||
@ -116,7 +119,8 @@ AC_CHECK_FUNCS(JS_NewGlobalObject XFixesCreatePointerBarrier)
|
|||||||
CFLAGS=$saved_CFLAGS
|
CFLAGS=$saved_CFLAGS
|
||||||
LIBS=$saved_LIBS
|
LIBS=$saved_LIBS
|
||||||
|
|
||||||
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(GNOME_SHELL_JS, gio-2.0 gjs-internals-1.0 >= $GJS_MIN_VERSION)
|
||||||
|
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 x11)
|
||||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
||||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
|
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
|
||||||
@ -139,6 +143,33 @@ PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedatas
|
|||||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||||
AC_SUBST(CALENDAR_SERVER_LIBS)
|
AC_SUBST(CALENDAR_SERVER_LIBS)
|
||||||
|
|
||||||
|
AC_ARG_WITH(systemd,
|
||||||
|
AS_HELP_STRING([--with-systemd],
|
||||||
|
[Add systemd support]),
|
||||||
|
[with_systemd=$withval], [with_systemd=auto])
|
||||||
|
|
||||||
|
PKG_CHECK_MODULES(SYSTEMD,
|
||||||
|
[libsystemd-login libsystemd-daemon],
|
||||||
|
[have_systemd=yes], [have_systemd=no])
|
||||||
|
|
||||||
|
if test "x$with_systemd" = "xauto" ; then
|
||||||
|
if test x$have_systemd = xno ; then
|
||||||
|
use_systemd=no
|
||||||
|
else
|
||||||
|
use_systemd=yes
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
use_systemd=$with_systemd
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$use_systemd" = "xyes"; then
|
||||||
|
if test "x$have_systemd" = "xno"; then
|
||||||
|
AC_MSG_ERROR([Systemd support explicitly required, but systemd not found])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_DEFINE(WITH_SYSTEMD, 1, [systemd support])
|
||||||
|
fi
|
||||||
|
|
||||||
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
|
MUTTER_GIR_DIR=`$PKG_CONFIG --variable=girdir libmutter`
|
||||||
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
|
MUTTER_TYPELIB_DIR=`$PKG_CONFIG --variable=typelibdir libmutter`
|
||||||
AC_SUBST(MUTTER_GIR_DIR)
|
AC_SUBST(MUTTER_GIR_DIR)
|
||||||
@ -181,7 +212,7 @@ GTK_DOC_CHECK([1.15], [--flavour no-tmpl])
|
|||||||
# minimum/yes/maximum are the same, however.
|
# minimum/yes/maximum are the same, however.
|
||||||
AC_ARG_ENABLE(compile_warnings,
|
AC_ARG_ENABLE(compile_warnings,
|
||||||
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
|
AS_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],[Turn on compiler warnings]),,
|
||||||
enable_compile_warnings=maximum)
|
enable_compile_warnings=error)
|
||||||
|
|
||||||
changequote(,)dnl
|
changequote(,)dnl
|
||||||
if test "$enable_compile_warnings" != no ; then
|
if test "$enable_compile_warnings" != no ; then
|
||||||
@ -197,7 +228,7 @@ if test "$enable_compile_warnings" != no ; then
|
|||||||
if test "$enable_compile_warnings" = error ; then
|
if test "$enable_compile_warnings" = error ; then
|
||||||
case " $CFLAGS " in
|
case " $CFLAGS " in
|
||||||
*[\ \ ]-Werror[\ \ ]*) ;;
|
*[\ \ ]-Werror[\ \ ]*) ;;
|
||||||
*) CFLAGS="$CFLAGS -Werror" ;;
|
*) CFLAGS="$CFLAGS -Werror -Wno-error=deprecated-declarations" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -205,7 +236,7 @@ fi
|
|||||||
changequote([,])dnl
|
changequote([,])dnl
|
||||||
|
|
||||||
AC_ARG_ENABLE(jhbuild-wrapper-script,
|
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)
|
AS_HELP_STRING([--enable-jhbuild-wrapper-script],[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)
|
AM_CONDITIONAL(USE_JHBUILD_WRAPPER_SCRIPT, test "x$enable_jhbuild_wrapper_script" = xyes)
|
||||||
|
|
||||||
AC_MSG_CHECKING([location of system Certificate Authority list])
|
AC_MSG_CHECKING([location of system Certificate Authority list])
|
||||||
@ -246,7 +277,6 @@ AC_CONFIG_FILES([
|
|||||||
docs/reference/st/Makefile
|
docs/reference/st/Makefile
|
||||||
docs/reference/st/st-docs.sgml
|
docs/reference/st/st-docs.sgml
|
||||||
js/Makefile
|
js/Makefile
|
||||||
js/misc/config.js
|
|
||||||
src/Makefile
|
src/Makefile
|
||||||
browser-plugin/Makefile
|
browser-plugin/Makefile
|
||||||
tests/Makefile
|
tests/Makefile
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
desktopdir=$(datadir)/applications
|
desktopdir=$(datadir)/applications
|
||||||
desktop_DATA = gnome-shell.desktop
|
desktop_DATA = gnome-shell.desktop gnome-shell-extension-prefs.desktop
|
||||||
|
|
||||||
# We substitute in bindir so it works as an autostart
|
# We substitute in bindir so it works as an autostart
|
||||||
# file when built in a non-system prefix
|
# file when built in a non-system prefix
|
||||||
@ -12,16 +12,23 @@ desktop_DATA = gnome-shell.desktop
|
|||||||
%.desktop:%.desktop.in
|
%.desktop:%.desktop.in
|
||||||
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
|
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
|
||||||
|
|
||||||
searchprovidersdir = $(pkgdatadir)/search_providers
|
searchprovidersdir = $(pkgdatadir)/open-search-providers
|
||||||
dist_searchproviders_DATA = \
|
dist_searchproviders_DATA = \
|
||||||
search_providers/google.xml \
|
open-search-providers/google.xml \
|
||||||
search_providers/wikipedia.xml
|
open-search-providers/wikipedia.xml
|
||||||
|
|
||||||
|
introspectiondir = $(datadir)/dbus-1/interfaces
|
||||||
|
introspection_DATA = org.gnome.ShellSearchProvider.xml
|
||||||
|
|
||||||
themedir = $(pkgdatadir)/theme
|
themedir = $(pkgdatadir)/theme
|
||||||
dist_theme_DATA = \
|
dist_theme_DATA = \
|
||||||
theme/calendar-arrow-left.svg \
|
theme/calendar-arrow-left.svg \
|
||||||
theme/calendar-arrow-right.svg \
|
theme/calendar-arrow-right.svg \
|
||||||
theme/calendar-today.svg \
|
theme/calendar-today.svg \
|
||||||
|
theme/checkbox-focused.svg \
|
||||||
|
theme/checkbox-off-focused.svg \
|
||||||
|
theme/checkbox-off.svg \
|
||||||
|
theme/checkbox.svg \
|
||||||
theme/close-window.svg \
|
theme/close-window.svg \
|
||||||
theme/close.svg \
|
theme/close.svg \
|
||||||
theme/corner-ripple-ltr.png \
|
theme/corner-ripple-ltr.png \
|
||||||
@ -31,7 +38,6 @@ dist_theme_DATA = \
|
|||||||
theme/filter-selected-rtl.svg \
|
theme/filter-selected-rtl.svg \
|
||||||
theme/gdm.css \
|
theme/gdm.css \
|
||||||
theme/gnome-shell.css \
|
theme/gnome-shell.css \
|
||||||
theme/panel-border.svg \
|
|
||||||
theme/panel-button-border.svg \
|
theme/panel-button-border.svg \
|
||||||
theme/panel-button-highlight-narrow.svg \
|
theme/panel-button-highlight-narrow.svg \
|
||||||
theme/panel-button-highlight-wide.svg \
|
theme/panel-button-highlight-wide.svg \
|
||||||
@ -59,6 +65,8 @@ gschemas.compiled: $(gsettings_SCHEMAS:.xml=.valid)
|
|||||||
|
|
||||||
all-local: gschemas.compiled
|
all-local: gschemas.compiled
|
||||||
|
|
||||||
|
convertdir = $(datadir)/GConf/gsettings
|
||||||
|
convert_DATA = gnome-shell-overrides.convert
|
||||||
|
|
||||||
shadersdir = $(pkgdatadir)/shaders
|
shadersdir = $(pkgdatadir)/shaders
|
||||||
shaders_DATA = \
|
shaders_DATA = \
|
||||||
@ -67,12 +75,16 @@ shaders_DATA = \
|
|||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
gnome-shell.desktop.in.in \
|
gnome-shell.desktop.in.in \
|
||||||
|
gnome-shell-extension-prefs.desktop.in.in \
|
||||||
|
$(introspection_DATA) \
|
||||||
$(menu_DATA) \
|
$(menu_DATA) \
|
||||||
$(shaders_DATA) \
|
$(shaders_DATA) \
|
||||||
|
$(convert_DATA) \
|
||||||
org.gnome.shell.gschema.xml.in
|
org.gnome.shell.gschema.xml.in
|
||||||
|
|
||||||
CLEANFILES = \
|
CLEANFILES = \
|
||||||
gnome-shell.desktop.in \
|
gnome-shell.desktop.in \
|
||||||
|
gnome-shell-extension-prefs.in \
|
||||||
$(desktop_DATA) \
|
$(desktop_DATA) \
|
||||||
$(gsettings_SCHEMAS) \
|
$(gsettings_SCHEMAS) \
|
||||||
gschemas.compiled
|
gschemas.compiled
|
||||||
|
12
data/gnome-shell-extension-prefs.desktop.in.in
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Type=Application
|
||||||
|
_Name=GNOME Shell Extension Preferences
|
||||||
|
_Comment=Configure GNOME Shell Extensions
|
||||||
|
Exec=@bindir@/gnome-shell-extension-prefs %u
|
||||||
|
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||||
|
X-GNOME-Bugzilla-Product=gnome-shell
|
||||||
|
X-GNOME-Bugzilla-Component=extensions
|
||||||
|
X-GNOME-Bugzilla-Version=@VERSION@
|
||||||
|
Categories=GNOME;GTK;
|
||||||
|
OnlyShowIn=GNOME;
|
||||||
|
NoDisplay=true
|
5
data/gnome-shell-overrides.convert
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[org.gnome.shell.overrides]
|
||||||
|
attach-modal-dialogs = /desktop/gnome/shell/windows/attach_modal_dialogs
|
||||||
|
button-layout = /desktop/gnome/shell/windows/button_layout
|
||||||
|
edge-tiling = /desktop/gnome/shell/windows/edge_tiling
|
||||||
|
workspaces-only-on-primary = /desktop/gnome/shell/windows/workspaces_only_on_primary
|
@ -13,4 +13,4 @@ NoDisplay=true
|
|||||||
X-GNOME-Autostart-Phase=WindowManager
|
X-GNOME-Autostart-Phase=WindowManager
|
||||||
X-GNOME-Provides=panel;windowmanager;
|
X-GNOME-Provides=panel;windowmanager;
|
||||||
X-GNOME-Autostart-Notify=true
|
X-GNOME-Autostart-Notify=true
|
||||||
X-GNOME-AutoRestart=true
|
X-GNOME-AutoRestart=false
|
||||||
|
147
data/org.gnome.ShellSearchProvider.xml
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<!DOCTYPE node PUBLIC
|
||||||
|
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
|
||||||
|
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
|
||||||
|
<node>
|
||||||
|
<interface name="org.gnome.Shell.SearchProvider">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
The interface used for integrating into GNOME Shell's search
|
||||||
|
interface.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
|
||||||
|
<method name="GetInitialResultSet">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Called when the user first begins a search.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
Array of search terms, which the provider should treat as
|
||||||
|
logical AND.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" direction="out">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
An array of result identifier strings representing items which
|
||||||
|
match the given search terms. Identifiers must be unique within
|
||||||
|
the provider's domain, but other than that may be chosen freely
|
||||||
|
by the provider.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="GetSubsearchResultSet">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Called when a search is performed which is a "subsearch" of
|
||||||
|
the previous search, e.g. the method may return less results, but
|
||||||
|
not more or different results.
|
||||||
|
|
||||||
|
This allows search providers to only search through the previous
|
||||||
|
result set, rather than possibly performing a full re-query.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
Array of item identifiers
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
Array of updated search terms, which the provider should treat as
|
||||||
|
logical AND.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="as" direction="out">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
An array of result identifier strings representing items which
|
||||||
|
match the given search terms. Identifiers must be unique within
|
||||||
|
the provider's domain, but other than that may be chosen freely
|
||||||
|
by the provider.
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="GetResultMetas">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Return an array of meta data used to display each given result
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="as" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
An array of result identifiers as returned by
|
||||||
|
GetInitialResultSet() or GetSubsearchResultSet()
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
<arg type="a{sv}" direction="out">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
A dictionary describing the given search result, containing
|
||||||
|
'id', 'name' (both strings) and either 'icon' (a serialized
|
||||||
|
GIcon) or 'icon-data' (raw image data as (iiibiiay) - width,
|
||||||
|
height, rowstride, has-alpha, bits per sample, channels, data)
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
|
||||||
|
<method name="ActivateResult">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:description>
|
||||||
|
<doc:para>
|
||||||
|
Called when the users chooses a given result. The result should
|
||||||
|
be displayed in the application associated with the corresponding
|
||||||
|
provider.
|
||||||
|
</doc:para>
|
||||||
|
</doc:description>
|
||||||
|
</doc:doc>
|
||||||
|
<arg type="s" direction="in">
|
||||||
|
<doc:doc>
|
||||||
|
<doc:summary>
|
||||||
|
<doc:para>
|
||||||
|
A result identifier as returned by GetInitialResultSet() or
|
||||||
|
GetSubsearchResultSet()
|
||||||
|
</doc:para>
|
||||||
|
</doc:summary>
|
||||||
|
</doc:doc>
|
||||||
|
</arg>
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
@ -53,15 +53,18 @@
|
|||||||
</key>
|
</key>
|
||||||
<key name="saved-im-presence" type="i">
|
<key name="saved-im-presence" type="i">
|
||||||
<default>1</default>
|
<default>1</default>
|
||||||
<_summary></_summary>
|
<_summary>Internally used to store the last IM presence explicitly set by the user. The
|
||||||
|
value here is from the TpConnectionPresenceType enumeration.</_summary>
|
||||||
</key>
|
</key>
|
||||||
<key name="saved-session-presence" type="i">
|
<key name="saved-session-presence" type="i">
|
||||||
<default>0</default>
|
<default>0</default>
|
||||||
<_summary></_summary>
|
<_summary>Internally used to store the last session presence status for the user. The
|
||||||
|
value here is from the GsmPresenceStatus enumeration.</_summary>
|
||||||
</key>
|
</key>
|
||||||
<child name="clock" schema="org.gnome.shell.clock"/>
|
<child name="clock" schema="org.gnome.shell.clock"/>
|
||||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||||
|
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||||
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
@ -76,6 +79,17 @@
|
|||||||
</key>
|
</key>
|
||||||
</schema>
|
</schema>
|
||||||
|
|
||||||
|
<schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/"
|
||||||
|
gettext-domain="@GETTEXT_PACKAGE@">
|
||||||
|
<key name="open-application-menu" type="as">
|
||||||
|
<default>["<Super>F10"]</default>
|
||||||
|
<_summary>Keybinding to open the application menu</_summary>
|
||||||
|
<_description>
|
||||||
|
Keybinding to open the application menu.
|
||||||
|
</_description>
|
||||||
|
</key>
|
||||||
|
</schema>
|
||||||
|
|
||||||
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
||||||
gettext-domain="@GETTEXT_PACKAGE@">
|
gettext-domain="@GETTEXT_PACKAGE@">
|
||||||
<key name="keyboard-type" type="s">
|
<key name="keyboard-type" type="s">
|
||||||
@ -108,7 +122,7 @@
|
|||||||
<schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
|
<schema id="org.gnome.shell.recorder" path="/org/gnome/shell/recorder/"
|
||||||
gettext-domain="@GETTEXT_PACKAGE@">
|
gettext-domain="@GETTEXT_PACKAGE@">
|
||||||
<key name="framerate" type="i">
|
<key name="framerate" type="i">
|
||||||
<default>15</default>
|
<default>30</default>
|
||||||
<_summary>Framerate used for recording screencasts.</_summary>
|
<_summary>Framerate used for recording screencasts.</_summary>
|
||||||
<_description>
|
<_description>
|
||||||
The framerate of the resulting screencast recordered
|
The framerate of the resulting screencast recordered
|
||||||
@ -127,7 +141,7 @@
|
|||||||
take care of its own output - this might be used to send the output
|
take care of its own output - this might be used to send the output
|
||||||
to an icecast server via shout2send or similar. When unset or set
|
to an icecast server via shout2send or similar. When unset or set
|
||||||
to an empty value, the default pipeline will be used. This is currently
|
to an empty value, the default pipeline will be used. This is currently
|
||||||
'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux'
|
'vp8enc quality=8 speed=6 threads=%T ! queue ! webmmux'
|
||||||
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
||||||
for a guess at the optimal thread count on the system.
|
for a guess at the optimal thread count on the system.
|
||||||
</_description>
|
</_description>
|
||||||
@ -170,6 +184,14 @@
|
|||||||
</description>
|
</description>
|
||||||
</key>
|
</key>
|
||||||
|
|
||||||
|
<key name="dynamic-workspaces" type="b">
|
||||||
|
<default>true</default>
|
||||||
|
<summary>Workspaces are managed dynamically</summary>
|
||||||
|
<description>
|
||||||
|
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||||
|
</description>
|
||||||
|
</key>
|
||||||
|
|
||||||
<key name="workspaces-only-on-primary" type="b">
|
<key name="workspaces-only-on-primary" type="b">
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
<summary>Workspaces only on primary monitor</summary>
|
<summary>Workspaces only on primary monitor</summary>
|
||||||
|
289
data/theme/checkbox-focused.svg
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24"
|
||||||
|
height="22"
|
||||||
|
id="svg3199"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.1 r9760"
|
||||||
|
sodipodi:docname="checkbox.svg">
|
||||||
|
<defs
|
||||||
|
id="defs3201">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15404"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop15406"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#515151;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop15408"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#292929;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<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="perspective3207" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3187"
|
||||||
|
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" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5872-5-1"
|
||||||
|
id="linearGradient5891-0-4"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="205.84143"
|
||||||
|
y1="246.7094"
|
||||||
|
x2="206.74803"
|
||||||
|
y2="231.24142" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient5872-5-1">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0b2e52;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop5874-4-4" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#1862af;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop5876-0-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5837-4-6"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect14768"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5884-4-7"
|
||||||
|
is_visible="true" />
|
||||||
|
<linearGradient
|
||||||
|
y2="-388.72955"
|
||||||
|
x2="-93.031357"
|
||||||
|
y1="-396.34738"
|
||||||
|
x1="-93.031357"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient14219"
|
||||||
|
xlink:href="#linearGradient15404"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10013-4-63-6">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#333333;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10015-2-76-1" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#292929;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10017-46-15-8" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10597-5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16191a;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10599-2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2b3133;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10601-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="-322.16354"
|
||||||
|
x2="921.22498"
|
||||||
|
y1="-330.05121"
|
||||||
|
x1="921.32812"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15374"
|
||||||
|
xlink:href="#linearGradient10013-4-63-6"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="translate(-1199.9852,216.38048)"
|
||||||
|
y2="-227.07961"
|
||||||
|
x2="1203.9177"
|
||||||
|
y1="-217.56708"
|
||||||
|
x1="1203.9177"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15376"
|
||||||
|
xlink:href="#linearGradient10597-5"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
y2="-388.72955"
|
||||||
|
x2="-93.031357"
|
||||||
|
y1="-396.34738"
|
||||||
|
x1="-93.031357"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient14219-6"
|
||||||
|
xlink:href="#linearGradient15404-9"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15404-9"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop15406-6"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#515151;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop15408-7"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#292929;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#2d2d2d"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageopacity="1"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="71.516955"
|
||||||
|
inkscape:cy="5.8710559"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1412"
|
||||||
|
inkscape:window-height="1067"
|
||||||
|
inkscape:window-x="2635"
|
||||||
|
inkscape:window-y="226"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
borderlayer="true"
|
||||||
|
inkscape:showpageshadow="false"
|
||||||
|
inkscape:snap-nodes="false"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showborder="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid14843"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata3204">
|
||||||
|
<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(-342.5,-521.36218)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.80230061,0,0,0.80230061,-87.624044,-453.10297)"
|
||||||
|
id="g14586-0"
|
||||||
|
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
||||||
|
id="g15291-9-6"
|
||||||
|
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new">
|
||||||
|
<g
|
||||||
|
transform="translate(877.50354,-102.83507)"
|
||||||
|
id="g16853-4-9"
|
||||||
|
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
|
||||||
|
<rect
|
||||||
|
transform="scale(1,-1)"
|
||||||
|
style="color:#000000;fill:url(#linearGradient14219-6);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:1.24833274;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:new"
|
||||||
|
id="rect6506-6"
|
||||||
|
width="11.281681"
|
||||||
|
height="11.26221"
|
||||||
|
x="-409.59354"
|
||||||
|
y="-284.40115"
|
||||||
|
rx="1.0052766"
|
||||||
|
ry="1.0052764" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="translate(343.99999,987.99997)"
|
||||||
|
id="g5886-5"
|
||||||
|
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
|
||||||
|
id="g14586">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
||||||
|
id="g15291-9"
|
||||||
|
style="display:inline;enable-background:new">
|
||||||
|
<g
|
||||||
|
transform="translate(877.50354,-102.83507)"
|
||||||
|
id="g16853-4"
|
||||||
|
style="enable-background:new" />
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="translate(343.99999,987.99997)"
|
||||||
|
id="g5886"
|
||||||
|
style="display:inline;enable-background:new">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient5891-0-4);stroke-width:7.11431503;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
||||||
|
id="path5835"
|
||||||
|
inkscape:path-effect="#path-effect5837-4-6"
|
||||||
|
inkscape:original-d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:original-d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
||||||
|
inkscape:path-effect="#path-effect5837-4-6"
|
||||||
|
id="path5880"
|
||||||
|
d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
||||||
|
style="fill:none;stroke:#4787c8;stroke-width:3.55715752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#7ea7d3;stroke-width:1.18571913px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 197.45937,240.47455 c -0.17828,-0.29362 -0.20087,-0.67548 -0.0603,-0.98892 0.14055,-0.31344 0.43739,-0.54812 0.77144,-0.62817 0.33405,-0.08 0.69314,-0.01 0.99635,0.15175 0.30321,0.16144 0.55146,0.40727 0.79165,0.65284 l 3.66429,3.74643 12.87946,-12.98973 c 0.20796,-0.20974 0.42306,-0.41969 0.68548,-0.55522 0.26242,-0.13553 0.57293,-0.19052 0.85827,-0.11426 0.14267,0.0381 0.27708,0.10787 0.38874,0.20452 0.11167,0.0966 0.20021,0.22004 0.25479,0.35726 0.0546,0.13722 0.075,0.28793 0.0585,0.43468 -0.0165,0.14674 -0.07,0.28919 -0.15422,0.41052"
|
||||||
|
id="path5882"
|
||||||
|
inkscape:path-effect="#path-effect5884-4-7"
|
||||||
|
inkscape:original-d="m 197.45937,240.47455 c 0.65604,-0.56057 2.02485,-1.34847 2.49911,-0.8125 l 3.66429,3.74643 12.87946,-12.98973 c 0.6875,-0.6875 2.09152,0.7375 2.09152,0.7375"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csccc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 11 KiB |
198
data/theme/checkbox-off-focused.svg
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24"
|
||||||
|
height="22"
|
||||||
|
id="svg3199"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.1 r9760"
|
||||||
|
sodipodi:docname="checkbox-off.svg">
|
||||||
|
<defs
|
||||||
|
id="defs3201">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15404"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop15406"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#515151;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop15408"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#292929;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<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="perspective3207" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3187"
|
||||||
|
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" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5837-4-6"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect14768"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5884-4-7"
|
||||||
|
is_visible="true" />
|
||||||
|
<linearGradient
|
||||||
|
y2="-388.72955"
|
||||||
|
x2="-93.031357"
|
||||||
|
y1="-396.34738"
|
||||||
|
x1="-93.031357"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient14219"
|
||||||
|
xlink:href="#linearGradient15404"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10013-4-63-6">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#333333;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10015-2-76-1" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#292929;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10017-46-15-8" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10597-5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16191a;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10599-2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2b3133;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10601-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="-322.16354"
|
||||||
|
x2="921.22498"
|
||||||
|
y1="-330.05121"
|
||||||
|
x1="921.32812"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15374"
|
||||||
|
xlink:href="#linearGradient10013-4-63-6"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="translate(-1199.9852,216.38048)"
|
||||||
|
y2="-227.07961"
|
||||||
|
x2="1203.9177"
|
||||||
|
y1="-217.56708"
|
||||||
|
x1="1203.9177"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15376"
|
||||||
|
xlink:href="#linearGradient10597-5"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#2d2d2d"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageopacity="1"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="6.1225392"
|
||||||
|
inkscape:cy="3.6003241"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1412"
|
||||||
|
inkscape:window-height="1067"
|
||||||
|
inkscape:window-x="2116"
|
||||||
|
inkscape:window-y="261"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
borderlayer="true"
|
||||||
|
inkscape:showpageshadow="false"
|
||||||
|
inkscape:snap-nodes="false"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showborder="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid14843"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata3204">
|
||||||
|
<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(-342.5,-521.36218)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.80230061,0,0,0.80230061,-87.624044,-453.10297)"
|
||||||
|
id="g14586"
|
||||||
|
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
||||||
|
id="g15291-9"
|
||||||
|
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new">
|
||||||
|
<g
|
||||||
|
transform="translate(877.50354,-102.83507)"
|
||||||
|
id="g16853-4"
|
||||||
|
style="stroke-width:1.18754292;stroke-miterlimit:4;stroke-dasharray:none;enable-background:new">
|
||||||
|
<rect
|
||||||
|
transform="scale(1,-1)"
|
||||||
|
style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:1.24833274;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:new"
|
||||||
|
id="rect6506-6"
|
||||||
|
width="11.281681"
|
||||||
|
height="11.26221"
|
||||||
|
x="-409.59354"
|
||||||
|
y="-284.40115"
|
||||||
|
rx="1.0052766"
|
||||||
|
ry="1.0052764" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="translate(343.99999,987.99997)"
|
||||||
|
id="g5886"
|
||||||
|
style="stroke-width:2.3714385;stroke-miterlimit:4;stroke-dasharray:none;display:inline;enable-background:new" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.5 KiB |
218
data/theme/checkbox-off.svg
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24"
|
||||||
|
height="22"
|
||||||
|
id="svg3199"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.1 r9760"
|
||||||
|
sodipodi:docname="checkbox.svg">
|
||||||
|
<defs
|
||||||
|
id="defs3201">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15404"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop15406"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#515151;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop15408"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#292929;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<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="perspective3207" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3187"
|
||||||
|
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" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5872-5-1"
|
||||||
|
id="linearGradient5891-0-4"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="205.84143"
|
||||||
|
y1="246.7094"
|
||||||
|
x2="206.74803"
|
||||||
|
y2="231.24142" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient5872-5-1">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0b2e52;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop5874-4-4" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#1862af;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop5876-0-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5837-4-6"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect14768"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5884-4-7"
|
||||||
|
is_visible="true" />
|
||||||
|
<linearGradient
|
||||||
|
y2="-388.72955"
|
||||||
|
x2="-93.031357"
|
||||||
|
y1="-396.34738"
|
||||||
|
x1="-93.031357"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient14219"
|
||||||
|
xlink:href="#linearGradient15404"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10013-4-63-6">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#333333;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10015-2-76-1" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#292929;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10017-46-15-8" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10597-5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16191a;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10599-2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2b3133;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10601-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="-322.16354"
|
||||||
|
x2="921.22498"
|
||||||
|
y1="-330.05121"
|
||||||
|
x1="921.32812"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15374"
|
||||||
|
xlink:href="#linearGradient10013-4-63-6"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="translate(-1199.9852,216.38048)"
|
||||||
|
y2="-227.07961"
|
||||||
|
x2="1203.9177"
|
||||||
|
y1="-217.56708"
|
||||||
|
x1="1203.9177"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15376"
|
||||||
|
xlink:href="#linearGradient10597-5"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#2d2d2d"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageopacity="1"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="4"
|
||||||
|
inkscape:cx="71.247925"
|
||||||
|
inkscape:cy="33.339093"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1412"
|
||||||
|
inkscape:window-height="1067"
|
||||||
|
inkscape:window-x="2116"
|
||||||
|
inkscape:window-y="261"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
borderlayer="true"
|
||||||
|
inkscape:showpageshadow="false"
|
||||||
|
inkscape:snap-nodes="false"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showborder="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid14843"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata3204">
|
||||||
|
<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(-342.5,-521.36218)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
|
||||||
|
id="g14586">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
||||||
|
id="g15291-9"
|
||||||
|
style="display:inline;enable-background:new">
|
||||||
|
<g
|
||||||
|
transform="translate(877.50354,-102.83507)"
|
||||||
|
id="g16853-4"
|
||||||
|
style="enable-background:new">
|
||||||
|
<rect
|
||||||
|
transform="scale(1,-1)"
|
||||||
|
style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#868686;stroke-width:0.59377144999999998;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:new"
|
||||||
|
id="rect6506-6"
|
||||||
|
width="11.281681"
|
||||||
|
height="11.26221"
|
||||||
|
x="-409.59354"
|
||||||
|
y="-284.40115"
|
||||||
|
rx="0.95632279"
|
||||||
|
ry="0.95632273" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="translate(343.99999,987.99997)"
|
||||||
|
id="g5886"
|
||||||
|
style="display:inline;enable-background:new" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 6.8 KiB |
243
data/theme/checkbox.svg
Normal file
@ -0,0 +1,243 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
width="24"
|
||||||
|
height="22"
|
||||||
|
id="svg3199"
|
||||||
|
version="1.1"
|
||||||
|
inkscape:version="0.48.1 r9760"
|
||||||
|
sodipodi:docname="checkbox-focused.svg">
|
||||||
|
<defs
|
||||||
|
id="defs3201">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient15404"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
id="stop15406"
|
||||||
|
offset="0"
|
||||||
|
style="stop-color:#515151;stop-opacity:1" />
|
||||||
|
<stop
|
||||||
|
id="stop15408"
|
||||||
|
offset="1"
|
||||||
|
style="stop-color:#292929;stop-opacity:1" />
|
||||||
|
</linearGradient>
|
||||||
|
<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="perspective3207" />
|
||||||
|
<inkscape:perspective
|
||||||
|
id="perspective3187"
|
||||||
|
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" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5872-5-1"
|
||||||
|
id="linearGradient5891-0-4"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
x1="205.84143"
|
||||||
|
y1="246.7094"
|
||||||
|
x2="206.74803"
|
||||||
|
y2="231.24142" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient5872-5-1">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0b2e52;stop-opacity:1"
|
||||||
|
offset="0"
|
||||||
|
id="stop5874-4-4" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#1862af;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop5876-0-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5837-4-6"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect14768"
|
||||||
|
is_visible="true" />
|
||||||
|
<inkscape:path-effect
|
||||||
|
effect="spiro"
|
||||||
|
id="path-effect5884-4-7"
|
||||||
|
is_visible="true" />
|
||||||
|
<linearGradient
|
||||||
|
y2="-388.72955"
|
||||||
|
x2="-93.031357"
|
||||||
|
y1="-396.34738"
|
||||||
|
x1="-93.031357"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.685418)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient14219"
|
||||||
|
xlink:href="#linearGradient15404"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10013-4-63-6">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#333333;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10015-2-76-1" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#292929;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10017-46-15-8" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
id="linearGradient10597-5">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#16191a;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10599-2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2b3133;stop-opacity:1"
|
||||||
|
offset="1"
|
||||||
|
id="stop10601-5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
y2="-322.16354"
|
||||||
|
x2="921.22498"
|
||||||
|
y1="-330.05121"
|
||||||
|
x1="921.32812"
|
||||||
|
gradientTransform="matrix(1.5918367,0,0,0.85714285,-1456.5464,275.45191)"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15374"
|
||||||
|
xlink:href="#linearGradient10013-4-63-6"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
<linearGradient
|
||||||
|
gradientTransform="translate(-1199.9852,216.38048)"
|
||||||
|
y2="-227.07961"
|
||||||
|
x2="1203.9177"
|
||||||
|
y1="-217.56708"
|
||||||
|
x1="1203.9177"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
id="linearGradient15376"
|
||||||
|
xlink:href="#linearGradient10597-5"
|
||||||
|
inkscape:collect="always" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="base"
|
||||||
|
pagecolor="#000000"
|
||||||
|
bordercolor="#2d2d2d"
|
||||||
|
borderopacity="1"
|
||||||
|
inkscape:pageopacity="1"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:zoom="1"
|
||||||
|
inkscape:cx="64.516955"
|
||||||
|
inkscape:cy="13.871056"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
inkscape:current-layer="layer1"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:window-width="1412"
|
||||||
|
inkscape:window-height="1067"
|
||||||
|
inkscape:window-x="2635"
|
||||||
|
inkscape:window-y="226"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
borderlayer="true"
|
||||||
|
inkscape:showpageshadow="false"
|
||||||
|
inkscape:snap-nodes="false"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showborder="false">
|
||||||
|
<inkscape:grid
|
||||||
|
type="xygrid"
|
||||||
|
id="grid14843"
|
||||||
|
empspacing="5"
|
||||||
|
visible="true"
|
||||||
|
enabled="true"
|
||||||
|
snapvisiblegridlinesonly="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<metadata
|
||||||
|
id="metadata3204">
|
||||||
|
<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(-342.5,-521.36218)">
|
||||||
|
<g
|
||||||
|
transform="matrix(0.84337,0,0,0.84337,-110.16632,-503.56182)"
|
||||||
|
id="g14586">
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="matrix(1.9969286,0,0,1.9969286,-397.05491,877.00482)"
|
||||||
|
id="g15291-9"
|
||||||
|
style="display:inline;enable-background:new">
|
||||||
|
<g
|
||||||
|
transform="translate(877.50354,-102.83507)"
|
||||||
|
id="g16853-4"
|
||||||
|
style="enable-background:new">
|
||||||
|
<rect
|
||||||
|
transform="scale(1,-1)"
|
||||||
|
style="color:#000000;fill:url(#linearGradient14219);fill-opacity:1;fill-rule:nonzero;stroke:#868686;stroke-width:0.59377144999999998;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:new"
|
||||||
|
id="rect6506-6"
|
||||||
|
width="11.281681"
|
||||||
|
height="11.26221"
|
||||||
|
x="-409.59354"
|
||||||
|
y="-284.40115"
|
||||||
|
rx="0.95632279"
|
||||||
|
ry="0.95632273" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
<g
|
||||||
|
inkscape:export-ydpi="90"
|
||||||
|
inkscape:export-xdpi="90"
|
||||||
|
inkscape:export-filename="/home/jimmac/SparkleShare/gnome-mockups/boxes/interactive/img/checkbox-on.png"
|
||||||
|
transform="translate(343.99999,987.99997)"
|
||||||
|
id="g5886"
|
||||||
|
style="display:inline;enable-background:new">
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:url(#linearGradient5891-0-4);stroke-width:7.11431503;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
||||||
|
id="path5835"
|
||||||
|
inkscape:path-effect="#path-effect5837-4-6"
|
||||||
|
inkscape:original-d="m 198.5,240 5.25,5.25 13.98616,-14.43081"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
inkscape:original-d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
||||||
|
inkscape:path-effect="#path-effect5837-4-6"
|
||||||
|
id="path5880"
|
||||||
|
d="m 198.5,240 5.25,5.25 13.91205,-14.31964"
|
||||||
|
style="fill:none;stroke:#4787c8;stroke-width:3.55715752;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||||
|
sodipodi:nodetypes="ccc" />
|
||||||
|
<path
|
||||||
|
style="fill:none;stroke:#7ea7d3;stroke-width:1.18571913px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||||
|
d="m 197.45937,240.47455 c -0.17828,-0.29362 -0.20087,-0.67548 -0.0603,-0.98892 0.14055,-0.31344 0.43739,-0.54812 0.77144,-0.62817 0.33405,-0.08 0.69314,-0.01 0.99635,0.15175 0.30321,0.16144 0.55146,0.40727 0.79165,0.65284 l 3.66429,3.74643 12.87946,-12.98973 c 0.20796,-0.20974 0.42306,-0.41969 0.68548,-0.55522 0.26242,-0.13553 0.57293,-0.19052 0.85827,-0.11426 0.14267,0.0381 0.27708,0.10787 0.38874,0.20452 0.11167,0.0966 0.20021,0.22004 0.25479,0.35726 0.0546,0.13722 0.075,0.28793 0.0585,0.43468 -0.0165,0.14674 -0.07,0.28919 -0.15422,0.41052"
|
||||||
|
id="path5882"
|
||||||
|
inkscape:path-effect="#path-effect5884-4-7"
|
||||||
|
inkscape:original-d="m 197.45937,240.47455 c 0.65604,-0.56057 2.02485,-1.34847 2.49911,-0.8125 l 3.66429,3.74643 12.87946,-12.98973 c 0.6875,-0.6875 2.09152,0.7375 2.09152,0.7375"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
sodipodi:nodetypes="csccc" />
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 8.8 KiB |
@ -17,10 +17,16 @@
|
|||||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Text Styles */
|
||||||
|
|
||||||
|
/* default text style */
|
||||||
stage {
|
stage {
|
||||||
font-family: cantarell, sans-serif;
|
font-family: cantarell, sans-serif;
|
||||||
|
font-size: 11pt;
|
||||||
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* links */
|
||||||
.shell-link {
|
.shell-link {
|
||||||
color: #0000ff;
|
color: #0000ff;
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
@ -30,10 +36,28 @@ stage {
|
|||||||
color: #0000e0;
|
color: #0000e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.label-shadow {
|
/* small */
|
||||||
color: rgba(0,0,0,0.5);
|
.app-well-menu,
|
||||||
|
.contact-details-status,
|
||||||
|
.run-dialog-label,
|
||||||
|
.run-dialog-error-label {
|
||||||
|
font-size: 9pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* small bold */
|
||||||
|
.dash-label,
|
||||||
|
.window-caption,
|
||||||
|
.switcher-list,
|
||||||
|
.source-title,
|
||||||
|
.app-well-app > .overview-icon,
|
||||||
|
.remove-favorite > .overview-icon,
|
||||||
|
.search-result-content > .overview-icon {
|
||||||
|
font-size: 9pt;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scroll Bars */
|
||||||
|
|
||||||
StScrollBar
|
StScrollBar
|
||||||
{
|
{
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
@ -44,6 +68,11 @@ StScrollView.vfade
|
|||||||
-st-vfade-offset: 68px;
|
-st-vfade-offset: 68px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StScrollView.hfade
|
||||||
|
{
|
||||||
|
-st-hfade-offset: 68px;
|
||||||
|
}
|
||||||
|
|
||||||
StScrollView StScrollBar
|
StScrollView StScrollBar
|
||||||
{
|
{
|
||||||
min-width: 16px;
|
min-width: 16px;
|
||||||
@ -79,15 +108,28 @@ StScrollBar StButton#vhandle:hover
|
|||||||
background-color: #292929;
|
background-color: #292929;
|
||||||
}
|
}
|
||||||
|
|
||||||
StTooltip StLabel {
|
/* Check Boxes */
|
||||||
border: 1px solid rgba(255,255,255,0.6);
|
|
||||||
border-radius: 5px;
|
.check-box ShellGenericContainer {
|
||||||
padding: 2px 12px;
|
spacing: .8em;
|
||||||
background-color: rgba(0,0,0,0.9);
|
}
|
||||||
color: #ffffff;
|
|
||||||
font-size: 0.8em;
|
.check-box StBin {
|
||||||
font-weight: normal;
|
width: 24px;
|
||||||
text-align: center;
|
height: 22px;
|
||||||
|
background-image: url("checkbox-off.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-box:focus StBin {
|
||||||
|
background-image: url("checkbox-off-focused.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-box:checked StBin {
|
||||||
|
background-image: url("checkbox.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.check-box:focus:checked StBin {
|
||||||
|
background-image: url("checkbox-focused.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PopupMenu */
|
/* PopupMenu */
|
||||||
@ -102,8 +144,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.popup-menu {
|
.popup-menu {
|
||||||
color: #ffffff;
|
|
||||||
font-size: 10.5pt;
|
|
||||||
min-width: 200px;
|
min-width: 200px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,8 +182,6 @@ StTooltip StLabel {
|
|||||||
.popup-combo-menu {
|
.popup-combo-menu {
|
||||||
background-color: rgba(0,0,0,0.9);
|
background-color: rgba(0,0,0,0.9);
|
||||||
padding: 1em 0em;
|
padding: 1em 0em;
|
||||||
color: #ffffff;
|
|
||||||
font-size: 10.5pt;
|
|
||||||
border: 1px solid #5f5f5f;
|
border: 1px solid #5f5f5f;
|
||||||
border-radius: 9px;
|
border-radius: 9px;
|
||||||
}
|
}
|
||||||
@ -213,10 +251,10 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.popup-menu-icon {
|
.popup-menu-icon {
|
||||||
icon-size: 1.14em;
|
icon-size: 1.09em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Switches (to be used in menus) */
|
/* Switches */
|
||||||
.toggle-switch {
|
.toggle-switch {
|
||||||
width: 65px;
|
width: 65px;
|
||||||
height: 22px;
|
height: 22px;
|
||||||
@ -224,51 +262,68 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.toggle-switch-us {
|
.toggle-switch-us {
|
||||||
background-image: url("toggle-off-us.svg");
|
background-image: url("toggle-off-us.svg");
|
||||||
|
background-size: contain;
|
||||||
}
|
}
|
||||||
.toggle-switch-us:checked {
|
.toggle-switch-us:checked {
|
||||||
background-image: url("toggle-on-us.svg");
|
background-image: url("toggle-on-us.svg");
|
||||||
|
background-size: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toggle-switch-intl {
|
.toggle-switch-intl {
|
||||||
background-image: url("toggle-off-intl.svg");
|
background-image: url("toggle-off-intl.svg");
|
||||||
|
background-size: contain;
|
||||||
}
|
}
|
||||||
.toggle-switch-intl:checked {
|
.toggle-switch-intl:checked {
|
||||||
background-image: url("toggle-on-intl.svg");
|
background-image: url("toggle-on-intl.svg");
|
||||||
|
background-size: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nm-menu-item-icons {
|
.nm-menu-item-icons {
|
||||||
spacing: .5em;
|
spacing: .5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Shared button properties */
|
/* Buttons */
|
||||||
|
|
||||||
.dash-search-button, .notification-button, .notification-icon-button,
|
.dash-search-button,
|
||||||
.hotplug-notification-item, .hotplug-resident-eject-button,
|
.notification-button,
|
||||||
|
.notification-icon-button,
|
||||||
|
.hotplug-notification-item,
|
||||||
|
.hotplug-resident-eject-button,
|
||||||
.modal-dialog-button {
|
.modal-dialog-button {
|
||||||
color: white;
|
font-weight: bold;
|
||||||
border: 1px solid #8b8b8b;
|
border: 1px solid #8b8b8b;
|
||||||
background-gradient-direction: vertical;
|
background-gradient-direction: vertical;
|
||||||
background-gradient-start: rgba(255, 255, 255, 0.2);
|
background-gradient-start: rgba(255, 255, 255, 0.2);
|
||||||
background-gradient-end: rgba(255, 255, 255, 0);
|
background-gradient-end: rgba(255, 255, 255, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-search-button:hover, .notification-button:hover,
|
.dash-search-button:hover,
|
||||||
.notification-icon-button:hover, .hotplug-notification-item:hover,
|
.notification-button:hover,
|
||||||
.hotplug-resident-eject-button:hover, .modal-dialog-button:hover {
|
.notification-icon-button:hover,
|
||||||
|
.hotplug-notification-item:hover,
|
||||||
|
.hotplug-resident-eject-button:hover,
|
||||||
|
.modal-dialog-button:hover {
|
||||||
background-gradient-start: rgba(255, 255, 255, 0.3);
|
background-gradient-start: rgba(255, 255, 255, 0.3);
|
||||||
background-gradient-end: rgba(255, 255, 255, 0.1);
|
background-gradient-end: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-search-button:selected, .notification-button:focus,
|
.dash-search-button:selected,
|
||||||
.notification-icon-button:focus, .hotplug-notification-item:focus,
|
.dash-search-button:focus,
|
||||||
|
.notification-button:focus,
|
||||||
|
.notification-icon-button:focus,
|
||||||
|
.hotplug-notification-item:focus,
|
||||||
.modal-dialog-button:focus {
|
.modal-dialog-button:focus {
|
||||||
border: 2px solid #8b8b8b;
|
border: 2px solid #8b8b8b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-search-button:active, .dash-search-button:pressed,
|
.dash-search-button:active,
|
||||||
.notification-button:active, .notification-icon-button:active,
|
.dash-search-button:pressed,
|
||||||
.hotplug-notification-item:active, .hotplug-resident-eject-button:active,
|
.notification-button:active,
|
||||||
.modal-dialog-button:active, .modal-dialog-button:pressed {
|
.notification-icon-button:active,
|
||||||
|
.hotplug-notification-item:active,
|
||||||
|
.hotplug-resident-eject-button:active,
|
||||||
|
.modal-dialog-button:active,
|
||||||
|
.modal-dialog-button:pressed {
|
||||||
background-gradient-start: rgba(255, 255, 255, 0);
|
background-gradient-start: rgba(255, 255, 255, 0);
|
||||||
background-gradient-end: rgba(255, 255, 255, 0.2);
|
background-gradient-end: rgba(255, 255, 255, 0.2);
|
||||||
}
|
}
|
||||||
@ -276,10 +331,7 @@ StTooltip StLabel {
|
|||||||
/* Panel */
|
/* Panel */
|
||||||
|
|
||||||
#panel {
|
#panel {
|
||||||
color: #ffffff;
|
|
||||||
background-color: black;
|
background-color: black;
|
||||||
border-image: url("panel-border.svg") 1;
|
|
||||||
font-size: 10.5pt;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
height: 1.86em;
|
height: 1.86em;
|
||||||
}
|
}
|
||||||
@ -307,22 +359,25 @@ StTooltip StLabel {
|
|||||||
.panel-corner {
|
.panel-corner {
|
||||||
-panel-corner-radius: 10px;
|
-panel-corner-radius: 10px;
|
||||||
-panel-corner-background-color: black;
|
-panel-corner-background-color: black;
|
||||||
-panel-corner-inner-border-width: 2px;
|
-panel-corner-border-width: 2px;
|
||||||
-panel-corner-inner-border-color: transparent;
|
-panel-corner-border-color: transparent;
|
||||||
-panel-corner-outer-border-width: 1px;
|
|
||||||
-panel-corner-outer-border-color: #536272;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-corner:active,
|
.panel-corner:active,
|
||||||
.panel-corner:overview,
|
.panel-corner:overview,
|
||||||
.panel-corner:focus {
|
.panel-corner:focus {
|
||||||
-panel-corner-inner-border-color: rgba(255,255,255,0.8);
|
-panel-corner-border-color: rgba(255,255,255,0.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
#appMenu {
|
#appMenu {
|
||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* used for the app menu header only */
|
||||||
|
.label-shadow {
|
||||||
|
color: rgba(0,0,0,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.panel-button #appMenuIcon {
|
.panel-button #appMenuIcon {
|
||||||
app-icon-bottom-clip: 1px;
|
app-icon-bottom-clip: 1px;
|
||||||
}
|
}
|
||||||
@ -376,6 +431,8 @@ StTooltip StLabel {
|
|||||||
-boxpointer-gap: 4px
|
-boxpointer-gap: 4px
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* User Menu */
|
||||||
|
|
||||||
#panelUserMenu {
|
#panelUserMenu {
|
||||||
spacing: 4px;
|
spacing: 4px;
|
||||||
}
|
}
|
||||||
@ -415,8 +472,6 @@ StTooltip StLabel {
|
|||||||
padding: .4em 0em;
|
padding: .4em 0em;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #5f5f5f;
|
border: 1px solid #5f5f5f;
|
||||||
color: #ffffff;
|
|
||||||
font-size: 10.5pt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-chooser-status-item,
|
.status-chooser-status-item,
|
||||||
@ -425,7 +480,7 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.system-status-icon {
|
.system-status-icon {
|
||||||
icon-size: 1.14em;
|
icon-size: 1.09em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Overview */
|
/* Overview */
|
||||||
@ -435,7 +490,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.window-caption {
|
.window-caption {
|
||||||
color: white;
|
|
||||||
spacing: 25px;
|
spacing: 25px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,16 +521,15 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.window-caption {
|
.window-caption {
|
||||||
background: rgba(0,0,0,0.8);
|
background: rgba(0,0,0,0.5);
|
||||||
border: 1px solid rgba(128,128,128,0.40);
|
border-radius: 8px;
|
||||||
border-radius: 10px;
|
padding: 4px 12px;
|
||||||
font-size: 9pt;
|
-shell-caption-spacing: 12px;
|
||||||
padding: 2px 8px;
|
|
||||||
-shell-caption-spacing: 4px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.window-close {
|
.window-close {
|
||||||
background-image: url("close-window.svg");
|
background-image: url("close-window.svg");
|
||||||
|
background-size: 34px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
width: 34px;
|
width: 34px;
|
||||||
-shell-close-overlap: 20px;
|
-shell-close-overlap: 20px;
|
||||||
@ -511,18 +564,20 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.placeholder {
|
.placeholder {
|
||||||
background-image: url("dash-placeholder.svg");
|
background-image: url("dash-placeholder.svg");
|
||||||
|
background-size: contain;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#viewSelector {
|
#viewSelector {
|
||||||
spacing: 1em;
|
spacing: 1em;
|
||||||
font-size: 12pt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#viewSelectorTabBar {
|
#viewSelectorTabBar {
|
||||||
padding: 1em;
|
padding: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search Box */
|
||||||
|
|
||||||
#searchArea {
|
#searchArea {
|
||||||
padding: 0px 24px;
|
padding: 0px 24px;
|
||||||
}
|
}
|
||||||
@ -530,6 +585,7 @@ StTooltip StLabel {
|
|||||||
#searchEntry {
|
#searchEntry {
|
||||||
padding: 4px 12px;
|
padding: 4px 12px;
|
||||||
border-radius: 17px;
|
border-radius: 17px;
|
||||||
|
font-size: 12pt;
|
||||||
color: rgb(128, 128, 128);
|
color: rgb(128, 128, 128);
|
||||||
border: 2px solid rgba(245,245,245,0.2);
|
border: 2px solid rgba(245,245,245,0.2);
|
||||||
background-gradient-start: rgba(5,5,6,0.1);
|
background-gradient-start: rgba(5,5,6,0.1);
|
||||||
@ -566,8 +622,11 @@ StTooltip StLabel {
|
|||||||
color: #8d8f8a;
|
color: #8d8f8a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* View Tabs */
|
||||||
|
|
||||||
.view-tab-title {
|
.view-tab-title {
|
||||||
color: #888a85;
|
color: #888a85;
|
||||||
|
font-size: 12pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
padding: 0px 0.75em;
|
padding: 0px 0.75em;
|
||||||
height: 1.5em;
|
height: 1.5em;
|
||||||
@ -583,6 +642,8 @@ StTooltip StLabel {
|
|||||||
border-radius: 0.25em;
|
border-radius: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Search Results */
|
||||||
|
|
||||||
#searchResults {
|
#searchResults {
|
||||||
padding: 20px 10px 10px 10px;
|
padding: 20px 10px 10px 10px;
|
||||||
spacing: 18px;
|
spacing: 18px;
|
||||||
@ -607,7 +668,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.search-section-results {
|
.search-section-results {
|
||||||
color: #ffffff;
|
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -634,27 +694,27 @@ StTooltip StLabel {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dash-search-button:focus,
|
||||||
.dash-search-button:selected {
|
.dash-search-button:selected {
|
||||||
padding-top: 3px;
|
padding-top: 3px;
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
width: 298px;
|
width: 298px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dash-search-button-label {
|
.dash-label {
|
||||||
color: white;
|
border-radius: 7px;
|
||||||
font-size: 11pt;
|
padding: 4px 12px;
|
||||||
|
background-color: rgba(0,0,0,0.5);
|
||||||
|
text-align: center;
|
||||||
|
-x-offset: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Apps */
|
/* Application Launchers and Grid */
|
||||||
|
|
||||||
.icon-grid {
|
.icon-grid {
|
||||||
spacing: 36px;
|
spacing: 36px;
|
||||||
-shell-grid-item-size: 118px;
|
-shell-grid-horizontal-item-size: 118px;
|
||||||
}
|
-shell-grid-vertical-item-size: 118px;
|
||||||
|
|
||||||
.contact-grid {
|
|
||||||
spacing: 36px;
|
|
||||||
-shell-grid-item-size: 272px; /* 2 * -shell-grid-item-size + spacing */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-grid .overview-icon {
|
.icon-grid .overview-icon {
|
||||||
@ -672,7 +732,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.app-filter {
|
.app-filter {
|
||||||
font-size: 10.5pt;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
height: 2.85em;
|
height: 2.85em;
|
||||||
color: #aaa;
|
color: #aaa;
|
||||||
@ -717,12 +776,32 @@ StTooltip StLabel {
|
|||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 3px;
|
padding: 3px;
|
||||||
border: 1px rgba(0,0,0,0);
|
border: 1px rgba(0,0,0,0);
|
||||||
font-size: 7.5pt;
|
|
||||||
color: white;
|
|
||||||
transition-duration: 100;
|
transition-duration: 100;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.app-well-app.running > .overview-icon {
|
||||||
|
text-shadow: black 0px 2px 2px;
|
||||||
|
background-image: url("running-indicator.svg");
|
||||||
|
background-size: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-well-app:hover > .overview-icon,
|
||||||
|
.remove-favorite:hover > .overview-icon,
|
||||||
|
.search-result-content:hover > .overview-icon {
|
||||||
|
background-color: rgba(255,255,255,0.1);
|
||||||
|
text-shadow: black 0px 2px 2px;
|
||||||
|
transition-duration: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contacts */
|
||||||
|
|
||||||
|
.contact-grid {
|
||||||
|
spacing: 36px;
|
||||||
|
-shell-grid-horizontal-item-size: 272px; /* 2 * -shell-grid-horizontal-item-size + spacing */
|
||||||
|
-shell-grid-vertical-item-size: 118px;
|
||||||
|
}
|
||||||
|
|
||||||
.contact {
|
.contact {
|
||||||
width: 272px; /* Same width as two normal results + spacing */
|
width: 272px; /* Same width as two normal results + spacing */
|
||||||
height: 118px; /* Aspect ratio = 1.75. Normal US business card ratio */
|
height: 118px; /* Aspect ratio = 1.75. Normal US business card ratio */
|
||||||
@ -733,13 +812,12 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.contact-content {
|
.contact-content {
|
||||||
border-radius: 2px;
|
border-radius: 7px;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
width: 232px;
|
width: 232px;
|
||||||
height: 84px;
|
height: 84px;
|
||||||
background-color: white;
|
background-color: rgba(0.0, 0.0, 0.0, 0.5);
|
||||||
color: black;
|
color: white;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact-icon {
|
.contact-icon {
|
||||||
@ -747,20 +825,16 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.contact-details {
|
.contact-details {
|
||||||
padding: 6px 8px 11px 8px;
|
padding: 0px 6px 22px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact-details-alias {
|
.contact-details-alias {
|
||||||
font-size: 16px;
|
font-size: 18px;
|
||||||
padding-bottom: 11px;
|
padding-bottom: 8px;
|
||||||
}
|
|
||||||
|
|
||||||
.contact-details-status {
|
|
||||||
font-size: 11pt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact-details-status-icon {
|
.contact-details-status-icon {
|
||||||
padding-right: 2px;
|
padding-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contact:hover {
|
.contact:hover {
|
||||||
@ -768,35 +842,15 @@ StTooltip StLabel {
|
|||||||
transition-duration: 100;
|
transition-duration: 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-well-app.running > .overview-icon {
|
.contact:focus,
|
||||||
text-shadow: black 0px 2px 2px;
|
.app-well-app:focus > .overview-icon,
|
||||||
background-image: url("running-indicator.svg");
|
.search-result-content:focus > .overview-icon,
|
||||||
}
|
|
||||||
|
|
||||||
.contact:selected,
|
.contact:selected,
|
||||||
.app-well-app:selected > .overview-icon,
|
.app-well-app:selected > .overview-icon,
|
||||||
.search-result-content:selected > .overview-icon {
|
.search-result-content:selected > .overview-icon {
|
||||||
background-color: rgba(255,255,255,0.33);
|
background-color: rgba(255,255,255,0.33);
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-well-app:hover > .overview-icon,
|
|
||||||
.remove-favorite:hover > .overview-icon,
|
|
||||||
.search-result-content:hover > .overview-icon {
|
|
||||||
background-color: rgba(255,255,255,0.1);
|
|
||||||
text-shadow: black 0px 2px 2px;
|
|
||||||
transition-duration: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.contact:focus,
|
|
||||||
.app-well-app:focus > .overview-icon,
|
|
||||||
.search-result-content:focus > .overview-icon {
|
|
||||||
border: 1px solid #cccccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-well-menu {
|
|
||||||
font-size: 9pt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LookingGlass */
|
/* LookingGlass */
|
||||||
|
|
||||||
#LookingGlassDialog
|
#LookingGlassDialog
|
||||||
@ -806,8 +860,6 @@ StTooltip StLabel {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
border: 2px solid grey;
|
border: 2px solid grey;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#LookingGlassDialog > #Toolbar
|
#LookingGlassDialog > #Toolbar
|
||||||
@ -847,14 +899,8 @@ StTooltip StLabel {
|
|||||||
padding-bottom: 8px;
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.lg-dialog StLabel
|
|
||||||
{
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lg-dialog StEntry
|
.lg-dialog StEntry
|
||||||
{
|
{
|
||||||
color: #ffffff;
|
|
||||||
selection-background-color: #bbbbbb;
|
selection-background-color: #bbbbbb;
|
||||||
selected-color: #333333;
|
selected-color: #333333;
|
||||||
}
|
}
|
||||||
@ -931,7 +977,6 @@ StTooltip StLabel {
|
|||||||
border: 2px solid grey;
|
border: 2px solid grey;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 6px;
|
padding: 6px;
|
||||||
color: #ffffff;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Calendar popup */
|
/* Calendar popup */
|
||||||
@ -1010,7 +1055,6 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.datemenu-date-label {
|
.datemenu-date-label {
|
||||||
padding: .4em 1.75em;
|
padding: .4em 1.75em;
|
||||||
font-size: 10.5pt;
|
|
||||||
color: #cccccc;
|
color: #cccccc;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
@ -1157,11 +1201,9 @@ StTooltip StLabel {
|
|||||||
background-gradient-start: rgba(0,0,0,0.01);
|
background-gradient-start: rgba(0,0,0,0.01);
|
||||||
background-gradient-end: rgba(0,0,0,0.82);
|
background-gradient-end: rgba(0,0,0,0.82);
|
||||||
height: 36px;
|
height: 36px;
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#notification {
|
#notification {
|
||||||
font-size: 11pt;
|
|
||||||
border-radius: 10px 10px 0px 0px;
|
border-radius: 10px 10px 0px 0px;
|
||||||
background: rgba(0,0,0,0.8);
|
background: rgba(0,0,0,0.8);
|
||||||
padding: 8px 8px 4px 8px;
|
padding: 8px 8px 4px 8px;
|
||||||
@ -1199,7 +1241,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.summary-boxpointer #summary-right-click-menu {
|
.summary-boxpointer #summary-right-click-menu {
|
||||||
font-size: 10.5pt;
|
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
}
|
}
|
||||||
@ -1249,7 +1290,6 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.notification-button {
|
.notification-button {
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
font-size: 11pt;
|
|
||||||
padding: 4px 42px 5px;
|
padding: 4px 42px 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1279,7 +1319,6 @@ StTooltip StLabel {
|
|||||||
.hotplug-notification-item {
|
.hotplug-notification-item {
|
||||||
padding: 2px 10px;
|
padding: 2px 10px;
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
font-size: 10.5pt;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.hotplug-notification-item:focus {
|
.hotplug-notification-item:focus {
|
||||||
@ -1422,7 +1461,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.summary-source-button {
|
.summary-source-button {
|
||||||
color: #fff;
|
|
||||||
text-shadow: black 0px 2px 2px;
|
text-shadow: black 0px 2px 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1432,6 +1470,7 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.summary-source-button:selected .summary-source {
|
.summary-source-button:selected .summary-source {
|
||||||
background-image: url("panel-button-highlight-narrow.svg");
|
background-image: url("panel-button-highlight-narrow.svg");
|
||||||
|
background-size: contain;
|
||||||
border-image: url("source-button-border.svg") 10 10 0 1;
|
border-image: url("source-button-border.svg") 10 10 0 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1442,6 +1481,7 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.summary-source-button:expanded:selected {
|
.summary-source-button:expanded:selected {
|
||||||
background-image: url("panel-button-highlight-wide.svg");
|
background-image: url("panel-button-highlight-wide.svg");
|
||||||
|
background-size: contain;
|
||||||
border-image: url("source-button-border.svg") 10 10 0 1;
|
border-image: url("source-button-border.svg") 10 10 0 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1473,8 +1513,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.source-title {
|
.source-title {
|
||||||
font-size: 9pt;
|
|
||||||
font-weight: bold;
|
|
||||||
padding-left: 4px;
|
padding-left: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1494,9 +1532,6 @@ StTooltip StLabel {
|
|||||||
border: 1px solid rgba(128,128,128,0.40);
|
border: 1px solid rgba(128,128,128,0.40);
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|
||||||
font-size: 9pt;
|
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.switcher-list-item-container {
|
.switcher-list-item-container {
|
||||||
@ -1555,6 +1590,7 @@ StTooltip StLabel {
|
|||||||
width: 52px;
|
width: 52px;
|
||||||
height: 52px;
|
height: 52px;
|
||||||
background-image: url("corner-ripple-ltr.png");
|
background-image: url("corner-ripple-ltr.png");
|
||||||
|
background-size: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.ripple-box:rtl {
|
.ripple-box:rtl {
|
||||||
@ -1615,12 +1651,20 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Modal Dialogs */
|
/* Modal Dialogs */
|
||||||
|
|
||||||
|
/* Dialog Subject Text Style */
|
||||||
|
.show-processes-dialog-subject,
|
||||||
|
.mount-question-dialog-subject,
|
||||||
|
.end-session-dialog-subject {
|
||||||
|
font-size: 14pt;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #999999;
|
||||||
|
}
|
||||||
|
|
||||||
.modal-dialog {
|
.modal-dialog {
|
||||||
font-size: 12pt;
|
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
background-color: rgba(0.0, 0.0, 0.0, 0.9);
|
background-color: rgba(0.0, 0.0, 0.0, 0.9);
|
||||||
border: 2px solid #868686;
|
border: 2px solid #868686;
|
||||||
color: #babdb6;
|
|
||||||
|
|
||||||
padding-right: 42px;
|
padding-right: 42px;
|
||||||
padding-left: 42px;
|
padding-left: 42px;
|
||||||
@ -1630,12 +1674,11 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.modal-dialog-button-box {
|
.modal-dialog-button-box {
|
||||||
spacing: 21px;
|
spacing: 21px;
|
||||||
|
padding-top: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-dialog-button {
|
.modal-dialog-button {
|
||||||
border-radius: 18px;
|
border-radius: 18px;
|
||||||
font-size: 11pt;
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
@ -1651,15 +1694,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Run Dialog */
|
/* Run Dialog */
|
||||||
.run-dialog-label {
|
|
||||||
font-size: 9pt;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.run-dialog-error-label {
|
|
||||||
font-size: 9pt;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.run-dialog-error-box {
|
.run-dialog-error-box {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
@ -1667,10 +1701,8 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.run-dialog-entry {
|
.run-dialog-entry {
|
||||||
font-size: 10.5pt;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
width: 23em;
|
width: 23em;
|
||||||
color: white;
|
|
||||||
selection-background-color: white;
|
selection-background-color: white;
|
||||||
selected-color: black;
|
selected-color: black;
|
||||||
}
|
}
|
||||||
@ -1688,18 +1720,18 @@ StTooltip StLabel {
|
|||||||
background-color: rgba(0, 0, 0, 0.4);
|
background-color: rgba(0, 0, 0, 0.4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.flashspot {
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
/* End Session Dialog */
|
/* End Session Dialog */
|
||||||
.end-session-dialog {
|
.end-session-dialog {
|
||||||
spacing: 42px;
|
spacing: 42px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.end-session-dialog-subject {
|
.end-session-dialog-subject {
|
||||||
font-size: 12pt;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #666666;
|
|
||||||
padding-top: 10px;
|
|
||||||
padding-left: 17px;
|
padding-left: 17px;
|
||||||
padding-bottom: 30px;
|
padding-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.end-session-dialog-subject:rtl {
|
.end-session-dialog-subject:rtl {
|
||||||
@ -1708,8 +1740,6 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.end-session-dialog-description {
|
.end-session-dialog-description {
|
||||||
font-size: 10pt;
|
|
||||||
color: white;
|
|
||||||
padding-left: 17px;
|
padding-left: 17px;
|
||||||
width: 28em;
|
width: 28em;
|
||||||
}
|
}
|
||||||
@ -1726,6 +1756,7 @@ StTooltip StLabel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.end-session-dialog-shutdown-icon {
|
.end-session-dialog-shutdown-icon {
|
||||||
|
color: #bebebe;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
}
|
}
|
||||||
@ -1792,14 +1823,15 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.show-processes-dialog-subject,
|
.show-processes-dialog-subject,
|
||||||
.mount-question-dialog-subject {
|
.mount-question-dialog-subject {
|
||||||
font-size: 12pt;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #666666;
|
|
||||||
padding-top: 10px;
|
padding-top: 10px;
|
||||||
padding-left: 17px;
|
padding-left: 17px;
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mount-question-dialog-subject {
|
||||||
|
max-width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
.show-processes-dialog-subject:rtl,
|
.show-processes-dialog-subject:rtl,
|
||||||
.mount-question-dialog-subject:rtl {
|
.mount-question-dialog-subject:rtl {
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
@ -1808,8 +1840,6 @@ StTooltip StLabel {
|
|||||||
|
|
||||||
.show-processes-dialog-description,
|
.show-processes-dialog-description,
|
||||||
.mount-question-dialog-description {
|
.mount-question-dialog-description {
|
||||||
font-size: 10pt;
|
|
||||||
color: white;
|
|
||||||
padding-left: 17px;
|
padding-left: 17px;
|
||||||
width: 28em;
|
width: 28em;
|
||||||
}
|
}
|
||||||
@ -1860,32 +1890,75 @@ StTooltip StLabel {
|
|||||||
font-size: 10pt;
|
font-size: 10pt;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* PolicyKit Authentication Dialog */
|
/* Password or Authentication Dialog */
|
||||||
.polkit-dialog {
|
.prompt-dialog {
|
||||||
/* this is the width of the entire modal popup */
|
/* this is the width of the entire modal popup */
|
||||||
width: 500px;
|
width: 500px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.polkit-dialog-main-layout {
|
.prompt-dialog-main-layout {
|
||||||
spacing: 24px;
|
spacing: 24px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.polkit-dialog-message-layout {
|
.prompt-dialog-message-layout {
|
||||||
spacing: 16px;
|
spacing: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.polkit-dialog-headline {
|
.prompt-dialog-headline {
|
||||||
font-size: 12pt;
|
font-size: 12pt;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: #666666;
|
color: #666666;
|
||||||
}
|
}
|
||||||
|
|
||||||
.polkit-dialog-description {
|
.prompt-dialog-password-label:ltr {
|
||||||
font-size: 10pt;
|
padding-right: 0.5em;
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prompt-dialog-password-label:rtl {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-dialog-password-entry {
|
||||||
|
background-gradient-start: rgb(236,236,236);
|
||||||
|
background-gradient-end: white;
|
||||||
|
background-gradient-direction: vertical;
|
||||||
|
color: black;
|
||||||
|
selected-color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 2px solid #555753;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-dialog-password-entry:focus {
|
||||||
|
border: 2px solid #3465a4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-dialog-password-entry .capslock-warning {
|
||||||
|
icon-size: 16px;
|
||||||
|
warning-color: #999;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-dialog-error-label {
|
||||||
|
font-size: 10pt;
|
||||||
|
color: #ffff00;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prompt-dialog-info-label {
|
||||||
|
font-size: 10pt;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* intentionally left transparent to avoid dialog changing size */
|
||||||
|
.prompt-dialog-null-label {
|
||||||
|
font-size: 10pt;
|
||||||
|
color: rgba(0,0,0,0);
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Polkit Dialog */
|
||||||
|
|
||||||
.polkit-dialog-user-layout {
|
.polkit-dialog-user-layout {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
spacing: 10px;
|
spacing: 10px;
|
||||||
@ -1900,56 +1973,16 @@ StTooltip StLabel {
|
|||||||
color: #ff0000;
|
color: #ff0000;
|
||||||
}
|
}
|
||||||
|
|
||||||
.polkit-dialog-password-label:ltr {
|
/* Network Agent Dialog */
|
||||||
padding-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.polkit-dialog-password-label:rtl {
|
|
||||||
padding-left: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.polkit-dialog-password-entry {
|
|
||||||
background-gradient-start: rgb(236,236,236);
|
|
||||||
background-gradient-end: white;
|
|
||||||
background-gradient-direction: vertical;
|
|
||||||
color: black;
|
|
||||||
selected-color: white;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 2px solid #555753;
|
|
||||||
}
|
|
||||||
|
|
||||||
.polkit-dialog-password-entry:focus {
|
|
||||||
border: 2px solid #3465a4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.polkit-dialog-password-entry .capslock-warning {
|
|
||||||
icon-size: 16px;
|
|
||||||
warning-color: #999;
|
|
||||||
padding: 0 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.polkit-dialog-error-label {
|
|
||||||
font-size: 10pt;
|
|
||||||
color: #ffff00;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.polkit-dialog-info-label {
|
|
||||||
font-size: 10pt;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* intentionally left transparent to avoid dialog changing size */
|
|
||||||
.polkit-dialog-null-label {
|
|
||||||
font-size: 10pt;
|
|
||||||
color: rgba(0,0,0,0);
|
|
||||||
padding-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.network-dialog-secret-table {
|
.network-dialog-secret-table {
|
||||||
spacing-rows: 15px;
|
spacing-rows: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.keyring-dialog-control-table {
|
||||||
|
spacing-rows: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Magnifier */
|
/* Magnifier */
|
||||||
|
|
||||||
.magnifier-zoom-region {
|
.magnifier-zoom-region {
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
<?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>
|
|
Before Width: | Height: | Size: 787 B |
@ -9,7 +9,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="64"
|
width="65"
|
||||||
height="22"
|
height="22"
|
||||||
id="svg3273"
|
id="svg3273"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
|
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
@ -9,7 +9,7 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
width="64"
|
width="65"
|
||||||
height="22"
|
height="22"
|
||||||
id="svg3012"
|
id="svg3012"
|
||||||
version="1.1"
|
version="1.1"
|
||||||
|
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
@ -18,11 +18,10 @@ DOC_MODULE=shell
|
|||||||
# The top-level SGML file. You can change this if you want to.
|
# The top-level SGML file. You can change this if you want to.
|
||||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
||||||
|
|
||||||
# Directories containing the source code, relative to $(srcdir).
|
# Directories containing the source code
|
||||||
# gtk-doc will search all .c and .h files beneath these paths
|
# gtk-doc will search all .c and .h files beneath these paths
|
||||||
# for inline comments documenting functions and macros.
|
# for inline comments documenting functions and macros.
|
||||||
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
|
DOC_SOURCE_DIR=$(top_srcdir)/src
|
||||||
DOC_SOURCE_DIR=../../../src
|
|
||||||
|
|
||||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
||||||
SCANGOBJ_OPTIONS=
|
SCANGOBJ_OPTIONS=
|
||||||
@ -58,7 +57,16 @@ EXTRA_HFILES=
|
|||||||
|
|
||||||
# Header files or dirs to ignore when scanning. Use base file/dir names
|
# Header files or dirs to ignore when scanning. Use base file/dir names
|
||||||
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
# e.g. IGNORE_HFILES=gtkdebug.h gtkintl.h private_code
|
||||||
IGNORE_HFILES=calendar-server gvc hotplug-sniffer st tray
|
IGNORE_HFILES= \
|
||||||
|
calendar-server \
|
||||||
|
gvc \
|
||||||
|
hotplug-sniffer \
|
||||||
|
st \
|
||||||
|
tray \
|
||||||
|
gactionmuxer.h \
|
||||||
|
gactionobservable.h \
|
||||||
|
gactionobserver.h \
|
||||||
|
shell-recorder-src.h
|
||||||
|
|
||||||
# Images to copy into HTML directory.
|
# Images to copy into HTML directory.
|
||||||
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
|
||||||
@ -79,7 +87,7 @@ expand_content_files=
|
|||||||
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
# e.g. GTKDOC_CFLAGS=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
|
||||||
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
|
||||||
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
|
GTKDOC_CFLAGS=$(GNOME_SHELL_CFLAGS)
|
||||||
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(top_builddir)/src/libgnome-shell.la
|
GTKDOC_LIBS=$(GNOME_SHELL_LIBS) $(BLUETOOTH_LIBS) $(top_builddir)/src/libgnome-shell.la
|
||||||
|
|
||||||
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
# This includes the standard gtk-doc make rules, copied by gtkdocize.
|
||||||
include $(top_srcdir)/gtk-doc.make
|
include $(top_srcdir)/gtk-doc.make
|
||||||
|
@ -18,11 +18,10 @@ DOC_MODULE=st
|
|||||||
# The top-level SGML file. You can change this if you want to.
|
# The top-level SGML file. You can change this if you want to.
|
||||||
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
|
||||||
|
|
||||||
# Directories containing the source code, relative to $(srcdir).
|
# Directories containing the source code
|
||||||
# gtk-doc will search all .c and .h files beneath these paths
|
# gtk-doc will search all .c and .h files beneath these paths
|
||||||
# for inline comments documenting functions and macros.
|
# for inline comments documenting functions and macros.
|
||||||
# e.g. DOC_SOURCE_DIR=../../../gtk ../../../gdk
|
DOC_SOURCE_DIR=$(top_srcdir)/src/st
|
||||||
DOC_SOURCE_DIR=../../../src/st
|
|
||||||
|
|
||||||
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
# Extra options to pass to gtkdoc-scangobj. Not normally needed.
|
||||||
SCANGOBJ_OPTIONS=
|
SCANGOBJ_OPTIONS=
|
||||||
|
@ -20,7 +20,6 @@
|
|||||||
<title>Abstract classes and Interfaces</title>
|
<title>Abstract classes and Interfaces</title>
|
||||||
<xi:include href="xml/st-widget.xml"/>
|
<xi:include href="xml/st-widget.xml"/>
|
||||||
<xi:include href="xml/st-widget-accessible.xml"/>
|
<xi:include href="xml/st-widget-accessible.xml"/>
|
||||||
<xi:include href="xml/st-container.xml"/>
|
|
||||||
<xi:include href="xml/st-scrollable.xml"/>
|
<xi:include href="xml/st-scrollable.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter id="widgets">
|
<chapter id="widgets">
|
||||||
@ -30,14 +29,11 @@
|
|||||||
<xi:include href="xml/st-entry.xml"/>
|
<xi:include href="xml/st-entry.xml"/>
|
||||||
<xi:include href="xml/st-icon.xml"/>
|
<xi:include href="xml/st-icon.xml"/>
|
||||||
<xi:include href="xml/st-label.xml"/>
|
<xi:include href="xml/st-label.xml"/>
|
||||||
<xi:include href="xml/st-tooltip.xml"/>
|
|
||||||
</chapter>
|
</chapter>
|
||||||
<chapter id="containers">
|
<chapter id="containers">
|
||||||
<title>Containers</title>
|
<title>Containers</title>
|
||||||
<xi:include href="xml/st-bin.xml"/>
|
<xi:include href="xml/st-bin.xml"/>
|
||||||
<xi:include href="xml/st-box-layout.xml"/>
|
<xi:include href="xml/st-box-layout.xml"/>
|
||||||
<xi:include href="xml/st-group.xml"/>
|
|
||||||
<xi:include href="xml/st-overflow-box.xml"/>
|
|
||||||
<xi:include href="xml/st-scroll-view.xml"/>
|
<xi:include href="xml/st-scroll-view.xml"/>
|
||||||
<xi:include href="xml/st-table.xml"/>
|
<xi:include href="xml/st-table.xml"/>
|
||||||
</chapter>
|
</chapter>
|
||||||
|
@ -66,4 +66,11 @@ its dependencies to build from tarballs.</description>
|
|||||||
<gnome:userid>marinaz</gnome:userid>
|
<gnome:userid>marinaz</gnome:userid>
|
||||||
</foaf:Person>
|
</foaf:Person>
|
||||||
</maintainer>
|
</maintainer>
|
||||||
|
<maintainer>
|
||||||
|
<foaf:Person>
|
||||||
|
<foaf:name>Florian Müllner</foaf:name>
|
||||||
|
<foaf:mbox rdf:resource="mailto:fmuellner@gnome.org" />
|
||||||
|
<gnome:userid>fmuellner</gnome:userid>
|
||||||
|
</foaf:Person>
|
||||||
|
</maintainer>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -1,4 +1,20 @@
|
|||||||
|
|
||||||
|
EXTRA_DIST = misc/config.js.in
|
||||||
|
CLEANFILES = misc/config.js
|
||||||
|
|
||||||
|
misc/config.js: misc/config.js.in Makefile
|
||||||
|
[ -d $(@D) ] || $(mkdir_p) $(@D) ; \
|
||||||
|
sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
|
||||||
|
-e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
|
||||||
|
-e "s|[@]GJS_VERSION@|$(GJS_VERSION)|g" \
|
||||||
|
-e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \
|
||||||
|
-e "s|[@]SHELL_SYSTEM_CA_FILE@|$(SHELL_SYSTEM_CA_FILE)|g" \
|
||||||
|
-e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \
|
||||||
|
-e "s|[@]datadir@|$(datadir)|g" \
|
||||||
|
-e "s|[@]libexecdir@|$(libexecdir)|g" \
|
||||||
|
-e "s|[@]sysconfdir@|$(sysconfdir)|g" \
|
||||||
|
$< > $@
|
||||||
|
|
||||||
jsdir = $(pkgdatadir)/js
|
jsdir = $(pkgdatadir)/js
|
||||||
|
|
||||||
nobase_dist_js_DATA = \
|
nobase_dist_js_DATA = \
|
||||||
@ -7,8 +23,10 @@ nobase_dist_js_DATA = \
|
|||||||
gdm/fingerprint.js \
|
gdm/fingerprint.js \
|
||||||
gdm/loginDialog.js \
|
gdm/loginDialog.js \
|
||||||
gdm/powerMenu.js \
|
gdm/powerMenu.js \
|
||||||
|
gdm/systemd.js \
|
||||||
|
extensionPrefs/main.js \
|
||||||
misc/config.js \
|
misc/config.js \
|
||||||
misc/docInfo.js \
|
misc/extensionUtils.js \
|
||||||
misc/fileUtils.js \
|
misc/fileUtils.js \
|
||||||
misc/format.js \
|
misc/format.js \
|
||||||
misc/gnomeSession.js \
|
misc/gnomeSession.js \
|
||||||
@ -26,17 +44,19 @@ nobase_dist_js_DATA = \
|
|||||||
ui/autorunManager.js \
|
ui/autorunManager.js \
|
||||||
ui/boxpointer.js \
|
ui/boxpointer.js \
|
||||||
ui/calendar.js \
|
ui/calendar.js \
|
||||||
|
ui/checkBox.js \
|
||||||
ui/contactDisplay.js \
|
ui/contactDisplay.js \
|
||||||
ui/ctrlAltTab.js \
|
ui/ctrlAltTab.js \
|
||||||
ui/dash.js \
|
ui/dash.js \
|
||||||
ui/dateMenu.js \
|
ui/dateMenu.js \
|
||||||
ui/dnd.js \
|
ui/dnd.js \
|
||||||
ui/docDisplay.js \
|
|
||||||
ui/endSessionDialog.js \
|
ui/endSessionDialog.js \
|
||||||
ui/environment.js \
|
ui/environment.js \
|
||||||
ui/extensionSystem.js \
|
ui/extensionSystem.js \
|
||||||
|
ui/flashspot.js \
|
||||||
ui/iconGrid.js \
|
ui/iconGrid.js \
|
||||||
ui/keyboard.js \
|
ui/keyboard.js \
|
||||||
|
ui/keyringPrompt.js \
|
||||||
ui/layout.js \
|
ui/layout.js \
|
||||||
ui/lightbox.js \
|
ui/lightbox.js \
|
||||||
ui/link.js \
|
ui/link.js \
|
||||||
@ -56,6 +76,7 @@ nobase_dist_js_DATA = \
|
|||||||
ui/placeDisplay.js \
|
ui/placeDisplay.js \
|
||||||
ui/polkitAuthenticationAgent.js \
|
ui/polkitAuthenticationAgent.js \
|
||||||
ui/popupMenu.js \
|
ui/popupMenu.js \
|
||||||
|
ui/remoteSearch.js \
|
||||||
ui/runDialog.js \
|
ui/runDialog.js \
|
||||||
ui/scripting.js \
|
ui/scripting.js \
|
||||||
ui/search.js \
|
ui/search.js \
|
||||||
@ -72,6 +93,7 @@ nobase_dist_js_DATA = \
|
|||||||
ui/tweener.js \
|
ui/tweener.js \
|
||||||
ui/userMenu.js \
|
ui/userMenu.js \
|
||||||
ui/viewSelector.js \
|
ui/viewSelector.js \
|
||||||
|
ui/wanda.js \
|
||||||
ui/windowAttentionHandler.js \
|
ui/windowAttentionHandler.js \
|
||||||
ui/windowManager.js \
|
ui/windowManager.js \
|
||||||
ui/workspace.js \
|
ui/workspace.js \
|
||||||
|
278
js/extensionPrefs/main.js
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Gettext = imports.gettext;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const GObject = imports.gi.GObject;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const Gtk = imports.gi.Gtk;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
|
|
||||||
|
const _ = Gettext.gettext;
|
||||||
|
|
||||||
|
const Config = imports.misc.config;
|
||||||
|
const Format = imports.misc.format;
|
||||||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
|
|
||||||
|
|
||||||
|
const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||||
|
<signal name="ExtensionStatusChanged">
|
||||||
|
<arg type="s" name="uuid"/>
|
||||||
|
<arg type="i" name="state"/>
|
||||||
|
<arg type="s" name="error"/>
|
||||||
|
</signal>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
|
||||||
|
|
||||||
|
function stripPrefix(string, prefix) {
|
||||||
|
if (string.slice(0, prefix.length) == prefix)
|
||||||
|
return string.slice(prefix.length);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Application = new Lang.Class({
|
||||||
|
Name: 'Application',
|
||||||
|
_init: function() {
|
||||||
|
GLib.set_prgname('gnome-shell-extension-prefs');
|
||||||
|
this.application = new Gtk.Application({
|
||||||
|
application_id: 'org.gnome.shell.ExtensionPrefs',
|
||||||
|
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE
|
||||||
|
});
|
||||||
|
|
||||||
|
this.application.connect('activate', Lang.bind(this, this._onActivate));
|
||||||
|
this.application.connect('command-line', Lang.bind(this, this._onCommandLine));
|
||||||
|
this.application.connect('startup', Lang.bind(this, this._onStartup));
|
||||||
|
|
||||||
|
this._extensionPrefsModules = {};
|
||||||
|
|
||||||
|
this._extensionIters = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildModel: function() {
|
||||||
|
this._model = new Gtk.ListStore();
|
||||||
|
this._model.set_column_types([GObject.TYPE_STRING, GObject.TYPE_STRING]);
|
||||||
|
},
|
||||||
|
|
||||||
|
_extensionAvailable: function(uuid) {
|
||||||
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
|
|
||||||
|
if (!extension)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (ExtensionUtils.isOutOfDate(extension))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!extension.dir.get_child('prefs.js').query_exists(null))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_setExtensionInsensitive: function(layout, cell, model, iter, data) {
|
||||||
|
let uuid = model.get_value(iter, 0);
|
||||||
|
cell.set_sensitive(this._extensionAvailable(uuid));
|
||||||
|
},
|
||||||
|
|
||||||
|
_getExtensionPrefsModule: function(extension) {
|
||||||
|
let uuid = extension.metadata.uuid;
|
||||||
|
|
||||||
|
if (this._extensionPrefsModules.hasOwnProperty(uuid))
|
||||||
|
return this._extensionPrefsModules[uuid];
|
||||||
|
|
||||||
|
ExtensionUtils.installImporter(extension);
|
||||||
|
|
||||||
|
let prefsModule = extension.imports.prefs;
|
||||||
|
prefsModule.init(extension.metadata);
|
||||||
|
|
||||||
|
this._extensionPrefsModules[uuid] = prefsModule;
|
||||||
|
return prefsModule;
|
||||||
|
},
|
||||||
|
|
||||||
|
_selectExtension: function(uuid) {
|
||||||
|
if (!this._extensionAvailable(uuid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
|
let widget;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let prefsModule = this._getExtensionPrefsModule(extension);
|
||||||
|
widget = prefsModule.buildPrefsWidget();
|
||||||
|
} catch (e) {
|
||||||
|
widget = this._buildErrorUI(extension, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy the current prefs widget, if it exists
|
||||||
|
if (this._extensionPrefsBin.get_child())
|
||||||
|
this._extensionPrefsBin.get_child().destroy();
|
||||||
|
|
||||||
|
this._extensionPrefsBin.add(widget);
|
||||||
|
this._extensionSelector.set_active_iter(this._extensionIters[uuid]);
|
||||||
|
},
|
||||||
|
|
||||||
|
_extensionSelected: function() {
|
||||||
|
let [success, iter] = this._extensionSelector.get_active_iter();
|
||||||
|
if (!success)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let uuid = this._model.get_value(iter, 0);
|
||||||
|
this._selectExtension(uuid);
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildErrorUI: function(extension, exc) {
|
||||||
|
let box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
||||||
|
let label = new Gtk.Label({
|
||||||
|
label: _("There was an error loading the preferences dialog for %s:").format(extension.metadata.name)
|
||||||
|
});
|
||||||
|
box.add(label);
|
||||||
|
|
||||||
|
let errortext = '';
|
||||||
|
errortext += exc;
|
||||||
|
errortext += '\n\n';
|
||||||
|
errortext += 'Stack trace:\n';
|
||||||
|
|
||||||
|
// Indent stack trace.
|
||||||
|
errortext += exc.stack.split('\n').map(function(line) {
|
||||||
|
return ' ' + line;
|
||||||
|
}).join('\n');
|
||||||
|
|
||||||
|
let scroll = new Gtk.ScrolledWindow({ vexpand: true });
|
||||||
|
let buffer = new Gtk.TextBuffer({ text: errortext });
|
||||||
|
let textview = new Gtk.TextView({ buffer: buffer });
|
||||||
|
textview.override_font(Pango.font_description_from_string('monospace'));
|
||||||
|
scroll.add(textview);
|
||||||
|
box.add(scroll);
|
||||||
|
|
||||||
|
box.show_all();
|
||||||
|
return box;
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildUI: function(app) {
|
||||||
|
this._window = new Gtk.ApplicationWindow({ application: app,
|
||||||
|
window_position: Gtk.WindowPosition.CENTER,
|
||||||
|
title: _("GNOME Shell Extension Preferences") });
|
||||||
|
|
||||||
|
this._window.set_size_request(600, 400);
|
||||||
|
|
||||||
|
let vbox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL });
|
||||||
|
this._window.add(vbox);
|
||||||
|
|
||||||
|
let toolbar = new Gtk.Toolbar();
|
||||||
|
toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR);
|
||||||
|
vbox.add(toolbar);
|
||||||
|
let toolitem;
|
||||||
|
|
||||||
|
let label = new Gtk.Label({ label: _("<b>Extension</b>"),
|
||||||
|
use_markup: true });
|
||||||
|
toolitem = new Gtk.ToolItem({ child: label });
|
||||||
|
toolbar.add(toolitem);
|
||||||
|
|
||||||
|
this._extensionSelector = new Gtk.ComboBox({ model: this._model,
|
||||||
|
margin_left: 8,
|
||||||
|
hexpand: true });
|
||||||
|
this._extensionSelector.get_style_context().add_class(Gtk.STYLE_CLASS_RAISED);
|
||||||
|
|
||||||
|
let renderer = new Gtk.CellRendererText();
|
||||||
|
this._extensionSelector.pack_start(renderer, true);
|
||||||
|
this._extensionSelector.add_attribute(renderer, 'text', 1);
|
||||||
|
this._extensionSelector.set_cell_data_func(renderer, Lang.bind(this, this._setExtensionInsensitive), null);
|
||||||
|
this._extensionSelector.connect('changed', Lang.bind(this, this._extensionSelected));
|
||||||
|
|
||||||
|
toolitem = new Gtk.ToolItem({ child: this._extensionSelector });
|
||||||
|
toolitem.set_expand(true);
|
||||||
|
toolbar.add(toolitem);
|
||||||
|
|
||||||
|
this._extensionPrefsBin = new Gtk.Frame();
|
||||||
|
vbox.add(this._extensionPrefsBin);
|
||||||
|
|
||||||
|
let label = new Gtk.Label({
|
||||||
|
label: _("Select an extension to configure using the combobox above."),
|
||||||
|
vexpand: true
|
||||||
|
});
|
||||||
|
|
||||||
|
this._extensionPrefsBin.add(label);
|
||||||
|
|
||||||
|
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
|
||||||
|
this._shellProxy.connectSignal('ExtensionStatusChanged', Lang.bind(this, function(proxy, senderName, [uuid, state, error]) {
|
||||||
|
if (ExtensionUtils.extensions[uuid] !== undefined)
|
||||||
|
this._scanExtensions();
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._window.show_all();
|
||||||
|
},
|
||||||
|
|
||||||
|
_scanExtensions: function() {
|
||||||
|
ExtensionUtils.scanExtensions(Lang.bind(this, function(uuid, dir, type) {
|
||||||
|
if (ExtensionUtils.extensions[uuid] !== undefined)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let extension;
|
||||||
|
try {
|
||||||
|
extension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||||
|
} catch(e) {
|
||||||
|
global.logError('' + e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let iter = this._model.append();
|
||||||
|
this._model.set(iter, [0, 1], [uuid, extension.metadata.name]);
|
||||||
|
this._extensionIters[uuid] = iter;
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onActivate: function() {
|
||||||
|
this._window.present();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onStartup: function(app) {
|
||||||
|
this._buildModel();
|
||||||
|
this._buildUI(app);
|
||||||
|
this._scanExtensions();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCommandLine: function(app, commandLine) {
|
||||||
|
app.activate();
|
||||||
|
let args = commandLine.get_arguments();
|
||||||
|
if (args.length) {
|
||||||
|
let uuid = args[0];
|
||||||
|
|
||||||
|
// Strip off "extension:///" prefix which fakes a URI, if it exists
|
||||||
|
uuid = stripPrefix(uuid, "extension:///");
|
||||||
|
|
||||||
|
if (!this._extensionAvailable(uuid))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
this._selectExtension(uuid);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function initEnvironment() {
|
||||||
|
// Monkey-patch in a "global" object that fakes some Shell utilities
|
||||||
|
// that ExtensionUtils depends on.
|
||||||
|
window.global = {
|
||||||
|
log: function() {
|
||||||
|
print([].join.call(arguments, ', '));
|
||||||
|
},
|
||||||
|
|
||||||
|
logError: function(s) {
|
||||||
|
global.log('ERROR: ' + s);
|
||||||
|
},
|
||||||
|
|
||||||
|
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell'])
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.format = Format.format;
|
||||||
|
}
|
||||||
|
|
||||||
|
function main(argv) {
|
||||||
|
initEnvironment();
|
||||||
|
ExtensionUtils.init();
|
||||||
|
|
||||||
|
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
|
||||||
|
Gettext.textdomain(Config.GETTEXT_PACKAGE);
|
||||||
|
|
||||||
|
let app = new Application();
|
||||||
|
app.application.run(argv);
|
||||||
|
}
|
@ -205,7 +205,8 @@ const UserListItem = new Lang.Class({
|
|||||||
// We use background-image instead of, say, St.TextureCache
|
// We use background-image instead of, say, St.TextureCache
|
||||||
// so the theme writers can add a rounded frame around the image
|
// so the theme writers can add a rounded frame around the image
|
||||||
// and so theme writers can pick the icon size.
|
// and so theme writers can pick the icon size.
|
||||||
this._iconBin.set_style('background-image: url("' + iconFile + '");');
|
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
||||||
|
'background-size: contain;');
|
||||||
} else {
|
} else {
|
||||||
this._iconBin.hide();
|
this._iconBin.hide();
|
||||||
}
|
}
|
||||||
@ -487,6 +488,9 @@ const UserList = new Lang.Class({
|
|||||||
if (user.is_system_account())
|
if (user.is_system_account())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (user.locked)
|
||||||
|
return;
|
||||||
|
|
||||||
let userName = user.get_user_name();
|
let userName = user.get_user_name();
|
||||||
|
|
||||||
if (!userName)
|
if (!userName)
|
||||||
@ -693,7 +697,7 @@ const SessionList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_populate: function() {
|
_populate: function() {
|
||||||
this._itemList.destroy_children();
|
this._itemList.destroy_all_children();
|
||||||
this._activeSessionId = null;
|
this._activeSessionId = null;
|
||||||
this._items = {};
|
this._items = {};
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ const Lang = imports.lang;
|
|||||||
const UPowerGlib = imports.gi.UPowerGlib;
|
const UPowerGlib = imports.gi.UPowerGlib;
|
||||||
|
|
||||||
const ConsoleKit = imports.gdm.consoleKit;
|
const ConsoleKit = imports.gdm.consoleKit;
|
||||||
|
const Systemd = imports.gdm.systemd;
|
||||||
|
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
|
|
||||||
@ -31,9 +33,13 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('system-shutdown', null);
|
this.parent('system-shutdown', null);
|
||||||
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
|
|
||||||
this._upClient = new UPowerGlib.Client();
|
this._upClient = new UPowerGlib.Client();
|
||||||
|
|
||||||
|
if (Systemd.haveSystemd())
|
||||||
|
this._systemdLoginManager = new Systemd.SystemdLoginManager();
|
||||||
|
else
|
||||||
|
this._consoleKitManager = new ConsoleKit.ConsoleKitManager();
|
||||||
|
|
||||||
this._createSubMenu();
|
this._createSubMenu();
|
||||||
|
|
||||||
this._upClient.connect('notify::can-suspend',
|
this._upClient.connect('notify::can-suspend',
|
||||||
@ -61,39 +67,75 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveShutdown: function() {
|
_updateHaveShutdown: function() {
|
||||||
this._consoleKitManager.CanStopRemote(Lang.bind(this,
|
|
||||||
function(result, error) {
|
|
||||||
if (!error)
|
|
||||||
this._haveShutdown = result;
|
|
||||||
else
|
|
||||||
this._haveShutdown = false;
|
|
||||||
|
|
||||||
if (this._haveShutdown) {
|
if (Systemd.haveSystemd()) {
|
||||||
this._powerOffItem.actor.show();
|
this._systemdLoginManager.CanPowerOffRemote(Lang.bind(this,
|
||||||
} else {
|
function(result, error) {
|
||||||
this._powerOffItem.actor.hide();
|
if (!error)
|
||||||
}
|
this._haveShutdown = result != 'no';
|
||||||
|
else
|
||||||
|
this._haveShutdown = false;
|
||||||
|
|
||||||
this._updateVisibility();
|
if (this._haveShutdown)
|
||||||
}));
|
this._powerOffItem.actor.show();
|
||||||
|
else
|
||||||
|
this._powerOffItem.actor.hide();
|
||||||
|
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this._consoleKitManager.CanStopRemote(Lang.bind(this,
|
||||||
|
function(result, error) {
|
||||||
|
if (!error)
|
||||||
|
this._haveShutdown = result;
|
||||||
|
else
|
||||||
|
this._haveShutdown = false;
|
||||||
|
|
||||||
|
if (this._haveShutdown) {
|
||||||
|
this._powerOffItem.actor.show();
|
||||||
|
} else {
|
||||||
|
this._powerOffItem.actor.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveRestart: function() {
|
_updateHaveRestart: function() {
|
||||||
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
|
|
||||||
function(result, error) {
|
|
||||||
if (!error)
|
|
||||||
this._haveRestart = result;
|
|
||||||
else
|
|
||||||
this._haveRestart = false;
|
|
||||||
|
|
||||||
if (this._haveRestart) {
|
if (Systemd.haveSystemd()) {
|
||||||
this._restartItem.actor.show();
|
this._systemdLoginManager.CanRebootRemote(Lang.bind(this,
|
||||||
} else {
|
function(result, error) {
|
||||||
this._restartItem.actor.hide();
|
if (!error)
|
||||||
}
|
this._haveRestart = result != 'no';
|
||||||
|
else
|
||||||
|
this._haveRestart = false;
|
||||||
|
|
||||||
this._updateVisibility();
|
if (this._haveRestart)
|
||||||
}));
|
this._restartItem.actor.show();
|
||||||
|
else
|
||||||
|
this._restartItem.actor.hide();
|
||||||
|
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
this._consoleKitManager.CanRestartRemote(Lang.bind(this,
|
||||||
|
function(result, error) {
|
||||||
|
if (!error)
|
||||||
|
this._haveRestart = result;
|
||||||
|
else
|
||||||
|
this._haveRestart = false;
|
||||||
|
|
||||||
|
if (this._haveRestart) {
|
||||||
|
this._restartItem.actor.show();
|
||||||
|
} else {
|
||||||
|
this._restartItem.actor.hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._updateVisibility();
|
||||||
|
}));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateHaveSuspend: function() {
|
_updateHaveSuspend: function() {
|
||||||
@ -132,12 +174,22 @@ const PowerMenuButton = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onActivateRestart: function() {
|
_onActivateRestart: function() {
|
||||||
if (this._haveRestart)
|
if (!this._haveRestart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Systemd.haveSystemd())
|
||||||
|
this._systemdLoginManager.RebootRemote(true);
|
||||||
|
else
|
||||||
this._consoleKitManager.RestartRemote();
|
this._consoleKitManager.RestartRemote();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivatePowerOff: function() {
|
_onActivatePowerOff: function() {
|
||||||
if (this._haveShutdown)
|
if (!this._haveShutdown)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Systemd.haveSystemd())
|
||||||
|
this._systemdLoginManager.PowerOffRemote(true);
|
||||||
|
else
|
||||||
this._consoleKitManager.StopRemote();
|
this._consoleKitManager.StopRemote();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
31
js/gdm/systemd.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
|
||||||
|
const SystemdLoginManagerIface = <interface name='org.freedesktop.login1.Manager'>
|
||||||
|
<method name='PowerOff'>
|
||||||
|
<arg type='b' direction='in'/>
|
||||||
|
</method>
|
||||||
|
<method name='Reboot'>
|
||||||
|
<arg type='b' direction='in'/>
|
||||||
|
</method>
|
||||||
|
<method name='CanPowerOff'>
|
||||||
|
<arg type='s' direction='out'/>
|
||||||
|
</method>
|
||||||
|
<method name='CanReboot'>
|
||||||
|
<arg type='s' direction='out'/>
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
const SystemdLoginManagerProxy = Gio.DBusProxy.makeProxyWrapper(SystemdLoginManagerIface);
|
||||||
|
|
||||||
|
function SystemdLoginManager() {
|
||||||
|
return new SystemdLoginManagerProxy(Gio.DBus.system,
|
||||||
|
'org.freedesktop.login1',
|
||||||
|
'/org/freedesktop/login1');
|
||||||
|
};
|
||||||
|
|
||||||
|
function haveSystemd() {
|
||||||
|
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
|
||||||
|
}
|
@ -10,3 +10,10 @@ const GJS_VERSION = '@GJS_VERSION@';
|
|||||||
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
|
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
|
||||||
/* The system TLS CA list */
|
/* The system TLS CA list */
|
||||||
const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@';
|
const SHELL_SYSTEM_CA_FILE = '@SHELL_SYSTEM_CA_FILE@';
|
||||||
|
/* gettext package */
|
||||||
|
const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
|
||||||
|
/* locale dir */
|
||||||
|
const LOCALEDIR = '@datadir@/locale';
|
||||||
|
/* other standard directories */
|
||||||
|
const LIBEXECDIR = '@libexecdir@';
|
||||||
|
const SYSCONFDIR = '@sysconfdir@';
|
||||||
|
@ -1,136 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const St = imports.gi.St;
|
|
||||||
const Shell = imports.gi.Shell;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Signals = imports.signals;
|
|
||||||
const Search = imports.ui.search;
|
|
||||||
|
|
||||||
const THUMBNAIL_ICON_MARGIN = 2;
|
|
||||||
|
|
||||||
const DocInfo = new Lang.Class({
|
|
||||||
Name: 'DocInfo',
|
|
||||||
|
|
||||||
_init : function(recentInfo) {
|
|
||||||
this.recentInfo = recentInfo;
|
|
||||||
// We actually used get_modified() instead of get_visited()
|
|
||||||
// here, as GtkRecentInfo doesn't updated get_visited()
|
|
||||||
// correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094
|
|
||||||
this.timestamp = recentInfo.get_modified();
|
|
||||||
this.name = recentInfo.get_display_name();
|
|
||||||
this._lowerName = this.name.toLowerCase();
|
|
||||||
this.uri = recentInfo.get_uri();
|
|
||||||
this.mimeType = recentInfo.get_mime_type();
|
|
||||||
},
|
|
||||||
|
|
||||||
createIcon : function(size) {
|
|
||||||
return St.TextureCache.get_default().load_recent_thumbnail(size, this.recentInfo);
|
|
||||||
},
|
|
||||||
|
|
||||||
launch : function(workspaceIndex) {
|
|
||||||
Shell.DocSystem.get_default().open(this.recentInfo, workspaceIndex);
|
|
||||||
},
|
|
||||||
|
|
||||||
matchTerms: function(terms) {
|
|
||||||
let mtype = Search.MatchType.NONE;
|
|
||||||
for (let i = 0; i < terms.length; i++) {
|
|
||||||
let term = terms[i];
|
|
||||||
let idx = this._lowerName.indexOf(term);
|
|
||||||
if (idx == 0) {
|
|
||||||
mtype = Search.MatchType.PREFIX;
|
|
||||||
} else if (idx > 0) {
|
|
||||||
if (mtype == Search.MatchType.NONE)
|
|
||||||
mtype = Search.MatchType.SUBSTRING;
|
|
||||||
} else {
|
|
||||||
return Search.MatchType.NONE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mtype;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
var docManagerInstance = null;
|
|
||||||
|
|
||||||
function getDocManager() {
|
|
||||||
if (docManagerInstance == null)
|
|
||||||
docManagerInstance = new DocManager();
|
|
||||||
return docManagerInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* DocManager wraps the DocSystem, primarily to expose DocInfo objects.
|
|
||||||
*/
|
|
||||||
const DocManager = new Lang.Class({
|
|
||||||
Name: 'DocManager',
|
|
||||||
|
|
||||||
_init: function() {
|
|
||||||
this._docSystem = Shell.DocSystem.get_default();
|
|
||||||
this._infosByTimestamp = [];
|
|
||||||
this._infosByUri = {};
|
|
||||||
this._docSystem.connect('changed', Lang.bind(this, this._reload));
|
|
||||||
this._reload();
|
|
||||||
},
|
|
||||||
|
|
||||||
_reload: function() {
|
|
||||||
let docs = this._docSystem.get_all();
|
|
||||||
this._infosByTimestamp = [];
|
|
||||||
this._infosByUri = {};
|
|
||||||
for (let i = 0; i < docs.length; i++) {
|
|
||||||
let recentInfo = docs[i];
|
|
||||||
|
|
||||||
let docInfo = new DocInfo(recentInfo);
|
|
||||||
this._infosByTimestamp.push(docInfo);
|
|
||||||
this._infosByUri[docInfo.uri] = docInfo;
|
|
||||||
}
|
|
||||||
this.emit('changed');
|
|
||||||
},
|
|
||||||
|
|
||||||
getTimestampOrderedInfos: function() {
|
|
||||||
return this._infosByTimestamp;
|
|
||||||
},
|
|
||||||
|
|
||||||
getInfosByUri: function() {
|
|
||||||
return this._infosByUri;
|
|
||||||
},
|
|
||||||
|
|
||||||
lookupByUri: function(uri) {
|
|
||||||
return this._infosByUri[uri];
|
|
||||||
},
|
|
||||||
|
|
||||||
queueExistenceCheck: function(count) {
|
|
||||||
return this._docSystem.queue_existence_check(count);
|
|
||||||
},
|
|
||||||
|
|
||||||
_searchDocs: function(items, terms) {
|
|
||||||
let multiplePrefixMatches = [];
|
|
||||||
let prefixMatches = [];
|
|
||||||
let multipleSubtringMatches = [];
|
|
||||||
let substringMatches = [];
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
|
||||||
let item = items[i];
|
|
||||||
let mtype = item.matchTerms(terms);
|
|
||||||
if (mtype == Search.MatchType.MULTIPLE_PREFIX)
|
|
||||||
multiplePrefixMatches.push(item.uri);
|
|
||||||
else if (mtype == Search.MatchType.PREFIX)
|
|
||||||
prefixMatches.push(item.uri);
|
|
||||||
else if (mtype == Search.MatchType.MULTIPLE_SUBSTRING)
|
|
||||||
multipleSubtringMatches.push(item.uri);
|
|
||||||
else if (mtype == Search.MatchType.SUBSTRING)
|
|
||||||
substringMatches.push(item.uri);
|
|
||||||
}
|
|
||||||
return multiplePrefixMatches.concat(prefixMatches.concat(multipleSubtringMatches.concat(substringMatches)));
|
|
||||||
},
|
|
||||||
|
|
||||||
initialSearch: function(terms) {
|
|
||||||
return this._searchDocs(this._infosByTimestamp, terms);
|
|
||||||
},
|
|
||||||
|
|
||||||
subsearch: function(previousResults, terms) {
|
|
||||||
return this._searchDocs(previousResults.map(Lang.bind(this,
|
|
||||||
function(url) {
|
|
||||||
return this._infosByUri[url];
|
|
||||||
})), terms);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Signals.addSignalMethods(DocManager.prototype);
|
|
194
js/misc/extensionUtils.js
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
// Common utils for the extension system and the extension
|
||||||
|
// preferences tool
|
||||||
|
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const ShellJS = imports.gi.ShellJS;
|
||||||
|
|
||||||
|
const Config = imports.misc.config;
|
||||||
|
|
||||||
|
const ExtensionType = {
|
||||||
|
SYSTEM: 1,
|
||||||
|
PER_USER: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// GFile for user extensions
|
||||||
|
var userExtensionsDir = null;
|
||||||
|
|
||||||
|
// Maps uuid -> metadata object
|
||||||
|
const extensions = {};
|
||||||
|
|
||||||
|
function getCurrentExtension() {
|
||||||
|
let stack = (new Error()).stack;
|
||||||
|
|
||||||
|
// Assuming we're importing this directly from an extension (and we shouldn't
|
||||||
|
// ever not be), its UUID should be directly in the path here.
|
||||||
|
let extensionStackLine = stack.split('\n')[1];
|
||||||
|
if (!extensionStackLine)
|
||||||
|
throw new Error('Could not find current extension');
|
||||||
|
|
||||||
|
// The stack line is like:
|
||||||
|
// init([object Object])@/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
||||||
|
//
|
||||||
|
// In the case that we're importing from
|
||||||
|
// module scope, the first field is blank:
|
||||||
|
// @/home/user/data/gnome-shell/extensions/u@u.id/prefs.js:8
|
||||||
|
let match = new RegExp('@(.+):\\d+').exec(extensionStackLine);
|
||||||
|
if (!match)
|
||||||
|
throw new Error('Could not find current extension');
|
||||||
|
|
||||||
|
let path = match[1];
|
||||||
|
let uuid = GLib.path_get_basename(GLib.path_get_dirname(path));
|
||||||
|
|
||||||
|
let extension = extensions[uuid];
|
||||||
|
if (extension === undefined)
|
||||||
|
throw new Error('Could not find current extension');
|
||||||
|
|
||||||
|
return extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* versionCheck:
|
||||||
|
* @required: an array of versions we're compatible with
|
||||||
|
* @current: the version we have
|
||||||
|
*
|
||||||
|
* Check if a component is compatible for an extension.
|
||||||
|
* @required is an array, and at least one version must match.
|
||||||
|
* @current must be in the format <major>.<minor>.<point>.<micro>
|
||||||
|
* <micro> is always ignored
|
||||||
|
* <point> is ignored if <minor> is even (so you can target the
|
||||||
|
* whole stable release)
|
||||||
|
* <minor> and <major> must match
|
||||||
|
* Each target version must be at least <major> and <minor>
|
||||||
|
*/
|
||||||
|
function versionCheck(required, current) {
|
||||||
|
let currentArray = current.split('.');
|
||||||
|
let major = currentArray[0];
|
||||||
|
let minor = currentArray[1];
|
||||||
|
let point = currentArray[2];
|
||||||
|
for (let i = 0; i < required.length; i++) {
|
||||||
|
let requiredArray = required[i].split('.');
|
||||||
|
if (requiredArray[0] == major &&
|
||||||
|
requiredArray[1] == minor &&
|
||||||
|
(requiredArray[2] == point ||
|
||||||
|
(requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isOutOfDate(extension) {
|
||||||
|
if (!versionCheck(extension.metadata['shell-version'], Config.PACKAGE_VERSION))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (extension.metadata['js-version'] && !versionCheck(extension.metadata['js-version'], Config.GJS_VERSION))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createExtensionObject(uuid, dir, type) {
|
||||||
|
let info;
|
||||||
|
|
||||||
|
let metadataFile = dir.get_child('metadata.json');
|
||||||
|
if (!metadataFile.query_exists(null)) {
|
||||||
|
throw new Error('Missing metadata.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
let metadataContents, success, tag;
|
||||||
|
try {
|
||||||
|
[success, metadataContents, tag] = metadataFile.load_contents(null);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Failed to load metadata.json: ' + e);
|
||||||
|
}
|
||||||
|
let meta;
|
||||||
|
try {
|
||||||
|
meta = JSON.parse(metadataContents);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('Failed to parse metadata.json: ' + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
|
||||||
|
for (let i = 0; i < requiredProperties.length; i++) {
|
||||||
|
let prop = requiredProperties[i];
|
||||||
|
if (!meta[prop]) {
|
||||||
|
throw new Error('missing "' + prop + '" property in metadata.json');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encourage people to add this
|
||||||
|
if (!meta.url) {
|
||||||
|
global.log('Warning: Missing "url" property in metadata.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uuid != meta.uuid) {
|
||||||
|
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
||||||
|
}
|
||||||
|
|
||||||
|
let extension = {};
|
||||||
|
|
||||||
|
extension.metadata = meta;
|
||||||
|
extension.uuid = meta.uuid;
|
||||||
|
extension.type = type;
|
||||||
|
extension.dir = dir;
|
||||||
|
extension.path = dir.get_path();
|
||||||
|
extension.error = '';
|
||||||
|
extension.hasPrefs = dir.get_child('prefs.js').query_exists(null);
|
||||||
|
|
||||||
|
extensions[uuid] = extension;
|
||||||
|
|
||||||
|
return extension;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _extension = null;
|
||||||
|
|
||||||
|
function installImporter(extension) {
|
||||||
|
_extension = extension;
|
||||||
|
ShellJS.add_extension_importer('imports.misc.extensionUtils._extension', 'imports', extension.path);
|
||||||
|
_extension = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
|
||||||
|
userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
|
||||||
|
try {
|
||||||
|
if (!userExtensionsDir.query_exists(null))
|
||||||
|
userExtensionsDir.make_directory_with_parents(null);
|
||||||
|
} catch (e) {
|
||||||
|
global.logError('' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function scanExtensionsInDirectory(callback, dir, type) {
|
||||||
|
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)
|
||||||
|
continue;
|
||||||
|
let uuid = info.get_name();
|
||||||
|
let extensionDir = dir.get_child(uuid);
|
||||||
|
callback(uuid, extensionDir, type);
|
||||||
|
}
|
||||||
|
fileEnum.close(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scanExtensions(callback) {
|
||||||
|
let systemDataDirs = GLib.get_system_data_dirs();
|
||||||
|
scanExtensionsInDirectory(callback, userExtensionsDir, ExtensionType.PER_USER);
|
||||||
|
for (let i = 0; i < systemDataDirs.length; i++) {
|
||||||
|
let dirPath = GLib.build_filenamev([systemDataDirs[i], 'gnome-shell', 'extensions']);
|
||||||
|
let dir = Gio.file_new_for_path(dirPath);
|
||||||
|
if (dir.query_exists(null))
|
||||||
|
scanExtensionsInDirectory(callback, dir, ExtensionType.SYSTEM);
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,7 @@ function recursivelyDeleteDir(dir) {
|
|||||||
let child = dir.get_child(info.get_name());
|
let child = dir.get_child(info.get_name());
|
||||||
if (type == Gio.FileType.REGULAR)
|
if (type == Gio.FileType.REGULAR)
|
||||||
deleteGFile(child);
|
deleteGFile(child);
|
||||||
else if (type == Gio.TypeType.DIRECTORY)
|
else if (type == Gio.FileType.DIRECTORY)
|
||||||
recursivelyDeleteDir(child);
|
recursivelyDeleteDir(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const ShellJS = imports.gi.ShellJS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This function is intended to extend the String object and provide
|
* This function is intended to extend the String object and provide
|
||||||
* an String.format API for string formatting.
|
* an String.format API for string formatting.
|
||||||
@ -17,11 +19,16 @@ function format() {
|
|||||||
let i = 0;
|
let i = 0;
|
||||||
let args = arguments;
|
let args = arguments;
|
||||||
|
|
||||||
return str.replace(/%([0-9]+)?(?:\.([0-9]+))?(.)/g, function (str, widthGroup, precisionGroup, genericGroup) {
|
return str.replace(/%(I+)?([0-9]+)?(?:\.([0-9]+))?(.)/g, function (str, flagsGroup, widthGroup, precisionGroup, genericGroup) {
|
||||||
|
|
||||||
if (precisionGroup != '' && genericGroup != 'f')
|
if (precisionGroup != '' && genericGroup != 'f')
|
||||||
throw new Error("Precision can only be specified for 'f'");
|
throw new Error("Precision can only be specified for 'f'");
|
||||||
|
|
||||||
|
let hasAlternativeIntFlag = (flagsGroup.indexOf('I') != -1);
|
||||||
|
|
||||||
|
if (hasAlternativeIntFlag && genericGroup != 'd')
|
||||||
|
throw new Error("Alternative output digits can only be specfied for 'd'");
|
||||||
|
|
||||||
let fillChar = (widthGroup[0] == '0') ? '0' : ' ';
|
let fillChar = (widthGroup[0] == '0') ? '0' : ' ';
|
||||||
let width = parseInt(widthGroup, 10) || 0;
|
let width = parseInt(widthGroup, 10) || 0;
|
||||||
|
|
||||||
@ -41,7 +48,11 @@ function format() {
|
|||||||
s = args[i++].toString();
|
s = args[i++].toString();
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
s = parseInt(args[i++]).toString();
|
let intV = parseInt(args[i++]);
|
||||||
|
if (hasAlternativeIntFlag)
|
||||||
|
s = ShellJS.format_int_alternative_output(intV);
|
||||||
|
else
|
||||||
|
s = intV.toString();
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
s = parseInt(args[i++]).toString(16);
|
s = parseInt(args[i++]).toString(16);
|
||||||
|
@ -31,12 +31,12 @@ function Presence(initCallback, cancellable) {
|
|||||||
// change at runtime (changes always come in the form
|
// change at runtime (changes always come in the form
|
||||||
// of new inhibitors)
|
// of new inhibitors)
|
||||||
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
|
const InhibitorIface = <interface name="org.gnome.SessionManager.Inhibitor">
|
||||||
<property name="app_id" type="s" access="read" />
|
<method name="GetAppId">
|
||||||
<property name="client_id" type="s" access="read" />
|
<arg type="s" direction="out" />
|
||||||
<property name="reason" type="s" access="read" />
|
</method>
|
||||||
<property name="flags" type="u" access="read" />
|
<method name="GetReason">
|
||||||
<property name="toplevel_xid" type="u" access="read" />
|
<arg type="s" direction="out" />
|
||||||
<property name="cookie" type="u" access="read" />
|
</method>
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
|
var InhibitorProxy = Gio.DBusProxy.makeProxyWrapper(InhibitorIface);
|
||||||
|
@ -10,9 +10,7 @@ const Signals = imports.signals;
|
|||||||
|
|
||||||
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
|
const ModemGsmNetworkInterface = <interface name="org.freedesktop.ModemManager.Modem.Gsm.Network">
|
||||||
<method name="GetRegistrationInfo">
|
<method name="GetRegistrationInfo">
|
||||||
<arg type="u" direction="out" />
|
<arg type="(uss)" direction="out" />
|
||||||
<arg type="s" direction="out" />
|
|
||||||
<arg type="s" direction="out" />
|
|
||||||
</method>
|
</method>
|
||||||
<method name="GetSignalQuality">
|
<method name="GetSignalQuality">
|
||||||
<arg type="u" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
@ -35,9 +33,7 @@ const ModemCdmaInterface = <interface name="org.freedesktop.ModemManager.Modem.C
|
|||||||
<arg type="u" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
</method>
|
</method>
|
||||||
<method name="GetServingSystem">
|
<method name="GetServingSystem">
|
||||||
<arg type="u" direction="out" />
|
<arg type="(usu)" direction="out" />
|
||||||
<arg type="s" direction="out" />
|
|
||||||
<arg type="u" direction="out" />
|
|
||||||
</method>
|
</method>
|
||||||
<signal name="SignalQuality">
|
<signal name="SignalQuality">
|
||||||
<arg type="u" direction="out" />
|
<arg type="u" direction="out" />
|
||||||
@ -72,7 +68,7 @@ const ModemGsm = new Lang.Class({
|
|||||||
this.operator_name = this._findOperatorName(name, code);
|
this.operator_name = this._findOperatorName(name, code);
|
||||||
this.emit('notify::operator-name');
|
this.emit('notify::operator-name');
|
||||||
}));
|
}));
|
||||||
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function(result, err) {
|
this._proxy.GetRegistrationInfoRemote(Lang.bind(this, function([result], err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log(err);
|
log(err);
|
||||||
return;
|
return;
|
||||||
@ -165,7 +161,7 @@ const ModemCdma = new Lang.Class({
|
|||||||
|
|
||||||
this.signal_quality = 0;
|
this.signal_quality = 0;
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
this._proxy.connect('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
|
this._proxy.connectSignal('SignalQuality', Lang.bind(this, function(proxy, sender, params) {
|
||||||
this.signal_quality = params[0];
|
this.signal_quality = params[0];
|
||||||
this.emit('notify::signal-quality');
|
this.emit('notify::signal-quality');
|
||||||
|
|
||||||
@ -187,7 +183,7 @@ const ModemCdma = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_refreshServingSystem: function() {
|
_refreshServingSystem: function() {
|
||||||
this._proxy.GetServingSystemRemote(Lang.bind(this, function(result, err) {
|
this._proxy.GetServingSystemRemote(Lang.bind(this, function([result], err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
// it will return an error if the device is not connected
|
// it will return an error if the device is not connected
|
||||||
this.operator_name = null;
|
this.operator_name = null;
|
||||||
|
@ -232,3 +232,53 @@ function fixupPCIDescription(desc) {
|
|||||||
|
|
||||||
return out.join(' ');
|
return out.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lowerBound:
|
||||||
|
// @array: an array or array-like object, already sorted
|
||||||
|
// according to @cmp
|
||||||
|
// @val: the value to add
|
||||||
|
// @cmp: a comparator (or undefined to compare as numbers)
|
||||||
|
//
|
||||||
|
// Returns the position of the first element that is not
|
||||||
|
// lower than @val, according to @cmp.
|
||||||
|
// That is, returns the first position at which it
|
||||||
|
// is possible to insert @val without violating the
|
||||||
|
// order.
|
||||||
|
// This is quite like an ordinary binary search, except
|
||||||
|
// that it doesn't stop at first element comparing equal.
|
||||||
|
|
||||||
|
function lowerBound(array, val, cmp) {
|
||||||
|
let min, max, mid, v;
|
||||||
|
cmp = cmp || function(a, b) { return a - b; };
|
||||||
|
|
||||||
|
if (array.length == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
min = 0; max = array.length;
|
||||||
|
while (min < (max - 1)) {
|
||||||
|
mid = Math.floor((min + max) / 2);
|
||||||
|
v = cmp(array[mid], val);
|
||||||
|
|
||||||
|
if (v < 0)
|
||||||
|
min = mid + 1;
|
||||||
|
else
|
||||||
|
max = mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (min == max || cmp(array[min], val) < 0) ? max : min;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insertSorted:
|
||||||
|
// @array: an array sorted according to @cmp
|
||||||
|
// @val: a value to insert
|
||||||
|
// @cmp: the sorting function
|
||||||
|
//
|
||||||
|
// Inserts @val into @array, preserving the
|
||||||
|
// sorting invariants.
|
||||||
|
// Returns the position at which it was inserted
|
||||||
|
function insertSorted(array, val, cmp) {
|
||||||
|
let pos = lowerBound(array, val, cmp);
|
||||||
|
array.splice(pos, 0, val);
|
||||||
|
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
140
js/ui/altTab.js
@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gdk = imports.gi.Gdk;
|
const Gdk = imports.gi.Gdk;
|
||||||
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
@ -125,7 +127,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
if (childBox.x2 > primary.x + primary.width - rightPadding)
|
if (childBox.x2 > primary.x + primary.width - rightPadding)
|
||||||
childBox.x2 = primary.x + primary.width - rightPadding;
|
childBox.x2 = primary.x + primary.width - rightPadding;
|
||||||
childBox.y1 = this._appSwitcher.actor.allocation.y2 + spacing;
|
childBox.y1 = this._appSwitcher.actor.allocation.y2 + spacing;
|
||||||
this._thumbnails.addClones(primary.height - bottomPadding - childBox.y1);
|
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
|
||||||
let [childMinHeight, childNaturalHeight] = this._thumbnails.actor.get_preferred_height(-1);
|
let [childMinHeight, childNaturalHeight] = this._thumbnails.actor.get_preferred_height(-1);
|
||||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||||
this._thumbnails.actor.allocate(childBox, flags);
|
this._thumbnails.actor.allocate(childBox, flags);
|
||||||
@ -139,7 +141,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
|
|
||||||
let screen = global.screen;
|
let screen = global.screen;
|
||||||
let display = screen.get_display();
|
let display = screen.get_display();
|
||||||
let windows = display.get_tab_list(Meta.TabList.NORMAL, screen,
|
let windows = display.get_tab_list(Meta.TabList.NORMAL_ALL, screen,
|
||||||
screen.get_active_workspace());
|
screen.get_active_workspace());
|
||||||
|
|
||||||
// windows is only the windows on the current workspace. For
|
// windows is only the windows on the current workspace. For
|
||||||
@ -264,7 +266,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
|
|
||||||
_keyPressEvent : function(actor, event) {
|
_keyPressEvent : function(actor, event) {
|
||||||
let keysym = event.get_key_symbol();
|
let keysym = event.get_key_symbol();
|
||||||
let event_state = Shell.get_event_state(event);
|
let event_state = event.get_state();
|
||||||
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
|
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
|
||||||
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
|
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
|
||||||
|
|
||||||
@ -517,6 +519,7 @@ const AltTabPopup = new Lang.Class({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
this._thumbnails = null;
|
this._thumbnails = null;
|
||||||
|
this._appSwitcher._items[this._currentApp].remove_accessible_state (Atk.StateType.EXPANDED);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createThumbnails : function() {
|
_createThumbnails : function() {
|
||||||
@ -537,6 +540,8 @@ const AltTabPopup = new Lang.Class({
|
|||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
|
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._appSwitcher._items[this._currentApp].add_accessible_state (Atk.StateType.EXPANDED);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -561,14 +566,14 @@ const SwitcherList = new Lang.Class({
|
|||||||
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this._list.connect('allocate', Lang.bind(this, this._allocate));
|
this._list.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
|
|
||||||
this._clipBin = new St.Bin({style_class: 'cbin'});
|
this._scrollView = new St.ScrollView({ style_class: 'hfade',
|
||||||
this._clipBin.child = this._list;
|
enable_mouse_scrolling: false });
|
||||||
this.actor.add_actor(this._clipBin);
|
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.NEVER);
|
||||||
|
|
||||||
this._leftGradient = new St.BoxLayout({style_class: 'thumbnail-scroll-gradient-left', vertical: true});
|
let scrollBox = new St.BoxLayout();
|
||||||
this._rightGradient = new St.BoxLayout({style_class: 'thumbnail-scroll-gradient-right', vertical: true});
|
scrollBox.add_actor(this._list);
|
||||||
this.actor.add_actor(this._leftGradient);
|
this._scrollView.add_actor(scrollBox);
|
||||||
this.actor.add_actor(this._rightGradient);
|
this.actor.add_actor(this._scrollView);
|
||||||
|
|
||||||
// Those arrows indicate whether scrolling in one direction is possible
|
// Those arrows indicate whether scrolling in one direction is possible
|
||||||
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
|
this._leftArrow = new St.DrawingArea({ style_class: 'switcher-arrow',
|
||||||
@ -599,21 +604,9 @@ const SwitcherList = new Lang.Class({
|
|||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
let scrollable = this._minSize > box.x2 - box.x1;
|
let scrollable = this._minSize > box.x2 - box.x1;
|
||||||
|
|
||||||
this._clipBin.allocate(box, flags);
|
box.y1 -= this.actor.get_theme_node().get_padding(St.Side.TOP);
|
||||||
|
box.y2 += this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
|
||||||
childBox.x1 = 0;
|
this._scrollView.allocate(box, flags);
|
||||||
childBox.y1 = 0;
|
|
||||||
childBox.x2 = this._leftGradient.width;
|
|
||||||
childBox.y2 = this.actor.height;
|
|
||||||
this._leftGradient.allocate(childBox, flags);
|
|
||||||
this._leftGradient.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
|
|
||||||
|
|
||||||
childBox.x1 = (this.actor.allocation.x2 - this.actor.allocation.x1) - this._rightGradient.width;
|
|
||||||
childBox.y1 = 0;
|
|
||||||
childBox.x2 = childBox.x1 + this._rightGradient.width;
|
|
||||||
childBox.y2 = this.actor.height;
|
|
||||||
this._rightGradient.allocate(childBox, flags);
|
|
||||||
this._rightGradient.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
|
|
||||||
|
|
||||||
let arrowWidth = Math.floor(leftPadding / 3);
|
let arrowWidth = Math.floor(leftPadding / 3);
|
||||||
let arrowHeight = arrowWidth * 2;
|
let arrowHeight = arrowWidth * 2;
|
||||||
@ -622,7 +615,7 @@ const SwitcherList = new Lang.Class({
|
|||||||
childBox.x2 = childBox.x1 + arrowWidth;
|
childBox.x2 = childBox.x1 + arrowWidth;
|
||||||
childBox.y2 = childBox.y1 + arrowHeight;
|
childBox.y2 = childBox.y1 + arrowHeight;
|
||||||
this._leftArrow.allocate(childBox, flags);
|
this._leftArrow.allocate(childBox, flags);
|
||||||
this._leftArrow.opacity = this._leftGradient.opacity;
|
this._leftArrow.opacity = (this._scrollableLeft && scrollable) ? 255 : 0;
|
||||||
|
|
||||||
arrowWidth = Math.floor(rightPadding / 3);
|
arrowWidth = Math.floor(rightPadding / 3);
|
||||||
arrowHeight = arrowWidth * 2;
|
arrowHeight = arrowWidth * 2;
|
||||||
@ -631,7 +624,7 @@ const SwitcherList = new Lang.Class({
|
|||||||
childBox.x2 = childBox.x1 + arrowWidth;
|
childBox.x2 = childBox.x1 + arrowWidth;
|
||||||
childBox.y2 = childBox.y1 + arrowHeight;
|
childBox.y2 = childBox.y1 + arrowHeight;
|
||||||
this._rightArrow.allocate(childBox, flags);
|
this._rightArrow.allocate(childBox, flags);
|
||||||
this._rightArrow.opacity = this._rightGradient.opacity;
|
this._rightArrow.opacity = (this._scrollableRight && scrollable) ? 255 : 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
addItem : function(item, label) {
|
addItem : function(item, label) {
|
||||||
@ -648,6 +641,8 @@ const SwitcherList = new Lang.Class({
|
|||||||
bbox.label_actor = label;
|
bbox.label_actor = label;
|
||||||
|
|
||||||
this._items.push(bbox);
|
this._items.push(bbox);
|
||||||
|
|
||||||
|
return bbox;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onItemClicked: function (index) {
|
_onItemClicked: function (index) {
|
||||||
@ -679,47 +674,66 @@ const SwitcherList = new Lang.Class({
|
|||||||
this._items[this._highlighted].add_style_pseudo_class('selected');
|
this._items[this._highlighted].add_style_pseudo_class('selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let adjustment = this._scrollView.hscroll.adjustment;
|
||||||
|
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
||||||
let [absItemX, absItemY] = this._items[index].get_transformed_position();
|
let [absItemX, absItemY] = this._items[index].get_transformed_position();
|
||||||
let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
|
let [result, posX, posY] = this.actor.transform_stage_point(absItemX, 0);
|
||||||
let [containerWidth, containerHeight] = this.actor.get_transformed_size();
|
let [containerWidth, containerHeight] = this.actor.get_transformed_size();
|
||||||
if (posX + this._items[index].get_width() > containerWidth)
|
if (posX + this._items[index].get_width() > containerWidth)
|
||||||
this._scrollToRight();
|
this._scrollToRight();
|
||||||
else if (posX < 0)
|
else if (this._items[index].allocation.x1 - value < 0)
|
||||||
this._scrollToLeft();
|
this._scrollToLeft();
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_scrollToLeft : function() {
|
_scrollToLeft : function() {
|
||||||
let x = this._items[this._highlighted].allocation.x1;
|
let adjustment = this._scrollView.hscroll.adjustment;
|
||||||
|
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
||||||
|
|
||||||
|
let item = this._items[this._highlighted];
|
||||||
|
|
||||||
|
if (item.allocation.x1 < value)
|
||||||
|
value = Math.min(0, item.allocation.x1);
|
||||||
|
else if (item.allocation.x2 > value + pageSize)
|
||||||
|
value = Math.max(upper, item.allocation.x2 - pageSize);
|
||||||
|
|
||||||
this._scrollableRight = true;
|
this._scrollableRight = true;
|
||||||
Tweener.addTween(this._list, { anchor_x: x,
|
Tweener.addTween(adjustment,
|
||||||
time: POPUP_SCROLL_TIME,
|
{ value: value,
|
||||||
transition: 'easeOutQuad',
|
time: POPUP_SCROLL_TIME,
|
||||||
onComplete: Lang.bind(this, function () {
|
transition: 'easeOutQuad',
|
||||||
if (this._highlighted == 0) {
|
onComplete: Lang.bind(this, function () {
|
||||||
this._scrollableLeft = false;
|
if (this._highlighted == 0) {
|
||||||
this.actor.queue_relayout();
|
this._scrollableLeft = false;
|
||||||
}
|
this.actor.queue_relayout();
|
||||||
})
|
}
|
||||||
});
|
})
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_scrollToRight : function() {
|
_scrollToRight : function() {
|
||||||
|
let adjustment = this._scrollView.hscroll.adjustment;
|
||||||
|
let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
|
||||||
|
|
||||||
|
let item = this._items[this._highlighted];
|
||||||
|
|
||||||
|
if (item.allocation.x1 < value)
|
||||||
|
value = Math.max(0, item.allocation.x1);
|
||||||
|
else if (item.allocation.x2 > value + pageSize)
|
||||||
|
value = Math.min(upper, item.allocation.x2 - pageSize);
|
||||||
|
|
||||||
this._scrollableLeft = true;
|
this._scrollableLeft = true;
|
||||||
let monitor = Main.layoutManager.primaryMonitor;
|
Tweener.addTween(adjustment,
|
||||||
let padding = this.actor.get_theme_node().get_horizontal_padding();
|
{ value: value,
|
||||||
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
|
time: POPUP_SCROLL_TIME,
|
||||||
let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding;
|
transition: 'easeOutQuad',
|
||||||
Tweener.addTween(this._list, { anchor_x: x,
|
onComplete: Lang.bind(this, function () {
|
||||||
time: POPUP_SCROLL_TIME,
|
if (this._highlighted == this._items.length - 1) {
|
||||||
transition: 'easeOutQuad',
|
this._scrollableRight = false;
|
||||||
onComplete: Lang.bind(this, function () {
|
this.actor.queue_relayout();
|
||||||
if (this._highlighted == this._items.length - 1) {
|
}
|
||||||
this._scrollableRight = false;
|
})
|
||||||
this.actor.queue_relayout();
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_itemActivated: function(n) {
|
_itemActivated: function(n) {
|
||||||
@ -805,14 +819,6 @@ const SwitcherList = new Lang.Class({
|
|||||||
|
|
||||||
let primary = Main.layoutManager.primaryMonitor;
|
let primary = Main.layoutManager.primaryMonitor;
|
||||||
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
|
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
|
||||||
if (this.actor.allocation.x2 == primary.x + primary.width - parentRightPadding) {
|
|
||||||
if (this._squareItems)
|
|
||||||
childWidth = childHeight;
|
|
||||||
else {
|
|
||||||
let [childMin, childNat] = children[0].get_preferred_width(childHeight);
|
|
||||||
childWidth = childMin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < children.length; i++) {
|
for (let i = 0; i < children.length; i++) {
|
||||||
if (this._items.indexOf(children[i]) != -1) {
|
if (this._items.indexOf(children[i]) != -1) {
|
||||||
@ -838,14 +844,6 @@ const SwitcherList = new Lang.Class({
|
|||||||
// we don't allocate it.
|
// we don't allocate it.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
|
|
||||||
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
|
|
||||||
let topPadding = this.actor.get_theme_node().get_padding(St.Side.TOP);
|
|
||||||
let bottomPadding = this.actor.get_theme_node().get_padding(St.Side.BOTTOM);
|
|
||||||
|
|
||||||
// Clip the area for scrolling
|
|
||||||
this._clipBin.set_clip(0, -topPadding, (this.actor.allocation.x2 - this.actor.allocation.x1) - leftPadding - rightPadding, this.actor.height + bottomPadding);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1025,7 +1023,7 @@ const AppSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
_addIcon : function(appIcon) {
|
_addIcon : function(appIcon) {
|
||||||
this.icons.push(appIcon);
|
this.icons.push(appIcon);
|
||||||
this.addItem(appIcon.actor, appIcon.label);
|
let item = this.addItem(appIcon.actor, appIcon.label);
|
||||||
|
|
||||||
let n = this._arrows.length;
|
let n = this._arrows.length;
|
||||||
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
||||||
@ -1035,6 +1033,8 @@ const AppSwitcher = new Lang.Class({
|
|||||||
|
|
||||||
if (appIcon.cachedWindows.length == 1)
|
if (appIcon.cachedWindows.length == 1)
|
||||||
arrow.hide();
|
arrow.hide();
|
||||||
|
else
|
||||||
|
item.add_accessible_state (Atk.StateType.EXPANDABLE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ const Signals = imports.signals;
|
|||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const AppFavorites = imports.ui.appFavorites;
|
const AppFavorites = imports.ui.appFavorites;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
@ -148,7 +149,9 @@ const ViewByCategories = new Lang.Class({
|
|||||||
this._categories = [];
|
this._categories = [];
|
||||||
this._apps = null;
|
this._apps = null;
|
||||||
|
|
||||||
this._categoryBox = new St.BoxLayout({ vertical: true, reactive: true });
|
this._categoryBox = new St.BoxLayout({ vertical: true,
|
||||||
|
reactive: true,
|
||||||
|
accessible_role: Atk.Role.LIST });
|
||||||
this._categoryScroll = new St.ScrollView({ x_fill: false,
|
this._categoryScroll = new St.ScrollView({ x_fill: false,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
style_class: 'vfade' });
|
style_class: 'vfade' });
|
||||||
@ -214,7 +217,8 @@ const ViewByCategories = new Lang.Class({
|
|||||||
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
|
let button = new St.Button({ label: GLib.markup_escape_text (name, -1),
|
||||||
style_class: 'app-filter',
|
style_class: 'app-filter',
|
||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
can_focus: true });
|
can_focus: true ,
|
||||||
|
accessible_role: Atk.Role.LIST_ITEM });
|
||||||
button.connect('clicked', Lang.bind(this, function() {
|
button.connect('clicked', Lang.bind(this, function() {
|
||||||
this._selectCategory(index);
|
this._selectCategory(index);
|
||||||
}));
|
}));
|
||||||
@ -236,7 +240,7 @@ const ViewByCategories = new Lang.Class({
|
|||||||
|
|
||||||
_removeAll: function() {
|
_removeAll: function() {
|
||||||
this._categories = [];
|
this._categories = [];
|
||||||
this._categoryBox.destroy_children();
|
this._categoryBox.destroy_all_children();
|
||||||
},
|
},
|
||||||
|
|
||||||
refresh: function() {
|
refresh: function() {
|
||||||
@ -312,13 +316,18 @@ const AppSearchProvider = new Lang.Class({
|
|||||||
this._appSys = Shell.AppSystem.get_default();
|
this._appSys = Shell.AppSystem.get_default();
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMeta: function(app) {
|
getResultMetas: function(apps) {
|
||||||
return { 'id': app,
|
let metas = [];
|
||||||
'name': app.get_name(),
|
for (let i = 0; i < apps.length; i++) {
|
||||||
'createIcon': function(size) {
|
let app = apps[i];
|
||||||
return app.create_icon_texture(size);
|
metas.push({ 'id': app,
|
||||||
}
|
'name': app.get_name(),
|
||||||
};
|
'createIcon': function(size) {
|
||||||
|
return app.create_icon_texture(size);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return metas;
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms) {
|
||||||
@ -334,7 +343,7 @@ const AppSearchProvider = new Lang.Class({
|
|||||||
timestamp: 0 });
|
timestamp: 0 });
|
||||||
|
|
||||||
let event = Clutter.get_current_event();
|
let event = Clutter.get_current_event();
|
||||||
let modifiers = event ? Shell.get_event_state(event) : 0;
|
let modifiers = event ? event.get_state() : 0;
|
||||||
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
|
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
|
||||||
|
|
||||||
if (openNewWindow)
|
if (openNewWindow)
|
||||||
@ -369,13 +378,18 @@ const SettingsSearchProvider = new Lang.Class({
|
|||||||
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
|
this._gnomecc = this._appSys.lookup_app('gnome-control-center.desktop');
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMeta: function(pref) {
|
getResultMetas: function(prefs) {
|
||||||
return { 'id': pref,
|
let metas = [];
|
||||||
'name': pref.get_name(),
|
for (let i = 0; i < prefs.length; i++) {
|
||||||
'createIcon': function(size) {
|
let pref = prefs[i];
|
||||||
return pref.create_icon_texture(size);
|
metas.push({ 'id': pref,
|
||||||
}
|
'name': pref.get_name(),
|
||||||
};
|
'createIcon': function(size) {
|
||||||
|
return pref.create_icon_texture(size);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return metas;
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms) {
|
||||||
@ -470,6 +484,7 @@ const AppWellIcon = new Lang.Class({
|
|||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
this._onStateChanged));
|
this._onStateChanged));
|
||||||
this._onStateChanged();
|
this._onStateChanged();
|
||||||
|
this.isMenuUp = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
@ -551,8 +566,8 @@ const AppWellIcon = new Lang.Class({
|
|||||||
this._menuManager.addMenu(this._menu);
|
this._menuManager.addMenu(this._menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isMenuUp = true;
|
||||||
this.actor.set_hover(true);
|
this.actor.set_hover(true);
|
||||||
this.actor.show_tooltip();
|
|
||||||
this._menu.popup();
|
this._menu.popup();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -568,11 +583,12 @@ const AppWellIcon = new Lang.Class({
|
|||||||
|
|
||||||
_onMenuPoppedDown: function() {
|
_onMenuPoppedDown: function() {
|
||||||
this.actor.sync_hover();
|
this.actor.sync_hover();
|
||||||
|
this.isMenuUp = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onActivate: function (event) {
|
_onActivate: function (event) {
|
||||||
this.emit('launching');
|
this.emit('launching');
|
||||||
let modifiers = Shell.get_event_state(event);
|
let modifiers = event.get_state();
|
||||||
|
|
||||||
if (this._onActivateOverride) {
|
if (this._onActivateOverride) {
|
||||||
this._onActivateOverride(event);
|
this._onActivateOverride(event);
|
||||||
@ -612,7 +628,7 @@ const AppIconMenu = new Lang.Class({
|
|||||||
|
|
||||||
_init: function(source) {
|
_init: function(source) {
|
||||||
let side = St.Side.LEFT;
|
let side = St.Side.LEFT;
|
||||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
side = St.Side.RIGHT;
|
side = St.Side.RIGHT;
|
||||||
|
|
||||||
this.parent(source.actor, 0.5, side);
|
this.parent(source.actor, 0.5, side);
|
||||||
|
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||||
const ScreenSaver = imports.misc.screenSaver;
|
const ScreenSaver = imports.misc.screenSaver;
|
||||||
@ -43,7 +45,7 @@ function ConsoleKitManager() {
|
|||||||
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
g_flags: (Gio.DBusProxyFlags.DO_NOT_AUTO_START |
|
||||||
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES) });
|
||||||
|
|
||||||
self.connect('notify::g-name-owner', function() {
|
self._updateSessionActive = function() {
|
||||||
if (self.g_name_owner) {
|
if (self.g_name_owner) {
|
||||||
self.GetCurrentSessionRemote(function([session]) {
|
self.GetCurrentSessionRemote(function([session]) {
|
||||||
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
|
self._ckSession = new ConsoleKitSessionProxy(Gio.DBus.system, 'org.freedesktop.ConsoleKit', session);
|
||||||
@ -58,12 +60,19 @@ function ConsoleKitManager() {
|
|||||||
} else {
|
} else {
|
||||||
self.sessionActive = true;
|
self.sessionActive = true;
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
self.connect('notify::g-name-owner',
|
||||||
|
Lang.bind(self, self._updateSessionActive));
|
||||||
|
|
||||||
|
self._updateSessionActive();
|
||||||
self.init(null);
|
self.init(null);
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function haveSystemd() {
|
||||||
|
return GLib.access("/sys/fs/cgroup/systemd", 0) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
const AutomountManager = new Lang.Class({
|
const AutomountManager = new Lang.Class({
|
||||||
Name: 'AutomountManager',
|
Name: 'AutomountManager',
|
||||||
|
|
||||||
@ -71,7 +80,8 @@ const AutomountManager = new Lang.Class({
|
|||||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||||
this._volumeQueue = [];
|
this._volumeQueue = [];
|
||||||
|
|
||||||
this.ckListener = new ConsoleKitManager();
|
if (!haveSystemd())
|
||||||
|
this.ckListener = new ConsoleKitManager();
|
||||||
|
|
||||||
this._ssProxy = new ScreenSaver.ScreenSaverProxy();
|
this._ssProxy = new ScreenSaver.ScreenSaverProxy();
|
||||||
this._ssProxy.connectSignal('ActiveChanged',
|
this._ssProxy.connectSignal('ActiveChanged',
|
||||||
@ -119,11 +129,22 @@ const AutomountManager = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isSessionActive: function() {
|
||||||
|
// Return whether the current session is active, using the
|
||||||
|
// right mechanism: either systemd if available or ConsoleKit
|
||||||
|
// as fallback.
|
||||||
|
|
||||||
|
if (haveSystemd())
|
||||||
|
return Shell.session_is_active_for_systemd();
|
||||||
|
|
||||||
|
return this.ckListener.sessionActive;
|
||||||
|
},
|
||||||
|
|
||||||
_onDriveConnected: function() {
|
_onDriveConnected: function() {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// or screensaver is active, don't play sounds
|
// or screensaver is active, don't play sounds
|
||||||
if (!this.ckListener.sessionActive)
|
if (!this.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this._ssProxy.screenSaverActive)
|
if (this._ssProxy.screenSaverActive)
|
||||||
return;
|
return;
|
||||||
@ -134,8 +155,8 @@ const AutomountManager = new Lang.Class({
|
|||||||
_onDriveDisconnected: function() {
|
_onDriveDisconnected: function() {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// or screensaver is active, don't play sounds
|
// or screensaver is active, don't play sounds
|
||||||
if (!this.ckListener.sessionActive)
|
if (!this.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this._ssProxy.screenSaverActive)
|
if (this._ssProxy.screenSaverActive)
|
||||||
return;
|
return;
|
||||||
@ -146,7 +167,7 @@ const AutomountManager = new Lang.Class({
|
|||||||
_onDriveEjectButton: function(monitor, drive) {
|
_onDriveEjectButton: function(monitor, drive) {
|
||||||
// TODO: this code path is not tested, as the GVfs volume monitor
|
// TODO: this code path is not tested, as the GVfs volume monitor
|
||||||
// doesn't emit this signal just yet.
|
// doesn't emit this signal just yet.
|
||||||
if (!this.ckListener.sessionActive)
|
if (!this.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// we force stop/eject in this case, so we don't have to pass a
|
// we force stop/eject in this case, so we don't have to pass a
|
||||||
@ -185,7 +206,7 @@ const AutomountManager = new Lang.Class({
|
|||||||
if (params.checkSession) {
|
if (params.checkSession) {
|
||||||
// if we're not in the current ConsoleKit session,
|
// if we're not in the current ConsoleKit session,
|
||||||
// don't attempt automount
|
// don't attempt automount
|
||||||
if (!this.ckListener.sessionActive)
|
if (!this.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (this._ssProxy.screenSaverActive) {
|
if (this._ssProxy.screenSaverActive) {
|
||||||
|
@ -174,7 +174,7 @@ const AutorunManager = new Lang.Class({
|
|||||||
_onMountAdded: function(monitor, mount) {
|
_onMountAdded: function(monitor, mount) {
|
||||||
// don't do anything if our session is not the currently
|
// don't do anything if our session is not the currently
|
||||||
// active one
|
// active one
|
||||||
if (!Main.automountManager.ckListener.sessionActive)
|
if (!Main.automountManager.isSessionActive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
||||||
@ -339,7 +339,7 @@ const AutorunResidentNotification = new Lang.Class({
|
|||||||
|
|
||||||
updateForMounts: function(mounts) {
|
updateForMounts: function(mounts) {
|
||||||
// remove all the layout content
|
// remove all the layout content
|
||||||
this._layout.destroy_children();
|
this._layout.destroy_all_children();
|
||||||
|
|
||||||
for (let idx = 0; idx < mounts.length; idx++) {
|
for (let idx = 0; idx < mounts.length; idx++) {
|
||||||
let element = mounts[idx];
|
let element = mounts[idx];
|
||||||
@ -557,7 +557,7 @@ const AutorunTransientNotification = new Lang.Class({
|
|||||||
|
|
||||||
let label = new St.Bin({ y_align: St.Align.MIDDLE,
|
let label = new St.Bin({ y_align: St.Align.MIDDLE,
|
||||||
child: new St.Label
|
child: new St.Label
|
||||||
({ text: _("Open with %s").format(app.get_display_name()) })
|
({ text: _("Open with %s").format(app.get_name()) })
|
||||||
});
|
});
|
||||||
box.add(label);
|
box.add(label);
|
||||||
|
|
||||||
|
@ -45,6 +45,21 @@ const BoxPointer = new Lang.Class({
|
|||||||
this._xPosition = 0;
|
this._xPosition = 0;
|
||||||
this._yPosition = 0;
|
this._yPosition = 0;
|
||||||
this._sourceAlignment = 0.5;
|
this._sourceAlignment = 0.5;
|
||||||
|
this._capturedEventId = 0;
|
||||||
|
this._muteInput();
|
||||||
|
},
|
||||||
|
|
||||||
|
_muteInput: function() {
|
||||||
|
if (this._capturedEventId == 0)
|
||||||
|
this._capturedEventId = this.actor.connect('captured-event',
|
||||||
|
function() { return true; });
|
||||||
|
},
|
||||||
|
|
||||||
|
_unmuteInput: function() {
|
||||||
|
if (this._capturedEventId != 0) {
|
||||||
|
this.actor.disconnect(this._capturedEventId);
|
||||||
|
this._capturedEventId = 0;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function(animate, onComplete) {
|
show: function(animate, onComplete) {
|
||||||
@ -75,7 +90,11 @@ const BoxPointer = new Lang.Class({
|
|||||||
xOffset: 0,
|
xOffset: 0,
|
||||||
yOffset: 0,
|
yOffset: 0,
|
||||||
transition: 'linear',
|
transition: 'linear',
|
||||||
onComplete: onComplete,
|
onComplete: Lang.bind(this, function() {
|
||||||
|
this._unmuteInput();
|
||||||
|
if (onComplete)
|
||||||
|
onComplete();
|
||||||
|
}),
|
||||||
time: POPUP_ANIMATION_TIME });
|
time: POPUP_ANIMATION_TIME });
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -102,6 +121,8 @@ const BoxPointer = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._muteInput();
|
||||||
|
|
||||||
Tweener.addTween(this, { opacity: 0,
|
Tweener.addTween(this, { opacity: 0,
|
||||||
xOffset: xOffset,
|
xOffset: xOffset,
|
||||||
yOffset: yOffset,
|
yOffset: yOffset,
|
||||||
|
@ -406,7 +406,7 @@ const Calendar = new Lang.Class({
|
|||||||
|
|
||||||
_buildHeader: function() {
|
_buildHeader: function() {
|
||||||
let offsetCols = this._useWeekdate ? 1 : 0;
|
let offsetCols = this._useWeekdate ? 1 : 0;
|
||||||
this.actor.destroy_children();
|
this.actor.destroy_all_children();
|
||||||
|
|
||||||
// Top line of the calendar '<| September 2009 |>'
|
// Top line of the calendar '<| September 2009 |>'
|
||||||
this._topBox = new St.BoxLayout();
|
this._topBox = new St.BoxLayout();
|
||||||
@ -685,7 +685,7 @@ const EventsList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_showOtherDay: function(day) {
|
_showOtherDay: function(day) {
|
||||||
this.actor.destroy_children();
|
this.actor.destroy_all_children();
|
||||||
|
|
||||||
let dayBegin = _getBeginningOfDay(day);
|
let dayBegin = _getBeginningOfDay(day);
|
||||||
let dayEnd = _getEndOfDay(day);
|
let dayEnd = _getEndOfDay(day);
|
||||||
@ -702,7 +702,7 @@ const EventsList = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_showToday: function() {
|
_showToday: function() {
|
||||||
this.actor.destroy_children();
|
this.actor.destroy_all_children();
|
||||||
|
|
||||||
let now = new Date();
|
let now = new Date();
|
||||||
let dayBegin = _getBeginningOfDay(now);
|
let dayBegin = _getBeginningOfDay(now);
|
||||||
|
115
js/ui/checkBox.js
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
|
||||||
|
const CheckBoxContainer = new Lang.Class({
|
||||||
|
Name: 'CheckBoxContainer',
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.actor = new Shell.GenericContainer();
|
||||||
|
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('style-changed', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
let node = this.actor.get_theme_node();
|
||||||
|
this._spacing = node.get_length('spacing');
|
||||||
|
}));
|
||||||
|
this.actor.request_mode = Clutter.RequestMode.HEIGHT_FOR_WIDTH;
|
||||||
|
|
||||||
|
this._box = new St.Bin();
|
||||||
|
this.actor.add_actor(this._box);
|
||||||
|
|
||||||
|
this.label = new St.Label();
|
||||||
|
this.label.clutter_text.set_line_wrap(true);
|
||||||
|
this.label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
|
||||||
|
this.actor.add_actor(this.label);
|
||||||
|
|
||||||
|
this._spacing = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||||
|
let [minWidth, natWidth] = this._box.get_preferred_width(forHeight);
|
||||||
|
|
||||||
|
alloc.min_size = minWidth + this._spacing;
|
||||||
|
alloc.natural_size = natWidth + this._spacing;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||||
|
/* FIXME: StBoxlayout currently does not handle
|
||||||
|
height-for-width children correctly, so hard-code
|
||||||
|
two lines for the label until that problem is fixed.
|
||||||
|
|
||||||
|
https://bugzilla.gnome.org/show_bug.cgi?id=672543 */
|
||||||
|
/*
|
||||||
|
let [minBoxHeight, natBoxHeight] =
|
||||||
|
this._box.get_preferred_height(forWidth);
|
||||||
|
let [minLabelHeight, natLabelHeight] =
|
||||||
|
this.label.get_preferred_height(forWidth);
|
||||||
|
|
||||||
|
alloc.min_size = Math.max(minBoxHeight, minLabelHeight);
|
||||||
|
alloc.natural_size = Math.max(natBoxHeight, natLabelHeight);
|
||||||
|
*/
|
||||||
|
let [minBoxHeight, natBoxHeight] =
|
||||||
|
this._box.get_preferred_height(-1);
|
||||||
|
let [minLabelHeight, natLabelHeight] =
|
||||||
|
this.label.get_preferred_height(-1);
|
||||||
|
|
||||||
|
alloc.min_size = Math.max(minBoxHeight, 2 * minLabelHeight);
|
||||||
|
alloc.natural_size = Math.max(natBoxHeight, 2 * natLabelHeight);
|
||||||
|
},
|
||||||
|
|
||||||
|
_allocate: function(actor, box, flags) {
|
||||||
|
let availWidth = box.x2 - box.x1;
|
||||||
|
let availHeight = box.y2 - box.y1;
|
||||||
|
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
let [minBoxWidth, natBoxWidth] =
|
||||||
|
this._box.get_preferred_width(-1);
|
||||||
|
let [minBoxHeight, natBoxHeight] =
|
||||||
|
this._box.get_preferred_height(-1);
|
||||||
|
childBox.x1 = box.x1;
|
||||||
|
childBox.x2 = box.x1 + natBoxWidth;
|
||||||
|
childBox.y1 = box.y1;
|
||||||
|
childBox.y2 = box.y1 + natBoxHeight;
|
||||||
|
this._box.allocate(childBox, flags);
|
||||||
|
|
||||||
|
childBox.x1 = box.x1 + natBoxWidth + this._spacing;
|
||||||
|
childBox.x2 = availWidth - childBox.x1;
|
||||||
|
childBox.y1 = box.y1;
|
||||||
|
childBox.y2 = box.y2;
|
||||||
|
this.label.allocate(childBox, flags);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const CheckBox = new Lang.Class({
|
||||||
|
Name: 'CheckBox',
|
||||||
|
|
||||||
|
_init: function(label) {
|
||||||
|
this.actor = new St.Button({ style_class: 'check-box',
|
||||||
|
button_mask: St.ButtonMask.ONE,
|
||||||
|
toggle_mode: true,
|
||||||
|
can_focus: true,
|
||||||
|
x_fill: true,
|
||||||
|
y_fill: true });
|
||||||
|
this._container = new CheckBoxContainer();
|
||||||
|
this.actor.set_child(this._container.actor);
|
||||||
|
|
||||||
|
if (label)
|
||||||
|
this.setLabel(label);
|
||||||
|
},
|
||||||
|
|
||||||
|
setLabel: function(label) {
|
||||||
|
this._container.label.set_text(label);
|
||||||
|
},
|
||||||
|
|
||||||
|
getLabelActor: function() {
|
||||||
|
return this._container.label;
|
||||||
|
}
|
||||||
|
});
|
@ -5,6 +5,7 @@ const Lang = imports.lang;
|
|||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
@ -29,7 +30,9 @@ const Contact = new Lang.Class({
|
|||||||
|
|
||||||
this.actor = new St.Bin({ style_class: 'contact',
|
this.actor = new St.Bin({ style_class: 'contact',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
track_hover: true });
|
can_focus: true,
|
||||||
|
track_hover: true,
|
||||||
|
accessible_role: Atk.Role.PUSH_BUTTON });
|
||||||
|
|
||||||
let content = new St.BoxLayout( { style_class: 'contact-content',
|
let content = new St.BoxLayout( { style_class: 'contact-content',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
@ -68,6 +71,8 @@ const Contact = new Lang.Class({
|
|||||||
x_align: St.Align.START,
|
x_align: St.Align.START,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
this.actor.label_actor = aliasLabel;
|
||||||
|
|
||||||
let presence = this._createPresence(this.individual.presence_type);
|
let presence = this._createPresence(this.individual.presence_type);
|
||||||
details.add(presence, { x_fill: false,
|
details.add(presence, { x_fill: false,
|
||||||
y_fill: true,
|
y_fill: true,
|
||||||
@ -93,23 +98,30 @@ const Contact = new Lang.Class({
|
|||||||
text = _("Busy");
|
text = _("Busy");
|
||||||
iconName = 'user-busy';
|
iconName = 'user-busy';
|
||||||
break;
|
break;
|
||||||
default:
|
case Folks.PresenceType.OFFLINE:
|
||||||
text = _("Offline");
|
text = _("Offline");
|
||||||
iconName = 'user-offline';
|
iconName = 'user-offline';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
text = '';
|
||||||
|
iconName = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let icon = new St.Icon({ icon_name: iconName,
|
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
|
||||||
icon_size: 16,
|
|
||||||
style_class: 'contact-details-status-icon' });
|
|
||||||
let label = new St.Label({ text: text });
|
|
||||||
|
|
||||||
let box = new St.BoxLayout({ vertical: false,
|
let box = new St.BoxLayout({ vertical: false,
|
||||||
style_class: 'contact-details-status' });
|
style_class: 'contact-details-status' });
|
||||||
box.add(icon, { x_fill: true,
|
|
||||||
y_fill: false,
|
if (iconName) {
|
||||||
x_align: St.Align.START,
|
let icon = new St.Icon({ icon_name: iconName,
|
||||||
y_align: St.Align.START });
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: 16,
|
||||||
|
style_class: 'contact-details-status-icon' });
|
||||||
|
box.add(icon, { x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.START,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
}
|
||||||
|
|
||||||
|
let label = new St.Label({ text: text });
|
||||||
|
|
||||||
box.add(label, { x_fill: true,
|
box.add(label, { x_fill: true,
|
||||||
y_fill: false,
|
y_fill: false,
|
||||||
@ -142,14 +154,18 @@ const ContactSearchProvider = new Lang.Class({
|
|||||||
this._contactSys = Shell.ContactSystem.get_default();
|
this._contactSys = Shell.ContactSystem.get_default();
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMeta: function(id) {
|
getResultMetas: function(ids) {
|
||||||
let contact = new Contact(id);
|
let metas = [];
|
||||||
return { 'id': id,
|
for (let i = 0; i < ids.length; i++) {
|
||||||
'name': contact.alias,
|
let contact = new Contact(ids[i]);
|
||||||
'createIcon': function(size) {
|
metas.push({ 'id': ids[i],
|
||||||
return contact.createIcon(size);
|
'name': contact.alias,
|
||||||
}
|
'createIcon': function(size) {
|
||||||
};
|
return contact.createIcon(size);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return metas;
|
||||||
},
|
},
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
getInitialResultSet: function(terms) {
|
||||||
|
@ -233,7 +233,7 @@ const CtrlAltTabPopup = new Lang.Class({
|
|||||||
|
|
||||||
_keyPressEvent : function(actor, event) {
|
_keyPressEvent : function(actor, event) {
|
||||||
let keysym = event.get_key_symbol();
|
let keysym = event.get_key_symbol();
|
||||||
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
|
let shift = (event.get_state() & Clutter.ModifierType.SHIFT_MASK);
|
||||||
if (shift && keysym == Clutter.KEY_Tab)
|
if (shift && keysym == Clutter.KEY_Tab)
|
||||||
keysym = Clutter.ISO_Left_Tab;
|
keysym = Clutter.ISO_Left_Tab;
|
||||||
|
|
||||||
|
146
js/ui/dash.js
@ -6,6 +6,7 @@ const Lang = imports.lang;
|
|||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
|
|
||||||
const AppDisplay = imports.ui.appDisplay;
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
const AppFavorites = imports.ui.appFavorites;
|
const AppFavorites = imports.ui.appFavorites;
|
||||||
@ -16,6 +17,9 @@ const Tweener = imports.ui.tweener;
|
|||||||
const Workspace = imports.ui.workspace;
|
const Workspace = imports.ui.workspace;
|
||||||
|
|
||||||
const DASH_ANIMATION_TIME = 0.2;
|
const DASH_ANIMATION_TIME = 0.2;
|
||||||
|
const DASH_ITEM_LABEL_SHOW_TIME = 0.15;
|
||||||
|
const DASH_ITEM_LABEL_HIDE_TIME = 0.1;
|
||||||
|
const DASH_ITEM_HOVER_TIMEOUT = 300;
|
||||||
|
|
||||||
// A container like StBin, but taking the child's scale into account
|
// A container like StBin, but taking the child's scale into account
|
||||||
// when requesting a size
|
// when requesting a size
|
||||||
@ -32,6 +36,8 @@ const DashItemContainer = new Lang.Class({
|
|||||||
Lang.bind(this, this._allocate));
|
Lang.bind(this, this._allocate));
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
|
this.label = null;
|
||||||
|
|
||||||
this.child = null;
|
this.child = null;
|
||||||
this._childScale = 1;
|
this._childScale = 1;
|
||||||
this._childOpacity = 255;
|
this._childOpacity = 255;
|
||||||
@ -84,11 +90,65 @@ const DashItemContainer = new Lang.Class({
|
|||||||
alloc.natural_size = natWidth * this.child.scale_y;
|
alloc.natural_size = natWidth * this.child.scale_y;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showLabel: function() {
|
||||||
|
if (this.label == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.label.opacity = 0;
|
||||||
|
this.label.show();
|
||||||
|
|
||||||
|
let [stageX, stageY] = this.actor.get_transformed_position();
|
||||||
|
|
||||||
|
let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
|
||||||
|
|
||||||
|
let labelHeight = this.label.get_height();
|
||||||
|
let yOffset = Math.floor((itemHeight - labelHeight) / 2)
|
||||||
|
|
||||||
|
let y = stageY + yOffset;
|
||||||
|
|
||||||
|
let node = this.label.get_theme_node();
|
||||||
|
let xOffset = node.get_length('-x-offset');
|
||||||
|
|
||||||
|
let x;
|
||||||
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
|
x = stageX - this.label.get_width() - xOffset;
|
||||||
|
else
|
||||||
|
x = stageX + this.actor.get_width() + xOffset;
|
||||||
|
|
||||||
|
this.label.set_position(x, y);
|
||||||
|
Tweener.addTween(this.label,
|
||||||
|
{ opacity: 255,
|
||||||
|
time: DASH_ITEM_LABEL_SHOW_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setLabelText: function(text) {
|
||||||
|
if (this.label == null)
|
||||||
|
this.label = new St.Label({ style_class: 'dash-label'});
|
||||||
|
|
||||||
|
this.label.set_text(text);
|
||||||
|
Main.layoutManager.addChrome(this.label);
|
||||||
|
this.label.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
hideLabel: function () {
|
||||||
|
this.label.opacity = 255;
|
||||||
|
Tweener.addTween(this.label,
|
||||||
|
{ opacity: 0,
|
||||||
|
time: DASH_ITEM_LABEL_HIDE_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: Lang.bind(this, function() {
|
||||||
|
this.label.hide();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
setChild: function(actor) {
|
setChild: function(actor) {
|
||||||
if (this.child == actor)
|
if (this.child == actor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.actor.destroy_children();
|
this.actor.destroy_all_children();
|
||||||
|
|
||||||
this.child = actor;
|
this.child = actor;
|
||||||
this.actor.add_actor(this.child);
|
this.actor.add_actor(this.child);
|
||||||
@ -238,6 +298,9 @@ const Dash = new Lang.Class({
|
|||||||
this._dragPlaceholderPos = -1;
|
this._dragPlaceholderPos = -1;
|
||||||
this._animatingPlaceholdersCount = 0;
|
this._animatingPlaceholdersCount = 0;
|
||||||
this._favRemoveTarget = null;
|
this._favRemoveTarget = null;
|
||||||
|
this._showLabelTimeoutId = 0;
|
||||||
|
this._resetHoverTimeoutId = 0;
|
||||||
|
this._labelShowing = false;
|
||||||
|
|
||||||
this._box = new St.BoxLayout({ name: 'dash',
|
this._box = new St.BoxLayout({ name: 'dash',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
@ -324,6 +387,7 @@ const Dash = new Lang.Class({
|
|||||||
let srcIsFavorite = (id in favorites);
|
let srcIsFavorite = (id in favorites);
|
||||||
|
|
||||||
if (srcIsFavorite &&
|
if (srcIsFavorite &&
|
||||||
|
app.get_state() != Shell.AppState.RUNNING &&
|
||||||
dragEvent.source.actor &&
|
dragEvent.source.actor &&
|
||||||
this.actor.contains (dragEvent.source.actor) &&
|
this.actor.contains (dragEvent.source.actor) &&
|
||||||
this._favRemoveTarget == null) {
|
this._favRemoveTarget == null) {
|
||||||
@ -371,16 +435,53 @@ const Dash = new Lang.Class({
|
|||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
display.actor.opacity = 255;
|
display.actor.opacity = 255;
|
||||||
}));
|
}));
|
||||||
display.actor.set_tooltip_text(app.get_name());
|
|
||||||
|
|
||||||
let item = new DashItemContainer();
|
let item = new DashItemContainer();
|
||||||
item.setChild(display.actor);
|
item.setChild(display.actor);
|
||||||
|
|
||||||
display.icon.setIconSize(this.iconSize);
|
item.setLabelText(app.get_name());
|
||||||
|
// Override default AppWellIcon label_actor
|
||||||
|
display.actor.label_actor = item.label;
|
||||||
|
|
||||||
|
|
||||||
|
display.icon.setIconSize(this.iconSize);
|
||||||
|
display.actor.connect('notify::hover',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._onHover(item, display)
|
||||||
|
}));
|
||||||
return item;
|
return item;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onHover: function (item, display) {
|
||||||
|
if (display.actor.get_hover() && !display.isMenuUp) {
|
||||||
|
if (this._showLabelTimeoutId == 0) {
|
||||||
|
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
|
||||||
|
this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._labelShowing = true;
|
||||||
|
item.showLabel();
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
if (this._resetHoverTimeoutId > 0) {
|
||||||
|
Mainloop.source_remove(this._resetHoverTimeoutId);
|
||||||
|
this._resetHoverTimeoutId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this._showLabelTimeoutId > 0)
|
||||||
|
Mainloop.source_remove(this._showLabelTimeoutId);
|
||||||
|
this._showLabelTimeoutId = 0;
|
||||||
|
item.hideLabel();
|
||||||
|
if (this._labelShowing) {
|
||||||
|
this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
this._labelShowing = false;
|
||||||
|
return false;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_adjustIconSize: function() {
|
_adjustIconSize: function() {
|
||||||
// For the icon size, we only consider children which are "proper"
|
// For the icon size, we only consider children which are "proper"
|
||||||
// icons (i.e. ignoring drag placeholders) and which are not
|
// icons (i.e. ignoring drag placeholders) and which are not
|
||||||
@ -404,7 +505,7 @@ const Dash = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
||||||
let themeNode = this.actor.get_theme_node();
|
let themeNode = this._box.get_theme_node();
|
||||||
let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
|
let maxAllocation = new Clutter.ActorBox({ x1: 0, y1: 0,
|
||||||
x2: 42 /* whatever */,
|
x2: 42 /* whatever */,
|
||||||
y2: this._maxHeight });
|
y2: this._maxHeight });
|
||||||
@ -580,8 +681,8 @@ const Dash = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < addedItems.length; i++)
|
for (let i = 0; i < addedItems.length; i++)
|
||||||
this._box.insert_actor(addedItems[i].item.actor,
|
this._box.insert_child_at_index(addedItems[i].item.actor,
|
||||||
addedItems[i].pos);
|
addedItems[i].pos);
|
||||||
|
|
||||||
for (let i = 0; i < removedActors.length; i++) {
|
for (let i = 0; i < removedActors.length; i++) {
|
||||||
let item = removedActors[i]._delegate;
|
let item = removedActors[i]._delegate;
|
||||||
@ -646,20 +747,10 @@ const Dash = new Lang.Class({
|
|||||||
numChildren--;
|
numChildren--;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pos = Math.round(y * numChildren / boxHeight);
|
let pos = Math.floor(y * numChildren / boxHeight);
|
||||||
|
|
||||||
if (pos != this._dragPlaceholderPos && pos <= numFavorites) {
|
if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
|
||||||
if (this._animatingPlaceholdersCount > 0) {
|
this._dragPlaceholderPos = pos;
|
||||||
let appChildren = children.filter(function(actor) {
|
|
||||||
return actor._delegate &&
|
|
||||||
actor._delegate.child &&
|
|
||||||
actor._delegate.child._delegate &&
|
|
||||||
actor._delegate.child._delegate.app;
|
|
||||||
});
|
|
||||||
this._dragPlaceholderPos = children.indexOf(appChildren[pos]);
|
|
||||||
} else {
|
|
||||||
this._dragPlaceholderPos = pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Don't allow positioning before or after self
|
// Don't allow positioning before or after self
|
||||||
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
|
if (favPos != -1 && (pos == favPos || pos == favPos + 1)) {
|
||||||
@ -690,12 +781,20 @@ const Dash = new Lang.Class({
|
|||||||
this._dragPlaceholder = new DragPlaceholderItem();
|
this._dragPlaceholder = new DragPlaceholderItem();
|
||||||
this._dragPlaceholder.child.set_width (this.iconSize);
|
this._dragPlaceholder.child.set_width (this.iconSize);
|
||||||
this._dragPlaceholder.child.set_height (this.iconSize / 2);
|
this._dragPlaceholder.child.set_height (this.iconSize / 2);
|
||||||
this._box.insert_actor(this._dragPlaceholder.actor,
|
this._box.insert_child_at_index(this._dragPlaceholder.actor,
|
||||||
this._dragPlaceholderPos);
|
this._dragPlaceholderPos);
|
||||||
if (fadeIn)
|
if (fadeIn)
|
||||||
this._dragPlaceholder.animateIn();
|
this._dragPlaceholder.animateIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Remove the drag placeholder if we are not in the
|
||||||
|
// "favorites zone"
|
||||||
|
if (pos > numFavorites && this._dragPlaceholder) {
|
||||||
|
this._clearDragPlaceholder();
|
||||||
|
}
|
||||||
|
if (!this._dragPlaceholder)
|
||||||
|
return DND.DragMotionResult.NO_DROP;
|
||||||
|
|
||||||
let srcIsFavorite = (favPos != -1);
|
let srcIsFavorite = (favPos != -1);
|
||||||
|
|
||||||
if (srcIsFavorite)
|
if (srcIsFavorite)
|
||||||
@ -738,6 +837,11 @@ const Dash = new Lang.Class({
|
|||||||
favPos++;
|
favPos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No drag placeholder means we don't wan't to favorite the app
|
||||||
|
// and we are dragging it to its original position
|
||||||
|
if (!this._dragPlaceholder)
|
||||||
|
return true;
|
||||||
|
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
let appFavorites = AppFavorites.getAppFavorites();
|
let appFavorites = AppFavorites.getAppFavorites();
|
||||||
|
@ -8,6 +8,7 @@ const Cairo = imports.cairo;
|
|||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
@ -52,10 +53,15 @@ const DateMenuButton = new Lang.Class({
|
|||||||
let vbox;
|
let vbox;
|
||||||
|
|
||||||
let menuAlignment = 0.25;
|
let menuAlignment = 0.25;
|
||||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
menuAlignment = 1.0 - menuAlignment;
|
menuAlignment = 1.0 - menuAlignment;
|
||||||
this.parent(menuAlignment);
|
this.parent(menuAlignment);
|
||||||
|
|
||||||
|
// At this moment calendar menu is not keyboard navigable at
|
||||||
|
// all (so not accessible), so it doesn't make sense to set as
|
||||||
|
// role ATK_ROLE_MENU like other elements of the panel.
|
||||||
|
this.actor.accessible_role = Atk.Role.LABEL;
|
||||||
|
|
||||||
this._clock = new St.Label();
|
this._clock = new St.Label();
|
||||||
this.actor.add_actor(this._clock);
|
this.actor.add_actor(this._clock);
|
||||||
|
|
||||||
@ -69,6 +75,7 @@ const DateMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
// Date
|
// Date
|
||||||
this._date = new St.Label();
|
this._date = new St.Label();
|
||||||
|
this.actor.label_actor = this._date;
|
||||||
this._date.style_class = 'datemenu-date-label';
|
this._date.style_class = 'datemenu-date-label';
|
||||||
vbox.add(this._date);
|
vbox.add(this._date);
|
||||||
|
|
||||||
|
28
js/ui/dnd.js
@ -103,8 +103,8 @@ const _Draggable = new Lang.Class({
|
|||||||
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
|
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).
|
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
|
// During the drag, we eat enter/leave events so that actors don't prelight.
|
||||||
// tooltips. But we remember the actors that we first left/last entered so we can
|
// But we remember the actors that we first left/last entered so we can
|
||||||
// fix up the hover state after the drag ends.
|
// fix up the hover state after the drag ends.
|
||||||
this._firstLeaveActor = null;
|
this._firstLeaveActor = null;
|
||||||
this._lastEnterActor = null;
|
this._lastEnterActor = null;
|
||||||
@ -120,13 +120,7 @@ const _Draggable = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
this._buttonDown = true;
|
this._buttonDown = true;
|
||||||
// special case St.Button: grabbing the pointer would mess up the
|
this._grabActor();
|
||||||
// internal state, so we start the drag manually on hover change
|
|
||||||
if (this.actor instanceof St.Button)
|
|
||||||
this.actor.connect('notify::hover',
|
|
||||||
Lang.bind(this, this._onButtonHoverChanged));
|
|
||||||
else
|
|
||||||
this._grabActor();
|
|
||||||
|
|
||||||
let [stageX, stageY] = event.get_coords();
|
let [stageX, stageY] = event.get_coords();
|
||||||
this._dragStartX = stageX;
|
this._dragStartX = stageX;
|
||||||
@ -135,15 +129,6 @@ const _Draggable = new Lang.Class({
|
|||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onButtonHoverChanged: function(button) {
|
|
||||||
if (button.hover || !button.pressed)
|
|
||||||
return;
|
|
||||||
|
|
||||||
button.fake_release();
|
|
||||||
this.startDrag(this._dragStartX, this._dragStartY,
|
|
||||||
global.get_current_time());
|
|
||||||
},
|
|
||||||
|
|
||||||
_grabActor: function() {
|
_grabActor: function() {
|
||||||
Clutter.grab_pointer(this.actor);
|
Clutter.grab_pointer(this.actor);
|
||||||
this._onEventId = this.actor.connect('event',
|
this._onEventId = this.actor.connect('event',
|
||||||
@ -232,6 +217,13 @@ const _Draggable = new Lang.Class({
|
|||||||
currentDraggable = this;
|
currentDraggable = this;
|
||||||
this._dragInProgress = true;
|
this._dragInProgress = true;
|
||||||
|
|
||||||
|
// Special-case St.Button: the pointer grab messes with the internal
|
||||||
|
// state, so force a reset to a reasonable state here
|
||||||
|
if (this.actor instanceof St.Button) {
|
||||||
|
this.actor.fake_release();
|
||||||
|
this.actor.hover = false;
|
||||||
|
}
|
||||||
|
|
||||||
this.emit('drag-begin', time);
|
this.emit('drag-begin', time);
|
||||||
if (this._onEventId)
|
if (this._onEventId)
|
||||||
this._ungrabActor();
|
this._ungrabActor();
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
|
||||||
|
|
||||||
const DocInfo = imports.misc.docInfo;
|
|
||||||
const Lang = imports.lang;
|
|
||||||
const Params = imports.misc.params;
|
|
||||||
const Search = imports.ui.search;
|
|
||||||
|
|
||||||
const DocSearchProvider = new Lang.Class({
|
|
||||||
Name: 'DocSearchProvider',
|
|
||||||
Extends: Search.SearchProvider,
|
|
||||||
|
|
||||||
_init: function(name) {
|
|
||||||
this.parent(_("RECENT ITEMS"));
|
|
||||||
this._docManager = DocInfo.getDocManager();
|
|
||||||
},
|
|
||||||
|
|
||||||
getResultMeta: function(resultId) {
|
|
||||||
let docInfo = this._docManager.lookupByUri(resultId);
|
|
||||||
if (!docInfo)
|
|
||||||
return null;
|
|
||||||
return { 'id': resultId,
|
|
||||||
'name': docInfo.name,
|
|
||||||
'createIcon': function(size) {
|
|
||||||
return docInfo.createIcon(size);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
activateResult: function(id, params) {
|
|
||||||
params = Params.parse(params, { workspace: -1,
|
|
||||||
timestamp: 0 });
|
|
||||||
|
|
||||||
let docInfo = this._docManager.lookupByUri(id);
|
|
||||||
docInfo.launch(params.workspace);
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialResultSet: function(terms) {
|
|
||||||
return this._docManager.initialSearch(terms);
|
|
||||||
},
|
|
||||||
|
|
||||||
getSubsearchResultSet: function(previousResults, terms) {
|
|
||||||
return this._docManager.subsearch(previousResults, terms);
|
|
||||||
}
|
|
||||||
});
|
|
@ -116,30 +116,12 @@ const DialogContent = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function findAppFromInhibitor(inhibitor) {
|
function findAppFromInhibitor(inhibitor) {
|
||||||
let desktopFile = inhibitor.app_id;
|
let [desktopFile] = inhibitor.GetAppIdSync();
|
||||||
|
|
||||||
if (!GLib.str_has_suffix(desktopFile, '.desktop'))
|
if (!GLib.str_has_suffix(desktopFile, '.desktop'))
|
||||||
desktopFile += '.desktop';
|
desktopFile += '.desktop';
|
||||||
|
|
||||||
let candidateDesktopFiles = [];
|
return Shell.AppSystem.get_default().lookup_heuristic_basename(desktopFile);
|
||||||
|
|
||||||
candidateDesktopFiles.push(desktopFile);
|
|
||||||
candidateDesktopFiles.push('gnome-' + desktopFile);
|
|
||||||
|
|
||||||
let appSystem = Shell.AppSystem.get_default();
|
|
||||||
let app = null;
|
|
||||||
for (let i = 0; i < candidateDesktopFiles.length; i++) {
|
|
||||||
try {
|
|
||||||
app = appSystem.lookup_app(candidateDesktopFiles[i]);
|
|
||||||
|
|
||||||
if (app)
|
|
||||||
break;
|
|
||||||
} catch(e) {
|
|
||||||
// ignore errors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ListItem = new Lang.Class({
|
const ListItem = new Lang.Class({
|
||||||
@ -333,7 +315,8 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this._iconBin.child = null;
|
this._iconBin.child = null;
|
||||||
if (iconFile) {
|
if (iconFile) {
|
||||||
this._iconBin.show();
|
this._iconBin.show();
|
||||||
this._iconBin.set_style('background-image: url("' + iconFile + '");');
|
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
||||||
|
'background-size: contain;');
|
||||||
} else {
|
} else {
|
||||||
this._iconBin.hide();
|
this._iconBin.hide();
|
||||||
}
|
}
|
||||||
@ -481,7 +464,8 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
let app = findAppFromInhibitor(inhibitor);
|
let app = findAppFromInhibitor(inhibitor);
|
||||||
|
|
||||||
if (app) {
|
if (app) {
|
||||||
let item = new ListItem(app, inhibitor.reason);
|
let [reason] = inhibitor.GetReasonSync();
|
||||||
|
let item = new ListItem(app, reason);
|
||||||
item.connect('activate',
|
item.connect('activate',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
@ -500,11 +484,11 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
|
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
|
||||||
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
||||||
this._inhibitors = [];
|
this._inhibitors = [];
|
||||||
this._applicationList.destroy_children();
|
this._applicationList.destroy_all_children();
|
||||||
this._type = type;
|
this._type = type;
|
||||||
|
|
||||||
if (!(this._type in DialogContent)) {
|
if (!(this._type in DialogContent)) {
|
||||||
invocation.report_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
|
invocation.return_dbus_error('org.gnome.Shell.ModalDialog.TypeError',
|
||||||
"Unknown dialog type requested");
|
"Unknown dialog type requested");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -520,7 +504,7 @@ const EndSessionDialog = new Lang.Class({
|
|||||||
this._updateButtons();
|
this._updateButtons();
|
||||||
|
|
||||||
if (!this.open(timestamp)) {
|
if (!this.open(timestamp)) {
|
||||||
invocation.report_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
|
invocation.return_dbus_error('org.gnome.Shell.ModalDialog.GrabError',
|
||||||
"Cannot grab pointer and keyboard");
|
"Cannot grab pointer and keyboard");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -48,11 +48,6 @@ function init() {
|
|||||||
window.C_ = Gettext.pgettext;
|
window.C_ = Gettext.pgettext;
|
||||||
window.ngettext = Gettext.ngettext;
|
window.ngettext = Gettext.ngettext;
|
||||||
|
|
||||||
// Set the default direction for St widgets (this needs to be done before any use of St)
|
|
||||||
if (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) {
|
|
||||||
St.Widget.set_default_direction(St.TextDirection.RTL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Miscellaneous monkeypatching
|
// Miscellaneous monkeypatching
|
||||||
_patchContainerClass(St.BoxLayout);
|
_patchContainerClass(St.BoxLayout);
|
||||||
_patchContainerClass(St.Table);
|
_patchContainerClass(St.Table);
|
||||||
@ -64,10 +59,14 @@ function init() {
|
|||||||
let origToString = Object.prototype.toString;
|
let origToString = Object.prototype.toString;
|
||||||
Object.prototype.toString = function() {
|
Object.prototype.toString = function() {
|
||||||
let base = origToString.call(this);
|
let base = origToString.call(this);
|
||||||
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
try {
|
||||||
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
|
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
||||||
else
|
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
|
||||||
|
else
|
||||||
|
return base;
|
||||||
|
} catch(e) {
|
||||||
return base;
|
return base;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
||||||
|
@ -11,6 +11,7 @@ const Shell = imports.gi.Shell;
|
|||||||
const Soup = imports.gi.Soup;
|
const Soup = imports.gi.Soup;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
const FileUtils = imports.misc.fileUtils;
|
const FileUtils = imports.misc.fileUtils;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
|
|
||||||
@ -29,11 +30,6 @@ const ExtensionState = {
|
|||||||
UNINSTALLED: 99
|
UNINSTALLED: 99
|
||||||
};
|
};
|
||||||
|
|
||||||
const ExtensionType = {
|
|
||||||
SYSTEM: 1,
|
|
||||||
PER_USER: 2
|
|
||||||
};
|
|
||||||
|
|
||||||
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
const REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
|
||||||
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
const REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
|
||||||
const REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
|
const REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
|
||||||
@ -57,19 +53,10 @@ function _getCertFile() {
|
|||||||
|
|
||||||
_httpSession.ssl_ca_file = _getCertFile();
|
_httpSession.ssl_ca_file = _getCertFile();
|
||||||
|
|
||||||
// Maps uuid -> metadata object
|
|
||||||
const extensionMeta = {};
|
|
||||||
// Maps uuid -> importer object (extension directory tree)
|
|
||||||
const extensions = {};
|
|
||||||
// Maps uuid -> extension state object (returned from init())
|
|
||||||
const extensionStateObjs = {};
|
|
||||||
// Contains the order that extensions were enabled in.
|
|
||||||
const extensionOrder = [];
|
|
||||||
|
|
||||||
// Arrays of uuids
|
// Arrays of uuids
|
||||||
var enabledExtensions;
|
var enabledExtensions;
|
||||||
// GFile for user extensions
|
// Contains the order that extensions were enabled in.
|
||||||
var userExtensionsDir = null;
|
const extensionOrder = [];
|
||||||
|
|
||||||
// We don't really have a class to add signals on. So, create
|
// We don't really have a class to add signals on. So, create
|
||||||
// a simple dummy object, add the signal methods, and export those
|
// a simple dummy object, add the signal methods, and export those
|
||||||
@ -80,41 +67,8 @@ Signals.addSignalMethods(_signals);
|
|||||||
const connect = Lang.bind(_signals, _signals.connect);
|
const connect = Lang.bind(_signals, _signals.connect);
|
||||||
const disconnect = Lang.bind(_signals, _signals.disconnect);
|
const disconnect = Lang.bind(_signals, _signals.disconnect);
|
||||||
|
|
||||||
// UUID => Array of error messages
|
|
||||||
var errors = {};
|
|
||||||
|
|
||||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||||
|
|
||||||
/**
|
|
||||||
* versionCheck:
|
|
||||||
* @required: an array of versions we're compatible with
|
|
||||||
* @current: the version we have
|
|
||||||
*
|
|
||||||
* Check if a component is compatible for an extension.
|
|
||||||
* @required is an array, and at least one version must match.
|
|
||||||
* @current must be in the format <major>.<minor>.<point>.<micro>
|
|
||||||
* <micro> is always ignored
|
|
||||||
* <point> is ignored if <minor> is even (so you can target the
|
|
||||||
* whole stable release)
|
|
||||||
* <minor> and <major> must match
|
|
||||||
* Each target version must be at least <major> and <minor>
|
|
||||||
*/
|
|
||||||
function versionCheck(required, current) {
|
|
||||||
let currentArray = current.split('.');
|
|
||||||
let major = currentArray[0];
|
|
||||||
let minor = currentArray[1];
|
|
||||||
let point = currentArray[2];
|
|
||||||
for (let i = 0; i < required.length; i++) {
|
|
||||||
let requiredArray = required[i].split('.');
|
|
||||||
if (requiredArray[0] == major &&
|
|
||||||
requiredArray[1] == minor &&
|
|
||||||
(requiredArray[2] == point ||
|
|
||||||
(requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function installExtensionFromUUID(uuid, version_tag) {
|
function installExtensionFromUUID(uuid, version_tag) {
|
||||||
let params = { uuid: uuid,
|
let params = { uuid: uuid,
|
||||||
version_tag: version_tag,
|
version_tag: version_tag,
|
||||||
@ -132,8 +86,8 @@ function installExtensionFromUUID(uuid, version_tag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function uninstallExtensionFromUUID(uuid) {
|
function uninstallExtensionFromUUID(uuid) {
|
||||||
let meta = extensionMeta[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
if (!meta)
|
if (!extension)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||||
@ -142,22 +96,15 @@ function uninstallExtensionFromUUID(uuid) {
|
|||||||
disableExtension(uuid);
|
disableExtension(uuid);
|
||||||
|
|
||||||
// Don't try to uninstall system extensions
|
// Don't try to uninstall system extensions
|
||||||
if (meta.type != ExtensionType.PER_USER)
|
if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
meta.state = ExtensionState.UNINSTALLED;
|
extension.state = ExtensionState.UNINSTALLED;
|
||||||
_signals.emit('extension-state-changed', meta);
|
_signals.emit('extension-state-changed', extension);
|
||||||
|
|
||||||
delete extensionMeta[uuid];
|
delete ExtensionUtils.extensions[uuid];
|
||||||
|
|
||||||
// Importers are marked as PERMANENT, so we can't do this.
|
FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(extension.path));
|
||||||
// delete extensions[uuid];
|
|
||||||
extensions[uuid] = undefined;
|
|
||||||
|
|
||||||
delete extensionStateObjs[uuid];
|
|
||||||
delete errors[uuid];
|
|
||||||
|
|
||||||
FileUtils.recursivelyDeleteDir(Gio.file_new_for_path(meta.path));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -178,7 +125,7 @@ function gotExtensionZipFile(session, message, uuid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let stream = new Gio.UnixOutputStream({ fd: fd });
|
let stream = new Gio.UnixOutputStream({ fd: fd });
|
||||||
let dir = userExtensionsDir.get_child(uuid);
|
let dir = ExtensionUtils.userExtensionsDir.get_child(uuid);
|
||||||
Shell.write_soup_message_to_stream(stream, message);
|
Shell.write_soup_message_to_stream(stream, message);
|
||||||
stream.close(null);
|
stream.close(null);
|
||||||
let [success, pid] = GLib.spawn_async(null,
|
let [success, pid] = GLib.spawn_async(null,
|
||||||
@ -202,20 +149,18 @@ function gotExtensionZipFile(session, message, uuid) {
|
|||||||
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadExtension(dir, true, ExtensionType.PER_USER);
|
loadExtension(dir, ExtensionUtils.ExtensionType.PER_USER, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableExtension(uuid) {
|
function disableExtension(uuid) {
|
||||||
let meta = extensionMeta[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
if (!meta)
|
if (!extension)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (meta.state != ExtensionState.ENABLED)
|
if (extension.state != ExtensionState.ENABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let extensionState = extensionStateObjs[uuid];
|
|
||||||
|
|
||||||
// "Rebase" the extension order by disabling and then enabling extensions
|
// "Rebase" the extension order by disabling and then enabling extensions
|
||||||
// in order to help prevent conflicts.
|
// in order to help prevent conflicts.
|
||||||
|
|
||||||
@ -231,14 +176,14 @@ function disableExtension(uuid) {
|
|||||||
for (let i = 0; i < orderReversed.length; i++) {
|
for (let i = 0; i < orderReversed.length; i++) {
|
||||||
let uuid = orderReversed[i];
|
let uuid = orderReversed[i];
|
||||||
try {
|
try {
|
||||||
extensionStateObjs[uuid].disable();
|
ExtensionUtils.extensions[uuid].stateObj.disable();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
logExtensionError(uuid, e.toString());
|
logExtensionError(uuid, e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
extensionState.disable();
|
extension.stateObj.disable();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
logExtensionError(uuid, e.toString());
|
logExtensionError(uuid, e.toString());
|
||||||
return;
|
return;
|
||||||
@ -247,7 +192,7 @@ function disableExtension(uuid) {
|
|||||||
for (let i = 0; i < order.length; i++) {
|
for (let i = 0; i < order.length; i++) {
|
||||||
let uuid = order[i];
|
let uuid = order[i];
|
||||||
try {
|
try {
|
||||||
extensionStateObjs[uuid].enable();
|
ExtensionUtils.extensions[uuid].stateObj.enable();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
logExtensionError(uuid, e.toString());
|
logExtensionError(uuid, e.toString());
|
||||||
}
|
}
|
||||||
@ -255,41 +200,43 @@ function disableExtension(uuid) {
|
|||||||
|
|
||||||
extensionOrder.splice(orderIdx, 1);
|
extensionOrder.splice(orderIdx, 1);
|
||||||
|
|
||||||
meta.state = ExtensionState.DISABLED;
|
extension.state = ExtensionState.DISABLED;
|
||||||
_signals.emit('extension-state-changed', meta);
|
_signals.emit('extension-state-changed', extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
function enableExtension(uuid) {
|
function enableExtension(uuid) {
|
||||||
let meta = extensionMeta[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
if (!meta)
|
if (!extension)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (meta.state == ExtensionState.INITIALIZED) {
|
if (extension.state == ExtensionState.INITIALIZED)
|
||||||
loadExtension(meta.dir, meta.type, true);
|
initExtension(uuid);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (meta.state != ExtensionState.DISABLED)
|
if (extension.state != ExtensionState.DISABLED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let extensionState = extensionStateObjs[uuid];
|
|
||||||
|
|
||||||
extensionOrder.push(uuid);
|
extensionOrder.push(uuid);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
extensionState.enable();
|
extension.stateObj.enable();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
logExtensionError(uuid, e.toString());
|
logExtensionError(uuid, e.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
meta.state = ExtensionState.ENABLED;
|
extension.state = ExtensionState.ENABLED;
|
||||||
_signals.emit('extension-state-changed', meta);
|
_signals.emit('extension-state-changed', extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
function logExtensionError(uuid, message, state) {
|
function logExtensionError(uuid, message, state) {
|
||||||
if (!errors[uuid]) errors[uuid] = [];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
errors[uuid].push(message);
|
if (!extension)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!extension.errors)
|
||||||
|
extension.errors = [];
|
||||||
|
|
||||||
|
extension.errors.push(message);
|
||||||
global.logError('Extension "%s" had error: %s'.format(uuid, message));
|
global.logError('Extension "%s" had error: %s'.format(uuid, message));
|
||||||
state = state || ExtensionState.ERROR;
|
state = state || ExtensionState.ERROR;
|
||||||
_signals.emit('extension-state-changed', { uuid: uuid,
|
_signals.emit('extension-state-changed', { uuid: uuid,
|
||||||
@ -298,75 +245,49 @@ function logExtensionError(uuid, message, state) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadExtension(dir, type, enabled) {
|
function loadExtension(dir, type, enabled) {
|
||||||
let info;
|
|
||||||
let uuid = dir.get_basename();
|
let uuid = dir.get_basename();
|
||||||
|
let extension;
|
||||||
|
|
||||||
let metadataFile = dir.get_child('metadata.json');
|
if (ExtensionUtils.extensions[uuid] != undefined) {
|
||||||
if (!metadataFile.query_exists(null)) {
|
global.logError('Extension "%s" is already loaded'.format(uuid));
|
||||||
logExtensionError(uuid, 'Missing metadata.json');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let metadataContents;
|
|
||||||
try {
|
try {
|
||||||
metadataContents = Shell.get_file_contents_utf8_sync(metadataFile.get_path());
|
extension = ExtensionUtils.createExtensionObject(uuid, dir, type);
|
||||||
} catch (e) {
|
} catch(e) {
|
||||||
logExtensionError(uuid, 'Failed to load metadata.json: ' + e);
|
logExtensionError(uuid, e.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let meta;
|
|
||||||
try {
|
|
||||||
meta = JSON.parse(metadataContents);
|
|
||||||
} catch (e) {
|
|
||||||
logExtensionError(uuid, 'Failed to parse metadata.json: ' + e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
|
|
||||||
for (let i = 0; i < requiredProperties.length; i++) {
|
|
||||||
let prop = requiredProperties[i];
|
|
||||||
if (!meta[prop]) {
|
|
||||||
logExtensionError(uuid, 'missing "' + prop + '" property in metadata.json');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (extensions[uuid] != undefined) {
|
|
||||||
logExtensionError(uuid, 'extension already loaded');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encourage people to add this
|
|
||||||
if (!meta['url']) {
|
|
||||||
global.log('Warning: Missing "url" property in metadata.json');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uuid != meta.uuid) {
|
|
||||||
logExtensionError(uuid, 'uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
extensionMeta[uuid] = meta;
|
|
||||||
meta.type = type;
|
|
||||||
meta.dir = dir;
|
|
||||||
meta.path = dir.get_path();
|
|
||||||
meta.error = '';
|
|
||||||
|
|
||||||
// Default to error, we set success as the last step
|
// Default to error, we set success as the last step
|
||||||
meta.state = ExtensionState.ERROR;
|
extension.state = ExtensionState.ERROR;
|
||||||
|
|
||||||
if (!versionCheck(meta['shell-version'], Config.PACKAGE_VERSION) ||
|
if (ExtensionUtils.isOutOfDate(extension)) {
|
||||||
(meta['js-version'] && !versionCheck(meta['js-version'], Config.GJS_VERSION))) {
|
|
||||||
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
|
logExtensionError(uuid, 'extension is not compatible with current GNOME Shell and/or GJS version', ExtensionState.OUT_OF_DATE);
|
||||||
meta.state = ExtensionState.OUT_OF_DATE;
|
extension.state = ExtensionState.OUT_OF_DATE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled) {
|
if (enabled) {
|
||||||
meta.state = ExtensionState.INITIALIZED;
|
initExtension(uuid);
|
||||||
return;
|
if (extension.state == ExtensionState.DISABLED)
|
||||||
|
enableExtension(uuid);
|
||||||
|
} else {
|
||||||
|
extension.state = ExtensionState.INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_signals.emit('extension-state-changed', extension);
|
||||||
|
global.log('Loaded extension ' + uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initExtension(uuid) {
|
||||||
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
|
let dir = extension.dir;
|
||||||
|
|
||||||
|
if (!extension)
|
||||||
|
throw new Error("Extension was not properly created. Call loadExtension first");
|
||||||
|
|
||||||
let extensionJs = dir.get_child('extension.js');
|
let extensionJs = dir.get_child('extension.js');
|
||||||
if (!extensionJs.query_exists(null)) {
|
if (!extensionJs.query_exists(null)) {
|
||||||
logExtensionError(uuid, 'Missing extension.js');
|
logExtensionError(uuid, 'Missing extension.js');
|
||||||
@ -388,12 +309,12 @@ function loadExtension(dir, type, enabled) {
|
|||||||
let extensionModule;
|
let extensionModule;
|
||||||
let extensionState = null;
|
let extensionState = null;
|
||||||
try {
|
try {
|
||||||
global.add_extension_importer('imports.ui.extensionSystem.extensions', meta.uuid, dir.get_path());
|
ExtensionUtils.installImporter(extension);
|
||||||
extensionModule = extensions[meta.uuid].extension;
|
extensionModule = extension.imports.extension;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (stylesheetPath != null)
|
if (stylesheetPath != null)
|
||||||
theme.unload_stylesheet(stylesheetPath);
|
theme.unload_stylesheet(stylesheetPath);
|
||||||
logExtensionError(uuid, e);
|
logExtensionError(uuid, '' + e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +324,7 @@ function loadExtension(dir, type, enabled) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
extensionState = extensionModule.init(meta);
|
extensionState = extensionModule.init(extension);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (stylesheetPath != null)
|
if (stylesheetPath != null)
|
||||||
theme.unload_stylesheet(stylesheetPath);
|
theme.unload_stylesheet(stylesheetPath);
|
||||||
@ -413,7 +334,7 @@ function loadExtension(dir, type, enabled) {
|
|||||||
|
|
||||||
if (!extensionState)
|
if (!extensionState)
|
||||||
extensionState = extensionModule;
|
extensionState = extensionModule;
|
||||||
extensionStateObjs[uuid] = extensionState;
|
extension.stateObj = extensionState;
|
||||||
|
|
||||||
if (!extensionState.enable) {
|
if (!extensionState.enable) {
|
||||||
logExtensionError(uuid, 'missing \'enable\' function');
|
logExtensionError(uuid, 'missing \'enable\' function');
|
||||||
@ -424,13 +345,9 @@ function loadExtension(dir, type, enabled) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
meta.state = ExtensionState.DISABLED;
|
extension.state = ExtensionState.DISABLED;
|
||||||
|
|
||||||
enableExtension(uuid);
|
_signals.emit('extension-loaded', uuid);
|
||||||
|
|
||||||
_signals.emit('extension-loaded', meta.uuid);
|
|
||||||
_signals.emit('extension-state-changed', meta);
|
|
||||||
global.log('Loaded extension ' + meta.uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEnabledExtensionsChanged() {
|
function onEnabledExtensionsChanged() {
|
||||||
@ -456,50 +373,17 @@ function onEnabledExtensionsChanged() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
let userExtensionsPath = GLib.build_filenamev([global.userdatadir, 'extensions']);
|
ExtensionUtils.init();
|
||||||
userExtensionsDir = Gio.file_new_for_path(userExtensionsPath);
|
|
||||||
try {
|
|
||||||
if (!userExtensionsDir.query_exists(null))
|
|
||||||
userExtensionsDir.make_directory_with_parents(null);
|
|
||||||
} catch (e) {
|
|
||||||
global.logError('' + e);
|
|
||||||
}
|
|
||||||
|
|
||||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||||
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _loadExtensionsIn(dir, type) {
|
|
||||||
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)
|
|
||||||
continue;
|
|
||||||
let name = info.get_name();
|
|
||||||
let child = dir.get_child(name);
|
|
||||||
let enabled = enabledExtensions.indexOf(name) != -1;
|
|
||||||
loadExtension(child, type, enabled);
|
|
||||||
}
|
|
||||||
fileEnum.close(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
function loadExtensions() {
|
function loadExtensions() {
|
||||||
let systemDataDirs = GLib.get_system_data_dirs();
|
ExtensionUtils.scanExtensions(function(uuid, dir, type) {
|
||||||
for (let i = 0; i < systemDataDirs.length; i++) {
|
let enabled = enabledExtensions.indexOf(uuid) != -1;
|
||||||
let dirPath = systemDataDirs[i] + '/gnome-shell/extensions';
|
loadExtension(dir, type, enabled);
|
||||||
let dir = Gio.file_new_for_path(dirPath);
|
});
|
||||||
if (dir.query_exists(null))
|
|
||||||
_loadExtensionsIn(dir, ExtensionType.SYSTEM);
|
|
||||||
}
|
|
||||||
_loadExtensionsIn(userExtensionsDir, ExtensionType.PER_USER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const InstallExtensionDialog = new Lang.Class({
|
const InstallExtensionDialog = new Lang.Class({
|
||||||
@ -545,13 +429,11 @@ const InstallExtensionDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onInstallButtonPressed: function(button, event) {
|
_onInstallButtonPressed: function(button, event) {
|
||||||
let meta = { uuid: this._uuid,
|
let state = { uuid: this._uuid,
|
||||||
state: ExtensionState.DOWNLOADING,
|
state: ExtensionState.DOWNLOADING,
|
||||||
error: '' };
|
error: '' };
|
||||||
|
|
||||||
extensionMeta[this._uuid] = meta;
|
_signals.emit('extension-state-changed', state);
|
||||||
|
|
||||||
_signals.emit('extension-state-changed', meta);
|
|
||||||
|
|
||||||
let params = { version_tag: this._version_tag,
|
let params = { version_tag: this._version_tag,
|
||||||
shell_version: Config.PACKAGE_VERSION,
|
shell_version: Config.PACKAGE_VERSION,
|
||||||
|
45
js/ui/flashspot.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
|
||||||
|
const Lightbox = imports.ui.lightbox;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
|
const FLASHSPOT_ANIMATION_TIME = 0.25; // seconds
|
||||||
|
|
||||||
|
const Flashspot = new Lang.Class({
|
||||||
|
Name: 'Flashspot',
|
||||||
|
Extends: Lightbox.Lightbox,
|
||||||
|
|
||||||
|
_init: function(area) {
|
||||||
|
this.parent(Main.uiGroup, { inhibitEvents: true,
|
||||||
|
width: area.width,
|
||||||
|
height: area.height });
|
||||||
|
|
||||||
|
this.actor.style_class = 'flashspot';
|
||||||
|
this.actor.set_position(area.x, area.y);
|
||||||
|
},
|
||||||
|
|
||||||
|
fire: function() {
|
||||||
|
this.actor.opacity = 0;
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ opacity: 255,
|
||||||
|
time: FLASHSPOT_ANIMATION_TIME,
|
||||||
|
transition: 'linear',
|
||||||
|
onComplete: Lang.bind(this, this._onFireShowComplete)
|
||||||
|
});
|
||||||
|
this.actor.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onFireShowComplete: function() {
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ opacity: 0,
|
||||||
|
time: FLASHSPOT_ANIMATION_TIME,
|
||||||
|
transition: 'linear',
|
||||||
|
onComplete: Lang.bind(this, function() {
|
||||||
|
this.destroy();
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
@ -35,7 +35,8 @@ const BaseIcon = new Lang.Class({
|
|||||||
this.actor.set_child(box);
|
this.actor.set_child(box);
|
||||||
|
|
||||||
this.iconSize = ICON_SIZE;
|
this.iconSize = ICON_SIZE;
|
||||||
this._iconBin = new St.Bin();
|
this._iconBin = new St.Bin({ x_align: St.Align.MIDDLE,
|
||||||
|
y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
box.add_actor(this._iconBin);
|
box.add_actor(this._iconBin);
|
||||||
|
|
||||||
@ -125,12 +126,12 @@ const BaseIcon = new Lang.Class({
|
|||||||
this.iconSize = size;
|
this.iconSize = size;
|
||||||
this.icon = this.createIcon(this.iconSize);
|
this.icon = this.createIcon(this.iconSize);
|
||||||
|
|
||||||
|
this._iconBin.child = this.icon;
|
||||||
|
|
||||||
// The icon returned by createIcon() might actually be smaller than
|
// The icon returned by createIcon() might actually be smaller than
|
||||||
// the requested icon size (for instance StTextureCache does this
|
// the requested icon size (for instance StTextureCache does this
|
||||||
// for fallback icons), so set the size explicitly.
|
// for fallback icons), so set the size explicitly.
|
||||||
this.icon.set_size(this.iconSize, this.iconSize);
|
this._iconBin.set_size(this.iconSize, this.iconSize);
|
||||||
|
|
||||||
this._iconBin.child = this.icon;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onStyleChanged: function() {
|
_onStyleChanged: function() {
|
||||||
@ -164,7 +165,7 @@ const IconGrid = new Lang.Class({
|
|||||||
vertical: true });
|
vertical: true });
|
||||||
// Pulled from CSS, but hardcode some defaults here
|
// Pulled from CSS, but hardcode some defaults here
|
||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
this._item_size = ICON_SIZE;
|
this._hItemSize = this._vItemSize = ICON_SIZE;
|
||||||
this._grid = new Shell.GenericContainer();
|
this._grid = new Shell.GenericContainer();
|
||||||
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
|
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
|
||||||
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||||
@ -183,8 +184,8 @@ const IconGrid = new Lang.Class({
|
|||||||
// Kind of a lie, but not really an issue right now. If
|
// Kind of a lie, but not really an issue right now. If
|
||||||
// we wanted to support some sort of hidden/overflow that would
|
// we wanted to support some sort of hidden/overflow that would
|
||||||
// need higher level design
|
// need higher level design
|
||||||
alloc.min_size = this._item_size;
|
alloc.min_size = this._hItemSize;
|
||||||
alloc.natural_size = nColumns * this._item_size + totalSpacing;
|
alloc.natural_size = nColumns * this._hItemSize + totalSpacing;
|
||||||
},
|
},
|
||||||
|
|
||||||
_getVisibleChildren: function() {
|
_getVisibleChildren: function() {
|
||||||
@ -206,7 +207,7 @@ const IconGrid = new Lang.Class({
|
|||||||
if (this._rowLimit)
|
if (this._rowLimit)
|
||||||
nRows = Math.min(nRows, this._rowLimit);
|
nRows = Math.min(nRows, this._rowLimit);
|
||||||
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
|
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
|
||||||
let height = nRows * this._item_size + totalSpacing;
|
let height = nRows * this._vItemSize + totalSpacing;
|
||||||
alloc.min_size = height;
|
alloc.min_size = height;
|
||||||
alloc.natural_size = height;
|
alloc.natural_size = height;
|
||||||
},
|
},
|
||||||
@ -239,13 +240,13 @@ const IconGrid = new Lang.Class({
|
|||||||
= children[i].get_preferred_size();
|
= children[i].get_preferred_size();
|
||||||
|
|
||||||
/* Center the item in its allocation horizontally */
|
/* Center the item in its allocation horizontally */
|
||||||
let width = Math.min(this._item_size, childNaturalWidth);
|
let width = Math.min(this._hItemSize, childNaturalWidth);
|
||||||
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
|
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
|
||||||
let height = Math.min(this._item_size, childNaturalHeight);
|
let height = Math.min(this._vItemSize, childNaturalHeight);
|
||||||
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
|
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
|
||||||
|
|
||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
let _x = box.x2 - (x + width);
|
let _x = box.x2 - (x + width);
|
||||||
childBox.x1 = Math.floor(_x - childXSpacing);
|
childBox.x1 = Math.floor(_x - childXSpacing);
|
||||||
} else {
|
} else {
|
||||||
@ -269,10 +270,10 @@ const IconGrid = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (columnIndex == 0) {
|
if (columnIndex == 0) {
|
||||||
y += this._item_size + this._spacing;
|
y += this._vItemSize + this._spacing;
|
||||||
x = box.x1 + leftPadding;
|
x = box.x1 + leftPadding;
|
||||||
} else {
|
} else {
|
||||||
x += this._item_size + this._spacing;
|
x += this._hItemSize + this._spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -285,8 +286,8 @@ const IconGrid = new Lang.Class({
|
|||||||
let nColumns = 0;
|
let nColumns = 0;
|
||||||
let usedWidth = 0;
|
let usedWidth = 0;
|
||||||
while ((this._colLimit == null || nColumns < this._colLimit) &&
|
while ((this._colLimit == null || nColumns < this._colLimit) &&
|
||||||
(usedWidth + this._item_size <= forWidth)) {
|
(usedWidth + this._hItemSize <= forWidth)) {
|
||||||
usedWidth += this._item_size + this._spacing;
|
usedWidth += this._hItemSize + this._spacing;
|
||||||
nColumns += 1;
|
nColumns += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,7 +300,8 @@ const IconGrid = new Lang.Class({
|
|||||||
_onStyleChanged: function() {
|
_onStyleChanged: function() {
|
||||||
let themeNode = this.actor.get_theme_node();
|
let themeNode = this.actor.get_theme_node();
|
||||||
this._spacing = themeNode.get_length('spacing');
|
this._spacing = themeNode.get_length('spacing');
|
||||||
this._item_size = themeNode.get_length('-shell-grid-item-size');
|
this._hItemSize = themeNode.get_length('-shell-grid-horizontal-item-size') || ICON_SIZE;
|
||||||
|
this._vItemSize = themeNode.get_length('-shell-grid-vertical-item-size') || ICON_SIZE;
|
||||||
this._grid.queue_relayout();
|
this._grid.queue_relayout();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -269,6 +269,11 @@ const Keyboard = new Lang.Class({
|
|||||||
|
|
||||||
this._addKeys();
|
this._addKeys();
|
||||||
|
|
||||||
|
// Keys should be layout according to the group, not the
|
||||||
|
// locale; as Caribou already provides the expected layout,
|
||||||
|
// this means enforcing LTR for all locales.
|
||||||
|
this.actor.text_direction = Clutter.TextDirection.LTR;
|
||||||
|
|
||||||
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
|
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
|
||||||
this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
this._focusNotifyId = global.stage.connect('notify::key-focus', Lang.bind(this, this._onKeyFocusChanged));
|
||||||
|
|
||||||
|
207
js/ui/keyringPrompt.js
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const GObject = imports.gi.GObject;
|
||||||
|
const Gcr = imports.gi.Gcr;
|
||||||
|
|
||||||
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
const CheckBox = imports.ui.checkBox;
|
||||||
|
|
||||||
|
let prompter = null;
|
||||||
|
|
||||||
|
const KeyringDialog = new Lang.Class({
|
||||||
|
Name: 'KeyringDialog',
|
||||||
|
Extends: ModalDialog.ModalDialog,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent({ styleClass: 'prompt-dialog' });
|
||||||
|
|
||||||
|
this.prompt = new Shell.KeyringPrompt();
|
||||||
|
this.prompt.connect('show-password', Lang.bind(this, this._onShowPassword));
|
||||||
|
this.prompt.connect('show-confirm', Lang.bind(this, this._onShowConfirm));
|
||||||
|
this.prompt.connect('hide-prompt', Lang.bind(this, this._onHidePrompt));
|
||||||
|
|
||||||
|
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
||||||
|
vertical: false });
|
||||||
|
this.contentLayout.add(mainContentBox);
|
||||||
|
|
||||||
|
let icon = new St.Icon({ icon_name: 'dialog-password-symbolic' });
|
||||||
|
mainContentBox.add(icon,
|
||||||
|
{ x_fill: true,
|
||||||
|
y_fill: false,
|
||||||
|
x_align: St.Align.END,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
this._messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
||||||
|
vertical: true });
|
||||||
|
mainContentBox.add(this._messageBox,
|
||||||
|
{ y_align: St.Align.START, expand: true, x_fill: true, y_fill: true });
|
||||||
|
|
||||||
|
let subject = new St.Label({ style_class: 'prompt-dialog-headline' });
|
||||||
|
this.prompt.bind_property('message', subject, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
|
this._messageBox.add(subject,
|
||||||
|
{ y_fill: false,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
let description = new St.Label({ style_class: 'prompt-dialog-description' });
|
||||||
|
description.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
|
description.clutter_text.line_wrap = true;
|
||||||
|
this.prompt.bind_property('description', description, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this._messageBox.add(description,
|
||||||
|
{ y_fill: true,
|
||||||
|
y_align: St.Align.START });
|
||||||
|
|
||||||
|
this._controlTable = null;
|
||||||
|
|
||||||
|
let buttons = [{ label: '',
|
||||||
|
action: Lang.bind(this, this._onCancelButton),
|
||||||
|
key: Clutter.Escape
|
||||||
|
},
|
||||||
|
{ label: '',
|
||||||
|
action: Lang.bind(this, this._onContinueButton)
|
||||||
|
}]
|
||||||
|
|
||||||
|
this.setButtons(buttons);
|
||||||
|
this._cancelButton = buttons[0].button;
|
||||||
|
this._continueButton = buttons[1].button;
|
||||||
|
|
||||||
|
this.prompt.bind_property('cancel-label', this._cancelButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this.prompt.bind_property('continue-label', this._continueButton, 'label', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildControlTable: function() {
|
||||||
|
let table = new St.Table({ style_class: 'keyring-dialog-control-table' });
|
||||||
|
let row = 0;
|
||||||
|
|
||||||
|
if (this.prompt.password_visible) {
|
||||||
|
let label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||||
|
label.set_text(_("Password:"));
|
||||||
|
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||||
|
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
|
text: '',
|
||||||
|
can_focus: true});
|
||||||
|
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||||
|
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||||
|
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
|
||||||
|
table.add(this._passwordEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
|
||||||
|
row++;
|
||||||
|
} else {
|
||||||
|
this._passwordEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.prompt.confirm_visible) {
|
||||||
|
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||||
|
label.set_text(_("Type again:"));
|
||||||
|
table.add(label, { row: row, col: 0, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||||
|
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
|
text: '',
|
||||||
|
can_focus: true});
|
||||||
|
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||||
|
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
|
||||||
|
this._confirmEntry.clutter_text.connect('activate', Lang.bind(this, this._onConfirmActivate));
|
||||||
|
table.add(this._confirmEntry, { row: row, col: 1, x_expand: true, x_fill: true, x_align: St.Align.START });
|
||||||
|
row++;
|
||||||
|
} else {
|
||||||
|
this._confirmEntry = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.prompt.set_password_actor(this._passwordEntry ? this._passwordEntry.clutter_text : null);
|
||||||
|
this.prompt.set_confirm_actor(this._confirmEntry ? this._confirmEntry.clutter_text : null);
|
||||||
|
|
||||||
|
if (this.prompt.choice_visible) {
|
||||||
|
let choice = new CheckBox.CheckBox();
|
||||||
|
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
||||||
|
table.add(choice.actor, { row: row, col: 1, x_expand: false, x_fill: true, x_align: St.Align.START });
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
|
||||||
|
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
||||||
|
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
|
warning.clutter_text.line_wrap = true;
|
||||||
|
table.add(warning, { row: row, col: 1, x_expand: false, x_fill: false, x_align: St.Align.START });
|
||||||
|
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||||
|
|
||||||
|
if (this._controlTable) {
|
||||||
|
this._controlTable.destroy_all_children();
|
||||||
|
this._controlTable.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
this._controlTable = table;
|
||||||
|
this._messageBox.add(table, { x_fill: true, y_fill: true });
|
||||||
|
},
|
||||||
|
|
||||||
|
_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())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// The above 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.
|
||||||
|
|
||||||
|
log('keyringPrompt: Failed to show modal dialog.' +
|
||||||
|
' Dismissing prompt request');
|
||||||
|
this.prompt.cancel()
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onShowPassword: function(prompt) {
|
||||||
|
this._buildControlTable();
|
||||||
|
this._ensureOpen();
|
||||||
|
this._passwordEntry.grab_key_focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onShowConfirm: function(prompt) {
|
||||||
|
this._buildControlTable();
|
||||||
|
this._ensureOpen();
|
||||||
|
this._continueButton.grab_key_focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onHidePrompt: function(prompt) {
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onPasswordActivate: function() {
|
||||||
|
if (this.prompt.confirm_visible)
|
||||||
|
this._confirmEntry.grab_key_focus();
|
||||||
|
else
|
||||||
|
this._onContinueButton();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onConfirmActivate: function() {
|
||||||
|
this._onContinueButton();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onContinueButton: function() {
|
||||||
|
this.prompt.complete()
|
||||||
|
},
|
||||||
|
|
||||||
|
_onCancelButton: function() {
|
||||||
|
this.prompt.cancel()
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
prompter = new Gcr.SystemPrompter();
|
||||||
|
prompter.connect('new-prompt', function(prompter) {
|
||||||
|
let dialog = new KeyringDialog();
|
||||||
|
return dialog.prompt;
|
||||||
|
});
|
||||||
|
|
||||||
|
let connection = Gio.DBus.session;
|
||||||
|
prompter.register(connection);
|
||||||
|
Gio.bus_own_name_on_connection (connection, 'org.gnome.keyring.SystemPrompter',
|
||||||
|
Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||||
|
}
|
@ -8,6 +8,7 @@ const Shell = imports.gi.Shell;
|
|||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const DND = imports.ui.dnd;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const ScreenSaver = imports.misc.screenSaver;
|
const ScreenSaver = imports.misc.screenSaver;
|
||||||
@ -21,7 +22,7 @@ const LayoutManager = new Lang.Class({
|
|||||||
Name: 'LayoutManager',
|
Name: 'LayoutManager',
|
||||||
|
|
||||||
_init: function () {
|
_init: function () {
|
||||||
this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
|
this._rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
|
||||||
this.monitors = [];
|
this.monitors = [];
|
||||||
this.primaryMonitor = null;
|
this.primaryMonitor = null;
|
||||||
this.primaryIndex = -1;
|
this.primaryIndex = -1;
|
||||||
@ -404,7 +405,7 @@ const HotCorner = new Lang.Class({
|
|||||||
|
|
||||||
this.actor.add_actor(this._corner);
|
this.actor.add_actor(this._corner);
|
||||||
|
|
||||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
||||||
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||||
} else {
|
} else {
|
||||||
@ -433,9 +434,9 @@ const HotCorner = new Lang.Class({
|
|||||||
Lang.bind(this, this._onCornerLeft));
|
Lang.bind(this, this._onCornerLeft));
|
||||||
|
|
||||||
// Cache the three ripples instead of dynamically creating and destroying them.
|
// Cache the three ripples instead of dynamically creating and destroying them.
|
||||||
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
|
this._ripple1 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
||||||
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
|
this._ripple2 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
||||||
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0 });
|
this._ripple3 = new St.BoxLayout({ style_class: 'ripple-box', opacity: 0, visible: false });
|
||||||
|
|
||||||
Main.uiGroup.add_actor(this._ripple1);
|
Main.uiGroup.add_actor(this._ripple1);
|
||||||
Main.uiGroup.add_actor(this._ripple2);
|
Main.uiGroup.add_actor(this._ripple2);
|
||||||
@ -456,7 +457,7 @@ const HotCorner = new Lang.Class({
|
|||||||
|
|
||||||
ripple._opacity = startOpacity;
|
ripple._opacity = startOpacity;
|
||||||
|
|
||||||
if (ripple.get_direction() == St.TextDirection.RTL)
|
if (ripple.get_text_direction() == Clutter.TextDirection.RTL)
|
||||||
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||||
|
|
||||||
ripple.visible = true;
|
ripple.visible = true;
|
||||||
@ -490,13 +491,15 @@ const HotCorner = new Lang.Class({
|
|||||||
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
if (source != Main.xdndHandler)
|
if (source != Main.xdndHandler)
|
||||||
return;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||||
this.rippleAnimation();
|
this.rippleAnimation();
|
||||||
Main.overview.showTemporarily();
|
Main.overview.showTemporarily();
|
||||||
Main.overview.beginItemDrag(actor);
|
Main.overview.beginItemDrag(actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onCornerEntered : function() {
|
_onCornerEntered : function() {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
@ -57,11 +58,10 @@ const Lightbox = new Lang.Class({
|
|||||||
if (params.width && params.height) {
|
if (params.width && params.height) {
|
||||||
this.actor.width = params.width;
|
this.actor.width = params.width;
|
||||||
this.actor.height = params.height;
|
this.actor.height = params.height;
|
||||||
this._allocationChangedSignalId = 0;
|
|
||||||
} else {
|
} else {
|
||||||
this.actor.width = container.width;
|
let constraint = new Clutter.BindConstraint({ source: container,
|
||||||
this.actor.height = container.height;
|
coordinate: Clutter.BindCoordinate.ALL });
|
||||||
this._allocationChangedSignalId = container.connect('allocation-changed', Lang.bind(this, this._allocationChanged));
|
this.actor.add_constraint(constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._actorAddedSignalId = container.connect('actor-added', Lang.bind(this, this._actorAdded));
|
this._actorAddedSignalId = container.connect('actor-added', Lang.bind(this, this._actorAdded));
|
||||||
@ -70,16 +70,6 @@ const Lightbox = new Lang.Class({
|
|||||||
this._highlighted = null;
|
this._highlighted = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_allocationChanged : function(container, box, flags) {
|
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
|
||||||
this.actor.width = this.width;
|
|
||||||
this.actor.height = this.height;
|
|
||||||
return false;
|
|
||||||
}));
|
|
||||||
this.width = this._container.width;
|
|
||||||
this.height = this._container.height;
|
|
||||||
},
|
|
||||||
|
|
||||||
_actorAdded : function(container, newChild) {
|
_actorAdded : function(container, newChild) {
|
||||||
let children = this._container.get_children();
|
let children = this._container.get_children();
|
||||||
let myIndex = children.indexOf(this.actor);
|
let myIndex = children.indexOf(this.actor);
|
||||||
@ -187,8 +177,6 @@ const Lightbox = new Lang.Class({
|
|||||||
* by destroying its container or by explicitly calling this.destroy().
|
* by destroying its container or by explicitly calling this.destroy().
|
||||||
*/
|
*/
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
if (this._allocationChangedSignalId != 0)
|
|
||||||
this._container.disconnect(this._allocationChangedSignalId);
|
|
||||||
this._container.disconnect(this._actorAddedSignalId);
|
this._container.disconnect(this._actorAddedSignalId);
|
||||||
this._container.disconnect(this._actorRemovedSignalId);
|
this._container.disconnect(this._actorRemovedSignalId);
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@ const Mainloop = imports.mainloop;
|
|||||||
|
|
||||||
const History = imports.misc.history;
|
const History = imports.misc.history;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
const Link = imports.ui.link;
|
const Link = imports.ui.link;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
@ -399,7 +400,14 @@ const ObjInspector = new Lang.Class({
|
|||||||
button.connect('clicked', Lang.bind(this, this.close));
|
button.connect('clicked', Lang.bind(this, this.close));
|
||||||
hbox.add(button);
|
hbox.add(button);
|
||||||
if (typeof(obj) == typeof({})) {
|
if (typeof(obj) == typeof({})) {
|
||||||
|
let properties = [];
|
||||||
for (let propName in obj) {
|
for (let propName in obj) {
|
||||||
|
properties.push(propName);
|
||||||
|
}
|
||||||
|
properties.sort();
|
||||||
|
|
||||||
|
for (let i = 0; i < properties.length; i++) {
|
||||||
|
let propName = properties[i];
|
||||||
let valueStr;
|
let valueStr;
|
||||||
let link;
|
let link;
|
||||||
try {
|
try {
|
||||||
@ -728,7 +736,7 @@ const Extensions = new Lang.Class({
|
|||||||
this._extensionsList.add(this._noExtensions);
|
this._extensionsList.add(this._noExtensions);
|
||||||
this.actor.add(this._extensionsList);
|
this.actor.add(this._extensionsList);
|
||||||
|
|
||||||
for (let uuid in ExtensionSystem.extensionMeta)
|
for (let uuid in ExtensionUtils.extensions)
|
||||||
this._loadExtension(null, uuid);
|
this._loadExtension(null, uuid);
|
||||||
|
|
||||||
ExtensionSystem.connect('extension-loaded',
|
ExtensionSystem.connect('extension-loaded',
|
||||||
@ -736,10 +744,10 @@ const Extensions = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_loadExtension: function(o, uuid) {
|
_loadExtension: function(o, uuid) {
|
||||||
let extension = ExtensionSystem.extensionMeta[uuid];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
// There can be cases where we create dummy extension metadata
|
// There can be cases where we create dummy extension metadata
|
||||||
// that's not really a proper extension. Don't bother with these.
|
// that's not really a proper extension. Don't bother with these.
|
||||||
if (!extension.name)
|
if (!extension.metadata.name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let extensionDisplay = this._createExtensionDisplay(extension);
|
let extensionDisplay = this._createExtensionDisplay(extension);
|
||||||
@ -751,32 +759,31 @@ const Extensions = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onViewSource: function (actor) {
|
_onViewSource: function (actor) {
|
||||||
let meta = actor._extensionMeta;
|
let extension = actor._extension;
|
||||||
let file = Gio.file_new_for_path(meta.path);
|
let uri = extension.dir.get_uri();
|
||||||
let uri = file.get_uri();
|
|
||||||
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context());
|
Gio.app_info_launch_default_for_uri(uri, global.create_app_launch_context());
|
||||||
Main.lookingGlass.close();
|
Main.lookingGlass.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onWebPage: function (actor) {
|
_onWebPage: function (actor) {
|
||||||
let meta = actor._extensionMeta;
|
let extension = actor._extension;
|
||||||
Gio.app_info_launch_default_for_uri(meta.url, global.create_app_launch_context());
|
Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context());
|
||||||
Main.lookingGlass.close();
|
Main.lookingGlass.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onViewErrors: function (actor) {
|
_onViewErrors: function (actor) {
|
||||||
let meta = actor._extensionMeta;
|
let extension = actor._extension;
|
||||||
let shouldShow = !actor._isShowing;
|
let shouldShow = !actor._isShowing;
|
||||||
|
|
||||||
if (shouldShow) {
|
if (shouldShow) {
|
||||||
let errors = ExtensionSystem.errors[meta.uuid];
|
let errors = extension.errors;
|
||||||
let errorDisplay = new St.BoxLayout({ vertical: true });
|
let errorDisplay = new St.BoxLayout({ vertical: true });
|
||||||
if (errors && errors.length) {
|
if (errors && errors.length) {
|
||||||
for (let i = 0; i < errors.length; i ++)
|
for (let i = 0; i < errors.length; i ++)
|
||||||
errorDisplay.add(new St.Label({ text: errors[i] }));
|
errorDisplay.add(new St.Label({ text: errors[i] }));
|
||||||
} else {
|
} else {
|
||||||
/* Translators: argument is an extension UUID. */
|
/* Translators: argument is an extension UUID. */
|
||||||
let message = _("%s has not emitted any errors.").format(meta.uuid);
|
let message = _("%s has not emitted any errors.").format(extension.uuid);
|
||||||
errorDisplay.add(new St.Label({ text: message }));
|
errorDisplay.add(new St.Label({ text: message }));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -809,36 +816,36 @@ const Extensions = new Lang.Class({
|
|||||||
return 'Unknown'; // Not translated, shouldn't appear
|
return 'Unknown'; // Not translated, shouldn't appear
|
||||||
},
|
},
|
||||||
|
|
||||||
_createExtensionDisplay: function(meta) {
|
_createExtensionDisplay: function(extension) {
|
||||||
let box = new St.BoxLayout({ style_class: 'lg-extension', vertical: true });
|
let box = new St.BoxLayout({ style_class: 'lg-extension', vertical: true });
|
||||||
let name = new St.Label({ style_class: 'lg-extension-name',
|
let name = new St.Label({ style_class: 'lg-extension-name',
|
||||||
text: meta.name });
|
text: extension.metadata.name });
|
||||||
box.add(name, { expand: true });
|
box.add(name, { expand: true });
|
||||||
let description = new St.Label({ style_class: 'lg-extension-description',
|
let description = new St.Label({ style_class: 'lg-extension-description',
|
||||||
text: meta.description || 'No description' });
|
text: extension.metadata.description || 'No description' });
|
||||||
box.add(description, { expand: true });
|
box.add(description, { expand: true });
|
||||||
|
|
||||||
let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
|
let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
|
||||||
box.add(metaBox);
|
box.add(metaBox);
|
||||||
let stateString = this._stateToString(meta.state);
|
let stateString = this._stateToString(extension.state);
|
||||||
let state = new St.Label({ style_class: 'lg-extension-state',
|
let state = new St.Label({ style_class: 'lg-extension-state',
|
||||||
text: this._stateToString(meta.state) });
|
text: this._stateToString(extension.state) });
|
||||||
metaBox.add(state);
|
metaBox.add(state);
|
||||||
|
|
||||||
let viewsource = new Link.Link({ label: _("View Source") });
|
let viewsource = new Link.Link({ label: _("View Source") });
|
||||||
viewsource.actor._extensionMeta = meta;
|
viewsource.actor._extension = extension;
|
||||||
viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource));
|
viewsource.actor.connect('clicked', Lang.bind(this, this._onViewSource));
|
||||||
metaBox.add(viewsource.actor);
|
metaBox.add(viewsource.actor);
|
||||||
|
|
||||||
if (meta.url) {
|
if (extension.metadata.url) {
|
||||||
let webpage = new Link.Link({ label: _("Web Page") });
|
let webpage = new Link.Link({ label: _("Web Page") });
|
||||||
webpage.actor._extensionMeta = meta;
|
webpage.actor._extension = extension;
|
||||||
webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage));
|
webpage.actor.connect('clicked', Lang.bind(this, this._onWebPage));
|
||||||
metaBox.add(webpage.actor);
|
metaBox.add(webpage.actor);
|
||||||
}
|
}
|
||||||
|
|
||||||
let viewerrors = new Link.Link({ label: _("Show Errors") });
|
let viewerrors = new Link.Link({ label: _("Show Errors") });
|
||||||
viewerrors.actor._extensionMeta = meta;
|
viewerrors.actor._extension = extension;
|
||||||
viewerrors.actor._parentBox = box;
|
viewerrors.actor._parentBox = box;
|
||||||
viewerrors.actor._isShowing = false;
|
viewerrors.actor._isShowing = false;
|
||||||
viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
|
viewerrors.actor.connect('clicked', Lang.bind(this, this._onViewErrors));
|
||||||
@ -1038,7 +1045,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
actor.add(padBin);
|
actor.add(padBin);
|
||||||
|
|
||||||
this._completionActor = actor;
|
this._completionActor = actor;
|
||||||
this._evalBox.insert_before(this._completionActor, this._entryArea);
|
this._evalBox.insert_child_below(this._completionActor, this._entryArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._completionText.set_text(completions.join(', '));
|
this._completionText.set_text(completions.join(', '));
|
||||||
@ -1140,7 +1147,7 @@ const LookingGlass = new Lang.Class({
|
|||||||
// Handle key events which are relevant for all tabs of the LookingGlass
|
// Handle key events which are relevant for all tabs of the LookingGlass
|
||||||
_globalKeyPressEvent : function(actor, event) {
|
_globalKeyPressEvent : function(actor, event) {
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
let modifierState = Shell.get_event_state(event);
|
let modifierState = event.get_state();
|
||||||
if (symbol == Clutter.Escape) {
|
if (symbol == Clutter.Escape) {
|
||||||
if (this._objInspector.actor.visible) {
|
if (this._objInspector.actor.visible) {
|
||||||
this._objInspector.close();
|
this._objInspector.close();
|
||||||
|
@ -44,7 +44,7 @@ const Magnifier = new Lang.Class({
|
|||||||
this._zoomRegions = [];
|
this._zoomRegions = [];
|
||||||
|
|
||||||
// Create small clutter tree for the magnified mouse.
|
// Create small clutter tree for the magnified mouse.
|
||||||
let xfixesCursor = Shell.XFixesCursor.get_default();
|
let xfixesCursor = Shell.XFixesCursor.get_for_stage(global.stage);
|
||||||
this._mouseSprite = new Clutter.Texture();
|
this._mouseSprite = new Clutter.Texture();
|
||||||
xfixesCursor.update_texture_image(this._mouseSprite);
|
xfixesCursor.update_texture_image(this._mouseSprite);
|
||||||
this._cursorRoot = new Clutter.Group();
|
this._cursorRoot = new Clutter.Group();
|
||||||
@ -556,6 +556,7 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
|
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.FULL_SCREEN;
|
||||||
|
|
||||||
this._magView = null;
|
this._magView = null;
|
||||||
|
this._background = null;
|
||||||
this._uiGroupClone = null;
|
this._uiGroupClone = null;
|
||||||
this._mouseSourceActor = mouseSourceActor;
|
this._mouseSourceActor = mouseSourceActor;
|
||||||
this._mouseActor = null;
|
this._mouseActor = null;
|
||||||
@ -565,12 +566,15 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._viewPortX = 0;
|
this._viewPortX = 0;
|
||||||
this._viewPortY = 0;
|
this._viewPortY = 0;
|
||||||
this._viewPortWidth = global.screen_width;
|
this._viewPortWidth = global.screen_width;
|
||||||
this._viewPortWidth = global.screen_height;
|
this._viewPortHeight = global.screen_height;
|
||||||
this._xCenter = this._viewPortWidth / 2;
|
this._xCenter = this._viewPortWidth / 2;
|
||||||
this._yCenter = this._viewPortHeight / 2;
|
this._yCenter = this._viewPortHeight / 2;
|
||||||
this._xMagFactor = 1;
|
this._xMagFactor = 1;
|
||||||
this._yMagFactor = 1;
|
this._yMagFactor = 1;
|
||||||
this._followingCursor = false;
|
this._followingCursor = false;
|
||||||
|
|
||||||
|
Main.layoutManager.connect('monitors-changed',
|
||||||
|
Lang.bind(this, this._monitorsChanged));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -891,15 +895,15 @@ const ZoomRegion = new Lang.Class({
|
|||||||
|
|
||||||
// Add a background for when the magnified uiGroup is scrolled
|
// Add a background for when the magnified uiGroup is scrolled
|
||||||
// out of view (don't want to see desktop showing through).
|
// out of view (don't want to see desktop showing through).
|
||||||
let background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
|
this._background = new Clutter.Rectangle({ color: Main.DEFAULT_BACKGROUND_COLOR });
|
||||||
mainGroup.add_actor(background);
|
mainGroup.add_actor(this._background);
|
||||||
|
|
||||||
// Clone the group that contains all of UI on the screen. This is the
|
// Clone the group that contains all of UI on the screen. This is the
|
||||||
// chrome, the windows, etc.
|
// chrome, the windows, etc.
|
||||||
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
||||||
mainGroup.add_actor(this._uiGroupClone);
|
mainGroup.add_actor(this._uiGroupClone);
|
||||||
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
||||||
background.set_size(global.screen_width, global.screen_height);
|
this._background.set_size(global.screen_width, global.screen_height);
|
||||||
|
|
||||||
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
||||||
// it.
|
// it.
|
||||||
@ -923,6 +927,7 @@ const ZoomRegion = new Lang.Class({
|
|||||||
|
|
||||||
this._magView.destroy();
|
this._magView.destroy();
|
||||||
this._magView = null;
|
this._magView = null;
|
||||||
|
this._background = null;
|
||||||
this._uiGroupClone = null;
|
this._uiGroupClone = null;
|
||||||
this._mouseActor = null;
|
this._mouseActor = null;
|
||||||
this._crossHairsActor = null;
|
this._crossHairsActor = null;
|
||||||
@ -1145,6 +1150,22 @@ const ZoomRegion = new Lang.Class({
|
|||||||
this._crossHairsActor.set_position(xMagMouse - groupWidth / 2,
|
this._crossHairsActor.set_position(xMagMouse - groupWidth / 2,
|
||||||
yMagMouse - groupHeight / 2);
|
yMagMouse - groupHeight / 2);
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_monitorsChanged: function() {
|
||||||
|
if (!this.isActive())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Main.uiGroup.set_size(global.screen_width, global.screen_height);
|
||||||
|
this._background.set_size(global.screen_width, global.screen_height);
|
||||||
|
|
||||||
|
if (this._screenPosition == GDesktopEnums.MagnifierScreenPosition.NONE)
|
||||||
|
this._setViewPort({ x: this._viewPortX,
|
||||||
|
y: this._viewPortY,
|
||||||
|
width: this._viewPortWidth,
|
||||||
|
height: this._viewPortHeight });
|
||||||
|
else
|
||||||
|
this.setScreenPosition(this._screenPosition);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1175,6 +1196,14 @@ const Crosshairs = new Lang.Class({
|
|||||||
this._clipSize = [0, 0];
|
this._clipSize = [0, 0];
|
||||||
this._clones = [];
|
this._clones = [];
|
||||||
this.reCenter();
|
this.reCenter();
|
||||||
|
|
||||||
|
Main.layoutManager.connect('monitors-changed',
|
||||||
|
Lang.bind(this, this._monitorsChanged));
|
||||||
|
},
|
||||||
|
|
||||||
|
_monitorsChanged: function() {
|
||||||
|
this._actor.set_size(global.screen_width * 3, global.screen_height * 3);
|
||||||
|
this.reCenter();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,6 +15,7 @@ const AutorunManager = imports.ui.autorunManager;
|
|||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const EndSessionDialog = imports.ui.endSessionDialog;
|
const EndSessionDialog = imports.ui.endSessionDialog;
|
||||||
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
||||||
|
const KeyringPrompt = imports.ui.keyringPrompt;
|
||||||
const Environment = imports.ui.environment;
|
const Environment = imports.ui.environment;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
const Keyboard = imports.ui.keyboard;
|
const Keyboard = imports.ui.keyboard;
|
||||||
@ -37,6 +38,7 @@ const XdndHandler = imports.ui.xdndHandler;
|
|||||||
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
|
const StatusIconDispatcher = imports.ui.statusIconDispatcher;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
|
const OVERRIDES_SCHEMA = 'org.gnome.shell.overrides';
|
||||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
||||||
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
||||||
|
|
||||||
@ -70,6 +72,7 @@ let _startDate;
|
|||||||
let _defaultCssStylesheet = null;
|
let _defaultCssStylesheet = null;
|
||||||
let _cssStylesheet = null;
|
let _cssStylesheet = null;
|
||||||
let _gdmCssStylesheet = null;
|
let _gdmCssStylesheet = null;
|
||||||
|
let _overridesSettings = null;
|
||||||
|
|
||||||
let background = null;
|
let background = null;
|
||||||
|
|
||||||
@ -110,7 +113,9 @@ function _initRecorder() {
|
|||||||
} else {
|
} else {
|
||||||
// read the parameters from GSettings always in case they have changed
|
// read the parameters from GSettings always in case they have changed
|
||||||
recorder.set_framerate(recorderSettings.get_int('framerate'));
|
recorder.set_framerate(recorderSettings.get_int('framerate'));
|
||||||
recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
|
/* Translators: this is a filename used for screencast recording */
|
||||||
|
// xgettext:no-c-format
|
||||||
|
recorder.set_filename(_("Screencast from %d %t") + '.' + recorderSettings.get_string('file-extension'));
|
||||||
let pipeline = recorderSettings.get_string('pipeline');
|
let pipeline = recorderSettings.get_string('pipeline');
|
||||||
|
|
||||||
if (!pipeline.match(/^\s*$/))
|
if (!pipeline.match(/^\s*$/))
|
||||||
@ -166,9 +171,11 @@ function start() {
|
|||||||
// and recalculate application associations, so to avoid
|
// and recalculate application associations, so to avoid
|
||||||
// races for now we initialize it here. It's better to
|
// races for now we initialize it here. It's better to
|
||||||
// be predictable anyways.
|
// be predictable anyways.
|
||||||
Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
Shell.AppUsage.get_default();
|
Shell.AppUsage.get_default();
|
||||||
|
|
||||||
|
tracker.connect('startup-sequence-changed', _queueCheckWorkspaces);
|
||||||
|
|
||||||
// The stage is always covered so Clutter doesn't need to clear it; however
|
// The stage is always covered so Clutter doesn't need to clear it; however
|
||||||
// the color is used as the default contents for the Mutter root background
|
// the color is used as the default contents for the Mutter root background
|
||||||
// actor so set it anyways.
|
// actor so set it anyways.
|
||||||
@ -187,7 +194,16 @@ function start() {
|
|||||||
for (let i = 0; i < children.length; i++)
|
for (let i = 0; i < children.length; i++)
|
||||||
children[i].allocate_preferred_size(flags);
|
children[i].allocate_preferred_size(flags);
|
||||||
});
|
});
|
||||||
St.set_ui_root(global.stage, uiGroup);
|
uiGroup.connect('get-preferred-width',
|
||||||
|
function(actor, forHeight, alloc) {
|
||||||
|
let width = global.stage.width;
|
||||||
|
[alloc.min_size, alloc.natural_size] = [width, width];
|
||||||
|
});
|
||||||
|
uiGroup.connect('get-preferred-height',
|
||||||
|
function(actor, forWidth, alloc) {
|
||||||
|
let height = global.stage.height;
|
||||||
|
[alloc.min_size, alloc.natural_size] = [height, height];
|
||||||
|
});
|
||||||
global.window_group.reparent(uiGroup);
|
global.window_group.reparent(uiGroup);
|
||||||
global.overlay_group.reparent(uiGroup);
|
global.overlay_group.reparent(uiGroup);
|
||||||
global.stage.add_actor(uiGroup);
|
global.stage.add_actor(uiGroup);
|
||||||
@ -228,6 +244,9 @@ function start() {
|
|||||||
// Attempt to become a PolicyKit authentication agent
|
// Attempt to become a PolicyKit authentication agent
|
||||||
PolkitAuthenticationAgent.init()
|
PolkitAuthenticationAgent.init()
|
||||||
|
|
||||||
|
// Become a prompter for gnome keyring
|
||||||
|
KeyringPrompt.init();
|
||||||
|
|
||||||
_startDate = new Date();
|
_startDate = new Date();
|
||||||
|
|
||||||
global.stage.connect('captured-event', _globalKeyPressHandler);
|
global.stage.connect('captured-event', _globalKeyPressHandler);
|
||||||
@ -242,6 +261,9 @@ function start() {
|
|||||||
Scripting.runPerfScript(module, perfOutput);
|
Scripting.runPerfScript(module, perfOutput);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_overridesSettings = new Gio.Settings({ schema: OVERRIDES_SCHEMA });
|
||||||
|
_overridesSettings.connect('changed::dynamic-workspaces', _queueCheckWorkspaces);
|
||||||
|
|
||||||
global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
|
global.screen.connect('notify::n-workspaces', _nWorkspacesChanged);
|
||||||
|
|
||||||
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
|
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
|
||||||
@ -266,17 +288,30 @@ function _checkWorkspaces() {
|
|||||||
let i;
|
let i;
|
||||||
let emptyWorkspaces = [];
|
let emptyWorkspaces = [];
|
||||||
|
|
||||||
|
if (!Meta.prefs_get_dynamic_workspaces()) {
|
||||||
|
_checkWorkspacesId = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < _workspaces.length; i++) {
|
for (i = 0; i < _workspaces.length; i++) {
|
||||||
let lastRemoved = _workspaces[i]._lastRemovedWindow;
|
let lastRemoved = _workspaces[i]._lastRemovedWindow;
|
||||||
if (lastRemoved &&
|
if ((lastRemoved &&
|
||||||
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
|
(lastRemoved.get_window_type() == Meta.WindowType.SPLASHSCREEN ||
|
||||||
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
|
lastRemoved.get_window_type() == Meta.WindowType.DIALOG ||
|
||||||
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG))
|
lastRemoved.get_window_type() == Meta.WindowType.MODAL_DIALOG)) ||
|
||||||
|
_workspaces[i]._keepAliveId)
|
||||||
emptyWorkspaces[i] = false;
|
emptyWorkspaces[i] = false;
|
||||||
else
|
else
|
||||||
emptyWorkspaces[i] = true;
|
emptyWorkspaces[i] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sequences = Shell.WindowTracker.get_default().get_startup_sequences();
|
||||||
|
for (i = 0; i < sequences.length; i++) {
|
||||||
|
let index = sequences[i].get_workspace();
|
||||||
|
if (index >= 0 && index <= global.screen.n_workspaces)
|
||||||
|
emptyWorkspaces[index] = false;
|
||||||
|
}
|
||||||
|
|
||||||
let windows = global.get_window_actors();
|
let windows = global.get_window_actors();
|
||||||
for (i = 0; i < windows.length; i++) {
|
for (i = 0; i < windows.length; i++) {
|
||||||
let win = windows[i];
|
let win = windows[i];
|
||||||
@ -324,6 +359,17 @@ function _checkWorkspaces() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function keepWorkspaceAlive(workspace, duration) {
|
||||||
|
if (workspace._keepAliveId)
|
||||||
|
Mainloop.source_remove(workspace._keepAliveId);
|
||||||
|
|
||||||
|
workspace._keepAliveId = Mainloop.timeout_add(duration, function() {
|
||||||
|
workspace._keepAliveId = 0;
|
||||||
|
_queueCheckWorkspaces();
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function _windowRemoved(workspace, window) {
|
function _windowRemoved(workspace, window) {
|
||||||
workspace._lastRemovedWindow = window;
|
workspace._lastRemovedWindow = window;
|
||||||
_queueCheckWorkspaces();
|
_queueCheckWorkspaces();
|
||||||
@ -332,6 +378,7 @@ function _windowRemoved(workspace, window) {
|
|||||||
workspace._lastRemovedWindow = null;
|
workspace._lastRemovedWindow = null;
|
||||||
_queueCheckWorkspaces();
|
_queueCheckWorkspaces();
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -567,7 +614,8 @@ function _globalKeyPressHandler(actor, event) {
|
|||||||
|
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
let keyCode = event.get_key_code();
|
let keyCode = event.get_key_code();
|
||||||
let modifierState = Shell.get_event_state(event);
|
let ignoredModifiers = global.display.get_ignored_modifier_mask();
|
||||||
|
let modifierState = event.get_state() & ~ignoredModifiers;
|
||||||
|
|
||||||
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
// This relies on the fact that Clutter.ModifierType is the same as Gdk.ModifierType
|
||||||
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
let action = global.display.get_keybinding_action(keyCode, modifierState);
|
||||||
|
@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
|
|||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
@ -261,7 +262,9 @@ const FocusGrabber = new Lang.Class({
|
|||||||
|
|
||||||
this._hasFocus = true;
|
this._hasFocus = true;
|
||||||
|
|
||||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
if (!this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
|
||||||
|
this.actor.grab_key_focus();
|
||||||
|
|
||||||
this.emit('focus-grabbed');
|
this.emit('focus-grabbed');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -423,7 +426,7 @@ const Notification = new Lang.Class({
|
|||||||
this._bannerBodyText = null;
|
this._bannerBodyText = null;
|
||||||
this._bannerBodyMarkup = false;
|
this._bannerBodyMarkup = false;
|
||||||
this._titleFitsInBannerMode = true;
|
this._titleFitsInBannerMode = true;
|
||||||
this._titleDirection = St.TextDirection.NONE;
|
this._titleDirection = Clutter.TextDirection.DEFAULT;
|
||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
|
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
|
||||||
this._imageBin = null;
|
this._imageBin = null;
|
||||||
@ -433,7 +436,7 @@ const Notification = new Lang.Class({
|
|||||||
this.destroy(reason);
|
this.destroy(reason);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.actor = new St.Button();
|
this.actor = new St.Button({ accessible_role: Atk.Role.NOTIFICATION });
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
@ -544,9 +547,9 @@ const Notification = new Lang.Class({
|
|||||||
this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>');
|
this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>');
|
||||||
|
|
||||||
if (Pango.find_base_dir(title, -1) == Pango.Direction.RTL)
|
if (Pango.find_base_dir(title, -1) == Pango.Direction.RTL)
|
||||||
this._titleDirection = St.TextDirection.RTL;
|
this._titleDirection = Clutter.TextDirection.RTL;
|
||||||
else
|
else
|
||||||
this._titleDirection = St.TextDirection.LTR;
|
this._titleDirection = Clutter.TextDirection.LTR;
|
||||||
|
|
||||||
// Let the title's text direction control the overall direction
|
// Let the title's text direction control the overall direction
|
||||||
// of the notification - in case where different scripts are used
|
// of the notification - in case where different scripts are used
|
||||||
@ -554,7 +557,7 @@ const Notification = new Lang.Class({
|
|||||||
// arguably for action buttons as well. Labels other than the title
|
// arguably for action buttons as well. Labels other than the title
|
||||||
// will be allocated at the available width, so that their alignment
|
// will be allocated at the available width, so that their alignment
|
||||||
// is done correctly automatically.
|
// is done correctly automatically.
|
||||||
this._table.set_direction(this._titleDirection);
|
this._table.set_text_direction(this._titleDirection);
|
||||||
|
|
||||||
// Unless the notification has custom content, we save this._bannerBodyText
|
// Unless the notification has custom content, we save this._bannerBodyText
|
||||||
// to add it to the content of the notification if the notification is
|
// to add it to the content of the notification if the notification is
|
||||||
@ -574,7 +577,7 @@ const Notification = new Lang.Class({
|
|||||||
|
|
||||||
if (params.body)
|
if (params.body)
|
||||||
this.addBody(params.body, params.bodyMarkup);
|
this.addBody(params.body, params.bodyMarkup);
|
||||||
this._updated();
|
this.updated();
|
||||||
},
|
},
|
||||||
|
|
||||||
setIconVisible: function(visible) {
|
setIconVisible: function(visible) {
|
||||||
@ -613,7 +616,7 @@ const Notification = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._contentArea.add(actor, style ? style : {});
|
this._contentArea.add(actor, style ? style : {});
|
||||||
this._updated();
|
this.updated();
|
||||||
},
|
},
|
||||||
|
|
||||||
// addBody:
|
// addBody:
|
||||||
@ -676,7 +679,7 @@ const Notification = new Lang.Class({
|
|||||||
this._table.add_style_class_name('multi-line-notification');
|
this._table.add_style_class_name('multi-line-notification');
|
||||||
this._table.add(this._actionArea, props);
|
this._table.add(this._actionArea, props);
|
||||||
this._updateLastColumnSettings();
|
this._updateLastColumnSettings();
|
||||||
this._updated();
|
this.updated();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateLastColumnSettings: function() {
|
_updateLastColumnSettings: function() {
|
||||||
@ -757,7 +760,7 @@ const Notification = new Lang.Class({
|
|||||||
this._buttonFocusManager.add_group(this._buttonBox);
|
this._buttonFocusManager.add_group(this._buttonBox);
|
||||||
button.connect('clicked', Lang.bind(this, this._onActionInvoked, id));
|
button.connect('clicked', Lang.bind(this, this._onActionInvoked, id));
|
||||||
|
|
||||||
this._updated();
|
this.updated();
|
||||||
},
|
},
|
||||||
|
|
||||||
setUrgency: function(urgency) {
|
setUrgency: function(urgency) {
|
||||||
@ -802,7 +805,7 @@ const Notification = new Lang.Class({
|
|||||||
|
|
||||||
let titleBox = new Clutter.ActorBox();
|
let titleBox = new Clutter.ActorBox();
|
||||||
let titleBoxW = Math.min(titleNatW, availWidth);
|
let titleBoxW = Math.min(titleNatW, availWidth);
|
||||||
if (this._titleDirection == St.TextDirection.RTL) {
|
if (this._titleDirection == Clutter.TextDirection.RTL) {
|
||||||
titleBox.x1 = availWidth - titleBoxW;
|
titleBox.x1 = availWidth - titleBoxW;
|
||||||
titleBox.x2 = availWidth;
|
titleBox.x2 = availWidth;
|
||||||
} else {
|
} else {
|
||||||
@ -821,7 +824,7 @@ const Notification = new Lang.Class({
|
|||||||
} else {
|
} else {
|
||||||
let bannerBox = new Clutter.ActorBox();
|
let bannerBox = new Clutter.ActorBox();
|
||||||
|
|
||||||
if (this._titleDirection == St.TextDirection.RTL) {
|
if (this._titleDirection == Clutter.TextDirection.RTL) {
|
||||||
bannerBox.x1 = 0;
|
bannerBox.x1 = 0;
|
||||||
bannerBox.x2 = titleBox.x1 - this._spacing;
|
bannerBox.x2 = titleBox.x1 - this._spacing;
|
||||||
|
|
||||||
@ -853,7 +856,7 @@ const Notification = new Lang.Class({
|
|||||||
if (this._canExpandContent()) {
|
if (this._canExpandContent()) {
|
||||||
this._addBannerBody();
|
this._addBannerBody();
|
||||||
this._table.add_style_class_name('multi-line-notification');
|
this._table.add_style_class_name('multi-line-notification');
|
||||||
this._updated();
|
this.updated();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}));
|
}));
|
||||||
@ -864,7 +867,7 @@ const Notification = new Lang.Class({
|
|||||||
(!this._titleFitsInBannerMode && !this._table.has_style_class_name('multi-line-notification'));
|
(!this._titleFitsInBannerMode && !this._table.has_style_class_name('multi-line-notification'));
|
||||||
},
|
},
|
||||||
|
|
||||||
_updated: function() {
|
updated: function() {
|
||||||
if (this.expanded)
|
if (this.expanded)
|
||||||
this.expand(false);
|
this.expand(false);
|
||||||
},
|
},
|
||||||
@ -1005,9 +1008,9 @@ const Source = new Lang.Class({
|
|||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
|
|
||||||
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
|
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
|
||||||
let direction = this.actor.get_direction();
|
let direction = this.actor.get_text_direction();
|
||||||
|
|
||||||
if (direction == St.TextDirection.LTR) {
|
if (direction == Clutter.TextDirection.LTR) {
|
||||||
// allocate on the right in LTR
|
// allocate on the right in LTR
|
||||||
childBox.x1 = box.x2 - naturalWidth;
|
childBox.x1 = box.x2 - naturalWidth;
|
||||||
childBox.x2 = box.x2;
|
childBox.x2 = box.x2;
|
||||||
@ -1327,8 +1330,9 @@ const SummaryItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.notificationStack.get_children().length > 0)
|
let firstNotification = this._stackedNotifications[0];
|
||||||
this.notificationStack.get_children()[0]._delegate.setIconVisible(true);
|
if (firstNotification)
|
||||||
|
firstNotification.notification.setIconVisible(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Signals.addSignalMethods(SummaryItem.prototype);
|
Signals.addSignalMethods(SummaryItem.prototype);
|
||||||
@ -1340,16 +1344,14 @@ const MessageTray = new Lang.Class({
|
|||||||
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
|
this._presence = new GnomeSession.Presence(Lang.bind(this, function(proxy, error) {
|
||||||
this._onStatusChanged(proxy.status);
|
this._onStatusChanged(proxy.status);
|
||||||
}));
|
}));
|
||||||
this._userStatus = GnomeSession.PresenceStatus.AVAILABLE;
|
|
||||||
this._busy = false;
|
this._busy = false;
|
||||||
this._backFromAway = false;
|
|
||||||
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
this._presence.connectSignal('StatusChanged', Lang.bind(this, function(proxy, senderName, [status]) {
|
||||||
this._onStatusChanged(status);
|
this._onStatusChanged(status);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.actor = new St.Group({ name: 'message-tray',
|
this.actor = new St.Widget({ name: 'message-tray',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
track_hover: true });
|
track_hover: true });
|
||||||
this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged));
|
this.actor.connect('notify::hover', Lang.bind(this, this._onTrayHoverChanged));
|
||||||
|
|
||||||
this._notificationBin = new St.Bin();
|
this._notificationBin = new St.Bin();
|
||||||
@ -1388,6 +1390,12 @@ const MessageTray = new Lang.Class({
|
|||||||
this._summaryItemTitleWidth = 0;
|
this._summaryItemTitleWidth = 0;
|
||||||
this._pointerBarrier = 0;
|
this._pointerBarrier = 0;
|
||||||
|
|
||||||
|
this._unseenNotifications = [];
|
||||||
|
this._idleMonitorWatchId = 0;
|
||||||
|
this._backFromAway = false;
|
||||||
|
|
||||||
|
this.idleMonitor = new Shell.IdleMonitor();
|
||||||
|
|
||||||
// To simplify the summary item animation code, we pretend
|
// To simplify the summary item animation code, we pretend
|
||||||
// that there's an invisible SummaryItem to the left of the
|
// that there's an invisible SummaryItem to the left of the
|
||||||
// leftmost real summary item, and that it's expanded when all
|
// leftmost real summary item, and that it's expanded when all
|
||||||
@ -1430,8 +1438,16 @@ const MessageTray = new Lang.Class({
|
|||||||
this._notificationRemoved = false;
|
this._notificationRemoved = false;
|
||||||
this._reNotifyAfterHideNotification = null;
|
this._reNotifyAfterHideNotification = null;
|
||||||
|
|
||||||
|
this._corner = new Clutter.Rectangle({ width: 1,
|
||||||
|
height: 1,
|
||||||
|
opacity: 0,
|
||||||
|
reactive: true });
|
||||||
|
this._corner.connect('enter-event', Lang.bind(this, this._onCornerEnter));
|
||||||
|
Main.layoutManager.trayBox.add_actor(this._corner);
|
||||||
|
Main.layoutManager.trackChrome(this._corner);
|
||||||
|
|
||||||
Main.layoutManager.trayBox.add_actor(this.actor);
|
Main.layoutManager.trayBox.add_actor(this.actor);
|
||||||
this.actor.y = -1;
|
this.actor.y = this.actor.height;
|
||||||
Main.layoutManager.trackChrome(this.actor);
|
Main.layoutManager.trackChrome(this.actor);
|
||||||
Main.layoutManager.trackChrome(this._notificationBin);
|
Main.layoutManager.trackChrome(this._notificationBin);
|
||||||
|
|
||||||
@ -1470,12 +1486,24 @@ const MessageTray = new Lang.Class({
|
|||||||
this._chatSummaryItemsCount = 0;
|
this._chatSummaryItemsCount = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onCornerEnter: function(actor, event) {
|
||||||
|
this._pointerInSummary = true;
|
||||||
|
this._updateState();
|
||||||
|
},
|
||||||
|
|
||||||
_setSizePosition: function() {
|
_setSizePosition: function() {
|
||||||
let monitor = Main.layoutManager.bottomMonitor;
|
let monitor = Main.layoutManager.bottomMonitor;
|
||||||
this._notificationBin.x = 0;
|
this._notificationBin.x = 0;
|
||||||
this._notificationBin.width = monitor.width;
|
this._notificationBin.width = monitor.width;
|
||||||
this._summaryBin.x = 0;
|
this._summaryBin.x = 0;
|
||||||
this._summaryBin.width = monitor.width;
|
this._summaryBin.width = monitor.width;
|
||||||
|
|
||||||
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
|
this._corner.x = 0;
|
||||||
|
else
|
||||||
|
this._corner.x = Main.layoutManager.trayBox.width - 1;
|
||||||
|
|
||||||
|
this._corner.y = Main.layoutManager.trayBox.height - 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
contains: function(source) {
|
contains: function(source) {
|
||||||
@ -1499,10 +1527,10 @@ const MessageTray = new Lang.Class({
|
|||||||
let summaryItem = new SummaryItem(source);
|
let summaryItem = new SummaryItem(source);
|
||||||
|
|
||||||
if (source.isChat) {
|
if (source.isChat) {
|
||||||
this._summary.insert_actor(summaryItem.actor, 0);
|
this._summary.insert_child_at_index(summaryItem.actor, 0);
|
||||||
this._chatSummaryItemsCount++;
|
this._chatSummaryItemsCount++;
|
||||||
} else {
|
} else {
|
||||||
this._summary.insert_actor(summaryItem.actor, this._chatSummaryItemsCount);
|
this._summary.insert_child_at_index(summaryItem.actor, this._chatSummaryItemsCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleWidth = summaryItem.getTitleNaturalWidth();
|
let titleWidth = summaryItem.getTitleNaturalWidth();
|
||||||
@ -1611,6 +1639,10 @@ const MessageTray = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onNotificationDestroy: function(notification) {
|
_onNotificationDestroy: function(notification) {
|
||||||
|
let unseenNotificationsIndex = this._unseenNotifications.indexOf(notification);
|
||||||
|
if (unseenNotificationsIndex != -1)
|
||||||
|
this._unseenNotifications.splice(unseenNotificationsIndex, 1);
|
||||||
|
|
||||||
if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) {
|
if (this._notification == notification && (this._notificationState == State.SHOWN || this._notificationState == State.SHOWING)) {
|
||||||
this._updateNotificationTimeout(0);
|
this._updateNotificationTimeout(0);
|
||||||
this._notificationRemoved = true;
|
this._notificationRemoved = true;
|
||||||
@ -1894,16 +1926,10 @@ const MessageTray = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onStatusChanged: function(status) {
|
_onStatusChanged: function(status) {
|
||||||
this._backFromAway = (this._userStatus == GnomeSession.PresenceStatus.IDLE && this._userStatus != status);
|
|
||||||
this._userStatus = status;
|
|
||||||
|
|
||||||
if (status == GnomeSession.PresenceStatus.BUSY) {
|
if (status == GnomeSession.PresenceStatus.BUSY) {
|
||||||
// remove notification and allow the summary to be closed now
|
// remove notification and allow the summary to be closed now
|
||||||
this._updateNotificationTimeout(0);
|
this._updateNotificationTimeout(0);
|
||||||
if (this._summaryTimeoutId) {
|
this._unsetSummaryTimeout();
|
||||||
Mainloop.source_remove(this._summaryTimeoutId);
|
|
||||||
this._summaryTimeoutId = 0;
|
|
||||||
}
|
|
||||||
this._busy = true;
|
this._busy = true;
|
||||||
} else if (status != GnomeSession.PresenceStatus.IDLE) {
|
} else if (status != GnomeSession.PresenceStatus.IDLE) {
|
||||||
// We preserve the previous value of this._busy if the status turns to IDLE
|
// We preserve the previous value of this._busy if the status turns to IDLE
|
||||||
@ -1933,6 +1959,7 @@ const MessageTray = new Lang.Class({
|
|||||||
this._pointerInTray = false;
|
this._pointerInTray = false;
|
||||||
this._pointerInSummary = false;
|
this._pointerInSummary = false;
|
||||||
this._updateNotificationTimeout(0);
|
this._updateNotificationTimeout(0);
|
||||||
|
this._unsetSummaryTimeout();
|
||||||
this._updateState();
|
this._updateState();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -1943,6 +1970,7 @@ const MessageTray = new Lang.Class({
|
|||||||
this._pointerInTray = false;
|
this._pointerInTray = false;
|
||||||
this._pointerInSummary = false;
|
this._pointerInSummary = false;
|
||||||
this._updateNotificationTimeout(0);
|
this._updateNotificationTimeout(0);
|
||||||
|
this._unsetSummaryTimeout();
|
||||||
this._updateState();
|
this._updateState();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1988,15 +2016,13 @@ const MessageTray = new Lang.Class({
|
|||||||
|| notificationsVisible;
|
|| notificationsVisible;
|
||||||
|
|
||||||
if (this._summaryState == State.HIDDEN && !mustHideSummary) {
|
if (this._summaryState == State.HIDDEN && !mustHideSummary) {
|
||||||
if (this._backFromAway) {
|
if (summarySummoned) {
|
||||||
// Immediately set this to false, so that we don't schedule a timeout later
|
|
||||||
this._backFromAway = false;
|
|
||||||
if (!this._busy)
|
|
||||||
this._showSummary(LONGER_SUMMARY_TIMEOUT);
|
|
||||||
} else if (notificationsDone && this._newSummaryItems.length > 0 && !this._busy) {
|
|
||||||
this._showSummary(SUMMARY_TIMEOUT);
|
|
||||||
} else if (summarySummoned) {
|
|
||||||
this._showSummary(0);
|
this._showSummary(0);
|
||||||
|
} else if (notificationsDone && !this._busy) {
|
||||||
|
if (this._backFromAway && this._unseenNotifications.length > 0)
|
||||||
|
this._showSummary(LONGER_SUMMARY_TIMEOUT);
|
||||||
|
else if (this._newSummaryItems.length > 0)
|
||||||
|
this._showSummary(SUMMARY_TIMEOUT);
|
||||||
}
|
}
|
||||||
} else if (this._summaryState == State.SHOWN) {
|
} else if (this._summaryState == State.SHOWN) {
|
||||||
if (!summaryPinned || mustHideSummary)
|
if (!summaryPinned || mustHideSummary)
|
||||||
@ -2028,8 +2054,11 @@ const MessageTray = new Lang.Class({
|
|||||||
if (haveClickedSummaryItem && !summarySourceIsMainNotificationSource && canShowSummaryBoxPointer && !requestedNotificationStackIsEmpty)
|
if (haveClickedSummaryItem && !summarySourceIsMainNotificationSource && canShowSummaryBoxPointer && !requestedNotificationStackIsEmpty)
|
||||||
this._showSummaryBoxPointer();
|
this._showSummaryBoxPointer();
|
||||||
} else if (this._summaryBoxPointerState == State.SHOWN) {
|
} else if (this._summaryBoxPointerState == State.SHOWN) {
|
||||||
if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || mustHideSummary)
|
if (!haveClickedSummaryItem || !canShowSummaryBoxPointer || wrongSummaryBoxPointer || mustHideSummary) {
|
||||||
this._hideSummaryBoxPointer();
|
this._hideSummaryBoxPointer();
|
||||||
|
if (wrongSummaryBoxPointer)
|
||||||
|
this._showSummaryBoxPointer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tray itself
|
// Tray itself
|
||||||
@ -2076,14 +2105,38 @@ const MessageTray = new Lang.Class({
|
|||||||
|
|
||||||
_hideTray: function() {
|
_hideTray: function() {
|
||||||
this._tween(this.actor, '_trayState', State.HIDDEN,
|
this._tween(this.actor, '_trayState', State.HIDDEN,
|
||||||
{ y: -1,
|
{ y: this.actor.height,
|
||||||
time: ANIMATION_TIME,
|
time: ANIMATION_TIME,
|
||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onIdleMonitorWatch: function(monitor, id, userBecameIdle) {
|
||||||
|
this.idleMonitor.remove_watch(this._idleMonitorWatchId);
|
||||||
|
this._idleMonitorWatchId = 0;
|
||||||
|
|
||||||
|
if (userBecameIdle) {
|
||||||
|
// The user became idle, which means the user was active while the notifications were
|
||||||
|
// shown and we can unset this._unseenNotifications .
|
||||||
|
this._unseenNotiications = [];
|
||||||
|
} else if (this._unseenNotifications.length == 1 && this._unseenNotifications[0] == this._notification) {
|
||||||
|
// The user became active while the only notification in this._unseenNotifications is being shown
|
||||||
|
// as this._notification , so we can unset this._unseenNotifications .
|
||||||
|
this._unseenNotifications = [];
|
||||||
|
} else {
|
||||||
|
// The user became active and we have one or more unseen notifications. We should show
|
||||||
|
// the message tray to the user to inform the user about the missed notifications.
|
||||||
|
this._backFromAway = true;
|
||||||
|
this._updateState();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_showNotification: function() {
|
_showNotification: function() {
|
||||||
this._notification = this._notificationQueue.shift();
|
this._notification = this._notificationQueue.shift();
|
||||||
|
this._unseenNotifications.push(this._notification);
|
||||||
|
if (this._idleMonitorWatchId == 0)
|
||||||
|
this._idleMonitorWatchId = this.idleMonitor.add_watch(1000,
|
||||||
|
Lang.bind(this, this._onIdleMonitorWatch));
|
||||||
this._notificationClickedId = this._notification.connect('done-displaying',
|
this._notificationClickedId = this._notification.connect('done-displaying',
|
||||||
Lang.bind(this, this._escapeTray));
|
Lang.bind(this, this._escapeTray));
|
||||||
this._notificationBin.child = this._notification.actor;
|
this._notificationBin.child = this._notification.actor;
|
||||||
@ -2162,6 +2215,13 @@ const MessageTray = new Lang.Class({
|
|||||||
Lang.bind(this, this._notificationTimeout));
|
Lang.bind(this, this._notificationTimeout));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_unsetSummaryTimeout: function(timeout) {
|
||||||
|
if (this._summaryTimeoutId) {
|
||||||
|
Mainloop.source_remove(this._summaryTimeoutId);
|
||||||
|
this._summaryTimeoutId = 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_notificationTimeout: function() {
|
_notificationTimeout: function() {
|
||||||
let [x, y, mods] = global.get_pointer();
|
let [x, y, mods] = global.get_pointer();
|
||||||
if (y > this._lastSeenMouseY + 10 && !this.actor.hover) {
|
if (y > this._lastSeenMouseY + 10 && !this.actor.hover) {
|
||||||
@ -2245,6 +2305,7 @@ const MessageTray = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_showSummary: function(timeout) {
|
_showSummary: function(timeout) {
|
||||||
|
this._updateSeenSummaryItems();
|
||||||
this._summaryBin.opacity = 0;
|
this._summaryBin.opacity = 0;
|
||||||
this._summaryBin.y = this.actor.height;
|
this._summaryBin.y = this.actor.height;
|
||||||
this._tween(this._summaryBin, '_summaryState', State.SHOWN,
|
this._tween(this._summaryBin, '_summaryState', State.SHOWN,
|
||||||
@ -2259,8 +2320,6 @@ const MessageTray = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_showSummaryCompleted: function(timeout) {
|
_showSummaryCompleted: function(timeout) {
|
||||||
this._newSummaryItems = [];
|
|
||||||
|
|
||||||
if (timeout != 0) {
|
if (timeout != 0) {
|
||||||
this._summaryTimeoutId =
|
this._summaryTimeoutId =
|
||||||
Mainloop.timeout_add(timeout * 1000,
|
Mainloop.timeout_add(timeout * 1000,
|
||||||
@ -2275,6 +2334,7 @@ const MessageTray = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_hideSummary: function() {
|
_hideSummary: function() {
|
||||||
|
this._updateSeenSummaryItems();
|
||||||
this._tween(this._summaryBin, '_summaryState', State.HIDDEN,
|
this._tween(this._summaryBin, '_summaryState', State.HIDDEN,
|
||||||
{ opacity: 0,
|
{ opacity: 0,
|
||||||
time: ANIMATION_TIME,
|
time: ANIMATION_TIME,
|
||||||
@ -2282,13 +2342,20 @@ const MessageTray = new Lang.Class({
|
|||||||
onComplete: this._hideSummaryCompleted,
|
onComplete: this._hideSummaryCompleted,
|
||||||
onCompleteScope: this,
|
onCompleteScope: this,
|
||||||
});
|
});
|
||||||
this._newSummaryItems = [];
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_hideSummaryCompleted: function() {
|
_hideSummaryCompleted: function() {
|
||||||
this._setExpandedSummaryItem(null);
|
this._setExpandedSummaryItem(null);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updateSeenSummaryItems: function() {
|
||||||
|
if (this._backFromAway) {
|
||||||
|
this._backFromAway = false;
|
||||||
|
this._unseenNotifications = [];
|
||||||
|
}
|
||||||
|
this._newSummaryItems = [];
|
||||||
|
},
|
||||||
|
|
||||||
_showSummaryBoxPointer: function() {
|
_showSummaryBoxPointer: function() {
|
||||||
this._summaryBoxPointerItem = this._clickedSummaryItem;
|
this._summaryBoxPointerItem = this._clickedSummaryItem;
|
||||||
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
|
this._summaryBoxPointerContentUpdatedId = this._summaryBoxPointerItem.connect('content-updated',
|
||||||
@ -2370,9 +2437,8 @@ const MessageTray = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._summaryBoxPointerState = State.HIDING;
|
this._summaryBoxPointerState = State.HIDING;
|
||||||
// Unset this._clickedSummaryItem if we are no longer showing the summary or if
|
// Unset this._clickedSummaryItem if we are no longer showing the summary
|
||||||
// this._clickedSummaryItem is still the item associated with the currently showing box pointer
|
if (this._summaryState != State.SHOWN)
|
||||||
if (this._summaryState != State.SHOWN || this._summaryBoxPointerItem == this._clickedSummaryItem)
|
|
||||||
this._unsetClickedSummaryItem();
|
this._unsetClickedSummaryItem();
|
||||||
|
|
||||||
this._focusGrabber.ungrabFocus();
|
this._focusGrabber.ungrabFocus();
|
||||||
|
@ -10,6 +10,7 @@ const Pango = imports.gi.Pango;
|
|||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
@ -40,13 +41,14 @@ const ModalDialog = new Lang.Class({
|
|||||||
this._hasModal = false;
|
this._hasModal = false;
|
||||||
this._shellReactive = params.shellReactive;
|
this._shellReactive = params.shellReactive;
|
||||||
|
|
||||||
this._group = new St.Group({ visible: false,
|
this._group = new St.Widget({ visible: false,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0 });
|
y: 0,
|
||||||
|
accessible_role: Atk.Role.DIALOG });
|
||||||
Main.uiGroup.add_actor(this._group);
|
Main.uiGroup.add_actor(this._group);
|
||||||
|
|
||||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||||
coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
|
coordinate: Clutter.BindCoordinate.ALL });
|
||||||
this._group.add_constraint(constraint);
|
this._group.add_constraint(constraint);
|
||||||
|
|
||||||
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
||||||
@ -87,6 +89,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
this._buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box',
|
||||||
|
visible: false,
|
||||||
vertical: false });
|
vertical: false });
|
||||||
this._dialogLayout.add(this._buttonLayout,
|
this._dialogLayout.add(this._buttonLayout,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
@ -95,6 +98,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
|
|
||||||
global.focus_manager.add_group(this._dialogLayout);
|
global.focus_manager.add_group(this._dialogLayout);
|
||||||
this._initialKeyFocus = this._dialogLayout;
|
this._initialKeyFocus = this._dialogLayout;
|
||||||
|
this._initialKeyFocusDestroyId = 0;
|
||||||
this._savedKeyFocus = null;
|
this._savedKeyFocus = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -105,9 +109,11 @@ const ModalDialog = new Lang.Class({
|
|||||||
setButtons: function(buttons) {
|
setButtons: function(buttons) {
|
||||||
let hadChildren = this._buttonLayout.get_children() > 0;
|
let hadChildren = this._buttonLayout.get_children() > 0;
|
||||||
|
|
||||||
this._buttonLayout.destroy_children();
|
this._buttonLayout.destroy_all_children();
|
||||||
this._actionKeys = {};
|
this._actionKeys = {};
|
||||||
|
|
||||||
|
this._buttonLayout.visible = (buttons.length > 0);
|
||||||
|
|
||||||
for (let i = 0; i < buttons.length; i++) {
|
for (let i = 0; i < buttons.length; i++) {
|
||||||
let buttonInfo = buttons[i];
|
let buttonInfo = buttons[i];
|
||||||
let label = buttonInfo['label'];
|
let label = buttonInfo['label'];
|
||||||
@ -129,8 +135,7 @@ const ModalDialog = new Lang.Class({
|
|||||||
else
|
else
|
||||||
x_alignment = St.Align.MIDDLE;
|
x_alignment = St.Align.MIDDLE;
|
||||||
|
|
||||||
if (this._initialKeyFocus == this._dialogLayout ||
|
if (!this._initialKeyFocusDestroyId)
|
||||||
this._buttonLayout.contains(this._initialKeyFocus))
|
|
||||||
this._initialKeyFocus = buttonInfo.button;
|
this._initialKeyFocus = buttonInfo.button;
|
||||||
this._buttonLayout.add(buttonInfo.button,
|
this._buttonLayout.add(buttonInfo.button,
|
||||||
{ expand: true,
|
{ expand: true,
|
||||||
@ -200,7 +205,15 @@ const ModalDialog = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
setInitialKeyFocus: function(actor) {
|
setInitialKeyFocus: function(actor) {
|
||||||
|
if (this._initialKeyFocusDestroyId)
|
||||||
|
this._initialKeyFocus.disconnect(this._initialKeyFocusDestroyId);
|
||||||
|
|
||||||
this._initialKeyFocus = actor;
|
this._initialKeyFocus = actor;
|
||||||
|
|
||||||
|
this._initialKeyFocusDestroyId = actor.connect('destroy', Lang.bind(this, function() {
|
||||||
|
this._initialKeyFocus = this._dialogLayout;
|
||||||
|
this._initialKeyFocusDestroyId = 0;
|
||||||
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
open: function(timestamp) {
|
open: function(timestamp) {
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const GObject = imports.gi.GObject;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const NetworkManager = imports.gi.NetworkManager;
|
const NetworkManager = imports.gi.NetworkManager;
|
||||||
const NMClient = imports.gi.NMClient;
|
const NMClient = imports.gi.NMClient;
|
||||||
@ -28,16 +30,19 @@ const Pango = imports.gi.Pango;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const Config = imports.misc.config;
|
||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
|
||||||
|
const VPN_UI_GROUP = 'VPN Plugin UI';
|
||||||
|
|
||||||
const NetworkSecretDialog = new Lang.Class({
|
const NetworkSecretDialog = new Lang.Class({
|
||||||
Name: 'NetworkSecretDialog',
|
Name: 'NetworkSecretDialog',
|
||||||
Extends: ModalDialog.ModalDialog,
|
Extends: ModalDialog.ModalDialog,
|
||||||
|
|
||||||
_init: function(agent, requestId, connection, settingName, hints) {
|
_init: function(agent, requestId, connection, settingName, hints, contentOverride) {
|
||||||
this.parent({ styleClass: 'polkit-dialog' });
|
this.parent({ styleClass: 'prompt-dialog' });
|
||||||
|
|
||||||
this._agent = agent;
|
this._agent = agent;
|
||||||
this._requestId = requestId;
|
this._requestId = requestId;
|
||||||
@ -45,9 +50,12 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
this._settingName = settingName;
|
this._settingName = settingName;
|
||||||
this._hints = hints;
|
this._hints = hints;
|
||||||
|
|
||||||
this._content = this._getContent();
|
if (contentOverride)
|
||||||
|
this._content = contentOverride;
|
||||||
|
else
|
||||||
|
this._content = this._getContent();
|
||||||
|
|
||||||
let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
|
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
this.contentLayout.add(mainContentBox,
|
this.contentLayout.add(mainContentBox,
|
||||||
{ x_fill: true,
|
{ x_fill: true,
|
||||||
@ -60,19 +68,19 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
x_align: St.Align.END,
|
x_align: St.Align.END,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
let messageBox = new St.BoxLayout({ style_class: 'polkit-dialog-message-layout',
|
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
mainContentBox.add(messageBox,
|
mainContentBox.add(messageBox,
|
||||||
{ y_align: St.Align.START });
|
{ y_align: St.Align.START });
|
||||||
|
|
||||||
let subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
|
let subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
|
||||||
text: this._content.title });
|
text: this._content.title });
|
||||||
messageBox.add(subjectLabel,
|
messageBox.add(subjectLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
if (this._content.message != null) {
|
if (this._content.message != null) {
|
||||||
let descriptionLabel = new St.Label({ style_class: 'polkit-dialog-description',
|
let descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
|
||||||
text: this._content.message,
|
text: this._content.message,
|
||||||
// HACK: for reasons unknown to me, the label
|
// HACK: for reasons unknown to me, the label
|
||||||
// is not asked the correct height for width,
|
// is not asked the correct height for width,
|
||||||
@ -93,12 +101,12 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
let pos = 0;
|
let pos = 0;
|
||||||
for (let i = 0; i < this._content.secrets.length; i++) {
|
for (let i = 0; i < this._content.secrets.length; i++) {
|
||||||
let secret = this._content.secrets[i];
|
let secret = this._content.secrets[i];
|
||||||
let label = new St.Label({ style_class: 'polkit-dialog-password-label',
|
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||||||
text: secret.label });
|
text: secret.label });
|
||||||
|
|
||||||
let reactive = secret.key != null;
|
let reactive = secret.key != null;
|
||||||
|
|
||||||
secret.entry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
|
secret.entry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
text: secret.value, can_focus: reactive,
|
text: secret.value, can_focus: reactive,
|
||||||
reactive: reactive });
|
reactive: reactive });
|
||||||
ShellEntry.addContextMenu(secret.entry,
|
ShellEntry.addContextMenu(secret.entry,
|
||||||
@ -174,14 +182,14 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
this._agent.respond(this._requestId, false);
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
|
||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
}
|
}
|
||||||
// do nothing if not valid
|
// do nothing if not valid
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel: function() {
|
cancel: function() {
|
||||||
this._agent.respond(this._requestId, true);
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
||||||
this.close(global.get_current_time());
|
this.close(global.get_current_time());
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -357,6 +365,241 @@ const NetworkSecretDialog = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const VPNRequestHandler = new Lang.Class({
|
||||||
|
Name: 'VPNRequestHandler',
|
||||||
|
|
||||||
|
_init: function(agent, requestId, authHelper, serviceType, connection, hints, flags) {
|
||||||
|
this._agent = agent;
|
||||||
|
this._requestId = requestId;
|
||||||
|
this._connection = connection;
|
||||||
|
this._pluginOutBuffer = [];
|
||||||
|
this._title = null;
|
||||||
|
this._description = null;
|
||||||
|
this._content = [ ];
|
||||||
|
this._shellDialog = null;
|
||||||
|
|
||||||
|
let connectionSetting = connection.get_setting_connection();
|
||||||
|
|
||||||
|
let argv = [ authHelper.fileName,
|
||||||
|
'-u', connectionSetting.uuid,
|
||||||
|
'-n', connectionSetting.id,
|
||||||
|
'-s', serviceType
|
||||||
|
];
|
||||||
|
if (authHelper.externalUIMode)
|
||||||
|
argv.push('--external-ui-mode');
|
||||||
|
if (flags & NMClient.SecretAgentGetSecretsFlags.ALLOW_INTERACTION)
|
||||||
|
argv.push('-i');
|
||||||
|
if (flags & NMClient.SecretAgentGetSecretsFlags.REQUEST_NEW)
|
||||||
|
argv.push('-r');
|
||||||
|
|
||||||
|
this._newStylePlugin = authHelper.externalUIMode;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let [success, pid, stdin, stdout, stderr] =
|
||||||
|
GLib.spawn_async_with_pipes(null, /* pwd */
|
||||||
|
argv,
|
||||||
|
null, /* envp */
|
||||||
|
GLib.SpawnFlags.DO_NOT_REAP_CHILD,
|
||||||
|
null /* child_setup */);
|
||||||
|
|
||||||
|
this._childPid = pid;
|
||||||
|
this._stdin = new Gio.UnixOutputStream({ fd: stdin, close_fd: true });
|
||||||
|
this._stdout = new Gio.UnixInputStream({ fd: stdout, close_fd: true });
|
||||||
|
// We need this one too, even if don't actually care of what the process
|
||||||
|
// has to say on stderr, because otherwise the fd opened by g_spawn_async_with_pipes
|
||||||
|
// is kept open indefinitely
|
||||||
|
let stderrStream = new Gio.UnixInputStream({ fd: stderr, close_fd: true });
|
||||||
|
stderrStream.close(null);
|
||||||
|
this._dataStdout = new Gio.DataInputStream({ base_stream: this._stdout });
|
||||||
|
|
||||||
|
if (this._newStylePlugin)
|
||||||
|
this._readStdoutNewStyle();
|
||||||
|
else
|
||||||
|
this._readStdoutOldStyle();
|
||||||
|
|
||||||
|
this._childWatch = GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid,
|
||||||
|
Lang.bind(this, this._vpnChildFinished));
|
||||||
|
|
||||||
|
this._writeConnection();
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'error while spawning VPN auth helper');
|
||||||
|
|
||||||
|
this._agent.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel: function() {
|
||||||
|
if (this._newStylePlugin && this._shellDialog) {
|
||||||
|
this._shellDialog.close(global.get_current_time());
|
||||||
|
this._shellDialog.destroy();
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
this._stdin.write('QUIT\n\n', null);
|
||||||
|
} catch(e) { /* ignore broken pipe errors */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
this.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
if (this._destroyed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
GLib.source_remove(this._childWatch);
|
||||||
|
|
||||||
|
this._stdin.close(null);
|
||||||
|
// Stdout is closed when we finish reading from it
|
||||||
|
|
||||||
|
this._destroyed = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_vpnChildFinished: function(pid, status, requestObj) {
|
||||||
|
if (this._newStylePlugin) {
|
||||||
|
// For new style plugin, all work is done in the async reading functions
|
||||||
|
// Just reap the process here
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let [exited, exitStatus] = Shell.util_wifexited(status);
|
||||||
|
|
||||||
|
if (exited) {
|
||||||
|
if (exitStatus != 0)
|
||||||
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
|
||||||
|
else
|
||||||
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
|
||||||
|
} else
|
||||||
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||||
|
|
||||||
|
this.destroy();
|
||||||
|
},
|
||||||
|
|
||||||
|
_vpnChildProcessLineOldStyle: function(line) {
|
||||||
|
if (this._previousLine != undefined) {
|
||||||
|
// Two consecutive newlines mean that the child should be closed
|
||||||
|
// (the actual newlines are eaten by Gio.DataInputStream)
|
||||||
|
// Send a termination message
|
||||||
|
if (line == '' && this._previousLine == '') {
|
||||||
|
try {
|
||||||
|
this._stdin.write('QUIT\n\n', null);
|
||||||
|
} catch(e) { /* ignore broken pipe errors */ }
|
||||||
|
} else {
|
||||||
|
this._agent.set_password(this._requestId, this._previousLine, line);
|
||||||
|
this._previousLine = undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._previousLine = line;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_readStdoutOldStyle: function() {
|
||||||
|
this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(stream, result) {
|
||||||
|
let [line, len] = this._dataStdout.read_line_finish_utf8(result);
|
||||||
|
|
||||||
|
if (line == null) {
|
||||||
|
// end of file
|
||||||
|
this._stdout.close(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._vpnChildProcessLineOldStyle(line);
|
||||||
|
|
||||||
|
// try to read more!
|
||||||
|
this._readStdoutOldStyle();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_readStdoutNewStyle: function() {
|
||||||
|
this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null, Lang.bind(this, function(stream, result) {
|
||||||
|
let cnt = this._dataStdout.fill_finish(result);
|
||||||
|
|
||||||
|
if (cnt == 0) {
|
||||||
|
// end of file
|
||||||
|
this._showNewStyleDialog();
|
||||||
|
|
||||||
|
this._stdout.close(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read more
|
||||||
|
this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
|
||||||
|
this._readStdoutNewStyle();
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_showNewStyleDialog: function() {
|
||||||
|
let keyfile = new GLib.KeyFile();
|
||||||
|
let contentOverride;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let data = this._dataStdout.peek_buffer();
|
||||||
|
keyfile.load_from_data(data.toString(), data.length,
|
||||||
|
GLib.KeyFileFlags.NONE);
|
||||||
|
|
||||||
|
if (keyfile.get_integer(VPN_UI_GROUP, 'Version') != 2)
|
||||||
|
throw new Error('Invalid plugin keyfile version, is %d');
|
||||||
|
|
||||||
|
contentOverride = { title: keyfile.get_string(VPN_UI_GROUP, 'Title'),
|
||||||
|
message: keyfile.get_string(VPN_UI_GROUP, 'Description'),
|
||||||
|
secrets: [] };
|
||||||
|
|
||||||
|
let [groups, len] = keyfile.get_groups();
|
||||||
|
for (let i = 0; i < groups.length; i++) {
|
||||||
|
if (groups[i] == VPN_UI_GROUP)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let value = keyfile.get_string(groups[i], 'Value');
|
||||||
|
let shouldAsk = keyfile.get_boolean(groups[i], 'ShouldAsk');
|
||||||
|
|
||||||
|
if (shouldAsk) {
|
||||||
|
contentOverride.secrets.push({ label: keyfile.get_string(groups[i], 'Label'),
|
||||||
|
key: groups[i],
|
||||||
|
value: value,
|
||||||
|
password: keyfile.get_boolean(groups[i], 'IsSecret')
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!value.length) // Ignore empty secrets
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this._agent.set_password(this._requestId, groups[i], value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'error while reading VPN plugin output keyfile');
|
||||||
|
|
||||||
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentOverride.secrets.length) {
|
||||||
|
// Only show the dialog if we actually have something to ask
|
||||||
|
this._shellDialog = new NetworkSecretDialog(this._agent, this._requestId, this._connection, 'vpn', [], contentOverride);
|
||||||
|
this._shellDialog.open(global.get_current_time());
|
||||||
|
} else {
|
||||||
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_writeConnection: function() {
|
||||||
|
let vpnSetting = this._connection.get_setting_vpn();
|
||||||
|
|
||||||
|
try {
|
||||||
|
vpnSetting.foreach_data_item(Lang.bind(this, function(key, value) {
|
||||||
|
this._stdin.write('DATA_KEY=' + key + '\n', null);
|
||||||
|
this._stdin.write('DATA_VAL=' + (value || '') + '\n\n', null);
|
||||||
|
}));
|
||||||
|
vpnSetting.foreach_secret(Lang.bind(this, function(key, value) {
|
||||||
|
this._stdin.write('SECRET_KEY=' + key + '\n', null);
|
||||||
|
this._stdin.write('SECRET_VAL=' + (value || '') + '\n\n', null);
|
||||||
|
}));
|
||||||
|
this._stdin.write('DONE\n\n', null);
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'internal error while writing connection to helper');
|
||||||
|
|
||||||
|
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const NetworkAgent = new Lang.Class({
|
const NetworkAgent = new Lang.Class({
|
||||||
Name: 'NetworkAgent',
|
Name: 'NetworkAgent',
|
||||||
|
|
||||||
@ -365,11 +608,18 @@ const NetworkAgent = new Lang.Class({
|
|||||||
identifier: 'org.gnome.Shell.NetworkAgent' });
|
identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||||
|
|
||||||
this._dialogs = { };
|
this._dialogs = { };
|
||||||
|
this._vpnRequests = { };
|
||||||
|
|
||||||
this._native.connect('new-request', Lang.bind(this, this._newRequest));
|
this._native.connect('new-request', Lang.bind(this, this._newRequest));
|
||||||
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
this._native.connect('cancel-request', Lang.bind(this, this._cancelRequest));
|
||||||
},
|
},
|
||||||
|
|
||||||
_newRequest: function(agent, requestId, connection, settingName, hints) {
|
_newRequest: function(agent, requestId, connection, settingName, hints, flags) {
|
||||||
|
if (settingName == 'vpn') {
|
||||||
|
this._vpnRequest(requestId, connection, hints, flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let dialog = new NetworkSecretDialog(agent, requestId, connection, settingName, hints);
|
let dialog = new NetworkSecretDialog(agent, requestId, connection, settingName, hints);
|
||||||
dialog.connect('destroy', Lang.bind(this, function() {
|
dialog.connect('destroy', Lang.bind(this, function() {
|
||||||
delete this._dialogs[requestId];
|
delete this._dialogs[requestId];
|
||||||
@ -379,7 +629,74 @@ const NetworkAgent = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_cancelRequest: function(agent, requestId) {
|
_cancelRequest: function(agent, requestId) {
|
||||||
this._dialogs[requestId].close(global.get_current_time());
|
if (this._dialogs[requestId]) {
|
||||||
this._dialogs[requestId].destroy();
|
this._dialogs[requestId].close(global.get_current_time());
|
||||||
|
this._dialogs[requestId].destroy();
|
||||||
|
delete this._dialogs[requestId];
|
||||||
|
} else if (this._vpnRequests[requestId]) {
|
||||||
|
this._vpnRequests[requestId].cancel();
|
||||||
|
delete this._vpnRequests[requestId];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_vpnRequest: function(requestId, connection, hints, flags) {
|
||||||
|
let vpnSetting = connection.get_setting_vpn();
|
||||||
|
let serviceType = vpnSetting.service_type;
|
||||||
|
|
||||||
|
this._buildVPNServiceCache();
|
||||||
|
|
||||||
|
let binary = this._vpnBinaries[serviceType];
|
||||||
|
if (!binary) {
|
||||||
|
log('Invalid VPN service type (cannot find authentication binary)');
|
||||||
|
|
||||||
|
/* cancel the auth process */
|
||||||
|
this._native.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._vpnRequests[requestId] = new VPNRequestHandler(this._native, requestId, binary, serviceType, connection, hints, flags);
|
||||||
|
},
|
||||||
|
|
||||||
|
_buildVPNServiceCache: function() {
|
||||||
|
if (this._vpnCacheBuilt)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._vpnCacheBuilt = true;
|
||||||
|
this._vpnBinaries = { };
|
||||||
|
|
||||||
|
let dir = Gio.file_new_for_path(GLib.build_filenamev([Config.SYSCONFDIR, 'NetworkManager/VPN']));
|
||||||
|
try {
|
||||||
|
let fileEnum = dir.enumerate_children('standard::name', Gio.FileQueryInfoFlags.NONE, null);
|
||||||
|
let info;
|
||||||
|
|
||||||
|
while ((info = fileEnum.next_file(null))) {
|
||||||
|
let name = info.get_name();
|
||||||
|
if (name.substr(-5) != '.name')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let keyfile = new GLib.KeyFile();
|
||||||
|
keyfile.load_from_file(dir.get_child(name).get_path(), GLib.KeyFileFlags.NONE);
|
||||||
|
let service = keyfile.get_string('VPN Connection', 'service');
|
||||||
|
let binary = keyfile.get_string('GNOME', 'auth-dialog');
|
||||||
|
let externalUIMode = false;
|
||||||
|
try {
|
||||||
|
externalUIMode = keyfile.get_boolean('GNOME', 'supports-external-ui-mode');
|
||||||
|
} catch(e) { } // ignore errors if key does not exist
|
||||||
|
let path = GLib.build_filenamev([Config.LIBEXECDIR, binary]);
|
||||||
|
|
||||||
|
if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE))
|
||||||
|
this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode };
|
||||||
|
else
|
||||||
|
throw new Error('VPN plugin at %s is not executable'.format(path));
|
||||||
|
} catch(e) {
|
||||||
|
log('Error \'%s\' while processing VPN keyfile \'%s\''.
|
||||||
|
format(e.message, dir.get_child(name).get_path()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
logError(e, 'error while enumerating VPN auth helpers');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -94,7 +94,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
|
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(NotificationDaemonIface, this);
|
||||||
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
||||||
|
|
||||||
this._sources = {};
|
this._sources = [];
|
||||||
this._senderToPid = {};
|
this._senderToPid = {};
|
||||||
this._notifications = {};
|
this._notifications = {};
|
||||||
this._busProxy = new Bus();
|
this._busProxy = new Bus();
|
||||||
@ -152,14 +152,30 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_lookupSource: function(title, pid, trayIcon) {
|
||||||
|
for (let i = 0; i < this._sources.length; i++) {
|
||||||
|
let source = this._sources[i];
|
||||||
|
if (source.pid == pid &&
|
||||||
|
(source.initialTitle == title || source.trayIcon || trayIcon))
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
|
||||||
// Returns the source associated with ndata.notification if it is set.
|
// Returns the source associated with ndata.notification if it is set.
|
||||||
// Otherwise, returns the source associated with the pid if one is
|
// Otherwise, returns the source associated with the title and pid if
|
||||||
// stored in this._sources and the notification is not transient.
|
// such source is stored in this._sources and the notification is not
|
||||||
// Otherwise, creates a new source as long as pid is provided.
|
// transient. If the existing or requested source is associated with
|
||||||
|
// a tray icon and passed in pid matches a pid of an existing source,
|
||||||
|
// the title match is ignored to enable representing a tray icon and
|
||||||
|
// notifications from the same application with a single source.
|
||||||
|
//
|
||||||
|
// If no existing source is found, a new source is created as long as
|
||||||
|
// pid is provided.
|
||||||
//
|
//
|
||||||
// Either a pid or ndata.notification is needed to retrieve or
|
// Either a pid or ndata.notification is needed to retrieve or
|
||||||
// create a source.
|
// create a source.
|
||||||
_getSource: function(title, pid, ndata, sender) {
|
_getSource: function(title, pid, ndata, sender, trayIcon) {
|
||||||
if (!pid && !(ndata && ndata.notification))
|
if (!pid && !(ndata && ndata.notification))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -176,20 +192,24 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
// with a transient one from the same sender, so we
|
// with a transient one from the same sender, so we
|
||||||
// always create a new source object for new transient notifications
|
// always create a new source object for new transient notifications
|
||||||
// and never add it to this._sources .
|
// and never add it to this._sources .
|
||||||
if (!isForTransientNotification && this._sources[pid]) {
|
if (!isForTransientNotification) {
|
||||||
let source = this._sources[pid];
|
let source = this._lookupSource(title, pid, trayIcon);
|
||||||
source.setTitle(title);
|
if (source) {
|
||||||
return source;
|
source.setTitle(title);
|
||||||
|
return source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let source = new Source(title, pid, sender);
|
let source = new Source(title, pid, sender, trayIcon);
|
||||||
source.setTransient(isForTransientNotification);
|
source.setTransient(isForTransientNotification);
|
||||||
|
|
||||||
if (!isForTransientNotification) {
|
if (!isForTransientNotification) {
|
||||||
this._sources[pid] = source;
|
this._sources.push(source);
|
||||||
source.connect('destroy', Lang.bind(this,
|
source.connect('destroy', Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
delete this._sources[pid];
|
let index = this._sources.indexOf(source);
|
||||||
|
if (index >= 0)
|
||||||
|
this._sources.splice(index, 1);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +288,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
let sender = invocation.get_sender();
|
let sender = invocation.get_sender();
|
||||||
let pid = this._senderToPid[sender];
|
let pid = this._senderToPid[sender];
|
||||||
|
|
||||||
let source = this._getSource(appName, pid, ndata, sender);
|
let source = this._getSource(appName, pid, ndata, sender, null);
|
||||||
|
|
||||||
if (source) {
|
if (source) {
|
||||||
this._notifyForSource(source, ndata);
|
this._notifyForSource(source, ndata);
|
||||||
@ -294,7 +314,7 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let [pid] = result;
|
let [pid] = result;
|
||||||
source = this._getSource(appName, pid, ndata, sender);
|
source = this._getSource(appName, pid, ndata, sender, null);
|
||||||
|
|
||||||
// We only store sender-pid entries for persistent sources.
|
// We only store sender-pid entries for persistent sources.
|
||||||
// Removing the entries once the source is destroyed
|
// Removing the entries once the source is destroyed
|
||||||
@ -443,8 +463,8 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
if (!tracker.focus_app)
|
if (!tracker.focus_app)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (let id in this._sources) {
|
for (let i = 0; i < this._sources.length; i++) {
|
||||||
let source = this._sources[id];
|
let source = this._sources[i];
|
||||||
if (source.app == tracker.focus_app) {
|
if (source.app == tracker.focus_app) {
|
||||||
source.destroyNonResidentNotifications();
|
source.destroyNonResidentNotifications();
|
||||||
return;
|
return;
|
||||||
@ -463,12 +483,11 @@ const NotificationDaemon = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onTrayIconAdded: function(o, icon) {
|
_onTrayIconAdded: function(o, icon) {
|
||||||
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
|
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null, icon);
|
||||||
source.setTrayIcon(icon);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onTrayIconRemoved: function(o, icon) {
|
_onTrayIconRemoved: function(o, icon) {
|
||||||
let source = this._sources[icon.pid];
|
let source = this._lookupSource(null, icon.pid, true);
|
||||||
if (source)
|
if (source)
|
||||||
source.destroy();
|
source.destroy();
|
||||||
}
|
}
|
||||||
@ -478,10 +497,12 @@ const Source = new Lang.Class({
|
|||||||
Name: 'NotificationDaemonSource',
|
Name: 'NotificationDaemonSource',
|
||||||
Extends: MessageTray.Source,
|
Extends: MessageTray.Source,
|
||||||
|
|
||||||
_init: function(title, pid, sender) {
|
_init: function(title, pid, sender, trayIcon) {
|
||||||
this.parent(title);
|
this.parent(title);
|
||||||
|
|
||||||
this._pid = pid;
|
this.initialTitle = title;
|
||||||
|
|
||||||
|
this.pid = pid;
|
||||||
if (sender)
|
if (sender)
|
||||||
this._nameWatcherId = Gio.DBus.session.watch_name(sender,
|
this._nameWatcherId = Gio.DBus.session.watch_name(sender,
|
||||||
Gio.BusNameWatcherFlags.NONE,
|
Gio.BusNameWatcherFlags.NONE,
|
||||||
@ -495,7 +516,12 @@ const Source = new Lang.Class({
|
|||||||
this.title = this.app.get_name();
|
this.title = this.app.get_name();
|
||||||
else
|
else
|
||||||
this.useNotificationIcon = true;
|
this.useNotificationIcon = true;
|
||||||
this._trayIcon = null;
|
|
||||||
|
this.trayIcon = trayIcon;
|
||||||
|
if (this.trayIcon) {
|
||||||
|
this._setSummaryIcon(this.trayIcon);
|
||||||
|
this.useNotificationIcon = false;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onNameVanished: function() {
|
_onNameVanished: function() {
|
||||||
@ -522,7 +548,7 @@ const Source = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleSummaryClick: function() {
|
handleSummaryClick: function() {
|
||||||
if (!this._trayIcon)
|
if (!this.trayIcon)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let event = Clutter.get_current_event();
|
let event = Clutter.get_current_event();
|
||||||
@ -543,11 +569,11 @@ const Source = new Lang.Class({
|
|||||||
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
|
let id = global.connect('notify::stage-input-mode', Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
global.disconnect(id);
|
global.disconnect(id);
|
||||||
this._trayIcon.click(event);
|
this.trayIcon.click(event);
|
||||||
}));
|
}));
|
||||||
Main.overview.hide();
|
Main.overview.hide();
|
||||||
} else {
|
} else {
|
||||||
this._trayIcon.click(event);
|
this.trayIcon.click(event);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -556,31 +582,25 @@ const Source = new Lang.Class({
|
|||||||
if (this.app)
|
if (this.app)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
|
this.app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
|
||||||
if (!this.app)
|
if (!this.app)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Only override the icon if we were previously using
|
// Only override the icon if we were previously using
|
||||||
// notification-based icons (ie, not a trayicon) or if it was unset before
|
// notification-based icons (ie, not a trayicon) or if it was unset before
|
||||||
if (!this._trayIcon) {
|
if (!this.trayIcon) {
|
||||||
this.useNotificationIcon = false;
|
this.useNotificationIcon = false;
|
||||||
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
|
this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
setTrayIcon: function(icon) {
|
|
||||||
this._setSummaryIcon(icon);
|
|
||||||
this.useNotificationIcon = false;
|
|
||||||
this._trayIcon = icon;
|
|
||||||
},
|
|
||||||
|
|
||||||
open: function(notification) {
|
open: function(notification) {
|
||||||
this.destroyNonResidentNotifications();
|
this.destroyNonResidentNotifications();
|
||||||
this.openApp();
|
this.openApp();
|
||||||
},
|
},
|
||||||
|
|
||||||
_lastNotificationRemoved: function() {
|
_lastNotificationRemoved: function() {
|
||||||
if (!this._trayIcon)
|
if (!this.trayIcon)
|
||||||
this.destroy();
|
this.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -14,15 +14,16 @@ const AppDisplay = imports.ui.appDisplay;
|
|||||||
const ContactDisplay = imports.ui.contactDisplay;
|
const ContactDisplay = imports.ui.contactDisplay;
|
||||||
const Dash = imports.ui.dash;
|
const Dash = imports.ui.dash;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
const DocDisplay = imports.ui.docDisplay;
|
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const PlaceDisplay = imports.ui.placeDisplay;
|
const PlaceDisplay = imports.ui.placeDisplay;
|
||||||
|
const RemoteSearch = imports.ui.remoteSearch;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
const ViewSelector = imports.ui.viewSelector;
|
const ViewSelector = imports.ui.viewSelector;
|
||||||
|
const Wanda = imports.ui.wanda;
|
||||||
const WorkspacesView = imports.ui.workspacesView;
|
const WorkspacesView = imports.ui.workspacesView;
|
||||||
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
|
||||||
|
|
||||||
@ -108,7 +109,6 @@ const Overview = new Lang.Class({
|
|||||||
if (this.isDummy) {
|
if (this.isDummy) {
|
||||||
this.animationInProgress = false;
|
this.animationInProgress = false;
|
||||||
this.visible = false;
|
this.visible = false;
|
||||||
this.workspaces = null;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,8 +126,11 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
this._spacing = 0;
|
this._spacing = 0;
|
||||||
|
|
||||||
this._group = new St.Group({ name: 'overview',
|
/* Translators: This is the main view to select
|
||||||
reactive: true });
|
activities. See also note for "Activities" string. */
|
||||||
|
this._group = new St.Widget({ name: 'overview',
|
||||||
|
accessible_name: _("Overview"),
|
||||||
|
reactive: true });
|
||||||
this._group._delegate = this;
|
this._group._delegate = this;
|
||||||
this._group.connect('style-changed',
|
this._group.connect('style-changed',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
@ -180,8 +183,6 @@ const Overview = new Lang.Class({
|
|||||||
this._lastActiveWorkspaceIndex = -1;
|
this._lastActiveWorkspaceIndex = -1;
|
||||||
this._lastHoveredWindow = null;
|
this._lastHoveredWindow = null;
|
||||||
this._needsFakePointerEvent = false;
|
this._needsFakePointerEvent = false;
|
||||||
|
|
||||||
this.workspaces = null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// The members we construct that are implemented in JS might
|
// The members we construct that are implemented in JS might
|
||||||
@ -204,12 +205,16 @@ const Overview = new Lang.Class({
|
|||||||
this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
|
this._viewSelector.addViewTab('applications', _("Applications"), appView.actor, 'system-run');
|
||||||
|
|
||||||
// Default search providers
|
// Default search providers
|
||||||
|
// Wanda comes obviously first
|
||||||
|
this.addSearchProvider(new Wanda.WandaSearchProvider());
|
||||||
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
this.addSearchProvider(new AppDisplay.AppSearchProvider());
|
||||||
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
this.addSearchProvider(new AppDisplay.SettingsSearchProvider());
|
||||||
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
this.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
|
||||||
this.addSearchProvider(new DocDisplay.DocSearchProvider());
|
|
||||||
this.addSearchProvider(new ContactDisplay.ContactSearchProvider());
|
this.addSearchProvider(new ContactDisplay.ContactSearchProvider());
|
||||||
|
|
||||||
|
// Load remote search providers provided by applications
|
||||||
|
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, this.addSearchProvider));
|
||||||
|
|
||||||
// TODO - recalculate everything when desktop size changes
|
// TODO - recalculate everything when desktop size changes
|
||||||
this._dash = new Dash.Dash();
|
this._dash = new Dash.Dash();
|
||||||
this._group.add_actor(this._dash.actor);
|
this._group.add_actor(this._dash.actor);
|
||||||
@ -355,7 +360,7 @@ const Overview = new Lang.Class({
|
|||||||
let direction;
|
let direction;
|
||||||
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
||||||
direction = stageX > this._dragStartX ? -1 : 1;
|
direction = stageX > this._dragStartX ? -1 : 1;
|
||||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
direction *= -1;
|
direction *= -1;
|
||||||
} else {
|
} else {
|
||||||
direction = stageY > this._dragStartY ? -1 : 1;
|
direction = stageY > this._dragStartY ? -1 : 1;
|
||||||
@ -447,7 +452,7 @@ const Overview = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
||||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
|
this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
|
||||||
else
|
else
|
||||||
this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
|
this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
|
||||||
@ -488,7 +493,7 @@ const Overview = new Lang.Class({
|
|||||||
this.hide();
|
this.hide();
|
||||||
|
|
||||||
let primary = Main.layoutManager.primaryMonitor;
|
let primary = Main.layoutManager.primaryMonitor;
|
||||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
|
||||||
|
|
||||||
let contentY = Main.panel.actor.height;
|
let contentY = Main.panel.actor.height;
|
||||||
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
|
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
|
||||||
@ -587,13 +592,10 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
this._workspacesDisplay.show();
|
this._workspacesDisplay.show();
|
||||||
|
|
||||||
this.workspaces = this._workspacesDisplay.workspacesView;
|
|
||||||
global.overlay_group.add_actor(this.workspaces.actor);
|
|
||||||
|
|
||||||
if (!this._desktopFade.child)
|
if (!this._desktopFade.child)
|
||||||
this._desktopFade.child = this._getDesktopClone();
|
this._desktopFade.child = this._getDesktopClone();
|
||||||
|
|
||||||
if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
|
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
|
||||||
this._desktopFade.opacity = 255;
|
this._desktopFade.opacity = 255;
|
||||||
this._desktopFade.show();
|
this._desktopFade.show();
|
||||||
Tweener.addTween(this._desktopFade,
|
Tweener.addTween(this._desktopFade,
|
||||||
@ -728,7 +730,7 @@ const Overview = new Lang.Class({
|
|||||||
this.animationInProgress = true;
|
this.animationInProgress = true;
|
||||||
this._hideInProgress = true;
|
this._hideInProgress = true;
|
||||||
|
|
||||||
if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
|
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows()) {
|
||||||
this._desktopFade.opacity = 0;
|
this._desktopFade.opacity = 0;
|
||||||
this._desktopFade.show();
|
this._desktopFade.show();
|
||||||
Tweener.addTween(this._desktopFade,
|
Tweener.addTween(this._desktopFade,
|
||||||
@ -737,7 +739,7 @@ const Overview = new Lang.Class({
|
|||||||
transition: 'easeOutQuad' });
|
transition: 'easeOutQuad' });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workspaces.hide();
|
this._workspacesDisplay.zoomFromOverview();
|
||||||
|
|
||||||
// Make other elements fade out.
|
// Make other elements fade out.
|
||||||
Tweener.addTween(this._group,
|
Tweener.addTween(this._group,
|
||||||
@ -779,9 +781,6 @@ const Overview = new Lang.Class({
|
|||||||
|
|
||||||
global.window_group.show();
|
global.window_group.show();
|
||||||
|
|
||||||
this.workspaces.destroy();
|
|
||||||
this.workspaces = null;
|
|
||||||
|
|
||||||
this._workspacesDisplay.hide();
|
this._workspacesDisplay.hide();
|
||||||
|
|
||||||
this._desktopFade.hide();
|
this._desktopFade.hide();
|
||||||
|
272
js/ui/panel.js
@ -3,15 +3,20 @@
|
|||||||
const Cairo = imports.cairo;
|
const Cairo = imports.cairo;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Gtk = imports.gi.Gtk;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
|
const Meta = imports.gi.Meta;
|
||||||
const Pango = imports.gi.Pango;
|
const Pango = imports.gi.Pango;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
|
const DND = imports.ui.dnd;
|
||||||
const Layout = imports.ui.layout;
|
const Layout = imports.ui.layout;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const PopupMenu = imports.ui.popupMenu;
|
const PopupMenu = imports.ui.popupMenu;
|
||||||
@ -104,38 +109,47 @@ const AnimatedIcon = new Lang.Class({
|
|||||||
_init: function(name, size) {
|
_init: function(name, size) {
|
||||||
this.actor = new St.Bin({ visible: false });
|
this.actor = new St.Bin({ visible: false });
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
this.actor.connect('notify::visible', Lang.bind(this, function() {
|
this.actor.connect('notify::visible', Lang.bind(this, this._onVisibleNotify));
|
||||||
if (this.actor.visible) {
|
|
||||||
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
|
||||||
} else {
|
|
||||||
if (this._timeoutId)
|
|
||||||
Mainloop.source_remove(this._timeoutId);
|
|
||||||
this._timeoutId = 0;
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._timeoutId = 0;
|
this._timeoutId = 0;
|
||||||
this._i = 0;
|
this._frame = 0;
|
||||||
this._animations = St.TextureCache.get_default().load_sliced_image (global.datadir + '/theme/' + name, size, size);
|
this._animations = St.TextureCache.get_default().load_sliced_image (global.datadir + '/theme/' + name, size, size);
|
||||||
this.actor.set_child(this._animations);
|
this.actor.set_child(this._animations);
|
||||||
},
|
},
|
||||||
|
|
||||||
_update: function() {
|
_disconnectTimeout: function() {
|
||||||
this._animations.hide_all();
|
if (this._timeoutId > 0) {
|
||||||
this._animations.show();
|
Mainloop.source_remove(this._timeoutId);
|
||||||
if (this._i && this._i < this._animations.get_n_children())
|
this._timeoutId = 0;
|
||||||
this._animations.get_nth_child(this._i++).show();
|
|
||||||
else {
|
|
||||||
this._i = 1;
|
|
||||||
if (this._animations.get_n_children())
|
|
||||||
this._animations.get_nth_child(0).show();
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_onVisibleNotify: function() {
|
||||||
|
if (this.actor.visible)
|
||||||
|
this._timeoutId = Mainloop.timeout_add(ANIMATED_ICON_UPDATE_TIMEOUT, Lang.bind(this, this._update));
|
||||||
|
else
|
||||||
|
this._disconnectTimeout();
|
||||||
|
},
|
||||||
|
|
||||||
|
_showFrame: function(frame) {
|
||||||
|
let oldFrameActor = this._animations.get_child_at_index(this._frame);
|
||||||
|
if (oldFrameActor)
|
||||||
|
oldFrameActor.hide();
|
||||||
|
|
||||||
|
this._frame = (frame % this._animations.get_n_children());
|
||||||
|
|
||||||
|
let newFrameActor = this._animations.get_child_at_index(this._frame);
|
||||||
|
if (newFrameActor)
|
||||||
|
newFrameActor.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
_update: function() {
|
||||||
|
this._showFrame(this._frame + 1);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
if (this._timeoutId)
|
this._disconnectTimeout();
|
||||||
Mainloop.source_remove(this._timeoutId);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -235,15 +249,22 @@ const AppMenuButton = new Lang.Class({
|
|||||||
Name: 'AppMenuButton',
|
Name: 'AppMenuButton',
|
||||||
Extends: PanelMenu.Button,
|
Extends: PanelMenu.Button,
|
||||||
|
|
||||||
_init: function() {
|
_init: function(menuManager) {
|
||||||
this.parent(0.0);
|
this.parent(0.0, null, true);
|
||||||
|
|
||||||
|
this.actor.accessible_role = Atk.Role.MENU;
|
||||||
|
|
||||||
this._startingApps = [];
|
this._startingApps = [];
|
||||||
|
|
||||||
|
this._menuManager = menuManager;
|
||||||
this._targetApp = null;
|
this._targetApp = null;
|
||||||
|
this._appMenuNotifyId = 0;
|
||||||
|
this._actionGroupNotifyId = 0;
|
||||||
|
|
||||||
let bin = new St.Bin({ name: 'appMenu' });
|
let bin = new St.Bin({ name: 'appMenu' });
|
||||||
this.actor.add_actor(bin);
|
this.actor.add_actor(bin);
|
||||||
|
|
||||||
|
this.actor.bind_property("reactive", this.actor, "can-focus", 0);
|
||||||
this.actor.reactive = false;
|
this.actor.reactive = false;
|
||||||
this._targetIsCurrent = false;
|
this._targetIsCurrent = false;
|
||||||
|
|
||||||
@ -264,10 +285,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
this._iconBottomClip = 0;
|
this._iconBottomClip = 0;
|
||||||
|
|
||||||
this._quitMenu = new PopupMenu.PopupMenuItem('');
|
|
||||||
this.menu.addMenuItem(this._quitMenu);
|
|
||||||
this._quitMenu.connect('activate', Lang.bind(this, this._onQuit));
|
|
||||||
|
|
||||||
this._visible = !Main.overview.visible;
|
this._visible = !Main.overview.visible;
|
||||||
if (!this._visible)
|
if (!this._visible)
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
@ -287,7 +304,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
let appSys = Shell.AppSystem.get_default();
|
let appSys = Shell.AppSystem.get_default();
|
||||||
tracker.connect('notify::focus-app', Lang.bind(this, this._sync));
|
tracker.connect('notify::focus-app', Lang.bind(this, this._focusAppChanged));
|
||||||
appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
|
appSys.connect('app-state-changed', Lang.bind(this, this._onAppStateChanged));
|
||||||
|
|
||||||
global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
|
global.window_manager.connect('switch-workspace', Lang.bind(this, this._sync));
|
||||||
@ -301,11 +318,12 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
this._visible = true;
|
this._visible = true;
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
this.actor.reactive = true;
|
|
||||||
|
|
||||||
if (!this._targetIsCurrent)
|
if (!this._targetIsCurrent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
this.actor.reactive = true;
|
||||||
|
|
||||||
Tweener.removeTweens(this.actor);
|
Tweener.removeTweens(this.actor);
|
||||||
Tweener.addTween(this.actor,
|
Tweener.addTween(this.actor,
|
||||||
{ opacity: 255,
|
{ opacity: 255,
|
||||||
@ -400,12 +418,12 @@ const AppMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._iconBox.get_preferred_size();
|
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._iconBox.get_preferred_size();
|
||||||
|
|
||||||
let direction = this.actor.get_direction();
|
let direction = this.actor.get_text_direction();
|
||||||
|
|
||||||
let yPadding = Math.floor(Math.max(0, allocHeight - naturalHeight) / 2);
|
let yPadding = Math.floor(Math.max(0, allocHeight - naturalHeight) / 2);
|
||||||
childBox.y1 = yPadding;
|
childBox.y1 = yPadding;
|
||||||
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
||||||
if (direction == St.TextDirection.LTR) {
|
if (direction == Clutter.TextDirection.LTR) {
|
||||||
childBox.x1 = 0;
|
childBox.x1 = 0;
|
||||||
childBox.x2 = childBox.x1 + Math.min(naturalWidth, allocWidth);
|
childBox.x2 = childBox.x1 + Math.min(naturalWidth, allocWidth);
|
||||||
} else {
|
} else {
|
||||||
@ -422,7 +440,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
childBox.y1 = yPadding;
|
childBox.y1 = yPadding;
|
||||||
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
childBox.y2 = childBox.y1 + Math.min(naturalHeight, allocHeight);
|
||||||
|
|
||||||
if (direction == St.TextDirection.LTR) {
|
if (direction == Clutter.TextDirection.LTR) {
|
||||||
childBox.x1 = Math.floor(iconWidth / 2);
|
childBox.x1 = Math.floor(iconWidth / 2);
|
||||||
childBox.x2 = Math.min(childBox.x1 + naturalWidth, allocWidth);
|
childBox.x2 = Math.min(childBox.x1 + naturalWidth, allocWidth);
|
||||||
} else {
|
} else {
|
||||||
@ -431,7 +449,7 @@ const AppMenuButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this._label.actor.allocate(childBox, flags);
|
this._label.actor.allocate(childBox, flags);
|
||||||
|
|
||||||
if (direction == St.TextDirection.LTR) {
|
if (direction == Clutter.TextDirection.LTR) {
|
||||||
childBox.x1 = Math.floor(iconWidth / 2) + this._label.actor.width;
|
childBox.x1 = Math.floor(iconWidth / 2) + this._label.actor.width;
|
||||||
childBox.x2 = childBox.x1 + this._spinner.actor.width;
|
childBox.x2 = childBox.x1 + this._spinner.actor.width;
|
||||||
childBox.y1 = box.y1;
|
childBox.y1 = box.y1;
|
||||||
@ -446,12 +464,6 @@ const AppMenuButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onQuit: function() {
|
|
||||||
if (this._targetApp == null)
|
|
||||||
return;
|
|
||||||
this._targetApp.request_quit();
|
|
||||||
},
|
|
||||||
|
|
||||||
_onAppStateChanged: function(appSys, app) {
|
_onAppStateChanged: function(appSys, app) {
|
||||||
let state = app.state;
|
let state = app.state;
|
||||||
if (state != Shell.AppState.STARTING) {
|
if (state != Shell.AppState.STARTING) {
|
||||||
@ -468,16 +480,9 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._sync();
|
this._sync();
|
||||||
},
|
},
|
||||||
|
|
||||||
_sync: function() {
|
_focusAppChanged: function() {
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
let lastStartedApp = null;
|
|
||||||
let workspace = global.screen.get_active_workspace();
|
|
||||||
for (let i = 0; i < this._startingApps.length; i++)
|
|
||||||
if (this._startingApps[i].is_on_workspace(workspace))
|
|
||||||
lastStartedApp = this._startingApps[i];
|
|
||||||
|
|
||||||
let focusedApp = tracker.focus_app;
|
let focusedApp = tracker.focus_app;
|
||||||
|
|
||||||
if (!focusedApp) {
|
if (!focusedApp) {
|
||||||
// If the app has just lost focus to the panel, pretend
|
// If the app has just lost focus to the panel, pretend
|
||||||
// nothing happened; otherwise you can't keynav to the
|
// nothing happened; otherwise you can't keynav to the
|
||||||
@ -485,6 +490,17 @@ const AppMenuButton = new Lang.Class({
|
|||||||
if (global.stage_input_mode == Shell.StageInputMode.FOCUSED)
|
if (global.stage_input_mode == Shell.StageInputMode.FOCUSED)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this._sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
_sync: function() {
|
||||||
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
|
let focusedApp = tracker.focus_app;
|
||||||
|
let lastStartedApp = null;
|
||||||
|
let workspace = global.screen.get_active_workspace();
|
||||||
|
for (let i = 0; i < this._startingApps.length; i++)
|
||||||
|
if (this._startingApps[i].is_on_workspace(workspace))
|
||||||
|
lastStartedApp = this._startingApps[i];
|
||||||
|
|
||||||
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
|
let targetApp = focusedApp != null ? focusedApp : lastStartedApp;
|
||||||
|
|
||||||
@ -502,6 +518,9 @@ const AppMenuButton = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!targetApp.is_on_workspace(workspace))
|
||||||
|
return;
|
||||||
|
|
||||||
if (!this._targetIsCurrent) {
|
if (!this._targetIsCurrent) {
|
||||||
this.actor.reactive = true;
|
this.actor.reactive = true;
|
||||||
this._targetIsCurrent = true;
|
this._targetIsCurrent = true;
|
||||||
@ -513,8 +532,10 @@ const AppMenuButton = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (targetApp == this._targetApp) {
|
if (targetApp == this._targetApp) {
|
||||||
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING)
|
if (targetApp && targetApp.get_state() != Shell.AppState.STARTING) {
|
||||||
this.stopAnimation();
|
this.stopAnimation();
|
||||||
|
this._maybeSetMenu();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,20 +545,57 @@ const AppMenuButton = new Lang.Class({
|
|||||||
this._iconBox.hide();
|
this._iconBox.hide();
|
||||||
this._label.setText('');
|
this._label.setText('');
|
||||||
|
|
||||||
|
if (this._appMenuNotifyId)
|
||||||
|
this._targetApp.disconnect(this._appMenuNotifyId);
|
||||||
|
if (this._actionGroupNotifyId)
|
||||||
|
this._targetApp.disconnect(this._actionGroupNotifyId);
|
||||||
|
if (targetApp) {
|
||||||
|
this._appMenuNotifyId = targetApp.connect('notify::menu', Lang.bind(this, this._sync));
|
||||||
|
this._actionGroupNotifyId = targetApp.connect('notify::action-group', Lang.bind(this, this._sync));
|
||||||
|
} else {
|
||||||
|
this._appMenuNotifyId = 0;
|
||||||
|
this._actionGroupNotifyId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
this._targetApp = targetApp;
|
this._targetApp = targetApp;
|
||||||
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());
|
this._label.setText(targetApp.get_name());
|
||||||
// TODO - _quit() doesn't really work on apps in state STARTING yet
|
this.setName(targetApp.get_name());
|
||||||
this._quitMenu.label.set_text(_("Quit %s").format(targetApp.get_name()));
|
|
||||||
|
|
||||||
this._iconBox.set_child(icon);
|
this._iconBox.set_child(icon);
|
||||||
this._iconBox.show();
|
this._iconBox.show();
|
||||||
|
|
||||||
if (targetApp.get_state() == Shell.AppState.STARTING)
|
if (targetApp.get_state() == Shell.AppState.STARTING)
|
||||||
this.startAnimation();
|
this.startAnimation();
|
||||||
|
else
|
||||||
|
this._maybeSetMenu();
|
||||||
|
|
||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
|
},
|
||||||
|
|
||||||
|
_maybeSetMenu: function() {
|
||||||
|
let menu;
|
||||||
|
|
||||||
|
if (this._targetApp.action_group && this._targetApp.menu) {
|
||||||
|
if (this.menu instanceof PopupMenu.RemoteMenu &&
|
||||||
|
this.menu.actionGroup == this._targetApp.action_group)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu = new PopupMenu.RemoteMenu(this.actor, this._targetApp.menu, this._targetApp.action_group);
|
||||||
|
} else {
|
||||||
|
if (this.menu && !(this.menu instanceof PopupMenu.RemoteMenu))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// fallback to older menu
|
||||||
|
menu = new PopupMenu.PopupMenu(this.actor, 0.0, St.Side.TOP, 0);
|
||||||
|
menu.addAction(_("Quit"), Lang.bind(this, function() {
|
||||||
|
this._targetApp.request_quit();
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setMenu(menu);
|
||||||
|
this._menuManager.addMenu(menu);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -552,6 +610,7 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(0.0);
|
this.parent(0.0);
|
||||||
|
this.actor.accessible_role = Atk.Role.TOGGLE_BUTTON;
|
||||||
|
|
||||||
let container = new Shell.GenericContainer();
|
let container = new Shell.GenericContainer();
|
||||||
container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
||||||
@ -565,6 +624,8 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
this._label = new St.Label({ text: _("Activities") });
|
this._label = new St.Label({ text: _("Activities") });
|
||||||
container.add_actor(this._label);
|
container.add_actor(this._label);
|
||||||
|
|
||||||
|
this.actor.label_actor = this._label;
|
||||||
|
|
||||||
this._hotCorner = new Layout.HotCorner();
|
this._hotCorner = new Layout.HotCorner();
|
||||||
container.add_actor(this._hotCorner.actor);
|
container.add_actor(this._hotCorner.actor);
|
||||||
|
|
||||||
@ -580,10 +641,12 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||||
this.actor.add_style_pseudo_class('overview');
|
this.actor.add_style_pseudo_class('overview');
|
||||||
this._escapeMenuGrab();
|
this._escapeMenuGrab();
|
||||||
|
this.actor.add_accessible_state (Atk.StateType.CHECKED);
|
||||||
}));
|
}));
|
||||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||||
this.actor.remove_style_pseudo_class('overview');
|
this.actor.remove_style_pseudo_class('overview');
|
||||||
this._escapeMenuGrab();
|
this._escapeMenuGrab();
|
||||||
|
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._xdndTimeOut = 0;
|
this._xdndTimeOut = 0;
|
||||||
@ -605,7 +668,7 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
let primary = Main.layoutManager.primaryMonitor;
|
let primary = Main.layoutManager.primaryMonitor;
|
||||||
let hotBox = new Clutter.ActorBox();
|
let hotBox = new Clutter.ActorBox();
|
||||||
let ok, x, y;
|
let ok, x, y;
|
||||||
if (actor.get_direction() == St.TextDirection.LTR) {
|
if (actor.get_text_direction() == Clutter.TextDirection.LTR) {
|
||||||
[ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
|
[ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
|
||||||
} else {
|
} else {
|
||||||
[ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
|
[ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
|
||||||
@ -622,12 +685,14 @@ const ActivitiesButton = new Lang.Class({
|
|||||||
|
|
||||||
handleDragOver: function(source, actor, x, y, time) {
|
handleDragOver: function(source, actor, x, y, time) {
|
||||||
if (source != Main.xdndHandler)
|
if (source != Main.xdndHandler)
|
||||||
return;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
if (this._xdndTimeOut != 0)
|
if (this._xdndTimeOut != 0)
|
||||||
Mainloop.source_remove(this._xdndTimeOut);
|
Mainloop.source_remove(this._xdndTimeOut);
|
||||||
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
|
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
|
||||||
Lang.bind(this, this._xdndShowOverview, actor));
|
Lang.bind(this, this._xdndShowOverview, actor));
|
||||||
|
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
},
|
},
|
||||||
|
|
||||||
_escapeMenuGrab: function() {
|
_escapeMenuGrab: function() {
|
||||||
@ -757,7 +822,7 @@ const PanelCorner = new Lang.Class({
|
|||||||
|
|
||||||
let rtlAwareContainer = this._box instanceof St.BoxLayout;
|
let rtlAwareContainer = this._box instanceof St.BoxLayout;
|
||||||
if (rtlAwareContainer &&
|
if (rtlAwareContainer &&
|
||||||
this._box.get_direction() == St.TextDirection.RTL) {
|
this._box.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
if (this._side == St.Side.LEFT)
|
if (this._side == St.Side.LEFT)
|
||||||
side = St.Side.RIGHT;
|
side = St.Side.RIGHT;
|
||||||
else if (this._side == St.Side.RIGHT)
|
else if (this._side == St.Side.RIGHT)
|
||||||
@ -803,12 +868,10 @@ const PanelCorner = new Lang.Class({
|
|||||||
let node = this.actor.get_theme_node();
|
let node = this.actor.get_theme_node();
|
||||||
|
|
||||||
let cornerRadius = node.get_length("-panel-corner-radius");
|
let cornerRadius = node.get_length("-panel-corner-radius");
|
||||||
let innerBorderWidth = node.get_length('-panel-corner-inner-border-width');
|
let borderWidth = node.get_length('-panel-corner-border-width');
|
||||||
let outerBorderWidth = node.get_length('-panel-corner-outer-border-width');
|
|
||||||
|
|
||||||
let backgroundColor = node.get_color('-panel-corner-background-color');
|
let backgroundColor = node.get_color('-panel-corner-background-color');
|
||||||
let innerBorderColor = node.get_color('-panel-corner-inner-border-color');
|
let borderColor = node.get_color('-panel-corner-border-color');
|
||||||
let outerBorderColor = node.get_color('-panel-corner-outer-border-color');
|
|
||||||
|
|
||||||
let cr = this.actor.get_context();
|
let cr = this.actor.get_context();
|
||||||
cr.setOperator(Cairo.Operator.SOURCE);
|
cr.setOperator(Cairo.Operator.SOURCE);
|
||||||
@ -816,40 +879,23 @@ const PanelCorner = new Lang.Class({
|
|||||||
cr.moveTo(0, 0);
|
cr.moveTo(0, 0);
|
||||||
if (this._side == St.Side.LEFT)
|
if (this._side == St.Side.LEFT)
|
||||||
cr.arc(cornerRadius,
|
cr.arc(cornerRadius,
|
||||||
innerBorderWidth + cornerRadius,
|
borderWidth + cornerRadius,
|
||||||
cornerRadius, Math.PI, 3 * Math.PI / 2);
|
cornerRadius, Math.PI, 3 * Math.PI / 2);
|
||||||
else
|
else
|
||||||
cr.arc(0,
|
cr.arc(0,
|
||||||
innerBorderWidth + cornerRadius,
|
borderWidth + cornerRadius,
|
||||||
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
|
cornerRadius, 3 * Math.PI / 2, 2 * Math.PI);
|
||||||
cr.lineTo(cornerRadius, 0);
|
cr.lineTo(cornerRadius, 0);
|
||||||
cr.closePath();
|
cr.closePath();
|
||||||
|
|
||||||
let savedPath = cr.copyPath();
|
let savedPath = cr.copyPath();
|
||||||
|
|
||||||
let over = _over(innerBorderColor,
|
|
||||||
_over(outerBorderColor, backgroundColor));
|
|
||||||
Clutter.cairo_set_source_color(cr, over);
|
|
||||||
cr.fill();
|
|
||||||
|
|
||||||
let xOffsetDirection = this._side == St.Side.LEFT ? -1 : 1;
|
let xOffsetDirection = this._side == St.Side.LEFT ? -1 : 1;
|
||||||
let offset = outerBorderWidth;
|
let over = _over(borderColor, backgroundColor);
|
||||||
over = _over(innerBorderColor, backgroundColor);
|
|
||||||
Clutter.cairo_set_source_color(cr, over);
|
Clutter.cairo_set_source_color(cr, over);
|
||||||
|
|
||||||
cr.save();
|
|
||||||
cr.translate(xOffsetDirection * offset, - offset);
|
|
||||||
cr.appendPath(savedPath);
|
|
||||||
cr.fill();
|
|
||||||
cr.restore();
|
|
||||||
|
|
||||||
if (this._side == St.Side.LEFT)
|
|
||||||
cr.rectangle(cornerRadius - offset, 0, offset, outerBorderWidth);
|
|
||||||
else
|
|
||||||
cr.rectangle(0, 0, offset, outerBorderWidth);
|
|
||||||
cr.fill();
|
cr.fill();
|
||||||
|
|
||||||
offset = innerBorderWidth;
|
let offset = borderWidth;
|
||||||
Clutter.cairo_set_source_color(cr, backgroundColor);
|
Clutter.cairo_set_source_color(cr, backgroundColor);
|
||||||
|
|
||||||
cr.save();
|
cr.save();
|
||||||
@ -863,10 +909,10 @@ const PanelCorner = new Lang.Class({
|
|||||||
let node = this.actor.get_theme_node();
|
let node = this.actor.get_theme_node();
|
||||||
|
|
||||||
let cornerRadius = node.get_length("-panel-corner-radius");
|
let cornerRadius = node.get_length("-panel-corner-radius");
|
||||||
let innerBorderWidth = node.get_length('-panel-corner-inner-border-width');
|
let borderWidth = node.get_length('-panel-corner-border-width');
|
||||||
|
|
||||||
this.actor.set_size(cornerRadius, innerBorderWidth + cornerRadius);
|
this.actor.set_size(cornerRadius, borderWidth + cornerRadius);
|
||||||
this.actor.set_anchor_point(0, innerBorderWidth);
|
this.actor.set_anchor_point(0, borderWidth);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -897,14 +943,14 @@ const Panel = new Lang.Class({
|
|||||||
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
||||||
this.actor.add_actor(this._rightBox);
|
this.actor.add_actor(this._rightBox);
|
||||||
|
|
||||||
if (this.actor.get_direction() == St.TextDirection.RTL)
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
||||||
this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT);
|
this._leftCorner = new PanelCorner(this._rightBox, St.Side.LEFT);
|
||||||
else
|
else
|
||||||
this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT);
|
this._leftCorner = new PanelCorner(this._leftBox, St.Side.LEFT);
|
||||||
|
|
||||||
this.actor.add_actor(this._leftCorner.actor);
|
this.actor.add_actor(this._leftCorner.actor);
|
||||||
|
|
||||||
if (this.actor.get_direction() == St.TextDirection.RTL)
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
||||||
this._rightCorner = new PanelCorner(this._leftBox, St.Side.RIGHT);
|
this._rightCorner = new PanelCorner(this._leftBox, St.Side.RIGHT);
|
||||||
else
|
else
|
||||||
this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT);
|
this._rightCorner = new PanelCorner(this._rightBox, St.Side.RIGHT);
|
||||||
@ -913,6 +959,7 @@ const Panel = new Lang.Class({
|
|||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
|
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||||
|
|
||||||
/* Button on the left side of the panel. */
|
/* Button on the left side of the panel. */
|
||||||
if (global.session_type == Shell.SessionType.USER) {
|
if (global.session_type == Shell.SessionType.USER) {
|
||||||
@ -924,9 +971,8 @@ const Panel = new Lang.Class({
|
|||||||
// more cleanly with the rest of the panel
|
// more cleanly with the rest of the panel
|
||||||
this._menus.addMenu(this._activitiesButton.menu);
|
this._menus.addMenu(this._activitiesButton.menu);
|
||||||
|
|
||||||
this._appMenu = new AppMenuButton();
|
this._appMenu = new AppMenuButton(this._menus);
|
||||||
this._leftBox.add(this._appMenu.actor);
|
this._leftBox.add(this._appMenu.actor);
|
||||||
this._menus.addMenu(this._appMenu.menu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* center */
|
/* center */
|
||||||
@ -981,7 +1027,7 @@ const Panel = new Lang.Class({
|
|||||||
|
|
||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.y2 = allocHeight;
|
childBox.y2 = allocHeight;
|
||||||
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
|
childBox.x1 = allocWidth - Math.min(Math.floor(sideWidth),
|
||||||
leftNaturalWidth);
|
leftNaturalWidth);
|
||||||
childBox.x2 = allocWidth;
|
childBox.x2 = allocWidth;
|
||||||
@ -1000,7 +1046,7 @@ const Panel = new Lang.Class({
|
|||||||
|
|
||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.y2 = allocHeight;
|
childBox.y2 = allocHeight;
|
||||||
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
childBox.x1 = 0;
|
childBox.x1 = 0;
|
||||||
childBox.x2 = Math.min(Math.floor(sideWidth),
|
childBox.x2 = Math.min(Math.floor(sideWidth),
|
||||||
rightNaturalWidth);
|
rightNaturalWidth);
|
||||||
@ -1028,6 +1074,54 @@ const Panel = new Lang.Class({
|
|||||||
this._rightCorner.actor.allocate(childBox, flags);
|
this._rightCorner.actor.allocate(childBox, flags);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onButtonPress: function(actor, event) {
|
||||||
|
if (event.get_source() != actor)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let button = event.get_button();
|
||||||
|
if (button != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let focusWindow = global.display.focus_window;
|
||||||
|
if (!focusWindow)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let dragWindow = focusWindow.is_attached_dialog() ? focusWindow.get_transient_for()
|
||||||
|
: focusWindow;
|
||||||
|
if (!dragWindow)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
let rect = dragWindow.get_outer_rect();
|
||||||
|
let [stageX, stageY] = event.get_coords();
|
||||||
|
|
||||||
|
let allowDrag = dragWindow.maximized_vertically &&
|
||||||
|
stageX > rect.x && stageX < rect.x + rect.width;
|
||||||
|
|
||||||
|
if (!allowDrag)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
global.display.begin_grab_op(global.screen,
|
||||||
|
dragWindow,
|
||||||
|
Meta.GrabOp.MOVING,
|
||||||
|
false, /* pointer grab */
|
||||||
|
true, /* frame action */
|
||||||
|
button,
|
||||||
|
event.get_state(),
|
||||||
|
event.get_time(),
|
||||||
|
stageX, stageY);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
openAppMenu: function() {
|
||||||
|
let menu = this._appMenu.menu;
|
||||||
|
if (Main.overview.visible || menu.isOpen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
menu.open();
|
||||||
|
menu.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
|
},
|
||||||
|
|
||||||
startStatusArea: function() {
|
startStatusArea: function() {
|
||||||
for (let i = 0; i < this._status_area_order.length; i++) {
|
for (let i = 0; i < this._status_area_order.length; i++) {
|
||||||
let role = this._status_area_order[i];
|
let role = this._status_area_order[i];
|
||||||
@ -1048,13 +1142,13 @@ const Panel = new Lang.Class({
|
|||||||
for (i = children.length - 1; i >= 0; i--) {
|
for (i = children.length - 1; i >= 0; i--) {
|
||||||
let rolePosition = children[i]._rolePosition;
|
let rolePosition = children[i]._rolePosition;
|
||||||
if (position > rolePosition) {
|
if (position > rolePosition) {
|
||||||
this._rightBox.insert_actor(actor, i + 1);
|
this._rightBox.insert_child_at_index(actor, i + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (i == -1) {
|
if (i == -1) {
|
||||||
// If we didn't find a position, we must be first
|
// If we didn't find a position, we must be first
|
||||||
this._rightBox.insert_actor(actor, 0);
|
this._rightBox.insert_child_at_index(actor, 0);
|
||||||
}
|
}
|
||||||
actor._rolePosition = position;
|
actor._rolePosition = position;
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,7 @@ const Lang = imports.lang;
|
|||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
@ -96,35 +97,65 @@ const Button = new Lang.Class({
|
|||||||
Name: 'PanelMenuButton',
|
Name: 'PanelMenuButton',
|
||||||
Extends: ButtonBox,
|
Extends: ButtonBox,
|
||||||
|
|
||||||
_init: function(menuAlignment) {
|
_init: function(menuAlignment, nameText, dontCreateMenu) {
|
||||||
this.parent({ reactive: true,
|
this.parent({ reactive: true,
|
||||||
can_focus: true,
|
can_focus: true,
|
||||||
track_hover: true });
|
track_hover: true,
|
||||||
|
accessible_role: Atk.Role.MENU });
|
||||||
|
|
||||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||||
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
|
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
|
||||||
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP);
|
|
||||||
this.menu.actor.add_style_class_name('panel-menu');
|
if (dontCreateMenu)
|
||||||
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
this.menu = null;
|
||||||
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
else
|
||||||
Main.uiGroup.add_actor(this.menu.actor);
|
this.setMenu(new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0));
|
||||||
this.menu.actor.hide();
|
|
||||||
|
this.setName(nameText);
|
||||||
|
},
|
||||||
|
|
||||||
|
setName: function(text) {
|
||||||
|
if (text != null) {
|
||||||
|
// This is the easiest way to provide a accessible name to
|
||||||
|
// this widget. The label could be also used for other
|
||||||
|
// purposes in the future.
|
||||||
|
if (!this.label) {
|
||||||
|
this.label = new St.Label({ text: text });
|
||||||
|
this.actor.label_actor = this.label;
|
||||||
|
} else
|
||||||
|
this.label.text = text;
|
||||||
|
} else {
|
||||||
|
this.label = null;
|
||||||
|
this.actor.label_actor = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
setMenu: function(menu) {
|
||||||
|
if (this.menu)
|
||||||
|
this.menu.destroy();
|
||||||
|
|
||||||
|
this.menu = menu;
|
||||||
|
if (this.menu) {
|
||||||
|
this.menu.actor.add_style_class_name('panel-menu');
|
||||||
|
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||||
|
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
||||||
|
|
||||||
|
Main.uiGroup.add_actor(this.menu.actor);
|
||||||
|
this.menu.actor.hide();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onButtonPress: function(actor, event) {
|
_onButtonPress: function(actor, event) {
|
||||||
if (!this.menu.isOpen) {
|
if (!this.menu)
|
||||||
// Setting the max-height won't do any good if the minimum height of the
|
return;
|
||||||
// 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 = Main.layoutManager.primaryMonitor;
|
|
||||||
this.menu.actor.style = ('max-height: ' +
|
|
||||||
Math.round(monitor.height - Main.panel.actor.height) +
|
|
||||||
'px;');
|
|
||||||
}
|
|
||||||
this.menu.toggle();
|
this.menu.toggle();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onSourceKeyPress: function(actor, event) {
|
_onSourceKeyPress: function(actor, event) {
|
||||||
|
if (!this.menu)
|
||||||
|
return false;
|
||||||
|
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||||
this.menu.toggle();
|
this.menu.toggle();
|
||||||
@ -160,6 +191,14 @@ const Button = new Lang.Class({
|
|||||||
this.actor.add_style_pseudo_class('active');
|
this.actor.add_style_pseudo_class('active');
|
||||||
else
|
else
|
||||||
this.actor.remove_style_pseudo_class('active');
|
this.actor.remove_style_pseudo_class('active');
|
||||||
|
|
||||||
|
// 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 = Main.layoutManager.primaryMonitor;
|
||||||
|
this.menu.actor.style = ('max-height: ' +
|
||||||
|
Math.round(monitor.height - Main.panel.actor.height) +
|
||||||
|
'px;');
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -177,21 +216,20 @@ Signals.addSignalMethods(Button.prototype);
|
|||||||
*
|
*
|
||||||
* This class manages one System Status indicator (network, keyboard,
|
* This class manages one System Status indicator (network, keyboard,
|
||||||
* volume, bluetooth...), which is just a PanelMenuButton with an
|
* volume, bluetooth...), which is just a PanelMenuButton with an
|
||||||
* icon and a tooltip
|
* icon.
|
||||||
*/
|
*/
|
||||||
const SystemStatusButton = new Lang.Class({
|
const SystemStatusButton = new Lang.Class({
|
||||||
Name: 'SystemStatusButton',
|
Name: 'SystemStatusButton',
|
||||||
Extends: Button,
|
Extends: Button,
|
||||||
|
|
||||||
_init: function(iconName,tooltipText) {
|
_init: function(iconName, nameText) {
|
||||||
this.parent(0.0);
|
this.parent(0.0, nameText);
|
||||||
|
|
||||||
this._iconActor = new St.Icon({ icon_name: iconName,
|
this._iconActor = new St.Icon({ icon_name: iconName,
|
||||||
icon_type: St.IconType.SYMBOLIC,
|
icon_type: St.IconType.SYMBOLIC,
|
||||||
style_class: 'system-status-icon' });
|
style_class: 'system-status-icon' });
|
||||||
this.actor.add_actor(this._iconActor);
|
this.actor.add_actor(this._iconActor);
|
||||||
this.actor.add_style_class_name('panel-status-button');
|
this.actor.add_style_class_name('panel-status-button');
|
||||||
this.setTooltip(tooltipText);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setIcon: function(iconName) {
|
setIcon: function(iconName) {
|
||||||
@ -200,16 +238,5 @@ const SystemStatusButton = new Lang.Class({
|
|||||||
|
|
||||||
setGIcon: function(gicon) {
|
setGIcon: function(gicon) {
|
||||||
this._iconActor.gicon = gicon;
|
this._iconActor.gicon = gicon;
|
||||||
},
|
|
||||||
|
|
||||||
setTooltip: function(text) {
|
|
||||||
if (text != null) {
|
|
||||||
this.tooltip = text;
|
|
||||||
this.actor.has_tooltip = true;
|
|
||||||
this.actor.tooltip_text = text;
|
|
||||||
} else {
|
|
||||||
this.actor.has_tooltip = false;
|
|
||||||
this.tooltip = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -155,9 +155,12 @@ const PlacesManager = new Lang.Class({
|
|||||||
|
|
||||||
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
|
this._connect = new PlaceInfo('special:connect', _("Connect to..."),
|
||||||
function (size) {
|
function (size) {
|
||||||
return new St.Icon({ icon_name: 'applications-internet',
|
// do NOT use St.Icon here, it crashes the shell
|
||||||
icon_type: St.IconType.FULLCOLOR,
|
// see wanda.js for details
|
||||||
icon_size: size });
|
return St.TextureCache.get_default().load_icon_name(null,
|
||||||
|
'applications-internet',
|
||||||
|
St.IconType.FULLCOLOR,
|
||||||
|
size);
|
||||||
},
|
},
|
||||||
function (params) {
|
function (params) {
|
||||||
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't
|
// BUG: nautilus-connect-server doesn't have a desktop file, so we can't
|
||||||
@ -364,16 +367,21 @@ const PlaceSearchProvider = new Lang.Class({
|
|||||||
this.parent(_("PLACES & DEVICES"));
|
this.parent(_("PLACES & DEVICES"));
|
||||||
},
|
},
|
||||||
|
|
||||||
getResultMeta: function(resultId) {
|
getResultMetas: function(resultIds) {
|
||||||
let placeInfo = Main.placesManager.lookupPlaceById(resultId);
|
let metas = [];
|
||||||
if (!placeInfo)
|
for (let i = 0; i < resultIds.length; i++) {
|
||||||
return null;
|
let placeInfo = Main.placesManager.lookupPlaceById(resultIds[i]);
|
||||||
return { 'id': resultId,
|
if (!placeInfo)
|
||||||
'name': placeInfo.name,
|
metas.push(null);
|
||||||
'createIcon': function(size) {
|
else
|
||||||
return placeInfo.iconFactory(size);
|
metas.push({ 'id': resultIds[i],
|
||||||
}
|
'name': placeInfo.name,
|
||||||
};
|
'createIcon': function(size) {
|
||||||
|
return placeInfo.iconFactory(size);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return metas;
|
||||||
},
|
},
|
||||||
|
|
||||||
activateResult: function(id, params) {
|
activateResult: function(id, params) {
|
||||||
|
@ -41,7 +41,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
Extends: ModalDialog.ModalDialog,
|
Extends: ModalDialog.ModalDialog,
|
||||||
|
|
||||||
_init: function(actionId, message, cookie, userNames) {
|
_init: function(actionId, message, cookie, userNames) {
|
||||||
this.parent({ styleClass: 'polkit-dialog' });
|
this.parent({ styleClass: 'prompt-dialog' });
|
||||||
|
|
||||||
this.actionId = actionId;
|
this.actionId = actionId;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
@ -49,7 +49,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
this._wasDismissed = false;
|
this._wasDismissed = false;
|
||||||
this._completed = false;
|
this._completed = false;
|
||||||
|
|
||||||
let mainContentBox = new St.BoxLayout({ style_class: 'polkit-dialog-main-layout',
|
let mainContentBox = new St.BoxLayout({ style_class: 'prompt-dialog-main-layout',
|
||||||
vertical: false });
|
vertical: false });
|
||||||
this.contentLayout.add(mainContentBox,
|
this.contentLayout.add(mainContentBox,
|
||||||
{ x_fill: true,
|
{ x_fill: true,
|
||||||
@ -62,19 +62,19 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
x_align: St.Align.END,
|
x_align: St.Align.END,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
let messageBox = new St.BoxLayout({ style_class: 'polkit-dialog-message-layout',
|
let messageBox = new St.BoxLayout({ style_class: 'prompt-dialog-message-layout',
|
||||||
vertical: true });
|
vertical: true });
|
||||||
mainContentBox.add(messageBox,
|
mainContentBox.add(messageBox,
|
||||||
{ y_align: St.Align.START });
|
{ y_align: St.Align.START });
|
||||||
|
|
||||||
this._subjectLabel = new St.Label({ style_class: 'polkit-dialog-headline',
|
this._subjectLabel = new St.Label({ style_class: 'prompt-dialog-headline',
|
||||||
text: _("Authentication Required") });
|
text: _("Authentication Required") });
|
||||||
|
|
||||||
messageBox.add(this._subjectLabel,
|
messageBox.add(this._subjectLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
y_align: St.Align.START });
|
y_align: St.Align.START });
|
||||||
|
|
||||||
this._descriptionLabel = new St.Label({ style_class: 'polkit-dialog-description',
|
this._descriptionLabel = new St.Label({ style_class: 'prompt-dialog-description',
|
||||||
text: message });
|
text: message });
|
||||||
this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._descriptionLabel.clutter_text.line_wrap = true;
|
this._descriptionLabel.clutter_text.line_wrap = true;
|
||||||
@ -137,9 +137,9 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
|
|
||||||
this._passwordBox = new St.BoxLayout({ vertical: false });
|
this._passwordBox = new St.BoxLayout({ vertical: false });
|
||||||
messageBox.add(this._passwordBox);
|
messageBox.add(this._passwordBox);
|
||||||
this._passwordLabel = new St.Label(({ style_class: 'polkit-dialog-password-label' }));
|
this._passwordLabel = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||||
this._passwordBox.add(this._passwordLabel);
|
this._passwordBox.add(this._passwordLabel);
|
||||||
this._passwordEntry = new St.Entry({ style_class: 'polkit-dialog-password-entry',
|
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||||
text: "",
|
text: "",
|
||||||
can_focus: true});
|
can_focus: true});
|
||||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||||
@ -149,13 +149,13 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
this.setInitialKeyFocus(this._passwordEntry);
|
this.setInitialKeyFocus(this._passwordEntry);
|
||||||
this._passwordBox.hide();
|
this._passwordBox.hide();
|
||||||
|
|
||||||
this._errorMessageLabel = new St.Label({ style_class: 'polkit-dialog-error-label' });
|
this._errorMessageLabel = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
||||||
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._errorMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._errorMessageLabel.clutter_text.line_wrap = true;
|
this._errorMessageLabel.clutter_text.line_wrap = true;
|
||||||
messageBox.add(this._errorMessageLabel);
|
messageBox.add(this._errorMessageLabel);
|
||||||
this._errorMessageLabel.hide();
|
this._errorMessageLabel.hide();
|
||||||
|
|
||||||
this._infoMessageLabel = new St.Label({ style_class: 'polkit-dialog-info-label' });
|
this._infoMessageLabel = new St.Label({ style_class: 'prompt-dialog-info-label' });
|
||||||
this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._infoMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._infoMessageLabel.clutter_text.line_wrap = true;
|
this._infoMessageLabel.clutter_text.line_wrap = true;
|
||||||
messageBox.add(this._infoMessageLabel);
|
messageBox.add(this._infoMessageLabel);
|
||||||
@ -165,7 +165,7 @@ const AuthenticationDialog = new Lang.Class({
|
|||||||
* infoMessage and errorMessageLabel - but it is still invisible because
|
* infoMessage and errorMessageLabel - but it is still invisible because
|
||||||
* gnome-shell.css sets the color to be transparent
|
* gnome-shell.css sets the color to be transparent
|
||||||
*/
|
*/
|
||||||
this._nullMessageLabel = new St.Label({ style_class: 'polkit-dialog-null-label',
|
this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label',
|
||||||
text: 'abc'});
|
text: 'abc'});
|
||||||
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._nullMessageLabel.clutter_text.line_wrap = true;
|
this._nullMessageLabel.clutter_text.line_wrap = true;
|
||||||
@ -393,6 +393,7 @@ const AuthenticationAgent = new Lang.Class({
|
|||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
function() {
|
function() {
|
||||||
this._reallyCompleteRequest(wasDismissed);
|
this._reallyCompleteRequest(wasDismissed);
|
||||||
|
return false;
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
this._reallyCompleteRequest(wasDismissed);
|
this._reallyCompleteRequest(wasDismissed);
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
|
|
||||||
const Cairo = imports.cairo;
|
const Cairo = imports.cairo;
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
const Gtk = imports.gi.Gtk;
|
const Gtk = imports.gi.Gtk;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const BoxPointer = imports.ui.boxpointer;
|
const BoxPointer = imports.ui.boxpointer;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -39,7 +42,8 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item',
|
this.actor = new Shell.GenericContainer({ style_class: 'popup-menu-item',
|
||||||
reactive: params.reactive,
|
reactive: params.reactive,
|
||||||
track_hover: params.reactive,
|
track_hover: params.reactive,
|
||||||
can_focus: params.reactive });
|
can_focus: params.reactive,
|
||||||
|
accessible_role: Atk.Role.MENU_ITEM});
|
||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
@ -271,7 +275,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
_allocate: function(actor, box, flags) {
|
_allocate: function(actor, box, flags) {
|
||||||
let height = box.y2 - box.y1;
|
let height = box.y2 - box.y1;
|
||||||
let direction = this.actor.get_direction();
|
let direction = this.actor.get_text_direction();
|
||||||
|
|
||||||
if (this._dot) {
|
if (this._dot) {
|
||||||
// The dot is placed outside box
|
// The dot is placed outside box
|
||||||
@ -281,7 +285,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
let dotBox = new Clutter.ActorBox();
|
let dotBox = new Clutter.ActorBox();
|
||||||
let dotWidth = Math.round(box.x1 / 2);
|
let dotWidth = Math.round(box.x1 / 2);
|
||||||
|
|
||||||
if (direction == St.TextDirection.LTR) {
|
if (direction == Clutter.TextDirection.LTR) {
|
||||||
dotBox.x1 = Math.round(box.x1 / 4);
|
dotBox.x1 = Math.round(box.x1 / 4);
|
||||||
dotBox.x2 = dotBox.x1 + dotWidth;
|
dotBox.x2 = dotBox.x1 + dotWidth;
|
||||||
} else {
|
} else {
|
||||||
@ -294,7 +298,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let x;
|
let x;
|
||||||
if (direction == St.TextDirection.LTR)
|
if (direction == Clutter.TextDirection.LTR)
|
||||||
x = box.x1;
|
x = box.x1;
|
||||||
else
|
else
|
||||||
x = box.x2;
|
x = box.x2;
|
||||||
@ -309,7 +313,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
let availWidth, extraWidth;
|
let availWidth, extraWidth;
|
||||||
if (this._columnWidths) {
|
if (this._columnWidths) {
|
||||||
if (child.span == -1) {
|
if (child.span == -1) {
|
||||||
if (direction == St.TextDirection.LTR)
|
if (direction == Clutter.TextDirection.LTR)
|
||||||
availWidth = box.x2 - x;
|
availWidth = box.x2 - x;
|
||||||
else
|
else
|
||||||
availWidth = x - box.x1;
|
availWidth = x - box.x1;
|
||||||
@ -321,7 +325,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
extraWidth = availWidth - naturalWidth;
|
extraWidth = availWidth - naturalWidth;
|
||||||
} else {
|
} else {
|
||||||
if (child.span == -1) {
|
if (child.span == -1) {
|
||||||
if (direction == St.TextDirection.LTR)
|
if (direction == Clutter.TextDirection.LTR)
|
||||||
availWidth = box.x2 - x;
|
availWidth = box.x2 - x;
|
||||||
else
|
else
|
||||||
availWidth = x - box.x1;
|
availWidth = x - box.x1;
|
||||||
@ -331,7 +335,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
extraWidth = 0;
|
extraWidth = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (direction == St.TextDirection.LTR) {
|
if (direction == Clutter.TextDirection.LTR) {
|
||||||
if (child.expand) {
|
if (child.expand) {
|
||||||
childBox.x1 = x;
|
childBox.x1 = x;
|
||||||
childBox.x2 = x + availWidth;
|
childBox.x2 = x + availWidth;
|
||||||
@ -369,7 +373,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
child.actor.allocate(childBox, flags);
|
child.actor.allocate(childBox, flags);
|
||||||
|
|
||||||
if (direction == St.TextDirection.LTR)
|
if (direction == Clutter.TextDirection.LTR)
|
||||||
x += availWidth + this._spacing;
|
x += availWidth + this._spacing;
|
||||||
else
|
else
|
||||||
x -= availWidth + this._spacing;
|
x -= availWidth + this._spacing;
|
||||||
@ -387,6 +391,7 @@ const PopupMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
this.label = new St.Label({ text: text });
|
this.label = new St.Label({ text: text });
|
||||||
this.addActor(this.label);
|
this.addActor(this.label);
|
||||||
|
this.actor.label_actor = this.label
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -441,6 +446,7 @@ const PopupAlternatingMenuItem = new Lang.Class({
|
|||||||
this.label = new St.Label({ text: text });
|
this.label = new St.Label({ text: text });
|
||||||
this.state = PopupAlternatingMenuItemState.DEFAULT;
|
this.state = PopupAlternatingMenuItemState.DEFAULT;
|
||||||
this.addActor(this.label);
|
this.addActor(this.label);
|
||||||
|
this.actor.label_actor = this.label;
|
||||||
|
|
||||||
this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||||
},
|
},
|
||||||
@ -708,7 +714,8 @@ const Switch = new Lang.Class({
|
|||||||
Name: 'Switch',
|
Name: 'Switch',
|
||||||
|
|
||||||
_init: function(state) {
|
_init: function(state) {
|
||||||
this.actor = new St.Bin({ style_class: 'toggle-switch' });
|
this.actor = new St.Bin({ style_class: 'toggle-switch',
|
||||||
|
accessible_role: Atk.Role.CHECK_BOX});
|
||||||
// Translators: this MUST be either "toggle-switch-us"
|
// Translators: this MUST be either "toggle-switch-us"
|
||||||
// (for toggle switches containing the English words
|
// (for toggle switches containing the English words
|
||||||
// "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
// "ON" and "OFF") or "toggle-switch-intl" (for toggle
|
||||||
@ -741,6 +748,10 @@ const PopupSwitchMenuItem = new Lang.Class({
|
|||||||
this.label = new St.Label({ text: text });
|
this.label = new St.Label({ text: text });
|
||||||
this._switch = new Switch(active);
|
this._switch = new Switch(active);
|
||||||
|
|
||||||
|
this.actor.accessible_role = Atk.Role.CHECK_MENU_ITEM;
|
||||||
|
this.checkAccessibleState();
|
||||||
|
this.actor.label_actor = this.label;
|
||||||
|
|
||||||
this.addActor(this.label);
|
this.addActor(this.label);
|
||||||
|
|
||||||
this._statusBin = new St.Bin({ x_align: St.Align.END });
|
this._statusBin = new St.Bin({ x_align: St.Align.END });
|
||||||
@ -759,11 +770,14 @@ const PopupSwitchMenuItem = new Lang.Class({
|
|||||||
this._statusBin.child = this._statusLabel;
|
this._statusBin.child = this._statusLabel;
|
||||||
this.actor.reactive = false;
|
this.actor.reactive = false;
|
||||||
this.actor.can_focus = false;
|
this.actor.can_focus = false;
|
||||||
|
this.actor.accessible_role = Atk.Role.MENU_ITEM;
|
||||||
} else {
|
} else {
|
||||||
this._statusBin.child = this._switch.actor;
|
this._statusBin.child = this._switch.actor;
|
||||||
this.actor.reactive = true;
|
this.actor.reactive = true;
|
||||||
this.actor.can_focus = true;
|
this.actor.can_focus = true;
|
||||||
|
this.actor.accessible_role = Atk.Role.CHECK_MENU_ITEM;
|
||||||
}
|
}
|
||||||
|
this.checkAccessibleState();
|
||||||
},
|
},
|
||||||
|
|
||||||
activate: function(event) {
|
activate: function(event) {
|
||||||
@ -771,12 +785,19 @@ const PopupSwitchMenuItem = new Lang.Class({
|
|||||||
this.toggle();
|
this.toggle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we allow pressing space to toggle the switch
|
||||||
|
// without closing the menu
|
||||||
|
if (event.type() == Clutter.EventType.KEY_PRESS &&
|
||||||
|
event.get_key_symbol() == Clutter.KEY_space)
|
||||||
|
return;
|
||||||
|
|
||||||
this.parent(event);
|
this.parent(event);
|
||||||
},
|
},
|
||||||
|
|
||||||
toggle: function() {
|
toggle: function() {
|
||||||
this._switch.toggle();
|
this._switch.toggle();
|
||||||
this.emit('toggled', this._switch.state);
|
this.emit('toggled', this._switch.state);
|
||||||
|
this.checkAccessibleState();
|
||||||
},
|
},
|
||||||
|
|
||||||
get state() {
|
get state() {
|
||||||
@ -785,6 +806,20 @@ const PopupSwitchMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
setToggleState: function(state) {
|
setToggleState: function(state) {
|
||||||
this._switch.setToggleState(state);
|
this._switch.setToggleState(state);
|
||||||
|
this.checkAccessibleState();
|
||||||
|
},
|
||||||
|
|
||||||
|
checkAccessibleState: function() {
|
||||||
|
switch (this.actor.accessible_role) {
|
||||||
|
case Atk.Role.CHECK_MENU_ITEM:
|
||||||
|
if (this._switch.state)
|
||||||
|
this.actor.add_accessible_state (Atk.StateType.CHECKED);
|
||||||
|
else
|
||||||
|
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -867,6 +902,10 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
return menuItem;
|
return menuItem;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isEmpty: function() {
|
||||||
|
return this.box.get_children().length == 0;
|
||||||
|
},
|
||||||
|
|
||||||
isChildMenu: function(menu) {
|
isChildMenu: function(menu) {
|
||||||
return this._childMenus.indexOf(menu) != -1;
|
return this._childMenus.indexOf(menu) != -1;
|
||||||
},
|
},
|
||||||
@ -937,7 +976,12 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
this.emit('activate', menuItem);
|
this.emit('activate', menuItem);
|
||||||
this.close(true);
|
this.close(true);
|
||||||
}));
|
}));
|
||||||
menuItem.connect('destroy', Lang.bind(this, function(emitter) {
|
// the weird name is to avoid a conflict with some random property
|
||||||
|
// the menuItem may have, called destroyId
|
||||||
|
// (FIXME: in the future it may make sense to have container objects
|
||||||
|
// like PopupMenuManager does)
|
||||||
|
menuItem._popupMenuDestroyId = menuItem.connect('destroy', Lang.bind(this, function(menuItem) {
|
||||||
|
menuItem.disconnect(menuItem._popupMenuDestroyId);
|
||||||
menuItem.disconnect(menuItem._activateId);
|
menuItem.disconnect(menuItem._activateId);
|
||||||
menuItem.disconnect(menuItem._activeChangeId);
|
menuItem.disconnect(menuItem._activeChangeId);
|
||||||
menuItem.disconnect(menuItem._sensitiveChangeId);
|
menuItem.disconnect(menuItem._sensitiveChangeId);
|
||||||
@ -992,10 +1036,12 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
let items = this._getMenuItems();
|
let items = this._getMenuItems();
|
||||||
if (position < items.length) {
|
if (position < items.length) {
|
||||||
before_item = items[position].actor;
|
before_item = items[position].actor;
|
||||||
this.box.insert_before(menuItem.actor, before_item);
|
this.box.insert_child_below(menuItem.actor, before_item);
|
||||||
} else
|
} else {
|
||||||
this.box.add(menuItem.actor);
|
this.box.add(menuItem.actor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menuItem instanceof PopupMenuSection) {
|
if (menuItem instanceof PopupMenuSection) {
|
||||||
this._connectSubMenuSignals(menuItem, menuItem);
|
this._connectSubMenuSignals(menuItem, menuItem);
|
||||||
menuItem._closingId = this.connect('open-state-changed',
|
menuItem._closingId = this.connect('open-state-changed',
|
||||||
@ -1013,7 +1059,7 @@ const PopupMenuBase = new Lang.Class({
|
|||||||
if (before_item == null)
|
if (before_item == null)
|
||||||
this.box.add(menuItem.menu.actor);
|
this.box.add(menuItem.menu.actor);
|
||||||
else
|
else
|
||||||
this.box.insert_before(menuItem.menu.actor, before_item);
|
this.box.insert_child_below(menuItem.menu.actor, before_item);
|
||||||
this._connectSubMenuSignals(menuItem, menuItem.menu);
|
this._connectSubMenuSignals(menuItem, menuItem.menu);
|
||||||
this._connectItemSignals(menuItem);
|
this._connectItemSignals(menuItem);
|
||||||
menuItem._closingId = this.connect('open-state-changed', function(self, open) {
|
menuItem._closingId = this.connect('open-state-changed', function(self, open) {
|
||||||
@ -1187,6 +1233,9 @@ const PopupMenu = new Lang.Class({
|
|||||||
if (this.isOpen)
|
if (this.isOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (this.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
|
|
||||||
this._boxPointer.setPosition(this.sourceActor, this._arrowAlignment);
|
this._boxPointer.setPosition(this.sourceActor, this._arrowAlignment);
|
||||||
@ -1278,6 +1327,9 @@ const PopupSubMenu = new Lang.Class({
|
|||||||
if (this.isOpen)
|
if (this.isOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (this.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
|
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
@ -1391,12 +1443,23 @@ const PopupMenuSection = new Lang.Class({
|
|||||||
this.actor = this.box;
|
this.actor = this.box;
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
|
|
||||||
|
// an array of externally managed separators
|
||||||
|
this.separators = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
// deliberately ignore any attempt to open() or close(), but emit the
|
// deliberately ignore any attempt to open() or close(), but emit the
|
||||||
// corresponding signal so children can still pick it up
|
// corresponding signal so children can still pick it up
|
||||||
open: function(animate) { this.emit('open-state-changed', true); },
|
open: function(animate) { this.emit('open-state-changed', true); },
|
||||||
close: function() { this.emit('open-state-changed', false); },
|
close: function() { this.emit('open-state-changed', false); },
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
for (let i = 0; i < this.separators.length; i++)
|
||||||
|
this.separators[i].destroy();
|
||||||
|
this.separators = [];
|
||||||
|
|
||||||
|
this.parent();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const PopupSubMenuMenuItem = new Lang.Class({
|
const PopupSubMenuMenuItem = new Lang.Class({
|
||||||
@ -1410,6 +1473,7 @@ const PopupSubMenuMenuItem = new Lang.Class({
|
|||||||
|
|
||||||
this.label = new St.Label({ text: text });
|
this.label = new St.Label({ text: text });
|
||||||
this.addActor(this.label);
|
this.addActor(this.label);
|
||||||
|
this.actor.label_actor = this.label;
|
||||||
this._triangle = new St.Label({ text: '\u25B8' });
|
this._triangle = new St.Label({ text: '\u25B8' });
|
||||||
this.addActor(this._triangle, { align: St.Align.END });
|
this.addActor(this._triangle, { align: St.Align.END });
|
||||||
|
|
||||||
@ -1510,6 +1574,9 @@ const PopupComboMenu = new Lang.Class({
|
|||||||
if (this.isOpen)
|
if (this.isOpen)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (this.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
this.isOpen = true;
|
this.isOpen = true;
|
||||||
|
|
||||||
let [sourceX, sourceY] = this.sourceActor.get_transformed_position();
|
let [sourceX, sourceY] = this.sourceActor.get_transformed_position();
|
||||||
@ -1553,6 +1620,10 @@ const PopupComboMenu = new Lang.Class({
|
|||||||
this._activeItemPos = position;
|
this._activeItemPos = position;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getActiveItem: function() {
|
||||||
|
return this._getMenuItems()[this._activeItemPos];
|
||||||
|
},
|
||||||
|
|
||||||
setItemVisible: function(position, visible) {
|
setItemVisible: function(position, visible) {
|
||||||
if (!visible && position == this._activeItemPos) {
|
if (!visible && position == this._activeItemPos) {
|
||||||
log('Trying to hide the active menu item.');
|
log('Trying to hide the active menu item.');
|
||||||
@ -1574,6 +1645,8 @@ const PopupComboBoxMenuItem = new Lang.Class({
|
|||||||
_init: function (params) {
|
_init: function (params) {
|
||||||
this.parent(params);
|
this.parent(params);
|
||||||
|
|
||||||
|
this.actor.accessible_role = Atk.Role.COMBO_BOX;
|
||||||
|
|
||||||
this._itemBox = new Shell.Stack();
|
this._itemBox = new Shell.Stack();
|
||||||
this.addActor(this._itemBox);
|
this.addActor(this._itemBox);
|
||||||
|
|
||||||
@ -1670,6 +1743,11 @@ const PopupComboBoxMenuItem = new Lang.Class({
|
|||||||
Lang.bind(this, this._itemActivated, position));
|
Lang.bind(this, this._itemActivated, position));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
checkAccessibleLabel: function() {
|
||||||
|
let activeItem = this._menu.getActiveItem();
|
||||||
|
this.actor.label_actor = activeItem.label;
|
||||||
|
},
|
||||||
|
|
||||||
setActiveItem: function(position) {
|
setActiveItem: function(position) {
|
||||||
let item = this._items[position];
|
let item = this._items[position];
|
||||||
if (!item)
|
if (!item)
|
||||||
@ -1680,6 +1758,8 @@ const PopupComboBoxMenuItem = new Lang.Class({
|
|||||||
this._activeItemPos = position;
|
this._activeItemPos = position;
|
||||||
for (let i = 0; i < this._items.length; i++)
|
for (let i = 0; i < this._items.length; i++)
|
||||||
this._items[i].visible = (i == this._activeItemPos);
|
this._items[i].visible = (i == this._activeItemPos);
|
||||||
|
|
||||||
|
this.checkAccessibleLabel();
|
||||||
},
|
},
|
||||||
|
|
||||||
setItemVisible: function(position, visible) {
|
setItemVisible: function(position, visible) {
|
||||||
@ -1692,6 +1772,268 @@ const PopupComboBoxMenuItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RemoteMenu:
|
||||||
|
*
|
||||||
|
* A PopupMenu that tracks a GMenuModel and shows its actions
|
||||||
|
* (exposed by GApplication/GActionGroup)
|
||||||
|
*/
|
||||||
|
const RemoteMenu = new Lang.Class({
|
||||||
|
Name: 'RemoteMenu',
|
||||||
|
Extends: PopupMenu,
|
||||||
|
|
||||||
|
_init: function(sourceActor, model, actionGroup) {
|
||||||
|
this.parent(sourceActor, 0.0, St.Side.TOP);
|
||||||
|
|
||||||
|
this.model = model;
|
||||||
|
this.actionGroup = actionGroup;
|
||||||
|
|
||||||
|
this._actions = { };
|
||||||
|
this._modelChanged(this.model, 0, 0, this.model.get_n_items(), this);
|
||||||
|
|
||||||
|
this._actionStateChangeId = this.actionGroup.connect('action-state-changed', Lang.bind(this, this._actionStateChanged));
|
||||||
|
this._actionEnableChangeId = this.actionGroup.connect('action-enabled-changed', Lang.bind(this, this._actionEnabledChanged));
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
if (this._actionStateChangeId) {
|
||||||
|
this.actionGroup.disconnect(this._actionStateChangeId);
|
||||||
|
this._actionStateChangeId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._actionEnableChangeId) {
|
||||||
|
this.actionGroup.disconnect(this._actionEnableChangeId);
|
||||||
|
this._actionEnableChangeId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parent();
|
||||||
|
},
|
||||||
|
|
||||||
|
_createMenuItem: function(model, index) {
|
||||||
|
let labelValue = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_LABEL, null);
|
||||||
|
let label = labelValue ? labelValue.deep_unpack() : '';
|
||||||
|
// remove all underscores that are not followed by another underscore
|
||||||
|
label = label.replace(/_([^_])/, '$1');
|
||||||
|
|
||||||
|
let section_link = model.get_item_link(index, Gio.MENU_LINK_SECTION);
|
||||||
|
if (section_link) {
|
||||||
|
let item = new PopupMenuSection();
|
||||||
|
if (label) {
|
||||||
|
let title = new PopupMenuItem(label, { reactive: false,
|
||||||
|
style_class: 'popup-subtitle-menu-item' });
|
||||||
|
item._titleMenuItem = title;
|
||||||
|
title._ignored = true;
|
||||||
|
item.addMenuItem(title);
|
||||||
|
}
|
||||||
|
this._modelChanged(section_link, 0, 0, section_link.get_n_items(), item);
|
||||||
|
return [item, true, ''];
|
||||||
|
}
|
||||||
|
|
||||||
|
let submenu_link = model.get_item_link(index, Gio.MENU_LINK_SUBMENU);
|
||||||
|
|
||||||
|
if (submenu_link) {
|
||||||
|
let item = new PopupSubMenuMenuItem(label);
|
||||||
|
this._modelChanged(submenu_link, 0, 0, submenu_link.get_n_items(), item.menu);
|
||||||
|
return [item, false, ''];
|
||||||
|
}
|
||||||
|
|
||||||
|
let action_id = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_ACTION, null).deep_unpack();
|
||||||
|
if (!this.actionGroup.has_action(action_id)) {
|
||||||
|
// the action may not be there yet, wait for action-added
|
||||||
|
return [null, false, 'action-added'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._actions[action_id])
|
||||||
|
this._actions[action_id] = { enabled: this.actionGroup.get_action_enabled(action_id),
|
||||||
|
state: this.actionGroup.get_action_state(action_id),
|
||||||
|
items: [ ],
|
||||||
|
};
|
||||||
|
let action = this._actions[action_id];
|
||||||
|
let item, target, destroyId, specificSignalId;
|
||||||
|
|
||||||
|
if (action.state) {
|
||||||
|
// Docs have get_state_hint(), except that the DBus protocol
|
||||||
|
// has no provision for it (so ShellApp does not implement it,
|
||||||
|
// and neither GApplication), and g_action_get_state_hint()
|
||||||
|
// always returns null
|
||||||
|
// Funny :)
|
||||||
|
|
||||||
|
switch (String.fromCharCode(action.state.classify())) {
|
||||||
|
case 'b':
|
||||||
|
item = new PopupSwitchMenuItem(label, action.state.get_boolean());
|
||||||
|
action.items.push(item);
|
||||||
|
specificSignalId = item.connect('toggled', Lang.bind(this, function(item) {
|
||||||
|
this.actionGroup.activate_action(action_id, null);
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
item = new PopupMenuItem(label);
|
||||||
|
item._remoteTarget = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null).deep_unpack();
|
||||||
|
action.items.push(item);
|
||||||
|
item.setShowDot(action.state.deep_unpack() == item._remoteTarget);
|
||||||
|
specificSignalId = item.connect('activate', Lang.bind(this, function(item) {
|
||||||
|
this.actionGroup.activate_action(action_id, GLib.Variant.new_string(item._remoteTarget));
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
log('Action "%s" has state of type %s, which is not supported'.format(action_id, action.state.get_type_string()));
|
||||||
|
return [null, false, 'action-state-changed'];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
target = model.get_item_attribute_value(index, Gio.MENU_ATTRIBUTE_TARGET, null);
|
||||||
|
item = new PopupMenuItem(label);
|
||||||
|
action.items.push(item);
|
||||||
|
specificSignalId = item.connect('activate', Lang.bind(this, function() {
|
||||||
|
this.actionGroup.activate_action(action_id, target);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
item.actor.reactive = item.actor.can_focus = action.enabled;
|
||||||
|
if (action.enabled)
|
||||||
|
item.actor.remove_style_pseudo_class('insensitive');
|
||||||
|
else
|
||||||
|
item.actor.add_style_pseudo_class('insensitive');
|
||||||
|
|
||||||
|
destroyId = item.connect('destroy', Lang.bind(this, function() {
|
||||||
|
item.disconnect(destroyId);
|
||||||
|
item.disconnect(specificSignalId);
|
||||||
|
|
||||||
|
let pos = action.items.indexOf(item);
|
||||||
|
if (pos != -1)
|
||||||
|
action.items.splice(pos, 1);
|
||||||
|
}));
|
||||||
|
|
||||||
|
return [item, false, ''];
|
||||||
|
},
|
||||||
|
|
||||||
|
_modelChanged: function(model, position, removed, added, target) {
|
||||||
|
let j, k;
|
||||||
|
let j0, k0;
|
||||||
|
|
||||||
|
let currentItems = target._getMenuItems();
|
||||||
|
|
||||||
|
k0 = 0;
|
||||||
|
// skip ignored items at the beginning
|
||||||
|
while (k0 < currentItems.length && currentItems[k0]._ignored)
|
||||||
|
k0++;
|
||||||
|
// find the right menu item matching the model item
|
||||||
|
for (j0 = 0; j0 < position; j0++, k0++) {
|
||||||
|
if (currentItems[k0]._ignored)
|
||||||
|
k0++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removed == -1) {
|
||||||
|
// special flag to indicate we should destroy everything
|
||||||
|
for (k = k0; k < currentItems.length; k++)
|
||||||
|
currentItems[k].destroy();
|
||||||
|
} else {
|
||||||
|
for (j = j0, k = k0; j < j0 + removed; j++, k++) {
|
||||||
|
currentItems[k].destroy();
|
||||||
|
|
||||||
|
if (currentItems[k]._ignored)
|
||||||
|
j--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = j0, k = k0; j < j0 + added; j++, k++) {
|
||||||
|
let [item, addSeparator, changeSignal] = this._createMenuItem(model, j);
|
||||||
|
|
||||||
|
if (item) {
|
||||||
|
// separators must be added in the parent to make autohiding work
|
||||||
|
if (addSeparator) {
|
||||||
|
let separator = new PopupSeparatorMenuItem();
|
||||||
|
item.separators.push(separator);
|
||||||
|
separator._ignored = true;
|
||||||
|
target.addMenuItem(separator, k+1);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
target.addMenuItem(item, k);
|
||||||
|
|
||||||
|
if (addSeparator) {
|
||||||
|
let separator = new PopupSeparatorMenuItem();
|
||||||
|
item.separators.push(separator);
|
||||||
|
separator._ignored = true;
|
||||||
|
target.addMenuItem(separator, k+1);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
} else if (changeSignal) {
|
||||||
|
let signalId = this.actionGroup.connect(changeSignal, Lang.bind(this, function() {
|
||||||
|
this.actionGroup.disconnect(signalId);
|
||||||
|
|
||||||
|
// force a full update
|
||||||
|
this._modelChanged(model, 0, -1, model.get_n_items(), target);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!model._changedId) {
|
||||||
|
model._changedId = model.connect('items-changed', Lang.bind(this, this._modelChanged, target));
|
||||||
|
model._destroyId = target.connect('destroy', function() {
|
||||||
|
if (model._changedId)
|
||||||
|
model.disconnect(model._changedId);
|
||||||
|
if (model._destroyId)
|
||||||
|
target.disconnect(model._destroyId);
|
||||||
|
model._changedId = 0;
|
||||||
|
model._destroyId = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target instanceof PopupMenuSection) {
|
||||||
|
if (target._titleMenuItem)
|
||||||
|
target.actor.visible = target.numMenuItems != 1;
|
||||||
|
else
|
||||||
|
target.actor.visible = target.numMenuItems != 0;
|
||||||
|
} else {
|
||||||
|
let sourceItem = target.sourceActor._delegate;
|
||||||
|
if (sourceItem instanceof PopupSubMenuMenuItem)
|
||||||
|
sourceItem.actor.visible = target.numMenuItems != 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_actionStateChanged: function(actionGroup, action_id) {
|
||||||
|
let action = this._actions[action_id];
|
||||||
|
if (!action)
|
||||||
|
return;
|
||||||
|
|
||||||
|
action.state = actionGroup.get_action_state(action_id);
|
||||||
|
if (action.items.length) {
|
||||||
|
switch (String.fromCharCode(action.state.classify())) {
|
||||||
|
case 'b':
|
||||||
|
for (let i = 0; i < action.items.length; i++)
|
||||||
|
action.items[i].setToggleState(action.state.get_boolean());
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
for (let i = 0; i < action.items.length; i++)
|
||||||
|
action.items[i].setValue(action.state.get_double());
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
for (let i = 0; i < action.items.length; i++)
|
||||||
|
action.items[i].setShowDot(action.items[i]._remoteTarget == action.state.deep_unpack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_actionEnabledChanged: function(actionGroup, action_id) {
|
||||||
|
let action = this._actions[action_id];
|
||||||
|
if (!action)
|
||||||
|
return;
|
||||||
|
|
||||||
|
action.enabled = actionGroup.get_action_enabled(action_id);
|
||||||
|
if (action.items.length) {
|
||||||
|
for (let i = 0; i < action.items.length; i++) {
|
||||||
|
let item = action.items[i];
|
||||||
|
item.actor.reactive = item.actor.can_focus = action.enabled;
|
||||||
|
|
||||||
|
if (action.enabled)
|
||||||
|
item.actor.remove_style_pseudo_class('insensitive');
|
||||||
|
else
|
||||||
|
item.actor.add_style_pseudo_class('insensitive');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/* Basic implementation of a menu manager.
|
/* Basic implementation of a menu manager.
|
||||||
* Call addMenu to add menus
|
* Call addMenu to add menus
|
||||||
*/
|
*/
|
||||||
|
185
js/ui/remoteSearch.js
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const FileUtils = imports.misc.fileUtils;
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
|
const KEY_FILE_GROUP = 'Shell Search Provider';
|
||||||
|
|
||||||
|
const SearchProviderIface = <interface name="org.gnome.Shell.SearchProvider">
|
||||||
|
<method name="GetInitialResultSet">
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="as" direction="out" />
|
||||||
|
</method>
|
||||||
|
<method name="GetSubsearchResultSet">
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="as" direction="out" />
|
||||||
|
</method>
|
||||||
|
<method name="GetResultMetas">
|
||||||
|
<arg type="as" direction="in" />
|
||||||
|
<arg type="aa{sv}" direction="out" />
|
||||||
|
</method>
|
||||||
|
<method name="ActivateResult">
|
||||||
|
<arg type="s" direction="in" />
|
||||||
|
</method>
|
||||||
|
</interface>;
|
||||||
|
|
||||||
|
var SearchProviderProxy = Gio.DBusProxy.makeProxyWrapper(SearchProviderIface);
|
||||||
|
|
||||||
|
|
||||||
|
function loadRemoteSearchProviders(addProviderCallback) {
|
||||||
|
let dataDirs = GLib.get_system_data_dirs();
|
||||||
|
for (let i = 0; i < dataDirs.length; i++) {
|
||||||
|
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'search-providers']);
|
||||||
|
let dir = Gio.file_new_for_path(path);
|
||||||
|
if (!dir.query_exists(null))
|
||||||
|
continue;
|
||||||
|
loadRemoteSearchProvidersFromDir(dir, addProviderCallback);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadRemoteSearchProvidersFromDir(dir, addProviderCallback) {
|
||||||
|
let dirPath = dir.get_path();
|
||||||
|
FileUtils.listDirAsync(dir, Lang.bind(this, function(files) {
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
let keyfile = new GLib.KeyFile();
|
||||||
|
let path = GLib.build_filenamev([dirPath, files[i].get_name()]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
keyfile.load_from_file(path, 0);
|
||||||
|
} catch(e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!keyfile.has_group(KEY_FILE_GROUP))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let remoteProvider, title;
|
||||||
|
try {
|
||||||
|
let group = KEY_FILE_GROUP;
|
||||||
|
let icon = keyfile.get_string(group, 'Icon');
|
||||||
|
let busName = keyfile.get_string(group, 'BusName');
|
||||||
|
let objectPath = keyfile.get_string(group, 'ObjectPath');
|
||||||
|
title = keyfile.get_locale_string(group, 'Title', null);
|
||||||
|
|
||||||
|
remoteProvider = new RemoteSearchProvider(title,
|
||||||
|
icon,
|
||||||
|
busName,
|
||||||
|
objectPath);
|
||||||
|
} catch(e) {
|
||||||
|
log('Failed to add search provider "%s": %s'.format(title, e.toString()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
addProviderCallback(remoteProvider);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const RemoteSearchProvider = new Lang.Class({
|
||||||
|
Name: 'RemoteSearchProvider',
|
||||||
|
Extends: Search.SearchProvider,
|
||||||
|
|
||||||
|
_init: function(title, icon, dbusName, dbusPath) {
|
||||||
|
this._proxy = new SearchProviderProxy(Gio.DBus.session,
|
||||||
|
dbusName, dbusPath);
|
||||||
|
|
||||||
|
this.parent(title.toUpperCase());
|
||||||
|
this.async = true;
|
||||||
|
this._cancellable = new Gio.Cancellable();
|
||||||
|
},
|
||||||
|
|
||||||
|
createIcon: function(size, meta) {
|
||||||
|
if (meta['gicon']) {
|
||||||
|
return new St.Icon({ gicon: Gio.icon_new_for_string(meta['gicon']),
|
||||||
|
icon_size: size,
|
||||||
|
icon_type: St.IconType.FULLCOLOR });
|
||||||
|
} else if (meta['icon-data']) {
|
||||||
|
let [width, height, rowStride, hasAlpha,
|
||||||
|
bitsPerSample, nChannels, data] = meta['icon-data'];
|
||||||
|
let textureCache = St.TextureCache.get_default();
|
||||||
|
return textureCache.load_from_raw(data, hasAlpha,
|
||||||
|
width, height, rowStride, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ugh, but we want to fall back to something ...
|
||||||
|
return new St.Icon({ icon_name: 'text-x-generic',
|
||||||
|
icon_size: size,
|
||||||
|
icon_type: St.IconType.FULLCOLOR });
|
||||||
|
},
|
||||||
|
|
||||||
|
_getResultsFinished: function(results, error) {
|
||||||
|
if (error)
|
||||||
|
return;
|
||||||
|
this.searchSystem.pushResults(this, results[0]);
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialResultSetAsync: function(terms) {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
try {
|
||||||
|
this._proxy.GetInitialResultSetRemote(terms,
|
||||||
|
Lang.bind(this, this._getResultsFinished),
|
||||||
|
this._cancellable);
|
||||||
|
} catch(e) {
|
||||||
|
log('Error calling GetInitialResultSet for provider %s: %s'.format( this.title, e.toString()));
|
||||||
|
this.searchSystem.pushResults(this, []);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubsearchResultSetAsync: function(previousResults, newTerms) {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
try {
|
||||||
|
this._proxy.GetSubsearchResultSetRemote(previousResults, newTerms,
|
||||||
|
Lang.bind(this, this._getResultsFinished),
|
||||||
|
this._cancellable);
|
||||||
|
} catch(e) {
|
||||||
|
log('Error calling GetSubsearchResultSet for provider %s: %s'.format(this.title, e.toString()));
|
||||||
|
this.searchSystem.pushResults(this, []);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getResultMetasFinished: function(results, error, callback) {
|
||||||
|
if (error) {
|
||||||
|
callback([]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let metas = results[0];
|
||||||
|
let resultMetas = [];
|
||||||
|
for (let i = 0; i < metas.length; i++) {
|
||||||
|
for (let prop in metas[i])
|
||||||
|
metas[i][prop] = metas[i][prop].deep_unpack();
|
||||||
|
resultMetas.push({ id: metas[i]['id'],
|
||||||
|
name: metas[i]['name'],
|
||||||
|
createIcon: Lang.bind(this,
|
||||||
|
this.createIcon, metas[i]) });
|
||||||
|
}
|
||||||
|
callback(resultMetas);
|
||||||
|
},
|
||||||
|
|
||||||
|
getResultMetasAsync: function(ids, callback) {
|
||||||
|
this._cancellable.cancel();
|
||||||
|
this._cancellable.reset();
|
||||||
|
try {
|
||||||
|
this._proxy.GetResultMetasRemote(ids,
|
||||||
|
Lang.bind(this, this._getResultMetasFinished, callback),
|
||||||
|
this._cancellable);
|
||||||
|
} catch(e) {
|
||||||
|
log('Error calling GetResultMetas for provider %s: %s'.format(this.title, e.toString()));
|
||||||
|
callback([]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
activateResult: function(id) {
|
||||||
|
this._proxy.ActivateResultRemote(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
@ -209,6 +209,8 @@ const RunDialog = new Lang.Class({
|
|||||||
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
|
let entry = new St.Entry({ style_class: 'run-dialog-entry' });
|
||||||
ShellEntry.addContextMenu(entry);
|
ShellEntry.addContextMenu(entry);
|
||||||
|
|
||||||
|
entry.label_actor = label;
|
||||||
|
|
||||||
this._entryText = entry.clutter_text;
|
this._entryText = entry.clutter_text;
|
||||||
this.contentLayout.add(entry, { y_align: St.Align.START });
|
this.contentLayout.add(entry, { y_align: St.Align.START });
|
||||||
this.setInitialKeyFocus(this._entryText);
|
this.setInitialKeyFocus(this._entryText);
|
||||||
@ -242,7 +244,7 @@ const RunDialog = new Lang.Class({
|
|||||||
let symbol = e.get_key_symbol();
|
let symbol = e.get_key_symbol();
|
||||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||||
this.popModal();
|
this.popModal();
|
||||||
if (Shell.get_event_state(e) & Clutter.ModifierType.CONTROL_MASK)
|
if (e.get_state() & Clutter.ModifierType.CONTROL_MASK)
|
||||||
this._run(o.get_text(), true);
|
this._run(o.get_text(), true);
|
||||||
else
|
else
|
||||||
this._run(o.get_text(), false);
|
this._run(o.get_text(), false);
|
||||||
|
157
js/ui/search.js
@ -29,7 +29,6 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
_init: function(provider) {
|
_init: function(provider) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
this.selectionIndex = -1;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -51,20 +50,10 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* clear:
|
* clear:
|
||||||
* Remove all results from this display and reset the selection index.
|
* Remove all results from this display.
|
||||||
*/
|
*/
|
||||||
clear: function() {
|
clear: function() {
|
||||||
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
|
this.actor.get_children().forEach(function (actor) { actor.destroy(); });
|
||||||
this.selectionIndex = -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getSelectionIndex:
|
|
||||||
*
|
|
||||||
* Returns the index of the selected actor, or -1 if none.
|
|
||||||
*/
|
|
||||||
getSelectionIndex: function() {
|
|
||||||
return this.selectionIndex;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,25 +64,6 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
getVisibleResultCount: function() {
|
getVisibleResultCount: function() {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
|
||||||
* selectIndex:
|
|
||||||
* @index: Integer index
|
|
||||||
*
|
|
||||||
* Move selection to the given index.
|
|
||||||
* Return true if successful, false if no more results
|
|
||||||
* available.
|
|
||||||
*/
|
|
||||||
selectIndex: function() {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Activate the currently selected search result.
|
|
||||||
*/
|
|
||||||
activateSelected: function() {
|
|
||||||
throw new Error('Not implemented');
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -102,6 +72,11 @@ const SearchResultDisplay = new Lang.Class({
|
|||||||
* Subclass this object to add a new result type
|
* Subclass this object to add a new result type
|
||||||
* to the search system, then call registerProvider()
|
* to the search system, then call registerProvider()
|
||||||
* in SearchSystem with an instance.
|
* in SearchSystem with an instance.
|
||||||
|
* By default, search is synchronous and uses the
|
||||||
|
* getInitialResultSet()/getSubsearchResultSet() methods.
|
||||||
|
* For asynchronous search, set the async property to true
|
||||||
|
* and implement getInitialResultSetAsync()/getSubsearchResultSetAsync()
|
||||||
|
* instead.
|
||||||
*/
|
*/
|
||||||
const SearchProvider = new Lang.Class({
|
const SearchProvider = new Lang.Class({
|
||||||
Name: 'SearchProvider',
|
Name: 'SearchProvider',
|
||||||
@ -109,42 +84,7 @@ const SearchProvider = new Lang.Class({
|
|||||||
_init: function(title) {
|
_init: function(title) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.searchSystem = null;
|
this.searchSystem = null;
|
||||||
this.searchAsync = false;
|
this.async = false;
|
||||||
},
|
|
||||||
|
|
||||||
_asyncCancelled: function() {
|
|
||||||
},
|
|
||||||
|
|
||||||
startAsync: function() {
|
|
||||||
this.searchAsync = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
tryCancelAsync: function() {
|
|
||||||
if (!this.searchAsync)
|
|
||||||
return;
|
|
||||||
this._asyncCancelled();
|
|
||||||
this.searchAsync = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* addItems:
|
|
||||||
* @items: an array of result identifier strings representing
|
|
||||||
* items which match the last given search terms.
|
|
||||||
*
|
|
||||||
* This should be used for something that requires a bit more
|
|
||||||
* logic; it's designed to be an asyncronous way to add a result
|
|
||||||
* to the current search.
|
|
||||||
*/
|
|
||||||
addItems: function(items) {
|
|
||||||
if (!this.searchSystem)
|
|
||||||
throw new Error('Search provider not registered');
|
|
||||||
|
|
||||||
if (!items.length)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.tryCancelAsync();
|
|
||||||
|
|
||||||
this.searchSystem.addProviderItems(this, items);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -172,6 +112,18 @@ const SearchProvider = new Lang.Class({
|
|||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getInitialResultSetAsync:
|
||||||
|
* @terms: Array of search terms, treated as logical AND
|
||||||
|
*
|
||||||
|
* Like getInitialResultSet(), but the method should return immediately
|
||||||
|
* without a return value - use SearchSystem.pushResults() when the
|
||||||
|
* corresponding results are ready.
|
||||||
|
*/
|
||||||
|
getInitialResultSetAsync: function(terms) {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getSubsearchResultSet:
|
* getSubsearchResultSet:
|
||||||
* @previousResults: Array of item identifiers
|
* @previousResults: Array of item identifiers
|
||||||
@ -190,14 +142,40 @@ const SearchProvider = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getResultMeta:
|
* getSubsearchResultSetAsync:
|
||||||
* @id: Result identifier string
|
* @previousResults: Array of item identifiers
|
||||||
|
* @newTerms: Updated search terms
|
||||||
*
|
*
|
||||||
* Return an object with 'id', 'name', (both strings) and 'createIcon'
|
* Like getSubsearchResultSet(), but the method should return immediately
|
||||||
* (function(size) returning a Clutter.Texture) properties which describe
|
* without a return value - use SearchSystem.pushResults() when the
|
||||||
* the given search result.
|
* corresponding results are ready.
|
||||||
*/
|
*/
|
||||||
getResultMeta: function(id) {
|
getSubsearchResultSetAsync: function(previousResults, newTerms) {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getResultMetas:
|
||||||
|
* @ids: Result identifier strings
|
||||||
|
*
|
||||||
|
* Return an array of objects with 'id', 'name', (both strings) and
|
||||||
|
* 'createIcon' (function(size) returning a Clutter.Texture) properties
|
||||||
|
* with the same number of members as @ids
|
||||||
|
*/
|
||||||
|
getResultMetas: function(ids) {
|
||||||
|
throw new Error('Not implemented');
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getResultMetasAsync:
|
||||||
|
* @ids: Result identifier strings
|
||||||
|
* @callback: callback to pass the results to when ready
|
||||||
|
*
|
||||||
|
* Like getResultMetas(), but the method should return immediately
|
||||||
|
* without a return value - pass the results to the provided @callback
|
||||||
|
* when ready.
|
||||||
|
*/
|
||||||
|
getResultMetasAsync: function(ids, callback) {
|
||||||
throw new Error('Not implemented');
|
throw new Error('Not implemented');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -302,7 +280,7 @@ const OpenSearchSystem = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_addProvider: function(fileName) {
|
_addProvider: function(fileName) {
|
||||||
let path = global.datadir + '/search_providers/' + fileName;
|
let path = global.datadir + '/open-search-providers/' + fileName;
|
||||||
let source = Shell.get_file_contents_utf8_sync(path);
|
let source = Shell.get_file_contents_utf8_sync(path);
|
||||||
let [success, name, url, langs, icon_uri] = Shell.parse_search_provider(source);
|
let [success, name, url, langs, icon_uri] = Shell.parse_search_provider(source);
|
||||||
let provider ={ name: name,
|
let provider ={ name: name,
|
||||||
@ -319,7 +297,7 @@ const OpenSearchSystem = new Lang.Class({
|
|||||||
_refresh: function() {
|
_refresh: function() {
|
||||||
this._providers = [];
|
this._providers = [];
|
||||||
let names = global.settings.get_strv(DISABLED_OPEN_SEARCH_PROVIDERS_KEY);
|
let names = global.settings.get_strv(DISABLED_OPEN_SEARCH_PROVIDERS_KEY);
|
||||||
let file = Gio.file_new_for_path(global.datadir + '/search_providers');
|
let file = Gio.file_new_for_path(global.datadir + '/open-search-providers');
|
||||||
FileUtils.listDirAsync(file, Lang.bind(this, function(files) {
|
FileUtils.listDirAsync(file, Lang.bind(this, function(files) {
|
||||||
for (let i = 0; i < files.length; i++) {
|
for (let i = 0; i < files.length; i++) {
|
||||||
let enabled = true;
|
let enabled = true;
|
||||||
@ -369,8 +347,13 @@ const SearchSystem = new Lang.Class({
|
|||||||
this._previousResults = [];
|
this._previousResults = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
addProviderItems: function(provider, items) {
|
pushResults: function(provider, results) {
|
||||||
this.emit('search-updated', provider, items);
|
let i = this._providers.indexOf(provider);
|
||||||
|
if (i == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._previousResults[i] = [provider, results];
|
||||||
|
this.emit('search-updated', this._previousResults[i]);
|
||||||
},
|
},
|
||||||
|
|
||||||
updateSearch: function(searchString) {
|
updateSearch: function(searchString) {
|
||||||
@ -400,10 +383,14 @@ const SearchSystem = new Lang.Class({
|
|||||||
if (isSubSearch) {
|
if (isSubSearch) {
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
let [provider, previousResults] = this._previousResults[i];
|
let [provider, previousResults] = this._previousResults[i];
|
||||||
provider.tryCancelAsync();
|
|
||||||
try {
|
try {
|
||||||
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
|
if (provider.async) {
|
||||||
results.push([provider, providerResults]);
|
provider.getSubsearchResultSetAsync(previousResults, terms);
|
||||||
|
results.push([provider, []]);
|
||||||
|
} else {
|
||||||
|
let providerResults = provider.getSubsearchResultSet(previousResults, terms);
|
||||||
|
results.push([provider, providerResults]);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
||||||
}
|
}
|
||||||
@ -411,10 +398,14 @@ const SearchSystem = new Lang.Class({
|
|||||||
} else {
|
} else {
|
||||||
for (let i = 0; i < this._providers.length; i++) {
|
for (let i = 0; i < this._providers.length; i++) {
|
||||||
let provider = this._providers[i];
|
let provider = this._providers[i];
|
||||||
provider.tryCancelAsync();
|
|
||||||
try {
|
try {
|
||||||
let providerResults = provider.getInitialResultSet(terms);
|
if (provider.async) {
|
||||||
results.push([provider, providerResults]);
|
provider.getInitialResultSetAsync(terms);
|
||||||
|
results.push([provider, []]);
|
||||||
|
} else {
|
||||||
|
let providerResults = provider.getInitialResultSet(terms);
|
||||||
|
results.push([provider, providerResults]);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
global.log ('A ' + error.name + ' has occured in ' + provider.title + ': ' + error.message);
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ const SearchResult = new Lang.Class({
|
|||||||
if (content == null) {
|
if (content == null) {
|
||||||
content = new St.Bin({ style_class: 'search-result-content',
|
content = new St.Bin({ style_class: 'search-result-content',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
|
can_focus: true,
|
||||||
track_hover: true });
|
track_hover: true });
|
||||||
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||||
{ createIcon: this.metaInfo['createIcon'] });
|
{ createIcon: this.metaInfo['createIcon'] });
|
||||||
@ -110,70 +111,66 @@ const GridSearchResults = new Lang.Class({
|
|||||||
this.actor = new St.Bin({ x_align: St.Align.START });
|
this.actor = new St.Bin({ x_align: St.Align.START });
|
||||||
|
|
||||||
this.actor.set_child(this._grid.actor);
|
this.actor.set_child(this._grid.actor);
|
||||||
this.selectionIndex = -1;
|
|
||||||
this._width = 0;
|
this._width = 0;
|
||||||
this.actor.connect('notify::width', Lang.bind(this, function() {
|
this.actor.connect('notify::width', Lang.bind(this, function() {
|
||||||
this._width = this.actor.width;
|
this._width = this.actor.width;
|
||||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||||
this._tryAddResults();
|
let results = this.getResultsForDisplay();
|
||||||
|
if (results.length == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (provider.async) {
|
||||||
|
provider.getResultMetasAsync(results,
|
||||||
|
Lang.bind(this, this.renderResults));
|
||||||
|
} else {
|
||||||
|
let metas = provider.getResultMetas(results);
|
||||||
|
this.renderResults(metas);
|
||||||
|
}
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
this._notDisplayedResult = [];
|
this._notDisplayedResult = [];
|
||||||
this._terms = [];
|
this._terms = [];
|
||||||
|
this._pendingClear = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_tryAddResults: function() {
|
getResultsForDisplay: function() {
|
||||||
|
let alreadyVisible = this._pendingClear ? 0 : this._grid.visibleItemsCount();
|
||||||
let canDisplay = this._grid.childrenInRow(this._width) * MAX_SEARCH_RESULTS_ROWS
|
let canDisplay = this._grid.childrenInRow(this._width) * MAX_SEARCH_RESULTS_ROWS
|
||||||
- this._grid.visibleItemsCount();
|
- alreadyVisible;
|
||||||
|
|
||||||
for (let i = Math.min(this._notDisplayedResult.length, canDisplay); i > 0; i--) {
|
let numResults = Math.min(this._notDisplayedResult.length, canDisplay);
|
||||||
let result = this._notDisplayedResult.shift();
|
|
||||||
let meta = this.provider.getResultMeta(result);
|
return this._notDisplayedResult.splice(0, numResults);
|
||||||
let display = new SearchResult(this.provider, meta, this._terms);
|
|
||||||
this._grid.addItem(display.actor);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
getVisibleResultCount: function() {
|
getVisibleResultCount: function() {
|
||||||
return this._grid.visibleItemsCount();
|
return this._grid.visibleItemsCount();
|
||||||
},
|
},
|
||||||
|
|
||||||
renderResults: function(results, terms) {
|
setResults: function(results, terms) {
|
||||||
// copy the lists
|
// copy the lists
|
||||||
this._notDisplayedResult = results.slice(0);
|
this._notDisplayedResult = results.slice(0);
|
||||||
this._terms = terms.slice(0);
|
this._terms = terms.slice(0);
|
||||||
this._tryAddResults();
|
this._pendingClear = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
renderResults: function(metas) {
|
||||||
|
for (let i = 0; i < metas.length; i++) {
|
||||||
|
let display = new SearchResult(this.provider, metas[i], this._terms);
|
||||||
|
this._grid.addItem(display.actor);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
clear: function () {
|
clear: function () {
|
||||||
this._terms = [];
|
|
||||||
this._notDisplayedResult = [];
|
|
||||||
this._grid.removeAll();
|
this._grid.removeAll();
|
||||||
this.selectionIndex = -1;
|
this._pendingClear = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
selectIndex: function (index) {
|
getFirstResult: function() {
|
||||||
let nVisible = this.getVisibleResultCount();
|
if (this.getVisibleResultCount() > 0)
|
||||||
if (this.selectionIndex >= 0) {
|
return this._grid.getItemAtIndex(0)._delegate;
|
||||||
let prevActor = this._grid.getItemAtIndex(this.selectionIndex);
|
else
|
||||||
prevActor._delegate.setSelected(false);
|
return null;
|
||||||
}
|
|
||||||
this.selectionIndex = -1;
|
|
||||||
if (index >= nVisible)
|
|
||||||
return false;
|
|
||||||
else if (index < 0)
|
|
||||||
return false;
|
|
||||||
let targetActor = this._grid.getItemAtIndex(index);
|
|
||||||
targetActor._delegate.setSelected(true);
|
|
||||||
this.selectionIndex = index;
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
|
|
||||||
activateSelected: function() {
|
|
||||||
if (this.selectionIndex < 0)
|
|
||||||
return;
|
|
||||||
let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
|
|
||||||
targetActor._delegate.activate();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -215,7 +212,6 @@ const SearchResults = new Lang.Class({
|
|||||||
|
|
||||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||||
this._content.add(this._statusText);
|
this._content.add(this._statusText);
|
||||||
this._selectedProvider = -1;
|
|
||||||
this._providers = this._searchSystem.getProviders();
|
this._providers = this._searchSystem.getProviders();
|
||||||
this._providerMeta = [];
|
this._providerMeta = [];
|
||||||
this._providerMetaResults = {};
|
this._providerMetaResults = {};
|
||||||
@ -229,10 +225,12 @@ const SearchResults = new Lang.Class({
|
|||||||
this._openSearchProviders = [];
|
this._openSearchProviders = [];
|
||||||
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
|
this._openSearchSystem.connect('changed', Lang.bind(this, this._updateOpenSearchProviderButtons));
|
||||||
this._updateOpenSearchProviderButtons();
|
this._updateOpenSearchProviderButtons();
|
||||||
|
|
||||||
|
this._highlightDefault = false;
|
||||||
|
this._defaultResult = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateOpenSearchProviderButtons: function() {
|
_updateOpenSearchProviderButtons: function() {
|
||||||
this._selectedOpenSearchButton = -1;
|
|
||||||
for (let i = 0; i < this._openSearchProviders.length; i++)
|
for (let i = 0; i < this._openSearchProviders.length; i++)
|
||||||
this._openSearchProviders[i].actor.destroy();
|
this._openSearchProviders[i].actor.destroy();
|
||||||
this._openSearchProviders = this._openSearchSystem.getProviders();
|
this._openSearchProviders = this._openSearchSystem.getProviders();
|
||||||
@ -240,18 +238,10 @@ const SearchResults = new Lang.Class({
|
|||||||
this._createOpenSearchProviderButton(this._openSearchProviders[i]);
|
this._createOpenSearchProviderButton(this._openSearchProviders[i]);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateOpenSearchButtonState: function() {
|
|
||||||
for (let i = 0; i < this._openSearchProviders.length; i++) {
|
|
||||||
if (i == this._selectedOpenSearchButton)
|
|
||||||
this._openSearchProviders[i].actor.add_style_pseudo_class('selected');
|
|
||||||
else
|
|
||||||
this._openSearchProviders[i].actor.remove_style_pseudo_class('selected');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_createOpenSearchProviderButton: function(provider) {
|
_createOpenSearchProviderButton: function(provider) {
|
||||||
let button = new St.Button({ style_class: 'dash-search-button',
|
let button = new St.Button({ style_class: 'dash-search-button',
|
||||||
reactive: true,
|
reactive: true,
|
||||||
|
can_focus: true,
|
||||||
x_fill: true,
|
x_fill: true,
|
||||||
y_align: St.Align.MIDDLE });
|
y_align: St.Align.MIDDLE });
|
||||||
let bin = new St.Bin({ x_fill: false,
|
let bin = new St.Bin({ x_fill: false,
|
||||||
@ -267,6 +257,17 @@ const SearchResults = new Lang.Class({
|
|||||||
button.set_child(bin);
|
button.set_child(bin);
|
||||||
provider.actor = button;
|
provider.actor = button;
|
||||||
|
|
||||||
|
button.setSelected = function(selected) {
|
||||||
|
if (selected)
|
||||||
|
button.add_style_pseudo_class('selected');
|
||||||
|
else
|
||||||
|
button.remove_style_pseudo_class('selected');
|
||||||
|
};
|
||||||
|
button.activate = Lang.bind(this, function() {
|
||||||
|
this._openSearchSystem.activateResult(provider.id);
|
||||||
|
});
|
||||||
|
button.actor = button;
|
||||||
|
|
||||||
this._searchProvidersBox.add(button);
|
this._searchProvidersBox.add(button);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -289,7 +290,8 @@ const SearchResults = new Lang.Class({
|
|||||||
|
|
||||||
this._providerMeta.push({ provider: provider,
|
this._providerMeta.push({ provider: provider,
|
||||||
actor: providerBox,
|
actor: providerBox,
|
||||||
resultDisplay: resultDisplay });
|
resultDisplay: resultDisplay,
|
||||||
|
hasPendingResults: false });
|
||||||
this._content.add(providerBox);
|
this._content.add(providerBox);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -305,7 +307,6 @@ const SearchResults = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_clearDisplay: function() {
|
_clearDisplay: function() {
|
||||||
this._selectedProvider = -1;
|
|
||||||
this._visibleResultsCount = 0;
|
this._visibleResultsCount = 0;
|
||||||
for (let i = 0; i < this._providerMeta.length; i++) {
|
for (let i = 0; i < this._providerMeta.length; i++) {
|
||||||
let meta = this._providerMeta[i];
|
let meta = this._providerMeta[i];
|
||||||
@ -314,8 +315,8 @@ const SearchResults = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_clearDisplayForProvider: function(index) {
|
_clearDisplayForProvider: function(provider) {
|
||||||
let meta = this._providerMeta[index];
|
let meta = this._metaForProvider(provider);
|
||||||
meta.resultDisplay.clear();
|
meta.resultDisplay.clear();
|
||||||
meta.actor.hide();
|
meta.actor.hide();
|
||||||
},
|
},
|
||||||
@ -324,8 +325,6 @@ const SearchResults = new Lang.Class({
|
|||||||
this._searchSystem.reset();
|
this._searchSystem.reset();
|
||||||
this._statusText.hide();
|
this._statusText.hide();
|
||||||
this._clearDisplay();
|
this._clearDisplay();
|
||||||
this._selectedOpenSearchButton = -1;
|
|
||||||
this._updateOpenSearchButtonState();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
startingSearch: function() {
|
startingSearch: function() {
|
||||||
@ -342,13 +341,73 @@ const SearchResults = new Lang.Class({
|
|||||||
return this._providerMeta[this._providers.indexOf(provider)];
|
return this._providerMeta[this._providers.indexOf(provider)];
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateCurrentResults: function(searchSystem, provider, results) {
|
_maybeSetInitialSelection: function() {
|
||||||
|
let newDefaultResult = null;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._providerMeta.length; i++) {
|
||||||
|
let meta = this._providerMeta[i];
|
||||||
|
if (meta.hasPendingResults)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!meta.actor.visible)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let firstResult = meta.resultDisplay.getFirstResult();
|
||||||
|
if (firstResult) {
|
||||||
|
newDefaultResult = firstResult;
|
||||||
|
break; // select this one!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newDefaultResult)
|
||||||
|
newDefaultResult = this._searchProvidersBox.get_first_child();
|
||||||
|
|
||||||
|
if (newDefaultResult != this._defaultResult) {
|
||||||
|
if (this._defaultResult)
|
||||||
|
this._defaultResult.setSelected(false);
|
||||||
|
if (newDefaultResult)
|
||||||
|
newDefaultResult.setSelected(this._highlightDefault);
|
||||||
|
|
||||||
|
this._defaultResult = newDefaultResult;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateCurrentResults: function(searchSystem, results) {
|
||||||
let terms = searchSystem.getTerms();
|
let terms = searchSystem.getTerms();
|
||||||
|
let [provider, providerResults] = results;
|
||||||
let meta = this._metaForProvider(provider);
|
let meta = this._metaForProvider(provider);
|
||||||
meta.resultDisplay.clear();
|
meta.hasPendingResults = false;
|
||||||
meta.actor.show();
|
this._updateProviderResults(provider, providerResults, terms);
|
||||||
meta.resultDisplay.renderResults(results, terms);
|
},
|
||||||
return true;
|
|
||||||
|
_updateProviderResults: function(provider, providerResults, terms) {
|
||||||
|
let meta = this._metaForProvider(provider);
|
||||||
|
if (providerResults.length == 0) {
|
||||||
|
this._clearDisplayForProvider(provider);
|
||||||
|
meta.resultDisplay.setResults([], []);
|
||||||
|
} else {
|
||||||
|
this._providerMetaResults[provider.title] = providerResults;
|
||||||
|
meta.resultDisplay.setResults(providerResults, terms);
|
||||||
|
let results = meta.resultDisplay.getResultsForDisplay();
|
||||||
|
|
||||||
|
if (provider.async) {
|
||||||
|
provider.getResultMetasAsync(results, Lang.bind(this,
|
||||||
|
function(metas) {
|
||||||
|
this._clearDisplayForProvider(provider);
|
||||||
|
meta.actor.show();
|
||||||
|
this._content.hide();
|
||||||
|
meta.resultDisplay.renderResults(metas);
|
||||||
|
this._maybeSetInitialSelection();
|
||||||
|
this._content.show();
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
let metas = provider.getResultMetas(results);
|
||||||
|
this._clearDisplayForProvider(provider);
|
||||||
|
meta.actor.show();
|
||||||
|
meta.resultDisplay.renderResults(metas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._maybeSetInitialSelection();
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateResults: function(searchSystem, results) {
|
_updateResults: function(searchSystem, results) {
|
||||||
@ -356,127 +415,57 @@ const SearchResults = new Lang.Class({
|
|||||||
this._statusText.set_text(_("No matching results."));
|
this._statusText.set_text(_("No matching results."));
|
||||||
this._statusText.show();
|
this._statusText.show();
|
||||||
} else {
|
} else {
|
||||||
this._selectedOpenSearchButton = -1;
|
|
||||||
this._updateOpenSearchButtonState();
|
|
||||||
this._statusText.hide();
|
this._statusText.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
let terms = searchSystem.getTerms();
|
let terms = searchSystem.getTerms();
|
||||||
this._openSearchSystem.setSearchTerms(terms);
|
this._openSearchSystem.setSearchTerms(terms);
|
||||||
|
|
||||||
// To avoid CSS transitions causing flickering
|
// To avoid CSS transitions causing flickering when the first search
|
||||||
// of the selection when the first search result
|
// result stays the same, we hide the content while filling in the
|
||||||
// stays the same, we hide the content while
|
// results.
|
||||||
// filling in the results and setting the initial
|
|
||||||
// selection.
|
|
||||||
this._content.hide();
|
this._content.hide();
|
||||||
|
|
||||||
for (let i = 0; i < results.length; i++) {
|
for (let i = 0; i < results.length; i++) {
|
||||||
let [provider, providerResults] = results[i];
|
let [provider, providerResults] = results[i];
|
||||||
if (providerResults.length == 0) {
|
let meta = this._metaForProvider(provider);
|
||||||
this._clearDisplayForProvider(i);
|
meta.hasPendingResults = provider.async;
|
||||||
} else {
|
if (!meta.hasPendingResults)
|
||||||
this._providerMetaResults[provider.title] = providerResults;
|
this._updateProviderResults(provider, providerResults, terms);
|
||||||
this._clearDisplayForProvider(i);
|
|
||||||
let meta = this._metaForProvider(provider);
|
|
||||||
meta.actor.show();
|
|
||||||
meta.resultDisplay.renderResults(providerResults, terms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._selectedOpenSearchButton == -1)
|
|
||||||
this.selectDown(false);
|
|
||||||
|
|
||||||
this._content.show();
|
this._content.show();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_modifyActorSelection: function(resultDisplay, up) {
|
activateDefault: function() {
|
||||||
let success;
|
if (this._defaultResult)
|
||||||
let index = resultDisplay.getSelectionIndex();
|
this._defaultResult.activate();
|
||||||
if (up && index == -1)
|
|
||||||
index = resultDisplay.getVisibleResultCount() - 1;
|
|
||||||
else if (up)
|
|
||||||
index = index - 1;
|
|
||||||
else
|
|
||||||
index = index + 1;
|
|
||||||
return resultDisplay.selectIndex(index);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
selectUp: function(recursing) {
|
highlightDefault: function(highlight) {
|
||||||
if (this._selectedOpenSearchButton == -1) {
|
this._highlightDefault = highlight;
|
||||||
for (let i = this._selectedProvider; i >= 0; i--) {
|
if (this._defaultResult)
|
||||||
let meta = this._providerMeta[i];
|
this._defaultResult.setSelected(highlight);
|
||||||
if (!meta.actor.visible)
|
|
||||||
continue;
|
|
||||||
let success = this._modifyActorSelection(meta.resultDisplay, true);
|
|
||||||
if (success) {
|
|
||||||
this._selectedProvider = i;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this._selectedOpenSearchButton == -1)
|
|
||||||
this._selectedOpenSearchButton = this._openSearchProviders.length;
|
|
||||||
this._selectedOpenSearchButton--;
|
|
||||||
this._updateOpenSearchButtonState();
|
|
||||||
if (this._selectedOpenSearchButton >= 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this._providerMeta.length > 0 && !recursing) {
|
|
||||||
this._selectedProvider = this._providerMeta.length - 1;
|
|
||||||
this.selectUp(true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
selectDown: function(recursing) {
|
navigateFocus: function(direction) {
|
||||||
let current = this._selectedProvider;
|
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
|
||||||
if (this._selectedOpenSearchButton == -1) {
|
if (direction == Gtk.DirectionType.TAB_BACKWARD ||
|
||||||
if (current == -1)
|
direction == (rtl ? Gtk.DirectionType.RIGHT
|
||||||
current = 0;
|
: Gtk.DirectionType.LEFT) ||
|
||||||
for (let i = current; i < this._providerMeta.length; i++) {
|
direction == Gtk.DirectionType.UP) {
|
||||||
let meta = this._providerMeta[i];
|
this.actor.navigate_focus(null, direction, false);
|
||||||
if (!meta.actor.visible)
|
|
||||||
continue;
|
|
||||||
let success = this._modifyActorSelection(meta.resultDisplay, false);
|
|
||||||
if (success) {
|
|
||||||
this._selectedProvider = i;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this._selectedOpenSearchButton++;
|
|
||||||
|
|
||||||
if (this._selectedOpenSearchButton < this._openSearchProviders.length) {
|
|
||||||
this._updateOpenSearchButtonState();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._selectedOpenSearchButton = -1;
|
let from = this._defaultResult ? this._defaultResult.actor : null;
|
||||||
this._updateOpenSearchButtonState();
|
this.actor.navigate_focus(from, direction, false);
|
||||||
|
if (this._defaultResult) {
|
||||||
if (this._providerMeta.length > 0 && !recursing) {
|
// The default result appears focused, so navigate directly to the
|
||||||
this._selectedProvider = 0;
|
// next result.
|
||||||
this.selectDown(true);
|
this.actor.navigate_focus(global.stage.key_focus, direction, false);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
|
|
||||||
activateSelected: function() {
|
|
||||||
if (this._selectedOpenSearchButton != -1) {
|
|
||||||
let provider = this._openSearchProviders[this._selectedOpenSearchButton];
|
|
||||||
this._openSearchSystem.activateResult(provider.id);
|
|
||||||
Main.overview.hide();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let current = this._selectedProvider;
|
|
||||||
if (current < 0)
|
|
||||||
return;
|
|
||||||
let meta = this._providerMeta[current];
|
|
||||||
let resultDisplay = meta.resultDisplay;
|
|
||||||
resultDisplay.activateSelected();
|
|
||||||
Main.overview.hide();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -3,9 +3,12 @@
|
|||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Gio = imports.gi.Gio;
|
const Gio = imports.gi.Gio;
|
||||||
const GLib = imports.gi.GLib;
|
const GLib = imports.gi.GLib;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
|
const ExtensionUtils = imports.misc.extensionUtils;
|
||||||
|
const Flashspot = imports.ui.flashspot;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
const GnomeShellIface = <interface name="org.gnome.Shell">
|
const GnomeShellIface = <interface name="org.gnome.Shell">
|
||||||
@ -30,18 +33,29 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
|
|||||||
<arg type="i" direction="in" name="y"/>
|
<arg type="i" direction="in" name="y"/>
|
||||||
<arg type="i" direction="in" name="width"/>
|
<arg type="i" direction="in" name="width"/>
|
||||||
<arg type="i" direction="in" name="height"/>
|
<arg type="i" direction="in" name="height"/>
|
||||||
|
<arg type="b" direction="in" name="flash"/>
|
||||||
<arg type="s" direction="in" name="filename"/>
|
<arg type="s" direction="in" name="filename"/>
|
||||||
<arg type="b" direction="out" name="success"/>
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="ScreenshotWindow">
|
<method name="ScreenshotWindow">
|
||||||
<arg type="b" direction="in" name="include_frame"/>
|
<arg type="b" direction="in" name="include_frame"/>
|
||||||
|
<arg type="b" direction="in" name="include_cursor"/>
|
||||||
|
<arg type="b" direction="in" name="flash"/>
|
||||||
<arg type="s" direction="in" name="filename"/>
|
<arg type="s" direction="in" name="filename"/>
|
||||||
<arg type="b" direction="out" name="success"/>
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
<method name="Screenshot">
|
<method name="Screenshot">
|
||||||
|
<arg type="b" direction="in" name="include_cursor"/>
|
||||||
|
<arg type="b" direction="in" name="flash"/>
|
||||||
<arg type="s" direction="in" name="filename"/>
|
<arg type="s" direction="in" name="filename"/>
|
||||||
<arg type="b" direction="out" name="success"/>
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="FlashArea">
|
||||||
|
<arg type="i" direction="in" name="x"/>
|
||||||
|
<arg type="i" direction="in" name="y"/>
|
||||||
|
<arg type="i" direction="in" name="width"/>
|
||||||
|
<arg type="i" direction="in" name="height"/>
|
||||||
|
</method>
|
||||||
<method name="EnableExtension">
|
<method name="EnableExtension">
|
||||||
<arg type="s" direction="in" name="uuid"/>
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
</method>
|
</method>
|
||||||
@ -56,6 +70,9 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
|
|||||||
<arg type="s" direction="in" name="uuid"/>
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
<arg type="b" direction="out" name="success"/>
|
<arg type="b" direction="out" name="success"/>
|
||||||
</method>
|
</method>
|
||||||
|
<method name="LaunchExtensionPrefs">
|
||||||
|
<arg type="s" direction="in" name="uuid"/>
|
||||||
|
</method>
|
||||||
<property name="OverviewActive" type="b" access="readwrite" />
|
<property name="OverviewActive" type="b" access="readwrite" />
|
||||||
<property name="ApiVersion" type="i" access="read" />
|
<property name="ApiVersion" type="i" access="read" />
|
||||||
<property name="ShellVersion" type="s" access="read" />
|
<property name="ShellVersion" type="s" access="read" />
|
||||||
@ -109,12 +126,23 @@ const GnomeShell = new Lang.Class({
|
|||||||
return [success, returnValue];
|
return [success, returnValue];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onScreenshotComplete: function(obj, result, area, flash, invocation) {
|
||||||
|
if (flash) {
|
||||||
|
let flashspot = new Flashspot.Flashspot(area);
|
||||||
|
flashspot.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
let retval = GLib.Variant.new('(b)', [result]);
|
||||||
|
invocation.return_value(retval);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ScreenshotArea:
|
* ScreenshotArea:
|
||||||
* @x: The X coordinate of the area
|
* @x: The X coordinate of the area
|
||||||
* @y: The Y coordinate of the area
|
* @y: The Y coordinate of the area
|
||||||
* @width: The width of the area
|
* @width: The width of the area
|
||||||
* @height: The height of the area
|
* @height: The height of the area
|
||||||
|
* @flash: Whether to flash the area or not
|
||||||
* @filename: The filename for the screenshot
|
* @filename: The filename for the screenshot
|
||||||
*
|
*
|
||||||
* Takes a screenshot of the passed in area and saves it
|
* Takes a screenshot of the passed in area and saves it
|
||||||
@ -122,13 +150,19 @@ const GnomeShell = new Lang.Class({
|
|||||||
* indicating whether the operation was successful or not.
|
* indicating whether the operation was successful or not.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ScreenshotAreaAsync : function (x, y, width, height, filename, callback) {
|
ScreenshotAreaAsync : function (params, invocation) {
|
||||||
global.screenshot_area (x, y, width, height, filename, function (obj, result) { callback(result); });
|
let [x, y, width, height, flash, filename, callback] = params;
|
||||||
|
let screenshot = new Shell.Screenshot();
|
||||||
|
screenshot.screenshot_area (x, y, width, height, filename,
|
||||||
|
Lang.bind(this, this._onScreenshotComplete,
|
||||||
|
flash, invocation));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ScreenshotWindow:
|
* ScreenshotWindow:
|
||||||
* @include_frame: Whether to include the frame or not
|
* @include_frame: Whether to include the frame or not
|
||||||
|
* @include_cursor: Whether to include the cursor image or not
|
||||||
|
* @flash: Whether to flash the window area or not
|
||||||
* @filename: The filename for the screenshot
|
* @filename: The filename for the screenshot
|
||||||
*
|
*
|
||||||
* Takes a screenshot of the focused window (optionally omitting the frame)
|
* Takes a screenshot of the focused window (optionally omitting the frame)
|
||||||
@ -136,26 +170,41 @@ const GnomeShell = new Lang.Class({
|
|||||||
* indicating whether the operation was successful or not.
|
* indicating whether the operation was successful or not.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ScreenshotWindow : function (include_frame, filename) {
|
ScreenshotWindowAsync : function (params, invocation) {
|
||||||
return global.screenshot_window (include_frame, filename);
|
let [include_frame, include_cursor, flash, filename] = params;
|
||||||
|
let screenshot = new Shell.Screenshot();
|
||||||
|
screenshot.screenshot_window (include_frame, include_cursor, filename,
|
||||||
|
Lang.bind(this, this._onScreenshotComplete,
|
||||||
|
flash, invocation));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screenshot:
|
* Screenshot:
|
||||||
* @filename: The filename for the screenshot
|
* @filename: The filename for the screenshot
|
||||||
|
* @include_cursor: Whether to include the cursor image or not
|
||||||
|
* @flash: Whether to flash the screen or not
|
||||||
*
|
*
|
||||||
* Takes a screenshot of the whole screen and saves it
|
* Takes a screenshot of the whole screen and saves it
|
||||||
* in @filename as png image, it returns a boolean
|
* in @filename as png image, it returns a boolean
|
||||||
* indicating whether the operation was successful or not.
|
* indicating whether the operation was successful or not.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
ScreenshotAsync : function (filename, callback) {
|
ScreenshotAsync : function (params, invocation) {
|
||||||
global.screenshot(filename, function (obj, result) { callback(result); });
|
let [include_cursor, flash, filename] = params;
|
||||||
|
let screenshot = new Shell.Screenshot();
|
||||||
|
screenshot.screenshot(include_cursor, filename,
|
||||||
|
Lang.bind(this, this._onScreenshotComplete,
|
||||||
|
flash, invocation));
|
||||||
|
},
|
||||||
|
|
||||||
|
FlashArea: function(x, y, width, height) {
|
||||||
|
let flashspot = new Flashspot.Flashspot({ x : x, y : y, width: width, height: height});
|
||||||
|
flashspot.fire();
|
||||||
},
|
},
|
||||||
|
|
||||||
ListExtensions: function() {
|
ListExtensions: function() {
|
||||||
let out = {};
|
let out = {};
|
||||||
for (let uuid in ExtensionSystem.extensionMeta) {
|
for (let uuid in ExtensionUtils.extensions) {
|
||||||
let dbusObj = this.GetExtensionInfo(uuid);
|
let dbusObj = this.GetExtensionInfo(uuid);
|
||||||
out[uuid] = dbusObj;
|
out[uuid] = dbusObj;
|
||||||
}
|
}
|
||||||
@ -163,10 +212,23 @@ const GnomeShell = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
GetExtensionInfo: function(uuid) {
|
GetExtensionInfo: function(uuid) {
|
||||||
let meta = ExtensionSystem.extensionMeta[uuid] || {};
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
|
if (!extension)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
let obj = {};
|
||||||
|
Lang.copyProperties(extension.metadata, obj);
|
||||||
|
|
||||||
|
// Only serialize the properties that we actually need.
|
||||||
|
const serializedProperties = ["type", "state", "path", "error", "hasPrefs"];
|
||||||
|
|
||||||
|
serializedProperties.forEach(function(prop) {
|
||||||
|
obj[prop] = extension[prop];
|
||||||
|
});
|
||||||
|
|
||||||
let out = {};
|
let out = {};
|
||||||
for (let key in meta) {
|
for (let key in obj) {
|
||||||
let val = meta[key];
|
let val = obj[key];
|
||||||
let type;
|
let type;
|
||||||
switch (typeof val) {
|
switch (typeof val) {
|
||||||
case 'string':
|
case 'string':
|
||||||
@ -175,16 +237,27 @@ const GnomeShell = new Lang.Class({
|
|||||||
case 'number':
|
case 'number':
|
||||||
type = 'd';
|
type = 'd';
|
||||||
break;
|
break;
|
||||||
|
case 'boolean':
|
||||||
|
type = 'b';
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
out[key] = GLib.Variant.new(type, val);
|
out[key] = GLib.Variant.new(type, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
},
|
},
|
||||||
|
|
||||||
GetExtensionErrors: function(uuid) {
|
GetExtensionErrors: function(uuid) {
|
||||||
return ExtensionSystem.errors[uuid] || [];
|
let extension = ExtensionUtils.extensions[uuid];
|
||||||
|
if (!extension)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
if (!extension.errors)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return extension.errors;
|
||||||
},
|
},
|
||||||
|
|
||||||
EnableExtension: function(uuid) {
|
EnableExtension: function(uuid) {
|
||||||
@ -209,6 +282,13 @@ const GnomeShell = new Lang.Class({
|
|||||||
return ExtensionSystem.uninstallExtensionFromUUID(uuid);
|
return ExtensionSystem.uninstallExtensionFromUUID(uuid);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
LaunchExtensionPrefs: function(uuid) {
|
||||||
|
let appSys = Shell.AppSystem.get_default();
|
||||||
|
let app = appSys.lookup_app('gnome-shell-extension-prefs.desktop');
|
||||||
|
app.launch(global.display.get_current_time_roundtrip(),
|
||||||
|
['extension:///' + uuid], -1, null);
|
||||||
|
},
|
||||||
|
|
||||||
get OverviewActive() {
|
get OverviewActive() {
|
||||||
return Main.overview.visible;
|
return Main.overview.visible;
|
||||||
},
|
},
|
||||||
|
@ -211,6 +211,8 @@ const ShellMountQuestionDialog = new Lang.Class({
|
|||||||
{ y_align: St.Align.START });
|
{ y_align: St.Align.START });
|
||||||
|
|
||||||
this.subjectLabel = new St.Label({ style_class: 'mount-question-dialog-subject' });
|
this.subjectLabel = new St.Label({ style_class: 'mount-question-dialog-subject' });
|
||||||
|
this.subjectLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
|
this.subjectLabel.clutter_text.line_wrap = true;
|
||||||
|
|
||||||
messageLayout.add(this.subjectLabel,
|
messageLayout.add(this.subjectLabel,
|
||||||
{ y_fill: false,
|
{ y_fill: false,
|
||||||
@ -357,7 +359,7 @@ const ShellProcessesDialog = new Lang.Class({
|
|||||||
|
|
||||||
_setAppsForPids: function(pids) {
|
_setAppsForPids: function(pids) {
|
||||||
// remove all the items
|
// remove all the items
|
||||||
this._applicationList.destroy_children();
|
this._applicationList.destroy_all_children();
|
||||||
|
|
||||||
pids.forEach(Lang.bind(this, function(pid) {
|
pids.forEach(Lang.bind(this, function(pid) {
|
||||||
let tracker = Shell.WindowTracker.get_default();
|
let tracker = Shell.WindowTracker.get_default();
|
||||||
|
@ -44,7 +44,7 @@ const ATIndicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('preferences-desktop-accessibility', null);
|
this.parent('preferences-desktop-accessibility', _("Accessibility"));
|
||||||
|
|
||||||
let highContrast = this._buildHCItem();
|
let highContrast = this._buildHCItem();
|
||||||
this.menu.addMenuItem(highContrast);
|
this.menu.addMenuItem(highContrast);
|
||||||
|
@ -28,9 +28,8 @@ const Indicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('bluetooth-disabled', null);
|
this.parent('bluetooth-disabled', _("Bluetooth"));
|
||||||
|
|
||||||
GLib.spawn_command_line_sync ('pkill -f "^bluetooth-applet$"');
|
|
||||||
this._applet = new GnomeBluetoothApplet.Applet();
|
this._applet = new GnomeBluetoothApplet.Applet();
|
||||||
|
|
||||||
this._killswitch = new PopupMenu.PopupSwitchMenuItem(_("Bluetooth"), false);
|
this._killswitch = new PopupMenu.PopupSwitchMenuItem(_("Bluetooth"), false);
|
||||||
@ -182,7 +181,7 @@ const Indicator = new Lang.Class({
|
|||||||
|
|
||||||
// update connected property
|
// update connected property
|
||||||
if (device.can_connect)
|
if (device.can_connect)
|
||||||
item._connectedMenuitem.setToggleState(device.connected);
|
item._connectedMenuItem.setToggleState(device.connected);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createDeviceItem: function(device) {
|
_createDeviceItem: function(device) {
|
||||||
|
@ -41,7 +41,7 @@ const XKBIndicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.Button,
|
Extends: PanelMenu.Button,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(0.0);
|
this.parent(0.0, _("Keyboard"));
|
||||||
|
|
||||||
this._container = new Shell.GenericContainer();
|
this._container = new Shell.GenericContainer();
|
||||||
this._container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
this._container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
|
||||||
|
@ -113,6 +113,7 @@ const NMNetworkMenuItem = new Lang.Class({
|
|||||||
}
|
}
|
||||||
|
|
||||||
this._label = new St.Label({ text: title });
|
this._label = new St.Label({ text: title });
|
||||||
|
this.actor.label_actor = this._label;
|
||||||
this.addActor(this._label);
|
this.addActor(this._label);
|
||||||
this._icons = new St.BoxLayout({ style_class: 'nm-menu-item-icons' });
|
this._icons = new St.BoxLayout({ style_class: 'nm-menu-item-icons' });
|
||||||
this.addActor(this._icons, { align: St.Align.END });
|
this.addActor(this._icons, { align: St.Align.END });
|
||||||
@ -249,9 +250,11 @@ const NMWirelessSectionTitleMenuItem = new Lang.Class({
|
|||||||
updateForDevice: function(device) {
|
updateForDevice: function(device) {
|
||||||
// we show the switch
|
// we show the switch
|
||||||
// - if there not just one device
|
// - if there not just one device
|
||||||
// - if the switch is off
|
// - if the switch is off (but it can be turned on)
|
||||||
// - if the device is activated or disconnected
|
// - if the device is activated or disconnected
|
||||||
if (device && this._softwareEnabled && this._hardwareEnabled) {
|
if (!this._hardwareEnabled) {
|
||||||
|
this.setStatus(_("hardware disabled"));
|
||||||
|
} else if (device && this._softwareEnabled) {
|
||||||
let text = device.getStatusLabel();
|
let text = device.getStatusLabel();
|
||||||
this.setStatus(text);
|
this.setStatus(text);
|
||||||
} else
|
} else
|
||||||
@ -327,7 +330,7 @@ const NMDevice = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this.section = new PopupMenu.PopupMenuSection();
|
this.section = new PopupMenu.PopupMenuSection();
|
||||||
|
|
||||||
this._createSection();
|
this._deferredWorkId = Main.initializeDeferredWork(this.section.actor, Lang.bind(this, this._createSection));
|
||||||
},
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
@ -394,16 +397,29 @@ const NMDevice = new Lang.Class({
|
|||||||
this._activeConnection = activeConnection;
|
this._activeConnection = activeConnection;
|
||||||
|
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._queueCreateSection();
|
||||||
},
|
},
|
||||||
|
|
||||||
checkConnection: function(connection) {
|
checkConnection: function(connection) {
|
||||||
let exists = this._findConnection(connection._uuid) != -1;
|
let pos = this._findConnection(connection._uuid);
|
||||||
|
let exists = pos != -1;
|
||||||
let valid = this.connectionValid(connection);
|
let valid = this.connectionValid(connection);
|
||||||
|
|
||||||
if (exists && !valid)
|
if (exists && !valid)
|
||||||
this.removeConnection(connection);
|
this.removeConnection(connection);
|
||||||
else if (!exists && valid)
|
else if (!exists && valid)
|
||||||
this.addConnection(connection);
|
this.addConnection(connection);
|
||||||
|
else if (exists && valid) {
|
||||||
|
// propagate changes and update the UI
|
||||||
|
|
||||||
|
if (this._connections[pos].timestamp != connection._timestamp) {
|
||||||
|
this._connections[pos].timestamp = connection._timestamp;
|
||||||
|
this._connections.sort(this._connectionSortFunction);
|
||||||
|
|
||||||
|
this._clearSection();
|
||||||
|
this._queueCreateSection();
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addConnection: function(connection) {
|
addConnection: function(connection) {
|
||||||
@ -418,7 +434,7 @@ const NMDevice = new Lang.Class({
|
|||||||
this._connections.sort(this._connectionSortFunction);
|
this._connections.sort(this._connectionSortFunction);
|
||||||
|
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._queueCreateSection();
|
||||||
},
|
},
|
||||||
|
|
||||||
removeConnection: function(connection) {
|
removeConnection: function(connection) {
|
||||||
@ -442,7 +458,7 @@ const NMDevice = new Lang.Class({
|
|||||||
// (or in the case of NMDeviceWired, we want to hide
|
// (or in the case of NMDeviceWired, we want to hide
|
||||||
// the only explicit connection)
|
// the only explicit connection)
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._queueCreateSection();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -526,6 +542,11 @@ const NMDevice = new Lang.Class({
|
|||||||
return -1;
|
return -1;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_queueCreateSection: function() {
|
||||||
|
this._clearSection();
|
||||||
|
Main.queueDeferredWork(this._deferredWorkId);
|
||||||
|
},
|
||||||
|
|
||||||
_clearSection: function() {
|
_clearSection: function() {
|
||||||
// Clear everything
|
// Clear everything
|
||||||
this.section.removeAll();
|
this.section.removeAll();
|
||||||
@ -620,7 +641,7 @@ const NMDevice = new Lang.Class({
|
|||||||
this._updateStatusItem();
|
this._updateStatusItem();
|
||||||
|
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._queueCreateSection();
|
||||||
this.emit('state-changed');
|
this.emit('state-changed');
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -864,7 +885,12 @@ const NMDeviceBluetooth = new Lang.Class({
|
|||||||
this._autoConnectionName = this._makeConnectionName(this.device);
|
this._autoConnectionName = this._makeConnectionName(this.device);
|
||||||
|
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._queueCreateSection();
|
||||||
|
this._updateStatusItem();
|
||||||
|
},
|
||||||
|
|
||||||
|
_getDescription: function() {
|
||||||
|
return this.device.name || _("Bluetooth");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1209,7 +1235,6 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
accessPoints: [ accessPoint ]
|
accessPoints: [ accessPoint ]
|
||||||
};
|
};
|
||||||
apObj.ssidText = ssidToLabel(apObj.ssid);
|
apObj.ssidText = ssidToLabel(apObj.ssid);
|
||||||
needsupdate = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if this enables new connections for this group
|
// check if this enables new connections for this group
|
||||||
@ -1224,37 +1249,13 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsupdate) {
|
if (pos == -1 || needsupdate) {
|
||||||
if (apObj.item)
|
|
||||||
apObj.item.destroy();
|
|
||||||
|
|
||||||
if (pos != -1)
|
if (pos != -1)
|
||||||
this._networks.splice(pos, 1);
|
this._networks.splice(pos, 1);
|
||||||
|
pos = Util.insertSorted(this._networks, apObj, this._networkSortFunction);
|
||||||
|
|
||||||
if (this._networks.length == 0) {
|
this._clearSection();
|
||||||
// only network in the list
|
this._queueCreateSection();
|
||||||
this._networks.push(apObj);
|
|
||||||
this._clearSection();
|
|
||||||
this._createSection();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip networks that should appear earlier
|
|
||||||
let menuPos = 0;
|
|
||||||
for (pos = 0;
|
|
||||||
pos < this._networks.length &&
|
|
||||||
this._networkSortFunction(this._networks[pos], apObj) < 0; ++pos) {
|
|
||||||
if (this._networks[pos] != this._activeNetwork)
|
|
||||||
menuPos++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// (re-)add the network
|
|
||||||
this._networks.splice(pos, 0, apObj);
|
|
||||||
|
|
||||||
if (this._shouldShowConnectionList()) {
|
|
||||||
menuPos += (this._activeConnectionItem ? 1 : 0);
|
|
||||||
this._createNetworkItem(apObj, menuPos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1341,7 +1342,7 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
let obj = this._connections[pos];
|
let obj = this._connections[pos];
|
||||||
this._connections.splice(pos, 1);
|
this._connections.splice(pos, 1);
|
||||||
|
|
||||||
let anyauto = false, forceupdate = false;
|
let forceupdate = false;
|
||||||
for (let i = 0; i < this._networks.length; i++) {
|
for (let i = 0; i < this._networks.length; i++) {
|
||||||
let apObj = this._networks[i];
|
let apObj = this._networks[i];
|
||||||
let connections = apObj.connections;
|
let connections = apObj.connections;
|
||||||
@ -1349,16 +1350,14 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
if (connections[k]._uuid == connection._uuid) {
|
if (connections[k]._uuid == connection._uuid) {
|
||||||
// remove the connection from the access point group
|
// remove the connection from the access point group
|
||||||
connections.splice(k);
|
connections.splice(k);
|
||||||
anyauto = connections.length == 0;
|
forceupdate = forceupdate || connections.length == 0;
|
||||||
|
|
||||||
if (anyauto) {
|
if (forceupdate)
|
||||||
// this potentially changes the sorting order
|
|
||||||
forceupdate = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
if (apObj.item) {
|
if (apObj.item) {
|
||||||
if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
|
if (apObj.item instanceof PopupMenu.PopupSubMenuMenuItem) {
|
||||||
let items = apObj.item.menu.getMenuItems();
|
let items = apObj.item.menu._getMenuItems();
|
||||||
if (items.length == 2) {
|
if (items.length == 2) {
|
||||||
// we need to update the connection list to convert this to a normal item
|
// we need to update the connection list to convert this to a normal item
|
||||||
forceupdate = true;
|
forceupdate = true;
|
||||||
@ -1380,10 +1379,10 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (forceupdate || anyauto) {
|
if (forceupdate) {
|
||||||
this._networks.sort(this._networkSortFunction);
|
this._networks.sort(this._networkSortFunction);
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._queueCreateSection();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1416,13 +1415,13 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
if (forceupdate) {
|
if (forceupdate) {
|
||||||
this._networks.sort(this._networkSortFunction);
|
this._networks.sort(this._networkSortFunction);
|
||||||
this._clearSection();
|
this._clearSection();
|
||||||
this._createSection();
|
this._queueCreateSection();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_createActiveConnectionItem: function() {
|
_createActiveConnectionItem: function() {
|
||||||
let icon, title;
|
let icon, title;
|
||||||
if (this._activeConnection._connection) {
|
if (this._activeConnection && this._activeConnection._connection) {
|
||||||
let connection = this._activeConnection._connection;
|
let connection = this._activeConnection._connection;
|
||||||
if (this._activeNetwork)
|
if (this._activeNetwork)
|
||||||
this._activeConnectionItem = new NMNetworkMenuItem(this._activeNetwork.accessPoints, undefined,
|
this._activeConnectionItem = new NMNetworkMenuItem(this._activeNetwork.accessPoints, undefined,
|
||||||
@ -1515,7 +1514,7 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
if (!this._shouldShowConnectionList())
|
if (!this._shouldShowConnectionList())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if(this._activeConnection) {
|
if (this._activeNetwork) {
|
||||||
this._createActiveConnectionItem();
|
this._createActiveConnectionItem();
|
||||||
this.section.addMenuItem(this._activeConnectionItem);
|
this.section.addMenuItem(this._activeConnectionItem);
|
||||||
}
|
}
|
||||||
@ -1524,8 +1523,10 @@ const NMDeviceWireless = new Lang.Class({
|
|||||||
|
|
||||||
for(let j = 0; j < this._networks.length; j++) {
|
for(let j = 0; j < this._networks.length; j++) {
|
||||||
let apObj = this._networks[j];
|
let apObj = this._networks[j];
|
||||||
if (apObj == this._activeNetwork)
|
if (apObj == this._activeNetwork) {
|
||||||
|
activeOffset--;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
this._createNetworkItem(apObj, j + activeOffset);
|
this._createNetworkItem(apObj, j + activeOffset);
|
||||||
}
|
}
|
||||||
@ -1537,7 +1538,7 @@ const NMApplet = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('network-error', null);
|
this.parent('network-error', _("Network"));
|
||||||
|
|
||||||
this._client = NMClient.Client.new();
|
this._client = NMClient.Client.new();
|
||||||
|
|
||||||
@ -1803,6 +1804,7 @@ const NMApplet = new Lang.Class({
|
|||||||
let activating = null;
|
let activating = null;
|
||||||
let default_ip4 = null;
|
let default_ip4 = null;
|
||||||
let default_ip6 = null;
|
let default_ip6 = null;
|
||||||
|
let active_vpn = null;
|
||||||
for (let i = 0; i < this._activeConnections.length; i++) {
|
for (let i = 0; i < this._activeConnections.length; i++) {
|
||||||
let a = this._activeConnections[i];
|
let a = this._activeConnections[i];
|
||||||
|
|
||||||
@ -1832,6 +1834,8 @@ const NMApplet = new Lang.Class({
|
|||||||
default_ip4 = a;
|
default_ip4 = a;
|
||||||
if (a.default6)
|
if (a.default6)
|
||||||
default_ip6 = a;
|
default_ip6 = a;
|
||||||
|
if (a._type == 'vpn')
|
||||||
|
active_vpn = a;
|
||||||
|
|
||||||
if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
if (a.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||||
activating = a;
|
activating = a;
|
||||||
@ -1840,7 +1844,7 @@ const NMApplet = new Lang.Class({
|
|||||||
if (a._type != NetworkManager.SETTING_VPN_SETTING_NAME) {
|
if (a._type != NetworkManager.SETTING_VPN_SETTING_NAME) {
|
||||||
// find a good device to be considered primary
|
// find a good device to be considered primary
|
||||||
a._primaryDevice = null;
|
a._primaryDevice = null;
|
||||||
let devices = a.get_devices();
|
let devices = a.get_devices() || [];
|
||||||
for (let j = 0; j < devices.length; j++) {
|
for (let j = 0; j < devices.length; j++) {
|
||||||
let d = devices[j];
|
let d = devices[j];
|
||||||
if (d._delegate) {
|
if (d._delegate) {
|
||||||
@ -1862,7 +1866,7 @@ const NMApplet = new Lang.Class({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._mainConnection = activating || default_ip4 || default_ip6 || this._activeConnections[0] || null;
|
this._mainConnection = activating || active_vpn || default_ip4 || default_ip6 || this._activeConnections[0] || null;
|
||||||
},
|
},
|
||||||
|
|
||||||
_notifyActivated: function(activeConnection) {
|
_notifyActivated: function(activeConnection) {
|
||||||
|
@ -46,7 +46,6 @@ const PowerManagerInterface = <interface name="org.gnome.SettingsDaemon.Power">
|
|||||||
<method name="GetPrimaryDevice">
|
<method name="GetPrimaryDevice">
|
||||||
<arg type="(susdut)" direction="out" />
|
<arg type="(susdut)" direction="out" />
|
||||||
</method>
|
</method>
|
||||||
<signal name="Changed" />
|
|
||||||
<property name="Icon" type="s" access="read" />
|
<property name="Icon" type="s" access="read" />
|
||||||
</interface>;
|
</interface>;
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ const Indicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('battery-missing', null);
|
this.parent('battery-missing', _("Battery"));
|
||||||
|
|
||||||
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
this._proxy = new PowerManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH);
|
||||||
|
|
||||||
@ -76,7 +75,8 @@ const Indicator = new Lang.Class({
|
|||||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||||
this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
|
this.menu.addSettingsAction(_("Power Settings"), 'gnome-power-panel.desktop');
|
||||||
|
|
||||||
this._proxy.connectSignal('Changed', Lang.bind(this, this._devicesChanged));
|
this._proxy.connect('g-properties-changed',
|
||||||
|
Lang.bind(this, this._devicesChanged));
|
||||||
this._devicesChanged();
|
this._devicesChanged();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ const Indicator = new Lang.Class({
|
|||||||
Extends: PanelMenu.SystemStatusButton,
|
Extends: PanelMenu.SystemStatusButton,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent('audio-volume-muted', null);
|
this.parent('audio-volume-muted', _("Volume"));
|
||||||
|
|
||||||
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
this._control = new Gvc.MixerControl({ name: 'GNOME Shell Volume Control' });
|
||||||
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
this._control.connect('state-changed', Lang.bind(this, this._onControlStateChanged));
|
||||||
@ -35,6 +35,7 @@ const Indicator = new Lang.Class({
|
|||||||
this._output = null;
|
this._output = null;
|
||||||
this._outputVolumeId = 0;
|
this._outputVolumeId = 0;
|
||||||
this._outputMutedId = 0;
|
this._outputMutedId = 0;
|
||||||
|
/* Translators: This is the label for audio volume */
|
||||||
this._outputTitle = new PopupMenu.PopupMenuItem(_("Volume"), { reactive: false });
|
this._outputTitle = new PopupMenu.PopupMenuItem(_("Volume"), { reactive: false });
|
||||||
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
this._outputSlider = new PopupMenu.PopupSliderMenuItem(0);
|
||||||
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
this._outputSlider.connect('value-changed', Lang.bind(this, this._sliderChanged, '_output'));
|
||||||
|
@ -33,15 +33,6 @@ const NotificationDirection = {
|
|||||||
RECEIVED: 'chat-received'
|
RECEIVED: 'chat-received'
|
||||||
};
|
};
|
||||||
|
|
||||||
let contactFeatures = [Tp.ContactFeature.ALIAS,
|
|
||||||
Tp.ContactFeature.AVATAR_DATA,
|
|
||||||
Tp.ContactFeature.PRESENCE];
|
|
||||||
|
|
||||||
// This is GNOME Shell's implementation of the Telepathy 'Client'
|
|
||||||
// interface. Specifically, the shell is a Telepathy 'Observer', which
|
|
||||||
// lets us see messages even if they belong to another app (eg,
|
|
||||||
// Empathy).
|
|
||||||
|
|
||||||
function makeMessageFromTpMessage(tpMessage, direction) {
|
function makeMessageFromTpMessage(tpMessage, direction) {
|
||||||
let [text, flags] = tpMessage.to_text();
|
let [text, flags] = tpMessage.to_text();
|
||||||
|
|
||||||
@ -83,11 +74,21 @@ const Client = new Lang.Class({
|
|||||||
// account path -> AccountNotification
|
// account path -> AccountNotification
|
||||||
this._accountNotifications = {};
|
this._accountNotifications = {};
|
||||||
|
|
||||||
|
// Define features we want
|
||||||
|
this._accountManager = Tp.AccountManager.dup();
|
||||||
|
let factory = this._accountManager.get_factory();
|
||||||
|
factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
|
||||||
|
factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
|
||||||
|
factory.add_channel_features([Tp.Channel.get_feature_quark_contacts()]);
|
||||||
|
factory.add_contact_features([Tp.ContactFeature.ALIAS,
|
||||||
|
Tp.ContactFeature.AVATAR_DATA,
|
||||||
|
Tp.ContactFeature.PRESENCE,
|
||||||
|
Tp.ContactFeature.SUBSCRIPTION_STATES]);
|
||||||
|
|
||||||
// Set up a SimpleObserver, which will call _observeChannels whenever a
|
// Set up a SimpleObserver, which will call _observeChannels whenever a
|
||||||
// channel matching its filters is detected.
|
// channel matching its filters is detected.
|
||||||
// The second argument, recover, means _observeChannels will be run
|
// The second argument, recover, means _observeChannels will be run
|
||||||
// for any existing channel as well.
|
// for any existing channel as well.
|
||||||
this._accountManager = Tp.AccountManager.dup();
|
|
||||||
this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
|
this._tpClient = new Shell.TpClient({ 'account-manager': this._accountManager,
|
||||||
'name': 'GnomeShell',
|
'name': 'GnomeShell',
|
||||||
'uniquify-name': true })
|
'uniquify-name': true })
|
||||||
@ -114,16 +115,9 @@ const Client = new Lang.Class({
|
|||||||
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Watch subscription requests and connection errors
|
// Watch subscription requests and connection errors
|
||||||
this._subscriptionSource = null;
|
this._subscriptionSource = null;
|
||||||
this._accountSource = null;
|
this._accountSource = null;
|
||||||
let factory = this._accountManager.get_factory();
|
|
||||||
factory.add_account_features([Tp.Account.get_feature_quark_connection()]);
|
|
||||||
factory.add_connection_features([Tp.Connection.get_feature_quark_contact_list()]);
|
|
||||||
factory.add_contact_features([Tp.ContactFeature.SUBSCRIPTION_STATES,
|
|
||||||
Tp.ContactFeature.ALIAS,
|
|
||||||
Tp.ContactFeature.AVATAR_DATA]);
|
|
||||||
|
|
||||||
this._accountManager.connect('account-validity-changed',
|
this._accountManager.connect('account-validity-changed',
|
||||||
Lang.bind(this, this._accountValidityChanged));
|
Lang.bind(this, this._accountValidityChanged));
|
||||||
@ -133,22 +127,6 @@ const Client = new Lang.Class({
|
|||||||
|
|
||||||
_observeChannels: function(observer, account, conn, channels,
|
_observeChannels: function(observer, account, conn, channels,
|
||||||
dispatchOp, requests, context) {
|
dispatchOp, requests, context) {
|
||||||
// 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,
|
|
||||||
Lang.bind(this, function() {
|
|
||||||
this._finishObserveChannels(account, conn, channels, context);
|
|
||||||
}));
|
|
||||||
context.delay();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_finishObserveChannels: function(account, conn, channels, context) {
|
|
||||||
let len = channels.length;
|
let len = channels.length;
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let channel = channels[i];
|
let channel = channels[i];
|
||||||
@ -159,16 +137,7 @@ const Client = new Lang.Class({
|
|||||||
targetHandleType != Tp.HandleType.CONTACT)
|
targetHandleType != Tp.HandleType.CONTACT)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Request a TpContact */
|
this._createChatSource(account, conn, channel, channel.get_target_contact());
|
||||||
Shell.get_tp_contacts(conn, [targetHandle],
|
|
||||||
contactFeatures,
|
|
||||||
Lang.bind(this, function (connection, contacts, failed) {
|
|
||||||
if (contacts.length < 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* We got the TpContact */
|
|
||||||
this._createChatSource(account, conn, channel, contacts[0]);
|
|
||||||
}), null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
context.accept();
|
context.accept();
|
||||||
@ -197,11 +166,11 @@ const Client = new Lang.Class({
|
|||||||
|
|
||||||
_handleChannels: function(handler, account, conn, channels,
|
_handleChannels: function(handler, account, conn, channels,
|
||||||
requests, user_action_time, context) {
|
requests, user_action_time, context) {
|
||||||
this._handlingChannels(account, conn, channels);
|
this._handlingChannels(account, conn, channels, true);
|
||||||
context.accept();
|
context.accept();
|
||||||
},
|
},
|
||||||
|
|
||||||
_handlingChannels: function(account, conn, channels) {
|
_handlingChannels: function(account, conn, channels, notify) {
|
||||||
let len = channels.length;
|
let len = channels.length;
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let channel = channels[i];
|
let channel = channels[i];
|
||||||
@ -212,7 +181,18 @@ const Client = new Lang.Class({
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._tpClient.is_handling_channel(channel)) {
|
// 'notify' will be true when coming from an actual HandleChannels
|
||||||
|
// call, and not when from a successful Claim call. The point is
|
||||||
|
// we don't want to notify for a channel we just claimed which
|
||||||
|
// has no new messages (for example, a new channel which only has
|
||||||
|
// a delivery notification). We rely on _displayPendingMessages()
|
||||||
|
// and _messageReceived() to notify for new messages.
|
||||||
|
|
||||||
|
// But we should still notify from HandleChannels because the
|
||||||
|
// Telepathy spec states that handlers must foreground channels
|
||||||
|
// in HandleChannels calls which are already being handled.
|
||||||
|
|
||||||
|
if (notify && this._tpClient.is_handling_channel(channel)) {
|
||||||
// We are already handling the channel, display the source
|
// We are already handling the channel, display the source
|
||||||
let source = this._chatSources[channel.get_object_path()];
|
let source = this._chatSources[channel.get_object_path()];
|
||||||
if (source)
|
if (source)
|
||||||
@ -223,41 +203,25 @@ const Client = new Lang.Class({
|
|||||||
|
|
||||||
_displayRoomInvitation: function(conn, channel, dispatchOp, context) {
|
_displayRoomInvitation: function(conn, channel, dispatchOp, context) {
|
||||||
// We can only approve the rooms if we have been invited to it
|
// We can only approve the rooms if we have been invited to it
|
||||||
let selfHandle = channel.group_get_self_handle();
|
let selfContact = channel.group_get_self_contact();
|
||||||
if (selfHandle == 0) {
|
if (selfContact == null) {
|
||||||
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
|
let [invited, inviter, reason, msg] = channel.group_get_local_pending_contact_info(selfContact);
|
||||||
if (!invited) {
|
if (!invited) {
|
||||||
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request a TpContact for the inviter
|
|
||||||
Shell.get_tp_contacts(conn, [inviter],
|
|
||||||
contactFeatures,
|
|
||||||
Lang.bind(this, this._createRoomInviteSource, channel, context, dispatchOp));
|
|
||||||
|
|
||||||
context.delay();
|
|
||||||
},
|
|
||||||
|
|
||||||
_createRoomInviteSource: function(connection, contacts, failed, channel, context, dispatchOp) {
|
|
||||||
if (contacts.length < 1) {
|
|
||||||
Shell.decline_dispatch_op(context, 'Failed to get inviter');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We got the TpContact
|
|
||||||
|
|
||||||
// FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
// FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
||||||
// system-users for now as Empathy does.
|
// system-users for now as Empathy does.
|
||||||
let source = new ApproverSource(dispatchOp, _("Invitation"),
|
let source = new ApproverSource(dispatchOp, _("Invitation"),
|
||||||
Gio.icon_new_for_string('system-users'));
|
Gio.icon_new_for_string('system-users'));
|
||||||
Main.messageTray.add(source);
|
Main.messageTray.add(source);
|
||||||
|
|
||||||
let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
|
let notif = new RoomInviteNotification(source, dispatchOp, channel, inviter);
|
||||||
source.notify(notif);
|
source.notify(notif);
|
||||||
context.accept();
|
context.accept();
|
||||||
},
|
},
|
||||||
@ -269,8 +233,7 @@ const Client = new Lang.Class({
|
|||||||
|
|
||||||
if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
|
if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
|
||||||
this._approveTextChannel(account, conn, channel, dispatchOp, context);
|
this._approveTextChannel(account, conn, channel, dispatchOp, context);
|
||||||
else if (chanType == Tp.IFACE_CHANNEL_TYPE_STREAMED_MEDIA ||
|
else if (chanType == Tp.IFACE_CHANNEL_TYPE_CALL)
|
||||||
chanType == 'org.freedesktop.Telepathy.Channel.Type.Call.DRAFT')
|
|
||||||
this._approveCall(account, conn, channel, dispatchOp, context);
|
this._approveCall(account, conn, channel, dispatchOp, context);
|
||||||
else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
|
else if (chanType == Tp.IFACE_CHANNEL_TYPE_FILE_TRANSFER)
|
||||||
this._approveFileTransfer(account, conn, channel, dispatchOp, context);
|
this._approveFileTransfer(account, conn, channel, dispatchOp, context);
|
||||||
@ -285,7 +248,7 @@ const Client = new Lang.Class({
|
|||||||
Lang.bind(this, function(dispatchOp, result) {
|
Lang.bind(this, function(dispatchOp, result) {
|
||||||
try {
|
try {
|
||||||
dispatchOp.claim_with_finish(result);
|
dispatchOp.claim_with_finish(result);
|
||||||
this._handlingChannels(account, conn, [channel]);
|
this._handlingChannels(account, conn, [channel], false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error('Failed to Claim channel: ' + err);
|
throw new Error('Failed to Claim channel: ' + err);
|
||||||
}}));
|
}}));
|
||||||
@ -297,27 +260,11 @@ const Client = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_approveCall: function(account, conn, channel, dispatchOp, context) {
|
_approveCall: function(account, conn, channel, dispatchOp, context) {
|
||||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
|
||||||
|
|
||||||
Shell.get_tp_contacts(conn, [targetHandle],
|
|
||||||
contactFeatures,
|
|
||||||
Lang.bind(this, this._createAudioVideoSource, channel, context, dispatchOp));
|
|
||||||
|
|
||||||
context.delay();
|
|
||||||
},
|
|
||||||
|
|
||||||
_createAudioVideoSource: function(connection, contacts, failed, channel, context, dispatchOp) {
|
|
||||||
if (contacts.length < 1) {
|
|
||||||
Shell.decline_dispatch_op(context, 'Failed to get inviter');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isVideo = false;
|
let isVideo = false;
|
||||||
|
|
||||||
let props = channel.borrow_immutable_properties();
|
let props = channel.borrow_immutable_properties();
|
||||||
|
|
||||||
if (props['org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo'] ||
|
if (props[Tp.PROP_CHANNEL_TYPE_CALL_INITIAL_VIDEO])
|
||||||
props[Tp.PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO])
|
|
||||||
isVideo = true;
|
isVideo = true;
|
||||||
|
|
||||||
// We got the TpContact
|
// We got the TpContact
|
||||||
@ -326,27 +273,13 @@ const Client = new Lang.Class({
|
|||||||
Gio.icon_new_for_string('audio-input-microphone'));
|
Gio.icon_new_for_string('audio-input-microphone'));
|
||||||
Main.messageTray.add(source);
|
Main.messageTray.add(source);
|
||||||
|
|
||||||
let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo);
|
let notif = new AudioVideoNotification(source, dispatchOp, channel,
|
||||||
|
channel.get_target_contact(), isVideo);
|
||||||
source.notify(notif);
|
source.notify(notif);
|
||||||
context.accept();
|
context.accept();
|
||||||
},
|
},
|
||||||
|
|
||||||
_approveFileTransfer: function(account, conn, channel, dispatchOp, context) {
|
_approveFileTransfer: function(account, conn, channel, dispatchOp, context) {
|
||||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
|
||||||
|
|
||||||
Shell.get_tp_contacts(conn, [targetHandle],
|
|
||||||
contactFeatures,
|
|
||||||
Lang.bind(this, this._createFileTransferSource, channel, context, dispatchOp));
|
|
||||||
|
|
||||||
context.delay();
|
|
||||||
},
|
|
||||||
|
|
||||||
_createFileTransferSource: function(connection, contacts, failed, channel, context, dispatchOp) {
|
|
||||||
if (contacts.length < 1) {
|
|
||||||
Shell.decline_dispatch_op(context, 'Failed to get file sender');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use the icon of the file being transferred
|
// Use the icon of the file being transferred
|
||||||
let gicon = Gio.content_type_get_icon(channel.get_mime_type());
|
let gicon = Gio.content_type_get_icon(channel.get_mime_type());
|
||||||
|
|
||||||
@ -354,7 +287,8 @@ const Client = new Lang.Class({
|
|||||||
let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon);
|
let source = new ApproverSource(dispatchOp, _("File Transfer"), gicon);
|
||||||
Main.messageTray.add(source);
|
Main.messageTray.add(source);
|
||||||
|
|
||||||
let notif = new FileTransferNotification(source, dispatchOp, channel, contacts[0]);
|
let notif = new FileTransferNotification(source, dispatchOp, channel,
|
||||||
|
channel.get_target_contact());
|
||||||
source.notify(notif);
|
source.notify(notif);
|
||||||
context.accept();
|
context.accept();
|
||||||
},
|
},
|
||||||
@ -502,15 +436,9 @@ const ChatSource = new Lang.Class({
|
|||||||
this._notification.setUrgency(MessageTray.Urgency.HIGH);
|
this._notification.setUrgency(MessageTray.Urgency.HIGH);
|
||||||
this._notifyTimeoutId = 0;
|
this._notifyTimeoutId = 0;
|
||||||
|
|
||||||
// We ack messages when the message box is collapsed if user has
|
// We ack messages when the user expands the new notification or views the summary
|
||||||
// interacted with it before and so read the messages:
|
// notification, in which case the notification is also expanded.
|
||||||
// - user clicked on it the tray
|
this._notification.connect('expanded', Lang.bind(this, this._ackMessages));
|
||||||
// - user expanded the notification by hovering over the toaster notification
|
|
||||||
this._shouldAck = false;
|
|
||||||
|
|
||||||
this.connect('summary-item-clicked', Lang.bind(this, this._summaryItemClicked));
|
|
||||||
this._notification.connect('expanded', Lang.bind(this, this._notificationExpanded));
|
|
||||||
this._notification.connect('collapsed', Lang.bind(this, this._notificationCollapsed));
|
|
||||||
|
|
||||||
this._presence = contact.get_presence_type();
|
this._presence = contact.get_presence_type();
|
||||||
|
|
||||||
@ -734,12 +662,12 @@ const ChatSource = new Lang.Class({
|
|||||||
if (presence == Tp.ConnectionPresenceType.AVAILABLE) {
|
if (presence == Tp.ConnectionPresenceType.AVAILABLE) {
|
||||||
msg = _("%s is online.").format(title);
|
msg = _("%s is online.").format(title);
|
||||||
shouldNotify = (this._presence == Tp.ConnectionPresenceType.OFFLINE);
|
shouldNotify = (this._presence == Tp.ConnectionPresenceType.OFFLINE);
|
||||||
} else if (presence == Tp.ConnectionPresenceType.OFFLINE ||
|
} else if (presence == Tp.ConnectionPresenceType.OFFLINE) {
|
||||||
presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
|
|
||||||
presence = Tp.ConnectionPresenceType.OFFLINE;
|
presence = Tp.ConnectionPresenceType.OFFLINE;
|
||||||
msg = _("%s is offline.").format(title);
|
msg = _("%s is offline.").format(title);
|
||||||
shouldNotify = (this._presence != Tp.ConnectionPresenceType.OFFLINE);
|
shouldNotify = (this._presence != Tp.ConnectionPresenceType.OFFLINE);
|
||||||
} else if (presence == Tp.ConnectionPresenceType.AWAY) {
|
} else if (presence == Tp.ConnectionPresenceType.AWAY ||
|
||||||
|
presence == Tp.ConnectionPresenceType.EXTENDED_AWAY) {
|
||||||
msg = _("%s is away.").format(title);
|
msg = _("%s is away.").format(title);
|
||||||
shouldNotify = false;
|
shouldNotify = false;
|
||||||
} else if (presence == Tp.ConnectionPresenceType.BUSY) {
|
} else if (presence == Tp.ConnectionPresenceType.BUSY) {
|
||||||
@ -774,24 +702,6 @@ const ChatSource = new Lang.Class({
|
|||||||
// 'pending-message-removed' for each one.
|
// 'pending-message-removed' for each one.
|
||||||
this._channel.ack_all_pending_messages_async(Lang.bind(this, function(src, result) {
|
this._channel.ack_all_pending_messages_async(Lang.bind(this, function(src, result) {
|
||||||
this._channel.ack_all_pending_messages_finish(result);}));
|
this._channel.ack_all_pending_messages_finish(result);}));
|
||||||
},
|
|
||||||
|
|
||||||
_summaryItemClicked: function(source, button) {
|
|
||||||
if (button != 1)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._shouldAck = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_notificationExpanded: function() {
|
|
||||||
this._shouldAck = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
_notificationCollapsed: function() {
|
|
||||||
if (this._shouldAck)
|
|
||||||
this._ackMessages();
|
|
||||||
|
|
||||||
this._shouldAck = false;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -943,6 +853,8 @@ const ChatNotification = new Lang.Class({
|
|||||||
|
|
||||||
this._lastGroupActor.add(body, props.childProps);
|
this._lastGroupActor.add(body, props.childProps);
|
||||||
|
|
||||||
|
this.updated();
|
||||||
|
|
||||||
let timestamp = props.timestamp;
|
let timestamp = props.timestamp;
|
||||||
this._history.unshift({ actor: body, time: timestamp,
|
this._history.unshift({ actor: body, time: timestamp,
|
||||||
realMessage: group != 'meta' });
|
realMessage: group != 'meta' });
|
||||||
@ -1175,7 +1087,7 @@ const AudioVideoNotification = new Lang.Class({
|
|||||||
/* translators: argument is a contact name like Alice for example. */
|
/* translators: argument is a contact name like Alice for example. */
|
||||||
title = _("Call from %s").format(contact.get_alias());
|
title = _("Call from %s").format(contact.get_alias());
|
||||||
|
|
||||||
this.parent(this, source, title, null, { customContent: true });
|
this.parent(source, title, null, { customContent: true });
|
||||||
this.setResident(true);
|
this.setResident(true);
|
||||||
|
|
||||||
this.addButton('reject', _("Reject"));
|
this.addButton('reject', _("Reject"));
|
||||||
@ -1206,8 +1118,7 @@ const FileTransferNotification = new Lang.Class({
|
|||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(source, dispatchOp, channel, contact) {
|
_init: function(source, dispatchOp, channel, contact) {
|
||||||
this.parent(this,
|
this.parent(source,
|
||||||
source,
|
|
||||||
/* To translators: The first parameter is
|
/* To translators: The first parameter is
|
||||||
* the contact's alias and the second one is the
|
* the contact's alias and the second one is the
|
||||||
* file name. The string will be something
|
* file name. The string will be something
|
||||||
@ -1280,7 +1191,7 @@ const SubscriptionRequestNotification = new Lang.Class({
|
|||||||
Extends: MessageTray.Notification,
|
Extends: MessageTray.Notification,
|
||||||
|
|
||||||
_init: function(source, contact) {
|
_init: function(source, contact) {
|
||||||
this.parent(this, source,
|
this.parent(source,
|
||||||
/* To translators: The parameter is the contact's alias */
|
/* To translators: The parameter is the contact's alias */
|
||||||
_("%s would like permission to see when you are online").format(contact.get_alias()),
|
_("%s would like permission to see when you are online").format(contact.get_alias()),
|
||||||
null, { customContent: true });
|
null, { customContent: true });
|
||||||
@ -1407,7 +1318,7 @@ _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_FAILED)]
|
|||||||
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST)]
|
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_LOST)]
|
||||||
= _("Connection has been lost");
|
= _("Connection has been lost");
|
||||||
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ALREADY_CONNECTED)]
|
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.ALREADY_CONNECTED)]
|
||||||
= _("This resource is already connected to the server");
|
= _("This account is already connected to the server");
|
||||||
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED)]
|
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CONNECTION_REPLACED)]
|
||||||
= _("Connection has been replaced by a new connection using the same resource");
|
= _("Connection has been replaced by a new connection using the same resource");
|
||||||
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.REGISTRATION_EXISTS)]
|
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.REGISTRATION_EXISTS)]
|
||||||
@ -1420,6 +1331,8 @@ _connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_INSECURE)]
|
|||||||
= _("Certificate uses an insecure cipher algorithm or is cryptographically weak");
|
= _("Certificate uses an insecure cipher algorithm or is cryptographically weak");
|
||||||
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)]
|
_connectionErrorMessages[Tp.error_get_dbus_name(Tp.Error.CERT_LIMIT_EXCEEDED)]
|
||||||
= _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library");
|
= _("The length of the server certificate, or the depth of the server certificate chain, exceed the limits imposed by the cryptography library");
|
||||||
|
_connectionErrorMessages['org.freedesktop.DBus.Error.NoReply']
|
||||||
|
= _("Internal error");
|
||||||
|
|
||||||
const AccountNotification = new Lang.Class({
|
const AccountNotification = new Lang.Class({
|
||||||
Name: 'AccountNotification',
|
Name: 'AccountNotification',
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
@ -209,9 +210,14 @@ const ClutterFrameTicker = new Lang.Class({
|
|||||||
|
|
||||||
_init : function() {
|
_init : function() {
|
||||||
// We don't have a finite duration; tweener will tell us to stop
|
// We don't have a finite duration; tweener will tell us to stop
|
||||||
// when we need to stop, so use 1000 seconds as "infinity"
|
// when we need to stop, so use 1000 seconds as "infinity", and
|
||||||
|
// set the timeline to loop. Doing this means we have to track
|
||||||
|
// time ourselves, since clutter timeline's time will cycle
|
||||||
|
// instead of strictly increase.
|
||||||
this._timeline = new Clutter.Timeline({ duration: 1000*1000 });
|
this._timeline = new Clutter.Timeline({ duration: 1000*1000 });
|
||||||
|
this._timeline.set_loop(true);
|
||||||
this._startTime = -1;
|
this._startTime = -1;
|
||||||
|
this._currentTime = -1;
|
||||||
|
|
||||||
this._timeline.connect('new-frame', Lang.bind(this,
|
this._timeline.connect('new-frame', Lang.bind(this,
|
||||||
function(timeline, frame) {
|
function(timeline, frame) {
|
||||||
@ -234,17 +240,18 @@ const ClutterFrameTicker = new Lang.Class({
|
|||||||
// That looks bad, so we always start at the first frame of the
|
// That looks bad, so we always start at the first frame of the
|
||||||
// animation then only do frame dropping from there.
|
// animation then only do frame dropping from there.
|
||||||
if (this._startTime < 0)
|
if (this._startTime < 0)
|
||||||
this._startTime = this._timeline.get_elapsed_time();
|
this._startTime = GLib.get_monotonic_time() / 1000.0;
|
||||||
|
|
||||||
// currentTime is in milliseconds
|
// currentTime is in milliseconds
|
||||||
let perf_log = Shell.PerfLog.get_default();
|
let perf_log = Shell.PerfLog.get_default();
|
||||||
|
this._currentTime = GLib.get_monotonic_time() / 1000.0 - this._startTime;
|
||||||
perf_log.event("tweener.framePrepareStart");
|
perf_log.event("tweener.framePrepareStart");
|
||||||
this.emit('prepare-frame');
|
this.emit('prepare-frame');
|
||||||
perf_log.event("tweener.framePrepareDone");
|
perf_log.event("tweener.framePrepareDone");
|
||||||
},
|
},
|
||||||
|
|
||||||
getTime : function() {
|
getTime : function() {
|
||||||
return this._timeline.get_elapsed_time();
|
return this._currentTime;
|
||||||
},
|
},
|
||||||
|
|
||||||
start : function() {
|
start : function() {
|
||||||
@ -257,6 +264,7 @@ const ClutterFrameTicker = new Lang.Class({
|
|||||||
stop : function() {
|
stop : function() {
|
||||||
this._timeline.stop();
|
this._timeline.stop();
|
||||||
this._startTime = -1;
|
this._startTime = -1;
|
||||||
|
this._currentTime = -1;
|
||||||
global.end_work();
|
global.end_work();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -9,6 +9,7 @@ const Shell = imports.gi.Shell;
|
|||||||
const St = imports.gi.St;
|
const St = imports.gi.St;
|
||||||
const Tp = imports.gi.TelepathyGLib;
|
const Tp = imports.gi.TelepathyGLib;
|
||||||
const UPowerGlib = imports.gi.UPowerGlib;
|
const UPowerGlib = imports.gi.UPowerGlib;
|
||||||
|
const Atk = imports.gi.Atk;
|
||||||
|
|
||||||
const GnomeSession = imports.misc.gnomeSession;
|
const GnomeSession = imports.misc.gnomeSession;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -56,6 +57,7 @@ const IMStatusItem = new Lang.Class({
|
|||||||
this._icon.icon_name = iconName;
|
this._icon.icon_name = iconName;
|
||||||
|
|
||||||
this.label = new St.Label({ text: label });
|
this.label = new St.Label({ text: label });
|
||||||
|
this.actor.label_actor = this.label;
|
||||||
this.addActor(this.label);
|
this.addActor(this.label);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -163,6 +165,8 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
Lang.bind(this, this._IMAccountsChanged));
|
Lang.bind(this, this._IMAccountsChanged));
|
||||||
this._accountMgr.connect('account-removed',
|
this._accountMgr.connect('account-removed',
|
||||||
Lang.bind(this, this._IMAccountsChanged));
|
Lang.bind(this, this._IMAccountsChanged));
|
||||||
|
this._accountMgr.connect('account-validity-changed',
|
||||||
|
Lang.bind(this, this._IMAccountsChanged));
|
||||||
this._accountMgr.prepare_async(null, Lang.bind(this,
|
this._accountMgr.prepare_async(null, Lang.bind(this,
|
||||||
function(mgr) {
|
function(mgr) {
|
||||||
let [presence, status, msg] = mgr.get_most_available_presence();
|
let [presence, status, msg] = mgr.get_most_available_presence();
|
||||||
@ -239,7 +243,8 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_setIconFromFile: function(iconFile) {
|
_setIconFromFile: function(iconFile) {
|
||||||
this._iconBin.set_style('background-image: url("' + iconFile + '");');
|
this._iconBin.set_style('background-image: url("' + iconFile + '");' +
|
||||||
|
'background-size: contain;');
|
||||||
this._iconBin.child = null;
|
this._iconBin.child = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -375,7 +380,8 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
if (sessionStatus == GnomeSession.PresenceStatus.IDLE) {
|
if (sessionStatus == GnomeSession.PresenceStatus.IDLE) {
|
||||||
// Only change presence if the current one is "more present" than
|
// Only change presence if the current one is "more present" than
|
||||||
// idle
|
// idle
|
||||||
if (this._currentPresence != Tp.ConnectionPresenceType.OFFLINE)
|
if (this._currentPresence != Tp.ConnectionPresenceType.OFFLINE &&
|
||||||
|
this._currentPresence != Tp.ConnectionPresenceType.HIDDEN)
|
||||||
return Tp.ConnectionPresenceType.EXTENDED_AWAY;
|
return Tp.ConnectionPresenceType.EXTENDED_AWAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,8 +392,15 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
if (!this._imPresenceRestored)
|
if (!this._imPresenceRestored)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
let savedStatus = global.settings.get_int('saved-session-presence');
|
||||||
if (!this._sessionPresenceRestored) {
|
if (!this._sessionPresenceRestored) {
|
||||||
let savedStatus = global.settings.get_int('saved-session-presence');
|
|
||||||
|
// We should never save/restore a status other than AVAILABLE
|
||||||
|
// or BUSY
|
||||||
|
if (savedStatus != GnomeSession.PresenceStatus.AVAILABLE &&
|
||||||
|
savedStatus != GnomeSession.PresenceStatus.BUSY)
|
||||||
|
savedStatus = GnomeSession.PresenceStatus.AVAILABLE;
|
||||||
|
|
||||||
if (sessionStatus != savedStatus) {
|
if (sessionStatus != savedStatus) {
|
||||||
this._presence.status = savedStatus;
|
this._presence.status = savedStatus;
|
||||||
return;
|
return;
|
||||||
@ -395,7 +408,10 @@ const IMStatusChooserItem = new Lang.Class({
|
|||||||
this._sessionPresenceRestored = true;
|
this._sessionPresenceRestored = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
global.settings.set_int('saved-session-presence', sessionStatus);
|
if ((sessionStatus == GnomeSession.PresenceStatus.AVAILABLE ||
|
||||||
|
sessionStatus == GnomeSession.PresenceStatus.BUSY) &&
|
||||||
|
savedStatus != sessionStatus)
|
||||||
|
global.settings.set_int('saved-session-presence', sessionStatus);
|
||||||
|
|
||||||
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
|
let [presence, s, msg] = this._accountMgr.get_most_available_presence();
|
||||||
let newPresence, status;
|
let newPresence, status;
|
||||||
@ -421,6 +437,8 @@ const UserMenuButton = new Lang.Class({
|
|||||||
_init: function() {
|
_init: function() {
|
||||||
this.parent(0.0);
|
this.parent(0.0);
|
||||||
|
|
||||||
|
this.actor.accessible_role = Atk.Role.MENU;
|
||||||
|
|
||||||
let box = new St.BoxLayout({ name: 'panelUserMenu' });
|
let box = new St.BoxLayout({ name: 'panelUserMenu' });
|
||||||
this.actor.add_actor(box);
|
this.actor.add_actor(box);
|
||||||
|
|
||||||
@ -465,6 +483,7 @@ const UserMenuButton = new Lang.Class({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
this._name = new St.Label();
|
this._name = new St.Label();
|
||||||
|
this.actor.label_actor = this._name;
|
||||||
box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
|
box.add(this._name, { y_align: St.Align.MIDDLE, y_fill: false });
|
||||||
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName));
|
this._userLoadedId = this._user.connect('notify::is-loaded', Lang.bind(this, this._updateUserName));
|
||||||
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName));
|
this._userChangedId = this._user.connect('changed', Lang.bind(this, this._updateUserName));
|
||||||
@ -610,7 +629,7 @@ const UserMenuButton = new Lang.Class({
|
|||||||
this._statusChooser = item;
|
this._statusChooser = item;
|
||||||
|
|
||||||
item = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
|
item = new PopupMenu.PopupSwitchMenuItem(_("Notifications"));
|
||||||
item.connect('activate', Lang.bind(this, this._updatePresenceStatus));
|
item.connect('toggled', Lang.bind(this, this._updatePresenceStatus));
|
||||||
this.menu.addMenuItem(item);
|
this.menu.addMenuItem(item);
|
||||||
this._notificationsSwitch = item;
|
this._notificationsSwitch = item;
|
||||||
|
|
||||||
@ -715,8 +734,8 @@ const UserMenuButton = new Lang.Class({
|
|||||||
|
|
||||||
if (this._haveSuspend &&
|
if (this._haveSuspend &&
|
||||||
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
||||||
// Ensure we only suspend after the screensaver has activated
|
// Ensure we only suspend after locking the screen
|
||||||
this._screenSaverProxy.SetActiveRemote(true, Lang.bind(this, function() {
|
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
|
||||||
this._upClient.suspend_sync(null);
|
this._upClient.suspend_sync(null);
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
|
@ -133,14 +133,14 @@ const SearchTab = new Lang.Class({
|
|||||||
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
|
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
|
||||||
this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
|
this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
|
||||||
// We can't connect to 'activate' here because search providers
|
// We can't connect to 'activate' here because search providers
|
||||||
// might want to do something with the modifiers in activateSelected.
|
// might want to do something with the modifiers in activateDefault.
|
||||||
let symbol = e.get_key_symbol();
|
let symbol = e.get_key_symbol();
|
||||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||||
if (this._searchTimeoutId > 0) {
|
if (this._searchTimeoutId > 0) {
|
||||||
Mainloop.source_remove(this._searchTimeoutId);
|
Mainloop.source_remove(this._searchTimeoutId);
|
||||||
this._doSearch();
|
this._doSearch();
|
||||||
}
|
}
|
||||||
this._searchResults.activateSelected();
|
this._searchResults.activateDefault();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -148,9 +148,33 @@ const SearchTab = new Lang.Class({
|
|||||||
|
|
||||||
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||||
|
|
||||||
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
|
global.stage.connect('notify::key-focus', Lang.bind(this, this._onStageKeyFocusChanged));
|
||||||
|
|
||||||
this._capturedEventId = 0;
|
this._capturedEventId = 0;
|
||||||
|
|
||||||
|
this._text.connect('key-focus-in', Lang.bind(this, function() {
|
||||||
|
this._searchResults.highlightDefault(true);
|
||||||
|
}));
|
||||||
|
this._text.connect('key-focus-out', Lang.bind(this, function() {
|
||||||
|
this._searchResults.highlightDefault(false);
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Since the entry isn't inside the results container we install this
|
||||||
|
// dummy widget as the last results container child so that we can
|
||||||
|
// include the entry in the keynav tab path...
|
||||||
|
this._focusTrap = new St.Bin({ can_focus: true });
|
||||||
|
this._focusTrap.connect('key-focus-in', Lang.bind(this, function() {
|
||||||
|
this._entry.grab_key_focus();
|
||||||
|
}));
|
||||||
|
// ... but make it unfocusable using arrow keys keynav by making its
|
||||||
|
// bounding box always contain the possible focus source's bounding
|
||||||
|
// box since StWidget's keynav logic won't ever select it as a target
|
||||||
|
// in that case.
|
||||||
|
this._focusTrap.add_constraint(new Clutter.BindConstraint({ source: this._searchResults.actor,
|
||||||
|
coordinate: Clutter.BindCoordinate.ALL }));
|
||||||
|
this._searchResults.actor.add_actor(this._focusTrap);
|
||||||
|
|
||||||
|
global.focus_manager.add_group(this._searchResults.actor);
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
@ -163,21 +187,29 @@ const SearchTab = new Lang.Class({
|
|||||||
// incorrectly when we remove focus
|
// incorrectly when we remove focus
|
||||||
// (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
|
// (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
|
||||||
if (this._text.text != '')
|
if (this._text.text != '')
|
||||||
this._reset();
|
this.reset();
|
||||||
},
|
},
|
||||||
|
|
||||||
_reset: function () {
|
reset: function () {
|
||||||
this._text.text = '';
|
|
||||||
|
|
||||||
global.stage.set_key_focus(null);
|
global.stage.set_key_focus(null);
|
||||||
|
|
||||||
|
this._entry.text = '';
|
||||||
|
|
||||||
this._text.set_cursor_visible(true);
|
this._text.set_cursor_visible(true);
|
||||||
this._text.set_selection(0, 0);
|
this._text.set_selection(0, 0);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateCursorVisibility: function() {
|
_onStageKeyFocusChanged: function() {
|
||||||
let focus = global.stage.get_key_focus();
|
let focus = global.stage.get_key_focus();
|
||||||
this._text.set_cursor_visible(focus == this._text);
|
let appearFocused = (this._entry.contains(focus) ||
|
||||||
|
this._searchResults.actor.contains(focus));
|
||||||
|
|
||||||
|
this._text.set_cursor_visible(appearFocused);
|
||||||
|
|
||||||
|
if (appearFocused)
|
||||||
|
this._entry.add_style_pseudo_class('focus');
|
||||||
|
else
|
||||||
|
this._entry.remove_style_pseudo_class('focus');
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMapped: function() {
|
_onMapped: function() {
|
||||||
@ -228,7 +260,7 @@ const SearchTab = new Lang.Class({
|
|||||||
if (this._iconClickedId == 0) {
|
if (this._iconClickedId == 0) {
|
||||||
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
|
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
|
||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
this._reset();
|
this.reset();
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
this._activate();
|
this._activate();
|
||||||
@ -254,25 +286,37 @@ const SearchTab = new Lang.Class({
|
|||||||
|
|
||||||
_onKeyPress: function(entry, event) {
|
_onKeyPress: function(entry, event) {
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
if (symbol == Clutter.Up) {
|
if (symbol == Clutter.Escape) {
|
||||||
if (!this.active)
|
|
||||||
return true;
|
|
||||||
this._searchResults.selectUp(false);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else if (symbol == Clutter.Down) {
|
|
||||||
if (!this.active)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
this._searchResults.selectDown(false);
|
|
||||||
return true;
|
|
||||||
} else if (symbol == Clutter.Escape) {
|
|
||||||
if (this._isActivated()) {
|
if (this._isActivated()) {
|
||||||
this._reset();
|
this.reset();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (this.active) {
|
||||||
|
let arrowNext, nextDirection;
|
||||||
|
if (entry.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
|
arrowNext = Clutter.Left;
|
||||||
|
nextDirection = Gtk.DirectionType.LEFT;
|
||||||
|
} else {
|
||||||
|
arrowNext = Clutter.Right;
|
||||||
|
nextDirection = Gtk.DirectionType.RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbol == Clutter.Tab) {
|
||||||
|
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_FORWARD);
|
||||||
|
return true;
|
||||||
|
} else if (symbol == Clutter.ISO_Left_Tab) {
|
||||||
|
this._focusTrap.can_focus = false;
|
||||||
|
this._searchResults.navigateFocus(Gtk.DirectionType.TAB_BACKWARD);
|
||||||
|
this._focusTrap.can_focus = true;
|
||||||
|
return true;
|
||||||
|
} else if (symbol == Clutter.Down) {
|
||||||
|
this._searchResults.navigateFocus(Gtk.DirectionType.DOWN);
|
||||||
|
return true;
|
||||||
|
} else if (symbol == arrowNext && this._text.position == -1) {
|
||||||
|
this._searchResults.navigateFocus(nextDirection);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -284,7 +328,7 @@ const SearchTab = new Lang.Class({
|
|||||||
// the user clicked outside after activating the entry, but
|
// the user clicked outside after activating the entry, but
|
||||||
// with no search term entered and no keyboard button pressed
|
// with no search term entered and no keyboard button pressed
|
||||||
// - cancel the search
|
// - cancel the search
|
||||||
this._reset();
|
this.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,29 +463,6 @@ const ViewSelector = new Lang.Class({
|
|||||||
// not when setting the initially selected one.
|
// not when setting the initially selected one.
|
||||||
if (!tab.visible)
|
if (!tab.visible)
|
||||||
tab.show(!firstSwitch);
|
tab.show(!firstSwitch);
|
||||||
|
|
||||||
// Pull a Meg Ryan:
|
|
||||||
if (!firstSwitch && Main.overview.workspaces) {
|
|
||||||
if (tab != this._tabs[0]) {
|
|
||||||
Tweener.addTween(Main.overview.workspaces.actor,
|
|
||||||
{ opacity: 0,
|
|
||||||
time: 0.1,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: Lang.bind(this,
|
|
||||||
function() {
|
|
||||||
Main.overview.workspaces.actor.hide();
|
|
||||||
Main.overview.workspaces.actor.opacity = 255;
|
|
||||||
})
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
Main.overview.workspaces.actor.opacity = 0;
|
|
||||||
Main.overview.workspaces.actor.show();
|
|
||||||
Tweener.addTween(Main.overview.workspaces.actor,
|
|
||||||
{ opacity: 255,
|
|
||||||
time: 0.1,
|
|
||||||
transition: 'easeOutQuad' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
switchTab: function(id) {
|
switchTab: function(id) {
|
||||||
@ -509,7 +530,7 @@ const ViewSelector = new Lang.Class({
|
|||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.y2 = allocHeight;
|
childBox.y2 = allocHeight;
|
||||||
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
childBox.x1 = allocWidth - barNatWidth;
|
childBox.x1 = allocWidth - barNatWidth;
|
||||||
childBox.x2 = allocWidth;
|
childBox.x2 = allocWidth;
|
||||||
} else {
|
} else {
|
||||||
@ -518,7 +539,7 @@ const ViewSelector = new Lang.Class({
|
|||||||
}
|
}
|
||||||
this._tabBox.allocate(childBox, flags);
|
this._tabBox.allocate(childBox, flags);
|
||||||
|
|
||||||
if (this.actor.get_direction() == St.TextDirection.RTL) {
|
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL) {
|
||||||
childBox.x1 = 0;
|
childBox.x1 = 0;
|
||||||
childBox.x2 = searchNatWidth;
|
childBox.x2 = searchNatWidth;
|
||||||
} else {
|
} else {
|
||||||
@ -534,24 +555,34 @@ const ViewSelector = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onStageKeyPress: function(actor, event) {
|
_onStageKeyPress: function(actor, event) {
|
||||||
let modifiers = Shell.get_event_state(event);
|
let modifiers = event.get_state();
|
||||||
let symbol = event.get_key_symbol();
|
let symbol = event.get_key_symbol();
|
||||||
|
|
||||||
if (symbol == Clutter.Escape) {
|
if (symbol == Clutter.Escape) {
|
||||||
Main.overview.hide();
|
if (this._searchTab.active)
|
||||||
|
this._searchTab.reset();
|
||||||
|
else
|
||||||
|
Main.overview.hide();
|
||||||
return true;
|
return true;
|
||||||
} else if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
|
} else if (Clutter.keysym_to_unicode(symbol) ||
|
||||||
if (symbol == Clutter.Page_Up) {
|
(symbol == Clutter.BackSpace && this._searchTab.active)) {
|
||||||
if (!this._searchTab.active)
|
this._searchTab.startSearch(event);
|
||||||
|
} else if (!this._searchTab.active) {
|
||||||
|
if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
|
||||||
|
if (symbol == Clutter.Page_Up) {
|
||||||
this._prevTab();
|
this._prevTab();
|
||||||
return true;
|
return true;
|
||||||
} else if (symbol == Clutter.Page_Down) {
|
} else if (symbol == Clutter.Page_Down) {
|
||||||
if (!this._searchTab.active)
|
|
||||||
this._nextTab();
|
this._nextTab();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (symbol == Clutter.Tab) {
|
||||||
|
this._activeTab.page.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||||
|
return true;
|
||||||
|
} else if (symbol == Clutter.ISO_Left_Tab) {
|
||||||
|
this._activeTab.page.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if (Clutter.keysym_to_unicode(symbol)) {
|
|
||||||
this._searchTab.startSearch(event);
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
211
js/ui/wanda.js
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
|
||||||
|
const IconGrid = imports.ui.iconGrid;
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const Search = imports.ui.search;
|
||||||
|
|
||||||
|
// we could make these gsettings
|
||||||
|
const FISH_NAME = 'wanda';
|
||||||
|
const FISH_SPEED = 300;
|
||||||
|
const FISH_COMMAND = 'fortune';
|
||||||
|
|
||||||
|
const GNOME_PANEL_PIXMAPDIR = '../gnome-panel/fish';
|
||||||
|
const FISH_GROUP = 'Fish Animation';
|
||||||
|
|
||||||
|
const MAGIC_FISH_KEY = 'free the fish';
|
||||||
|
|
||||||
|
const WandaIcon = new Lang.Class({
|
||||||
|
Name: 'WandaIcon',
|
||||||
|
Extends: IconGrid.BaseIcon,
|
||||||
|
|
||||||
|
_init : function(fish, label, params) {
|
||||||
|
this._fish = fish;
|
||||||
|
let file = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR, fish + '.fish']);
|
||||||
|
|
||||||
|
if (GLib.file_test(file, GLib.FileTest.EXISTS)) {
|
||||||
|
this._keyfile = new GLib.KeyFile();
|
||||||
|
this._keyfile.load_from_file(file, GLib.KeyFileFlags.NONE);
|
||||||
|
|
||||||
|
this._imageFile = GLib.build_filenamev([global.datadir, GNOME_PANEL_PIXMAPDIR,
|
||||||
|
this._keyfile.get_string(FISH_GROUP, 'image')]);
|
||||||
|
|
||||||
|
let tmpPixbuf = GdkPixbuf.Pixbuf.new_from_file(this._imageFile);
|
||||||
|
|
||||||
|
this._imgHeight = tmpPixbuf.height;
|
||||||
|
this._imgWidth = tmpPixbuf.width / this._keyfile.get_integer(FISH_GROUP, 'frames');
|
||||||
|
} else {
|
||||||
|
this._imageFile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.parent(label, params);
|
||||||
|
},
|
||||||
|
|
||||||
|
createIcon: function(iconSize) {
|
||||||
|
if (this._animations)
|
||||||
|
this._animations.destroy();
|
||||||
|
|
||||||
|
if (!this._imageFile) {
|
||||||
|
return new St.Icon({ icon_name: 'face-smile',
|
||||||
|
icon_type: St.IconType.FULLCOLOR,
|
||||||
|
icon_size: iconSize
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this._animations = St.TextureCache.get_default().load_sliced_image(this._imageFile, this._imgWidth, this._imgHeight);
|
||||||
|
this._animations.connect('destroy', Lang.bind(this, function() {
|
||||||
|
if (this._timeoutId)
|
||||||
|
GLib.source_remove(this._timeoutId);
|
||||||
|
this._timeoutId = 0;
|
||||||
|
this._animations = null;
|
||||||
|
}));
|
||||||
|
this._animations.connect('notify::mapped', Lang.bind(this, function() {
|
||||||
|
if (this._animations.mapped && !this._timeoutId) {
|
||||||
|
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, FISH_SPEED, Lang.bind(this, this._update));
|
||||||
|
|
||||||
|
this._i = 0;
|
||||||
|
this._update();
|
||||||
|
} else if (!this._animations.mapped && this._timeoutId) {
|
||||||
|
GLib.source_remove(this._timeoutId);
|
||||||
|
this._timeoutId = 0;
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
this._i = 0;
|
||||||
|
|
||||||
|
return this._animations;
|
||||||
|
},
|
||||||
|
|
||||||
|
_update: function() {
|
||||||
|
let n = this._animations.get_n_children();
|
||||||
|
if (n == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._animations.get_child_at_index(this._i).hide();
|
||||||
|
this._i = (this._i + 1) % n;
|
||||||
|
this._animations.get_child_at_index(this._i).show();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const WandaIconBin = new Lang.Class({
|
||||||
|
Name: 'WandaIconBin',
|
||||||
|
|
||||||
|
_init: function(fish, label, params) {
|
||||||
|
this.actor = new St.Bin({ style_class: 'search-result-content',
|
||||||
|
reactive: true,
|
||||||
|
track_hover: true });
|
||||||
|
this.icon = new WandaIcon(fish, label, params);
|
||||||
|
|
||||||
|
this.actor.child = this.icon.actor;
|
||||||
|
this.actor.label_actor = this.icon.label;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const FortuneDialog = new Lang.Class({
|
||||||
|
Name: 'FortuneDialog',
|
||||||
|
|
||||||
|
_init: function(name, command) {
|
||||||
|
let text;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let [res, stdout, stderr, status] = GLib.spawn_command_line_sync(command);
|
||||||
|
text = String.fromCharCode.apply(null, stdout);
|
||||||
|
} catch(e) {
|
||||||
|
text = _("Sorry, no wisdom for you today:\n%s").format(e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._title = new St.Label({ style_class: 'prompt-dialog-headline',
|
||||||
|
text: _("%s the Oracle says").format(name) });
|
||||||
|
this._label = new St.Label({ style_class: 'prompt-dialog-description',
|
||||||
|
text: text });
|
||||||
|
this._label.clutter_text.line_wrap = true;
|
||||||
|
|
||||||
|
this._box = new St.BoxLayout({ vertical: true,
|
||||||
|
style_class: 'prompt-dialog' // this is just to force a reasonable width
|
||||||
|
});
|
||||||
|
this._box.add(this._title, { align: St.Align.MIDDLE });
|
||||||
|
this._box.add(this._label, { expand: true });
|
||||||
|
|
||||||
|
this._button = new St.Button({ button_mask: St.ButtonMask.ONE,
|
||||||
|
style_class: 'modal-dialog',
|
||||||
|
reactive: true });
|
||||||
|
this._button.connect('clicked', Lang.bind(this, this.destroy));
|
||||||
|
this._button.child = this._box;
|
||||||
|
|
||||||
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
|
|
||||||
|
Main.layoutManager.addChrome(this._button);
|
||||||
|
this._button.set_position(Math.floor(monitor.width / 2 - this._button.width / 2),
|
||||||
|
Math.floor(monitor.height / 2 - this._button.height / 2));
|
||||||
|
|
||||||
|
GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 10, Lang.bind(this, this.destroy));
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this._button.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function capitalize(str) {
|
||||||
|
return str[0].toUpperCase() + str.substring(1, str.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
const WandaSearchProvider = new Lang.Class({
|
||||||
|
Name: 'WandaSearchProvider',
|
||||||
|
Extends: Search.SearchProvider,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
this.parent(_("Your favorite Easter Egg"));
|
||||||
|
},
|
||||||
|
|
||||||
|
getResultMetas: function(fish) {
|
||||||
|
return [{ 'id': fish[0], // there may be many fish in the sea, but
|
||||||
|
// only one which speaks the truth!
|
||||||
|
'name': capitalize(fish[0]),
|
||||||
|
'createIcon': function(iconSize) {
|
||||||
|
// for DND only (maybe could be improved)
|
||||||
|
// DON'T use St.Icon here, it crashes the shell
|
||||||
|
// (dnd.js code assumes it can query the actor size
|
||||||
|
// without parenting it, while StWidget accesses
|
||||||
|
// StThemeNode in get_preferred_width/height, which
|
||||||
|
// triggers an assertion failure)
|
||||||
|
return St.TextureCache.get_default().load_icon_name(null,
|
||||||
|
'face-smile',
|
||||||
|
St.IconType.FULLCOLOR,
|
||||||
|
iconSize);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
|
||||||
|
getInitialResultSet: function(terms) {
|
||||||
|
if (terms.join(' ') == MAGIC_FISH_KEY) {
|
||||||
|
return [ FISH_NAME ];
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
getSubsearchResultSet: function(previousResults, terms) {
|
||||||
|
return this.getInitialResultSet(terms);
|
||||||
|
},
|
||||||
|
|
||||||
|
activateResult: function(fish, params) {
|
||||||
|
if (this._dialog)
|
||||||
|
this._dialog.destroy();
|
||||||
|
this._dialog = new FortuneDialog(capitalize(fish), FISH_COMMAND);
|
||||||
|
},
|
||||||
|
|
||||||
|
createResultActor: function (resultMeta, terms) {
|
||||||
|
let icon = new WandaIconBin(resultMeta.id, resultMeta.name);
|
||||||
|
return icon.actor;
|
||||||
|
}
|
||||||
|
});
|
@ -14,6 +14,12 @@ const WindowAttentionHandler = new Lang.Class({
|
|||||||
global.display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
|
global.display.connect('window-demands-attention', Lang.bind(this, this._onWindowDemandsAttention));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_getTitleAndBanner: function(app, window) {
|
||||||
|
let title = app.get_name();
|
||||||
|
let banner = _("'%s' is ready").format(window.get_title());
|
||||||
|
return [title, banner]
|
||||||
|
},
|
||||||
|
|
||||||
_onWindowDemandsAttention : function(display, window) {
|
_onWindowDemandsAttention : function(display, window) {
|
||||||
// We don't want to show the notification when the window is already focused,
|
// We don't want to show the notification when the window is already focused,
|
||||||
// because this is rather pointless.
|
// because this is rather pointless.
|
||||||
@ -30,16 +36,15 @@ const WindowAttentionHandler = new Lang.Class({
|
|||||||
let source = new Source(app, window);
|
let source = new Source(app, window);
|
||||||
Main.messageTray.add(source);
|
Main.messageTray.add(source);
|
||||||
|
|
||||||
let banner = _("'%s' is ready").format(window.title);
|
let [title, banner] = this._getTitleAndBanner(app, window);
|
||||||
let title = app.get_name();
|
|
||||||
|
|
||||||
let notification = new MessageTray.Notification(source, title, banner);
|
let notification = new MessageTray.Notification(source, title, banner);
|
||||||
source.notify(notification);
|
source.notify(notification);
|
||||||
|
|
||||||
source.signalIDs.push(window.connect('notify::title',
|
source.signalIDs.push(window.connect('notify::title', Lang.bind(this, function() {
|
||||||
Lang.bind(this, function() {
|
let [title, banner] = this._getTitleAndBanner(app, window);
|
||||||
notification.update(title, banner);
|
notification.update(title, banner);
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Tweener = imports.ui.tweener;
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
|
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||||
const WINDOW_ANIMATION_TIME = 0.25;
|
const WINDOW_ANIMATION_TIME = 0.25;
|
||||||
const DIM_TIME = 0.500;
|
const DIM_TIME = 0.500;
|
||||||
const UNDIM_TIME = 0.250;
|
const UNDIM_TIME = 0.250;
|
||||||
@ -134,6 +135,10 @@ const WindowManager = new Lang.Class({
|
|||||||
Lang.bind(this, this._startAppSwitcher));
|
Lang.bind(this, this._startAppSwitcher));
|
||||||
Meta.keybindings_set_custom_handler('switch-panels',
|
Meta.keybindings_set_custom_handler('switch-panels',
|
||||||
Lang.bind(this, this._startA11ySwitcher));
|
Lang.bind(this, this._startA11ySwitcher));
|
||||||
|
global.display.add_keybinding('open-application-menu',
|
||||||
|
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
||||||
|
Meta.KeyBindingFlags.NONE,
|
||||||
|
Lang.bind(this, this._openAppMenu));
|
||||||
|
|
||||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||||
for (let i = 0; i < this._dimmedWindows.length; i++)
|
for (let i = 0; i < this._dimmedWindows.length; i++)
|
||||||
@ -186,7 +191,7 @@ const WindowManager = new Lang.Class({
|
|||||||
|
|
||||||
let primary = Main.layoutManager.primaryMonitor;
|
let primary = Main.layoutManager.primaryMonitor;
|
||||||
let xDest = primary.x;
|
let xDest = primary.x;
|
||||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
|
||||||
xDest += primary.width;
|
xDest += primary.width;
|
||||||
|
|
||||||
Tweener.addTween(actor,
|
Tweener.addTween(actor,
|
||||||
@ -547,6 +552,10 @@ const WindowManager = new Lang.Class({
|
|||||||
Main.ctrlAltTabManager.popup(backwards, binding.get_mask());
|
Main.ctrlAltTabManager.popup(backwards, binding.get_mask());
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_openAppMenu : function(display, screen, window, event, binding) {
|
||||||
|
Main.panel.openAppMenu();
|
||||||
|
},
|
||||||
|
|
||||||
_showWorkspaceSwitcher : function(display, screen, window, binding) {
|
_showWorkspaceSwitcher : function(display, screen, window, binding) {
|
||||||
if (screen.n_workspaces == 1)
|
if (screen.n_workspaces == 1)
|
||||||
return;
|
return;
|
||||||
@ -567,7 +576,7 @@ const WindowManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
actionMoveWorkspaceLeft: function() {
|
actionMoveWorkspaceLeft: function() {
|
||||||
let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
|
||||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||||
let indexToActivate = activeWorkspaceIndex;
|
let indexToActivate = activeWorkspaceIndex;
|
||||||
if (rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1)
|
if (rtl && activeWorkspaceIndex < global.screen.n_workspaces - 1)
|
||||||
@ -583,7 +592,7 @@ const WindowManager = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
actionMoveWorkspaceRight: function() {
|
actionMoveWorkspaceRight: function() {
|
||||||
let rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
|
||||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||||
let indexToActivate = activeWorkspaceIndex;
|
let indexToActivate = activeWorkspaceIndex;
|
||||||
if (rtl && activeWorkspaceIndex > 0)
|
if (rtl && activeWorkspaceIndex > 0)
|
||||||
|
@ -23,6 +23,8 @@ const WINDOW_DND_SIZE = 256;
|
|||||||
|
|
||||||
const SCROLL_SCALE_AMOUNT = 100 / 5;
|
const SCROLL_SCALE_AMOUNT = 100 / 5;
|
||||||
|
|
||||||
|
const WINDOW_CLONE_MAXIMUM_SCALE = 0.7;
|
||||||
|
|
||||||
const LIGHTBOX_FADE_TIME = 0.1;
|
const LIGHTBOX_FADE_TIME = 0.1;
|
||||||
const CLOSE_BUTTON_FADE_TIME = 0.1;
|
const CLOSE_BUTTON_FADE_TIME = 0.1;
|
||||||
|
|
||||||
@ -94,10 +96,11 @@ const ScaledPoint = new Lang.Class({
|
|||||||
const WindowClone = new Lang.Class({
|
const WindowClone = new Lang.Class({
|
||||||
Name: 'WindowClone',
|
Name: 'WindowClone',
|
||||||
|
|
||||||
_init : function(realWindow) {
|
_init : function(realWindow, workspace) {
|
||||||
this.realWindow = realWindow;
|
this.realWindow = realWindow;
|
||||||
this.metaWindow = realWindow.meta_window;
|
this.metaWindow = realWindow.meta_window;
|
||||||
this.metaWindow._delegate = this;
|
this.metaWindow._delegate = this;
|
||||||
|
this._workspace = workspace;
|
||||||
|
|
||||||
let [borderX, borderY] = this._getInvisibleBorderPadding();
|
let [borderX, borderY] = this._getInvisibleBorderPadding();
|
||||||
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(),
|
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(),
|
||||||
@ -367,6 +370,7 @@ const WindowClone = new Lang.Class({
|
|||||||
if (this._selected)
|
if (this._selected)
|
||||||
return;
|
return;
|
||||||
let [x, y] = action.get_coords();
|
let [x, y] = action.get_coords();
|
||||||
|
action.release();
|
||||||
this._draggable.startDrag(x, y, global.get_current_time());
|
this._draggable.startDrag(x, y, global.get_current_time());
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -383,19 +387,12 @@ const WindowClone = new Lang.Class({
|
|||||||
this.emit('drag-begin');
|
this.emit('drag-begin');
|
||||||
},
|
},
|
||||||
|
|
||||||
_getWorkspaceActor : function() {
|
|
||||||
let index = this.metaWindow.get_workspace().index();
|
|
||||||
return Main.overview.workspaces.getWorkspaceByIndex(index);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDragOver : function(source, actor, x, y, time) {
|
handleDragOver : function(source, actor, x, y, time) {
|
||||||
let workspace = this._getWorkspaceActor();
|
return this._workspace.handleDragOver(source, actor, x, y, time);
|
||||||
return workspace.handleDragOver(source, actor, x, y, time);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
acceptDrop : function(source, actor, x, y, time) {
|
acceptDrop : function(source, actor, x, y, time) {
|
||||||
let workspace = this._getWorkspaceActor();
|
this._workspace.acceptDrop(source, actor, x, y, time);
|
||||||
workspace.acceptDrop(source, actor, x, y, time);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDragCancelled : function (draggable, time) {
|
_onDragCancelled : function (draggable, time) {
|
||||||
@ -494,6 +491,9 @@ const WindowOverlay = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
fadeIn: function() {
|
fadeIn: function() {
|
||||||
|
if (!this._hidden)
|
||||||
|
return;
|
||||||
|
|
||||||
this.show();
|
this.show();
|
||||||
this.title.opacity = 0;
|
this.title.opacity = 0;
|
||||||
this._parentActor.raise_top();
|
this._parentActor.raise_top();
|
||||||
@ -522,13 +522,13 @@ const WindowOverlay = new Lang.Class({
|
|||||||
// get_transformed_position() and get_transformed_size(),
|
// get_transformed_position() and get_transformed_size(),
|
||||||
// as windowClone might be moving.
|
// as windowClone might be moving.
|
||||||
// See Workspace._showWindowOverlay
|
// See Workspace._showWindowOverlay
|
||||||
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight) {
|
updatePositions: function(cloneX, cloneY, cloneWidth, cloneHeight, animate) {
|
||||||
let button = this.closeButton;
|
let button = this.closeButton;
|
||||||
let title = this.title;
|
let title = this.title;
|
||||||
|
|
||||||
let settings = new Gio.Settings({ schema: BUTTON_LAYOUT_SCHEMA });
|
let settings = new Gio.Settings({ schema: BUTTON_LAYOUT_SCHEMA });
|
||||||
let layout = settings.get_string(BUTTON_LAYOUT_KEY);
|
let layout = settings.get_string(BUTTON_LAYOUT_KEY);
|
||||||
let rtl = St.Widget.get_default_direction() == St.TextDirection.RTL;
|
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
|
||||||
|
|
||||||
let split = layout.split(":");
|
let split = layout.split(":");
|
||||||
let side;
|
let side;
|
||||||
@ -544,15 +544,34 @@ const WindowOverlay = new Lang.Class({
|
|||||||
else
|
else
|
||||||
buttonX = cloneX + (cloneWidth - button._overlap);
|
buttonX = cloneX + (cloneWidth - button._overlap);
|
||||||
|
|
||||||
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
if (animate)
|
||||||
|
this._animateOverlayActor(button, Math.floor(buttonX), Math.floor(buttonY), button.width);
|
||||||
|
else
|
||||||
|
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
||||||
|
|
||||||
if (!title.fullWidth)
|
if (!title.fullWidth)
|
||||||
title.fullWidth = title.width;
|
title.fullWidth = title.width;
|
||||||
title.width = Math.min(title.fullWidth, cloneWidth);
|
let titleWidth = Math.min(title.fullWidth, cloneWidth);
|
||||||
|
|
||||||
let titleX = cloneX + (cloneWidth - title.width) / 2;
|
let titleX = cloneX + (cloneWidth - titleWidth) / 2;
|
||||||
let titleY = cloneY + cloneHeight + title._spacing;
|
let titleY = cloneY + cloneHeight + title._spacing;
|
||||||
title.set_position(Math.floor(titleX), Math.floor(titleY));
|
|
||||||
|
if (animate)
|
||||||
|
this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY), titleWidth);
|
||||||
|
else {
|
||||||
|
title.width = titleWidth;
|
||||||
|
title.set_position(Math.floor(titleX), Math.floor(titleY));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_animateOverlayActor: function(actor, x, y, width) {
|
||||||
|
Tweener.addTween(actor,
|
||||||
|
{ x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
time: Overview.ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad'
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_closeWindow: function(actor) {
|
_closeWindow: function(actor) {
|
||||||
@ -948,7 +967,7 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
let scale = Math.min((width - buttonOuterWidth) / rect.width,
|
let scale = Math.min((width - buttonOuterWidth) / rect.width,
|
||||||
(height - buttonOuterHeight - captionHeight) / rect.height,
|
(height - buttonOuterHeight - captionHeight) / rect.height,
|
||||||
1.0);
|
WINDOW_CLONE_MAXIMUM_SCALE);
|
||||||
|
|
||||||
x = Math.floor(x + (width - scale * rect.width) / 2);
|
x = Math.floor(x + (width - scale * rect.width) / 2);
|
||||||
|
|
||||||
@ -1017,7 +1036,7 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
|
let [x, y, scale] = this._computeWindowLayout(metaWindow, slot);
|
||||||
|
|
||||||
if (overlay)
|
if (overlay && initialPositioning)
|
||||||
overlay.hide();
|
overlay.hide();
|
||||||
if (animate && isOnCurrentWorkspace) {
|
if (animate && isOnCurrentWorkspace) {
|
||||||
if (!metaWindow.showing_on_its_workspace()) {
|
if (!metaWindow.showing_on_its_workspace()) {
|
||||||
@ -1040,20 +1059,11 @@ const Workspace = new Lang.Class({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Tweener.addTween(clone.actor,
|
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
|
||||||
{ x: x,
|
|
||||||
y: y,
|
|
||||||
scale_x: scale,
|
|
||||||
scale_y: scale,
|
|
||||||
time: Overview.ANIMATION_TIME,
|
|
||||||
transition: 'easeOutQuad',
|
|
||||||
onComplete: Lang.bind(this, function() {
|
|
||||||
this._showWindowOverlay(clone, overlay, true);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
clone.actor.set_position(x, y);
|
clone.actor.set_position(x, y);
|
||||||
clone.actor.set_scale(scale, scale);
|
clone.actor.set_scale(scale, scale);
|
||||||
|
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, false);
|
||||||
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
|
this._showWindowOverlay(clone, overlay, isOnCurrentWorkspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1075,23 +1085,35 @@ const Workspace = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_animateClone: function(clone, overlay, x, y, scale, initialPositioning) {
|
||||||
|
Tweener.addTween(clone.actor,
|
||||||
|
{ x: x,
|
||||||
|
y: y,
|
||||||
|
scale_x: scale,
|
||||||
|
scale_y: scale,
|
||||||
|
time: Overview.ANIMATION_TIME,
|
||||||
|
transition: 'easeOutQuad',
|
||||||
|
onComplete: Lang.bind(this, function() {
|
||||||
|
this._showWindowOverlay(clone, overlay, true);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
this._updateWindowOverlayPositions(clone, overlay, x, y, scale, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateWindowOverlayPositions: function(clone, overlay, x, y, scale, animate) {
|
||||||
|
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
||||||
|
cloneWidth = scale * cloneWidth;
|
||||||
|
cloneHeight = scale * cloneHeight;
|
||||||
|
if (overlay)
|
||||||
|
overlay.updatePositions(x, y, cloneWidth, cloneHeight, animate);
|
||||||
|
},
|
||||||
|
|
||||||
_showWindowOverlay: function(clone, overlay, fade) {
|
_showWindowOverlay: function(clone, overlay, fade) {
|
||||||
if (clone.inDrag)
|
if (clone.inDrag)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// This is a little messy and complicated because when we
|
|
||||||
// start the fade-in we may not have done the final positioning
|
|
||||||
// of the workspaces. (Tweener doesn't necessarily finish
|
|
||||||
// all animations before calling onComplete callbacks.)
|
|
||||||
// So we need to manually compute where the window will
|
|
||||||
// be after the workspace animation finishes.
|
|
||||||
let [cloneX, cloneY] = clone.actor.get_position();
|
|
||||||
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
|
||||||
cloneWidth = clone.actor.scale_x * cloneWidth;
|
|
||||||
cloneHeight = clone.actor.scale_y * cloneHeight;
|
|
||||||
|
|
||||||
if (overlay) {
|
if (overlay) {
|
||||||
overlay.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
|
|
||||||
if (fade)
|
if (fade)
|
||||||
overlay.fadeIn();
|
overlay.fadeIn();
|
||||||
else
|
else
|
||||||
@ -1109,6 +1131,16 @@ const Workspace = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_hideAllOverlays: function() {
|
||||||
|
for (let i = 0; i < this._windows.length; i++) {
|
||||||
|
let clone = this._windows[i];
|
||||||
|
Tweener.removeTweens(clone.actor);
|
||||||
|
let overlay = this._windowOverlays[i];
|
||||||
|
if (overlay)
|
||||||
|
overlay.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
_delayedWindowRepositioning: function() {
|
_delayedWindowRepositioning: function() {
|
||||||
if (this._windowIsZooming)
|
if (this._windowIsZooming)
|
||||||
return true;
|
return true;
|
||||||
@ -1126,22 +1158,16 @@ const Workspace = new Lang.Class({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let actorUnderPointer = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||||
|
for (let i = 0; i < this._windows.length; i++) {
|
||||||
|
if (this._windows[i].actor == actorUnderPointer)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
|
|
||||||
showWindowsOverlays: function() {
|
|
||||||
if (this.leavingOverview)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this._windowOverlaysGroup.show();
|
|
||||||
this._showAllOverlays();
|
|
||||||
},
|
|
||||||
|
|
||||||
hideWindowsOverlays: function() {
|
|
||||||
this._windowOverlaysGroup.hide();
|
|
||||||
},
|
|
||||||
|
|
||||||
_doRemoveWindow : function(metaWin) {
|
_doRemoveWindow : function(metaWin) {
|
||||||
let win = metaWin.get_compositor_private();
|
let win = metaWin.get_compositor_private();
|
||||||
|
|
||||||
@ -1295,7 +1321,7 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
this.leavingOverview = true;
|
this.leavingOverview = true;
|
||||||
|
|
||||||
this.hideWindowsOverlays();
|
this._hideAllOverlays();
|
||||||
|
|
||||||
if (this._repositionWindowsId > 0) {
|
if (this._repositionWindowsId > 0) {
|
||||||
Mainloop.source_remove(this._repositionWindowsId);
|
Mainloop.source_remove(this._repositionWindowsId);
|
||||||
@ -1386,7 +1412,7 @@ const Workspace = new Lang.Class({
|
|||||||
|
|
||||||
// Create a clone of a (non-desktop) window and add it to the window list
|
// Create a clone of a (non-desktop) window and add it to the window list
|
||||||
_addWindowClone : function(win) {
|
_addWindowClone : function(win) {
|
||||||
let clone = new WindowClone(win);
|
let clone = new WindowClone(win, this);
|
||||||
let overlay = new WindowOverlay(clone, this._windowOverlaysGroup);
|
let overlay = new WindowOverlay(clone, this._windowOverlaysGroup);
|
||||||
|
|
||||||
clone.connect('selected',
|
clone.connect('selected',
|
||||||
|
@ -19,12 +19,12 @@ const WorkspaceSwitcherPopup = new Lang.Class({
|
|||||||
Name: 'WorkspaceSwitcherPopup',
|
Name: 'WorkspaceSwitcherPopup',
|
||||||
|
|
||||||
_init : function() {
|
_init : function() {
|
||||||
this.actor = new St.Group({ reactive: true,
|
this.actor = new St.Widget({ reactive: true,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
width: global.screen_width,
|
width: global.screen_width,
|
||||||
height: global.screen_height,
|
height: global.screen_height,
|
||||||
style_class: 'workspace-switcher-group' });
|
style_class: 'workspace-switcher-group' });
|
||||||
Main.uiGroup.add_actor(this.actor);
|
Main.uiGroup.add_actor(this.actor);
|
||||||
|
|
||||||
this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' });
|
this._container = new St.BoxLayout({ style_class: 'workspace-switcher-container' });
|
||||||
@ -105,7 +105,7 @@ const WorkspaceSwitcherPopup = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_redraw : function(direction, activeWorkspaceIndex) {
|
_redraw : function(direction, activeWorkspaceIndex) {
|
||||||
this._list.destroy_children();
|
this._list.destroy_all_children();
|
||||||
|
|
||||||
for (let i = 0; i < global.screen.n_workspaces; i++) {
|
for (let i = 0; i < global.screen.n_workspaces; i++) {
|
||||||
let indicator = null;
|
let indicator = null;
|
||||||
|
@ -25,6 +25,8 @@ const SLIDE_ANIMATION_TIME = 0.2;
|
|||||||
// placeholder exactly.
|
// placeholder exactly.
|
||||||
const WORKSPACE_CUT_SIZE = 10;
|
const WORKSPACE_CUT_SIZE = 10;
|
||||||
|
|
||||||
|
const WORKSPACE_KEEP_ALIVE_TIME = 100;
|
||||||
|
|
||||||
const WindowClone = new Lang.Class({
|
const WindowClone = new Lang.Class({
|
||||||
Name: 'WindowClone',
|
Name: 'WindowClone',
|
||||||
|
|
||||||
@ -51,6 +53,7 @@ const WindowClone = new Lang.Class({
|
|||||||
dragActorMaxSize: Workspace.WINDOW_DND_SIZE,
|
dragActorMaxSize: Workspace.WINDOW_DND_SIZE,
|
||||||
dragActorOpacity: Workspace.DRAGGING_WINDOW_OPACITY });
|
dragActorOpacity: Workspace.DRAGGING_WINDOW_OPACITY });
|
||||||
this._draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
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._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||||
this.inDrag = false;
|
this.inDrag = false;
|
||||||
},
|
},
|
||||||
@ -108,6 +111,10 @@ const WindowClone = new Lang.Class({
|
|||||||
this.emit('drag-begin');
|
this.emit('drag-begin');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_onDragCancelled : function (draggable, time) {
|
||||||
|
this.emit('drag-cancelled');
|
||||||
|
},
|
||||||
|
|
||||||
_onDragEnd : function (draggable, time, snapback) {
|
_onDragEnd : function (draggable, time, snapback) {
|
||||||
this.inDrag = false;
|
this.inDrag = false;
|
||||||
|
|
||||||
@ -149,24 +156,16 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
this.metaWorkspace = metaWorkspace;
|
this.metaWorkspace = metaWorkspace;
|
||||||
this.monitorIndex = Main.layoutManager.primaryIndex;
|
this.monitorIndex = Main.layoutManager.primaryIndex;
|
||||||
|
|
||||||
this.actor = new St.Group({ reactive: true,
|
this._removed = false;
|
||||||
clip_to_allocation: true,
|
|
||||||
style_class: 'workspace-thumbnail' });
|
this.actor = new St.Widget({ clip_to_allocation: true,
|
||||||
|
style_class: 'workspace-thumbnail' });
|
||||||
this.actor._delegate = this;
|
this.actor._delegate = this;
|
||||||
|
|
||||||
this._contents = new Clutter.Group();
|
this._contents = new Clutter.Group();
|
||||||
this.actor.add_actor(this._contents);
|
this.actor.add_actor(this._contents);
|
||||||
|
|
||||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||||
this.actor.connect('button-press-event', Lang.bind(this,
|
|
||||||
function(actor, event) {
|
|
||||||
return true;
|
|
||||||
}));
|
|
||||||
this.actor.connect('button-release-event', Lang.bind(this,
|
|
||||||
function(actor, event) {
|
|
||||||
this._activate();
|
|
||||||
return true;
|
|
||||||
}));
|
|
||||||
|
|
||||||
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
this._background = Meta.BackgroundActor.new_for_screen(global.screen);
|
||||||
this._contents.add_actor(this._background);
|
this._contents.add_actor(this._background);
|
||||||
@ -174,17 +173,21 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
let monitor = Main.layoutManager.primaryMonitor;
|
let monitor = Main.layoutManager.primaryMonitor;
|
||||||
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
|
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
|
||||||
|
|
||||||
let windows = global.get_window_actors().filter(this._isMyWindow, this);
|
let windows = global.get_window_actors().filter(this._isWorkspaceWindow, this);
|
||||||
|
|
||||||
// Create clones for windows that should be visible in the Overview
|
// Create clones for windows that should be visible in the Overview
|
||||||
this._windows = [];
|
this._windows = [];
|
||||||
|
this._allWindows = [];
|
||||||
|
this._minimizedChangedIds = [];
|
||||||
for (let i = 0; i < windows.length; i++) {
|
for (let i = 0; i < windows.length; i++) {
|
||||||
windows[i].meta_window._minimizedChangedId =
|
let minimizedChangedId =
|
||||||
windows[i].meta_window.connect('notify::minimized',
|
windows[i].meta_window.connect('notify::minimized',
|
||||||
Lang.bind(this,
|
Lang.bind(this,
|
||||||
this._updateMinimized));
|
this._updateMinimized));
|
||||||
|
this._allWindows.push(windows[i].meta_window);
|
||||||
|
this._minimizedChangedIds.push(minimizedChangedId);
|
||||||
|
|
||||||
if (this._isOverviewWindow(windows[i])) {
|
if (this._isMyWindow(windows[i]) && this._isOverviewWindow(windows[i])) {
|
||||||
this._addWindowClone(windows[i]);
|
this._addWindowClone(windows[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -269,17 +272,11 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
let clone = this._windows[index];
|
let clone = this._windows[index];
|
||||||
this._windows.splice(index, 1);
|
this._windows.splice(index, 1);
|
||||||
|
|
||||||
if (win && this._isOverviewWindow(win)) {
|
|
||||||
if (metaWin._minimizedChangedId) {
|
|
||||||
metaWin.disconnect(metaWin._minimizedChangedId);
|
|
||||||
delete metaWin._minimizedChangedId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
clone.destroy();
|
clone.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
_doAddWindow : function(metaWin) {
|
_doAddWindow : function(metaWin) {
|
||||||
if (this.leavingOverview)
|
if (this._removed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let win = metaWin.get_compositor_private();
|
let win = metaWin.get_compositor_private();
|
||||||
@ -289,7 +286,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
// the compositor finds out about them...
|
// the compositor finds out about them...
|
||||||
Mainloop.idle_add(Lang.bind(this,
|
Mainloop.idle_add(Lang.bind(this,
|
||||||
function () {
|
function () {
|
||||||
if (this.actor &&
|
if (!this._removed &&
|
||||||
metaWin.get_compositor_private() &&
|
metaWin.get_compositor_private() &&
|
||||||
metaWin.get_workspace() == this.metaWorkspace)
|
metaWin.get_workspace() == this.metaWorkspace)
|
||||||
this._doAddWindow(metaWin);
|
this._doAddWindow(metaWin);
|
||||||
@ -298,16 +295,19 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._allWindows.indexOf(metaWin) == -1) {
|
||||||
|
let minimizedChangedId = metaWin.connect('notify::minimized',
|
||||||
|
Lang.bind(this,
|
||||||
|
this._updateMinimized));
|
||||||
|
this._allWindows.push(metaWin);
|
||||||
|
this._minimizedChangedIds.push(minimizedChangedId);
|
||||||
|
}
|
||||||
|
|
||||||
// We might have the window in our list already if it was on all workspaces and
|
// We might have the window in our list already if it was on all workspaces and
|
||||||
// now was moved to this workspace
|
// now was moved to this workspace
|
||||||
if (this._lookupIndex (metaWin) != -1)
|
if (this._lookupIndex (metaWin) != -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!metaWin._minimizedChangedId)
|
|
||||||
metaWin._minimizedChangedId = metaWin.connect('notify::minimized',
|
|
||||||
Lang.bind(this,
|
|
||||||
this._updateMinimized));
|
|
||||||
|
|
||||||
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -319,6 +319,13 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_windowRemoved : function(metaWorkspace, metaWin) {
|
_windowRemoved : function(metaWorkspace, metaWin) {
|
||||||
|
let index = this._allWindows.indexOf(metaWin);
|
||||||
|
if (index != -1) {
|
||||||
|
metaWin.disconnect(this._minimizedChangedIds[index]);
|
||||||
|
this._allWindows.splice(index, 1);
|
||||||
|
this._minimizedChangedIds.splice(index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
this._doRemoveWindow(metaWin);
|
this._doRemoveWindow(metaWin);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -345,27 +352,36 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
this.actor.destroy();
|
this.actor.destroy();
|
||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function(actor) {
|
workspaceRemoved : function() {
|
||||||
|
if (this._removed)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._removed = true;
|
||||||
|
|
||||||
this.metaWorkspace.disconnect(this._windowAddedId);
|
this.metaWorkspace.disconnect(this._windowAddedId);
|
||||||
this.metaWorkspace.disconnect(this._windowRemovedId);
|
this.metaWorkspace.disconnect(this._windowRemovedId);
|
||||||
global.screen.disconnect(this._windowEnteredMonitorId);
|
global.screen.disconnect(this._windowEnteredMonitorId);
|
||||||
global.screen.disconnect(this._windowLeftMonitorId);
|
global.screen.disconnect(this._windowLeftMonitorId);
|
||||||
|
|
||||||
for (let i = 0; i < this._windows.length; i++) {
|
for (let i = 0; i < this._allWindows.length; i++)
|
||||||
let metaWin = this._windows[i].metaWindow;
|
this._allWindows[i].disconnect(this._minimizedChangedIds[i]);
|
||||||
if (metaWin._minimizedChangedId) {
|
},
|
||||||
metaWin.disconnect(metaWin._minimizedChangedId);
|
|
||||||
delete metaWin._minimizedChangedId;
|
_onDestroy: function(actor) {
|
||||||
}
|
this.workspaceRemoved();
|
||||||
}
|
|
||||||
|
|
||||||
this._windows = [];
|
this._windows = [];
|
||||||
this.actor = null;
|
this.actor = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Tests if @win belongs to this workspace
|
||||||
|
_isWorkspaceWindow : function (win) {
|
||||||
|
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index());
|
||||||
|
},
|
||||||
|
|
||||||
// Tests if @win belongs to this workspace and monitor
|
// Tests if @win belongs to this workspace and monitor
|
||||||
_isMyWindow : function (win) {
|
_isMyWindow : function (win) {
|
||||||
return Main.isWindowActorDisplayedOnWorkspace(win, this.metaWorkspace.index()) &&
|
return this._isWorkspaceWindow(win) &&
|
||||||
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
|
(!win.get_meta_window() || win.get_meta_window().get_monitor() == this.monitorIndex);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -381,11 +397,17 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
let clone = new WindowClone(win);
|
let clone = new WindowClone(win);
|
||||||
|
|
||||||
clone.connect('selected',
|
clone.connect('selected',
|
||||||
Lang.bind(this, this._activate));
|
Lang.bind(this, function(clone, time) {
|
||||||
|
this.activate(time);
|
||||||
|
}));
|
||||||
clone.connect('drag-begin',
|
clone.connect('drag-begin',
|
||||||
Lang.bind(this, function(clone) {
|
Lang.bind(this, function(clone) {
|
||||||
Main.overview.beginWindowDrag();
|
Main.overview.beginWindowDrag();
|
||||||
}));
|
}));
|
||||||
|
clone.connect('drag-cancelled',
|
||||||
|
Lang.bind(this, function(clone) {
|
||||||
|
Main.overview.cancelledWindowDrag();
|
||||||
|
}));
|
||||||
clone.connect('drag-end',
|
clone.connect('drag-end',
|
||||||
Lang.bind(this, function(clone) {
|
Lang.bind(this, function(clone) {
|
||||||
Main.overview.endWindowDrag();
|
Main.overview.endWindowDrag();
|
||||||
@ -402,7 +424,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
return clone;
|
return clone;
|
||||||
},
|
},
|
||||||
|
|
||||||
_activate : function (clone, time) {
|
activate : function (time) {
|
||||||
if (this.state > ThumbnailState.NORMAL)
|
if (this.state > ThumbnailState.NORMAL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -413,8 +435,8 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
this.metaWorkspace.activate(time);
|
this.metaWorkspace.activate(time);
|
||||||
},
|
},
|
||||||
|
|
||||||
// Draggable target interface
|
// Draggable target interface used only by ThumbnailsBox
|
||||||
handleDragOver : function(source, actor, x, y, time) {
|
handleDragOverInternal : function(source, time) {
|
||||||
if (source == Main.xdndHandler) {
|
if (source == Main.xdndHandler) {
|
||||||
this.metaWorkspace.activate(time);
|
this.metaWorkspace.activate(time);
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
@ -423,11 +445,6 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
if (this.state > ThumbnailState.NORMAL)
|
if (this.state > ThumbnailState.NORMAL)
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
let [w, h] = this.actor.get_transformed_size();
|
|
||||||
// Bubble up if we're in the "workspace cut".
|
|
||||||
if (y < WORKSPACE_CUT_SIZE || y > h - WORKSPACE_CUT_SIZE)
|
|
||||||
return DND.DragMotionResult.CONTINUE;
|
|
||||||
|
|
||||||
if (source.realWindow && !this._isMyWindow(source.realWindow))
|
if (source.realWindow && !this._isMyWindow(source.realWindow))
|
||||||
return DND.DragMotionResult.MOVE_DROP;
|
return DND.DragMotionResult.MOVE_DROP;
|
||||||
if (source.shellWorkspaceLaunch)
|
if (source.shellWorkspaceLaunch)
|
||||||
@ -436,7 +453,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
|||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
},
|
},
|
||||||
|
|
||||||
acceptDrop : function(source, actor, x, y, time) {
|
acceptDropInternal : function(source, time) {
|
||||||
if (this.state > ThumbnailState.NORMAL)
|
if (this.state > ThumbnailState.NORMAL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -474,7 +491,8 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
Name: 'ThumbnailsBox',
|
Name: 'ThumbnailsBox',
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new Shell.GenericContainer({ style_class: 'workspace-thumbnails',
|
this.actor = new Shell.GenericContainer({ reactive: true,
|
||||||
|
style_class: 'workspace-thumbnails',
|
||||||
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
|
request_mode: Clutter.RequestMode.WIDTH_FOR_HEIGHT });
|
||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
@ -503,6 +521,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
this._indicator = indicator;
|
this._indicator = indicator;
|
||||||
this.actor.add_actor(indicator);
|
this.actor.add_actor(indicator);
|
||||||
|
|
||||||
|
this._dropWorkspace = -1;
|
||||||
this._dropPlaceholderPos = -1;
|
this._dropPlaceholderPos = -1;
|
||||||
this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' });
|
this._dropPlaceholder = new St.Bin({ style_class: 'placeholder' });
|
||||||
this.actor.add_actor(this._dropPlaceholder);
|
this.actor.add_actor(this._dropPlaceholder);
|
||||||
@ -519,83 +538,187 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
this._stateCounts[ThumbnailState[key]] = 0;
|
this._stateCounts[ThumbnailState[key]] = 0;
|
||||||
|
|
||||||
this._thumbnails = [];
|
this._thumbnails = [];
|
||||||
|
|
||||||
|
this.actor.connect('button-press-event', function() { return true; });
|
||||||
|
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonRelease));
|
||||||
|
|
||||||
|
Main.overview.connect('item-drag-begin',
|
||||||
|
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-end',
|
||||||
|
Lang.bind(this, this._onDragEnd));
|
||||||
|
Main.overview.connect('window-drag-cancelled',
|
||||||
|
Lang.bind(this, this._onDragCancelled));
|
||||||
|
},
|
||||||
|
|
||||||
|
_onButtonRelease: function(actor, event) {
|
||||||
|
let [stageX, stageY] = event.get_coords();
|
||||||
|
let [r, x, y] = this.actor.transform_stage_point(stageX, stageY);
|
||||||
|
|
||||||
|
for (let i = 0; i < this._thumbnails.length; i++) {
|
||||||
|
let thumbnail = this._thumbnails[i]
|
||||||
|
let [w, h] = thumbnail.actor.get_transformed_size();
|
||||||
|
if (y >= thumbnail.actor.y && y <= thumbnail.actor.y + h) {
|
||||||
|
thumbnail.activate(event.time);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDragBegin: function() {
|
||||||
|
this._dragCancelled = false;
|
||||||
|
this._dragMonitor = {
|
||||||
|
dragMotion: Lang.bind(this, this._onDragMotion)
|
||||||
|
};
|
||||||
|
DND.addDragMonitor(this._dragMonitor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDragEnd: function() {
|
||||||
|
if (this._dragCancelled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._endDrag();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDragCancelled: function() {
|
||||||
|
this._dragCancelled = true;
|
||||||
|
this._endDrag();
|
||||||
|
},
|
||||||
|
|
||||||
|
_endDrag: function() {
|
||||||
|
this._clearDragPlaceholder();
|
||||||
|
DND.removeDragMonitor(this._dragMonitor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_onDragMotion: function(dragEvent) {
|
||||||
|
if (!this.actor.contains(dragEvent.targetActor))
|
||||||
|
this._onLeave();
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
},
|
||||||
|
|
||||||
|
_onLeave: function() {
|
||||||
|
this._clearDragPlaceholder();
|
||||||
|
},
|
||||||
|
|
||||||
|
_clearDragPlaceholder: function() {
|
||||||
|
if (this._dropPlaceholderPos == -1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._dropPlaceholderPos = -1;
|
||||||
|
this.actor.queue_relayout();
|
||||||
},
|
},
|
||||||
|
|
||||||
// Draggable target interface
|
// Draggable target interface
|
||||||
handleDragOver : function(source, actor, x, y, time) {
|
handleDragOver : function(source, actor, x, y, time) {
|
||||||
if (!source.realWindow && !source.shellWorkspaceLaunch)
|
if (!source.realWindow && !source.shellWorkspaceLaunch && source != Main.xdndHandler)
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
|
if (!Meta.prefs_get_dynamic_workspaces())
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
let spacing = this.actor.get_theme_node().get_length('spacing');
|
let spacing = this.actor.get_theme_node().get_length('spacing');
|
||||||
let thumbHeight = this._porthole.height * this._scale;
|
|
||||||
|
|
||||||
let workspace = -1;
|
|
||||||
let firstThumbY = this._thumbnails[0].actor.y;
|
|
||||||
for (let i = 0; i < this._thumbnails.length; i ++) {
|
|
||||||
let targetBase = firstThumbY + (thumbHeight + spacing) * i;
|
|
||||||
|
|
||||||
|
this._dropWorkspace = -1;
|
||||||
|
let placeholderPos = -1;
|
||||||
|
let targetBase;
|
||||||
|
if (this._dropPlaceholderPos == 0)
|
||||||
|
targetBase = this._dropPlaceholder.y;
|
||||||
|
else
|
||||||
|
targetBase = this._thumbnails[0].actor.y;
|
||||||
|
let targetTop = targetBase - spacing - WORKSPACE_CUT_SIZE;
|
||||||
|
let length = this._thumbnails.length;
|
||||||
|
for (let i = 0; i < length; i ++) {
|
||||||
// Allow the reorder target to have a 10px "cut" into
|
// Allow the reorder target to have a 10px "cut" into
|
||||||
// each side of the thumbnail, to make dragging onto the
|
// each side of the thumbnail, to make dragging onto the
|
||||||
// placeholder easier
|
// placeholder easier
|
||||||
let targetTop = targetBase - spacing - WORKSPACE_CUT_SIZE;
|
let [w, h] = this._thumbnails[i].actor.get_transformed_size();
|
||||||
let targetBottom = targetBase + WORKSPACE_CUT_SIZE;
|
let targetBottom = targetBase + WORKSPACE_CUT_SIZE;
|
||||||
|
let nextTargetBase = targetBase + h + spacing;
|
||||||
|
let nextTargetTop = nextTargetBase - spacing - ((i == length - 1) ? 0: WORKSPACE_CUT_SIZE);
|
||||||
|
|
||||||
// Expand the target to include the placeholder, if it exists.
|
// Expand the target to include the placeholder, if it exists.
|
||||||
if (i == this._dropPlaceholderPos)
|
if (i == this._dropPlaceholderPos)
|
||||||
targetBottom += this._dropPlaceholder.get_height();
|
targetBottom += this._dropPlaceholder.get_height();
|
||||||
|
|
||||||
if (y > targetTop && y <= targetBottom) {
|
if (y > targetTop && y <= targetBottom && source != Main.xdndHandler) {
|
||||||
workspace = i;
|
placeholderPos = i;
|
||||||
break;
|
break;
|
||||||
|
} else if (y > targetBottom && y <= nextTargetTop) {
|
||||||
|
this._dropWorkspace = i;
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
targetBase = nextTargetBase;
|
||||||
|
targetTop = nextTargetTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._dropPlaceholderPos = workspace;
|
if (this._dropPlaceholderPos != placeholderPos) {
|
||||||
this.actor.queue_relayout();
|
this._dropPlaceholderPos = placeholderPos;
|
||||||
|
this.actor.queue_relayout();
|
||||||
|
}
|
||||||
|
|
||||||
if (workspace == -1)
|
if (this._dropWorkspace != -1)
|
||||||
|
return this._thumbnails[this._dropWorkspace].handleDragOverInternal(source, time);
|
||||||
|
else if (this._dropPlaceholderPos != -1)
|
||||||
|
return source.realWindow ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.COPY_DROP;
|
||||||
|
else
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
return DND.DragMotionResult.MOVE_DROP;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
acceptDrop: function(source, actor, x, y, time) {
|
acceptDrop: function(source, actor, x, y, time) {
|
||||||
if (this._dropPlaceholderPos == -1)
|
if (this._dropWorkspace != -1) {
|
||||||
return false;
|
return this._thumbnails[this._dropWorkspace].acceptDropInternal(source, time);
|
||||||
|
} else if (this._dropPlaceholderPos != -1) {
|
||||||
|
if (!source.realWindow && !source.shellWorkspaceLaunch)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!source.realWindow && !source.shellWorkspaceLaunch)
|
let isWindow = !!source.realWindow;
|
||||||
return false;
|
|
||||||
|
|
||||||
let isWindow = !!source.realWindow;
|
// To create a new workspace, we first slide all the windows on workspaces
|
||||||
|
// below us to the next workspace, leaving a blank workspace for us to recycle.
|
||||||
|
let newWorkspaceIndex;
|
||||||
|
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
|
||||||
|
|
||||||
// To create a new workspace, we first slide all the windows on workspaces
|
// Nab all the windows below us.
|
||||||
// below us to the next workspace, leaving a blank workspace for us to recycle.
|
let windows = global.get_window_actors().filter(function(win) {
|
||||||
let newWorkspaceIndex;
|
if (isWindow)
|
||||||
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
|
return win.get_workspace() >= newWorkspaceIndex && win != source;
|
||||||
|
else
|
||||||
|
return win.get_workspace() >= newWorkspaceIndex;
|
||||||
|
});
|
||||||
|
|
||||||
|
// ... move them down one.
|
||||||
|
windows.forEach(function(win) {
|
||||||
|
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
|
||||||
|
true, time);
|
||||||
|
});
|
||||||
|
|
||||||
// Nab all the windows below us.
|
|
||||||
let windows = global.get_window_actors().filter(function(win) {
|
|
||||||
if (isWindow)
|
if (isWindow)
|
||||||
return win.get_workspace() >= newWorkspaceIndex && win != source;
|
// ... and bam, a workspace, good as new.
|
||||||
else
|
source.metaWindow.change_workspace_by_index(newWorkspaceIndex,
|
||||||
return win.get_workspace() >= newWorkspaceIndex;
|
true, time);
|
||||||
});
|
else if (source.shellWorkspaceLaunch) {
|
||||||
|
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
|
||||||
|
timestamp: time });
|
||||||
|
// This new workspace will be automatically removed if the application fails
|
||||||
|
// to open its first window within some time, as tracked by Shell.WindowTracker.
|
||||||
|
// Here, we only add a very brief timeout to avoid the _immediate_ removal of the
|
||||||
|
// workspace while we wait for the startup sequence to load.
|
||||||
|
Main.keepWorkspaceAlive(global.screen.get_workspace_by_index(newWorkspaceIndex),
|
||||||
|
WORKSPACE_KEEP_ALIVE_TIME);
|
||||||
|
}
|
||||||
|
|
||||||
// ... move them down one.
|
return true;
|
||||||
windows.forEach(function(win) {
|
} else {
|
||||||
win.meta_window.change_workspace_by_index(win.get_workspace() + 1,
|
return false;
|
||||||
true, time);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (isWindow)
|
|
||||||
// ... and bam, a workspace, good as new.
|
|
||||||
source.metaWindow.change_workspace_by_index(newWorkspaceIndex,
|
|
||||||
true, time);
|
|
||||||
else if (source.shellWorkspaceLaunch)
|
|
||||||
source.shellWorkspaceLaunch({ workspace: newWorkspaceIndex,
|
|
||||||
timestamp: time });
|
|
||||||
|
|
||||||
return true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
@ -670,8 +793,10 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
if (thumbnail.state > ThumbnailState.NORMAL)
|
if (thumbnail.state > ThumbnailState.NORMAL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (currentPos >= start && currentPos < start + count)
|
if (currentPos >= start && currentPos < start + count) {
|
||||||
|
thumbnail.workspaceRemoved();
|
||||||
this._setThumbnailState(thumbnail, ThumbnailState.REMOVING);
|
this._setThumbnailState(thumbnail, ThumbnailState.REMOVING);
|
||||||
|
}
|
||||||
|
|
||||||
currentPos++;
|
currentPos++;
|
||||||
}
|
}
|
||||||
@ -860,7 +985,7 @@ const ThumbnailsBox = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_allocate: function(actor, box, flags) {
|
_allocate: function(actor, box, flags) {
|
||||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||||
|
|
||||||
// See comment about this._background in _init()
|
// See comment about this._background in _init()
|
||||||
let themeNode = this._background.get_theme_node();
|
let themeNode = this._background.get_theme_node();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
|
|
||||||
const Clutter = imports.gi.Clutter;
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Gio = imports.gi.Gio;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Mainloop = imports.mainloop;
|
const Mainloop = imports.mainloop;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
@ -19,6 +20,7 @@ const WORKSPACE_SWITCH_TIME = 0.25;
|
|||||||
// Note that mutter has a compile-time limit of 36
|
// Note that mutter has a compile-time limit of 36
|
||||||
const MAX_WORKSPACES = 16;
|
const MAX_WORKSPACES = 16;
|
||||||
|
|
||||||
|
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
|
||||||
|
|
||||||
const CONTROLS_POP_IN_TIME = 0.1;
|
const CONTROLS_POP_IN_TIME = 0.1;
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
Name: 'WorkspacesView',
|
Name: 'WorkspacesView',
|
||||||
|
|
||||||
_init: function(workspaces) {
|
_init: function(workspaces) {
|
||||||
this.actor = new St.Group({ style_class: 'workspaces-view' });
|
this.actor = new St.Widget({ style_class: 'workspaces-view' });
|
||||||
|
|
||||||
// The actor itself isn't a drop target, so we don't want to pick on its area
|
// The actor itself isn't a drop target, so we don't want to pick on its area
|
||||||
this.actor.set_size(0, 0);
|
this.actor.set_size(0, 0);
|
||||||
@ -40,8 +42,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._spacing = node.get_length('spacing');
|
this._spacing = node.get_length('spacing');
|
||||||
this._updateWorkspaceActors(false);
|
this._updateWorkspaceActors(false);
|
||||||
}));
|
}));
|
||||||
this.actor.connect('notify::mapped',
|
|
||||||
Lang.bind(this, this._onMappedChanged));
|
|
||||||
|
|
||||||
this._width = 0;
|
this._width = 0;
|
||||||
this._height = 0;
|
this._height = 0;
|
||||||
@ -59,6 +59,11 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._zoomOut = false; // zoom to a larger area
|
this._zoomOut = false; // zoom to a larger area
|
||||||
this._inDrag = false; // dragging a window
|
this._inDrag = false; // dragging a window
|
||||||
|
|
||||||
|
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
|
||||||
|
this._updateExtraWorkspacesId =
|
||||||
|
this._settings.connect('changed::workspaces-only-on-primary',
|
||||||
|
Lang.bind(this, this._updateExtraWorkspaces));
|
||||||
|
|
||||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||||
this._workspaces = workspaces;
|
this._workspaces = workspaces;
|
||||||
|
|
||||||
@ -67,17 +72,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._workspaces[w].actor.reparent(this.actor);
|
this._workspaces[w].actor.reparent(this.actor);
|
||||||
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
||||||
|
|
||||||
this._extraWorkspaces = [];
|
this._updateExtraWorkspaces();
|
||||||
let monitors = Main.layoutManager.monitors;
|
|
||||||
let m = 0;
|
|
||||||
for (let i = 0; i < monitors.length; i++) {
|
|
||||||
if (i == Main.layoutManager.primaryIndex)
|
|
||||||
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
|
// Position/scale the desktop windows and their children after the
|
||||||
// workspaces have been created. This cannot be done first because
|
// workspaces have been created. This cannot be done first because
|
||||||
@ -88,6 +83,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
this._workspaces[w].zoomToOverview();
|
this._workspaces[w].zoomToOverview();
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||||
this._extraWorkspaces[w].zoomToOverview();
|
this._extraWorkspaces[w].zoomToOverview();
|
||||||
}));
|
}));
|
||||||
@ -98,14 +95,14 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._clipWidth, this._clipHeight);
|
this._clipWidth, this._clipHeight);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
this.scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
||||||
lower: 0,
|
lower: 0,
|
||||||
page_increment: 1,
|
page_increment: 1,
|
||||||
page_size: 1,
|
page_size: 1,
|
||||||
step_increment: 0,
|
step_increment: 0,
|
||||||
upper: this._workspaces.length });
|
upper: this._workspaces.length });
|
||||||
this._scrollAdjustment.connect('notify::value',
|
this.scrollAdjustment.connect('notify::value',
|
||||||
Lang.bind(this, this._onScroll));
|
Lang.bind(this, this._onScroll));
|
||||||
|
|
||||||
this._switchWorkspaceNotifyId =
|
this._switchWorkspaceNotifyId =
|
||||||
global.window_manager.connect('switch-workspace',
|
global.window_manager.connect('switch-workspace',
|
||||||
@ -119,8 +116,35 @@ const WorkspacesView = new Lang.Class({
|
|||||||
Lang.bind(this, this._dragBegin));
|
Lang.bind(this, this._dragBegin));
|
||||||
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
||||||
Lang.bind(this, this._dragEnd));
|
Lang.bind(this, this._dragEnd));
|
||||||
this._swipeScrollBeginId = 0;
|
},
|
||||||
this._swipeScrollEndId = 0;
|
|
||||||
|
_updateExtraWorkspaces: function() {
|
||||||
|
this._destroyExtraWorkspaces();
|
||||||
|
|
||||||
|
if (!this._settings.get_boolean('workspaces-only-on-primary'))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._extraWorkspaces = [];
|
||||||
|
let monitors = Main.layoutManager.monitors;
|
||||||
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
|
if (i == Main.layoutManager.primaryIndex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let ws = new Workspace.Workspace(null, i);
|
||||||
|
ws.setGeometry(monitors[i].x, monitors[i].y,
|
||||||
|
monitors[i].width, monitors[i].height);
|
||||||
|
global.overlay_group.add_actor(ws.actor);
|
||||||
|
this._extraWorkspaces.push(ws);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_destroyExtraWorkspaces: function() {
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (let m = 0; m < this._extraWorkspaces.length; m++)
|
||||||
|
this._extraWorkspaces[m].destroy();
|
||||||
|
this._extraWorkspaces = null;
|
||||||
},
|
},
|
||||||
|
|
||||||
setGeometry: function(x, y, width, height, spacing) {
|
setGeometry: function(x, y, width, height, spacing) {
|
||||||
@ -157,10 +181,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
return this._workspaces[active];
|
return this._workspaces[active];
|
||||||
},
|
},
|
||||||
|
|
||||||
getWorkspaceByIndex: function(index) {
|
|
||||||
return this._workspaces[index];
|
|
||||||
},
|
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||||
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||||
@ -171,6 +191,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
for (let w = 0; w < this._workspaces.length; w++)
|
for (let w = 0; w < this._workspaces.length; w++)
|
||||||
this._workspaces[w].zoomFromOverview();
|
this._workspaces[w].zoomFromOverview();
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
for (let w = 0; w < this._extraWorkspaces.length; w++)
|
||||||
this._extraWorkspaces[w].zoomFromOverview();
|
this._extraWorkspaces[w].zoomFromOverview();
|
||||||
},
|
},
|
||||||
@ -182,6 +204,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
syncStacking: function(stackIndices) {
|
syncStacking: function(stackIndices) {
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].syncStacking(stackIndices);
|
this._workspaces[i].syncStacking(stackIndices);
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].syncStacking(stackIndices);
|
this._extraWorkspaces[i].syncStacking(stackIndices);
|
||||||
},
|
},
|
||||||
@ -243,10 +267,8 @@ const WorkspacesView = new Lang.Class({
|
|||||||
for (let w = 0; w < this._workspaces.length; w++) {
|
for (let w = 0; w < this._workspaces.length; w++) {
|
||||||
let workspace = this._workspaces[w];
|
let workspace = this._workspaces[w];
|
||||||
if (this._animating || this._scrolling) {
|
if (this._animating || this._scrolling) {
|
||||||
workspace.hideWindowsOverlays();
|
|
||||||
workspace.actor.show();
|
workspace.actor.show();
|
||||||
} else {
|
} else {
|
||||||
workspace.showWindowsOverlays();
|
|
||||||
if (this._inDrag)
|
if (this._inDrag)
|
||||||
workspace.actor.visible = (Math.abs(w - active) <= 1);
|
workspace.actor.visible = (Math.abs(w - active) <= 1);
|
||||||
else
|
else
|
||||||
@ -262,7 +284,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._animatingScroll = true;
|
this._animatingScroll = true;
|
||||||
|
|
||||||
if (showAnimation) {
|
if (showAnimation) {
|
||||||
Tweener.addTween(this._scrollAdjustment, {
|
Tweener.addTween(this.scrollAdjustment, {
|
||||||
value: index,
|
value: index,
|
||||||
time: WORKSPACE_SWITCH_TIME,
|
time: WORKSPACE_SWITCH_TIME,
|
||||||
transition: 'easeOutQuad',
|
transition: 'easeOutQuad',
|
||||||
@ -272,7 +294,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this._scrollAdjustment.value = index;
|
this.scrollAdjustment.value = index;
|
||||||
this._animatingScroll = false;
|
this._animatingScroll = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -280,7 +302,7 @@ const WorkspacesView = new Lang.Class({
|
|||||||
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
|
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
|
||||||
let active = global.screen.get_active_workspace_index();
|
let active = global.screen.get_active_workspace_index();
|
||||||
|
|
||||||
Tweener.addTween(this._scrollAdjustment,
|
Tweener.addTween(this.scrollAdjustment,
|
||||||
{ upper: newNumWorkspaces,
|
{ upper: newNumWorkspaces,
|
||||||
time: WORKSPACE_SWITCH_TIME,
|
time: WORKSPACE_SWITCH_TIME,
|
||||||
transition: 'easeOutQuad'
|
transition: 'easeOutQuad'
|
||||||
@ -307,12 +329,12 @@ const WorkspacesView = new Lang.Class({
|
|||||||
},
|
},
|
||||||
|
|
||||||
_onDestroy: function() {
|
_onDestroy: function() {
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
this._destroyExtraWorkspaces();
|
||||||
this._extraWorkspaces[i].destroy();
|
this.scrollAdjustment.run_dispose();
|
||||||
this._scrollAdjustment.run_dispose();
|
|
||||||
Main.overview.disconnect(this._overviewShowingId);
|
Main.overview.disconnect(this._overviewShowingId);
|
||||||
Main.overview.disconnect(this._overviewShownId);
|
Main.overview.disconnect(this._overviewShownId);
|
||||||
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
||||||
|
this._settings.disconnect(this._updateExtraWorkspacesId);
|
||||||
|
|
||||||
if (this._inDrag)
|
if (this._inDrag)
|
||||||
this._dragEnd();
|
this._dragEnd();
|
||||||
@ -335,21 +357,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onMappedChanged: function() {
|
|
||||||
if (this.actor.mapped) {
|
|
||||||
let direction = Overview.SwipeScrollDirection.VERTICAL;
|
|
||||||
Main.overview.setScrollAdjustment(this._scrollAdjustment,
|
|
||||||
direction);
|
|
||||||
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
|
|
||||||
Lang.bind(this, this._swipeScrollBegin));
|
|
||||||
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
|
|
||||||
Lang.bind(this, this._swipeScrollEnd));
|
|
||||||
} else {
|
|
||||||
Main.overview.disconnect(this._swipeScrollBeginId);
|
|
||||||
Main.overview.disconnect(this._swipeScrollEndId);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
_dragBegin: function() {
|
_dragBegin: function() {
|
||||||
if (this._scrolling)
|
if (this._scrolling)
|
||||||
return;
|
return;
|
||||||
@ -371,6 +378,9 @@ const WorkspacesView = new Lang.Class({
|
|||||||
this._firstDragMotion = false;
|
this._firstDragMotion = false;
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
this._workspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||||
}
|
}
|
||||||
@ -384,15 +394,18 @@ const WorkspacesView = new Lang.Class({
|
|||||||
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++)
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
this._workspaces[i].setReservedSlot(null);
|
this._workspaces[i].setReservedSlot(null);
|
||||||
|
|
||||||
|
if (!this._extraWorkspaces)
|
||||||
|
return;
|
||||||
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
for (let i = 0; i < this._extraWorkspaces.length; i++)
|
||||||
this._extraWorkspaces[i].setReservedSlot(null);
|
this._extraWorkspaces[i].setReservedSlot(null);
|
||||||
},
|
},
|
||||||
|
|
||||||
_swipeScrollBegin: function() {
|
startSwipeScroll: function() {
|
||||||
this._scrolling = true;
|
this._scrolling = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_swipeScrollEnd: function(overview, result) {
|
endSwipeScroll: function(result) {
|
||||||
this._scrolling = false;
|
this._scrolling = false;
|
||||||
|
|
||||||
if (result == Overview.SwipeScrollResult.CLICK) {
|
if (result == Overview.SwipeScrollResult.CLICK) {
|
||||||
@ -441,7 +454,6 @@ const WorkspacesView = new Lang.Class({
|
|||||||
let dy = newY - currentY;
|
let dy = newY - currentY;
|
||||||
|
|
||||||
for (let i = 0; i < this._workspaces.length; i++) {
|
for (let i = 0; i < this._workspaces.length; i++) {
|
||||||
this._workspaces[i].hideWindowsOverlays();
|
|
||||||
this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
|
this._workspaces[i].actor.visible = Math.abs(i - adj.value) <= 1;
|
||||||
this._workspaces[i].actor.y += dy;
|
this._workspaces[i].actor.y += dy;
|
||||||
}
|
}
|
||||||
@ -462,6 +474,8 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||||
|
this.actor.connect('notify::mapped', Lang.bind(this, this._setupSwipeScrolling));
|
||||||
|
this.actor.connect('parent-set', Lang.bind(this, this._parentSet));
|
||||||
this.actor.set_clip_to_allocation(true);
|
this.actor.set_clip_to_allocation(true);
|
||||||
|
|
||||||
let controls = new St.Bin({ style_class: 'workspace-controls',
|
let controls = new St.Bin({ style_class: 'workspace-controls',
|
||||||
@ -478,22 +492,32 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
controls.connect('scroll-event',
|
controls.connect('scroll-event',
|
||||||
Lang.bind(this, this._onScrollEvent));
|
Lang.bind(this, this._onScrollEvent));
|
||||||
|
|
||||||
this._monitorIndex = Main.layoutManager.primaryIndex;
|
this._primaryIndex = Main.layoutManager.primaryIndex;
|
||||||
|
|
||||||
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
|
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
|
||||||
controls.add_actor(this._thumbnailsBox.actor);
|
controls.add_actor(this._thumbnailsBox.actor);
|
||||||
|
|
||||||
this.workspacesView = null;
|
this._workspacesViews = null;
|
||||||
|
this._primaryScrollAdjustment = null;
|
||||||
|
|
||||||
|
this._settings = new Gio.Settings({ schema: OVERRIDE_SCHEMA });
|
||||||
|
this._settings.connect('changed::workspaces-only-on-primary',
|
||||||
|
Lang.bind(this,
|
||||||
|
this._workspacesOnlyOnPrimaryChanged));
|
||||||
|
this._workspacesOnlyOnPrimaryChanged();
|
||||||
|
|
||||||
this._inDrag = false;
|
this._inDrag = false;
|
||||||
this._cancelledDrag = false;
|
this._cancelledDrag = false;
|
||||||
|
|
||||||
|
this._controlsInitiallyHovered = false;
|
||||||
this._alwaysZoomOut = false;
|
this._alwaysZoomOut = false;
|
||||||
this._zoomOut = false;
|
this._zoomOut = false;
|
||||||
this._zoomFraction = 0;
|
this._zoomFraction = 0;
|
||||||
|
|
||||||
this._updateAlwaysZoom();
|
this._updateAlwaysZoom();
|
||||||
|
|
||||||
|
// If we stop hiding the overview on layout changes, we will need to
|
||||||
|
// update the _workspacesViews here
|
||||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
||||||
|
|
||||||
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
|
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
|
||||||
@ -514,9 +538,25 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._windowDragBeginId = 0;
|
this._windowDragBeginId = 0;
|
||||||
this._windowDragCancelledId = 0;
|
this._windowDragCancelledId = 0;
|
||||||
this._windowDragEndId = 0;
|
this._windowDragEndId = 0;
|
||||||
|
this._notifyOpacityId = 0;
|
||||||
|
this._swipeScrollBeginId = 0;
|
||||||
|
this._swipeScrollEndId = 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
show: function() {
|
show: function() {
|
||||||
|
if(!this._alwaysZoomOut) {
|
||||||
|
let [mouseX, mouseY] = global.get_pointer();
|
||||||
|
let [x, y] = this._controls.get_transformed_position();
|
||||||
|
let [width, height] = this._controls.get_transformed_size();
|
||||||
|
let visibleWidth = this._controls.get_theme_node().get_length('visible-width');
|
||||||
|
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||||
|
if(rtl)
|
||||||
|
x = x + width - visibleWidth;
|
||||||
|
if(mouseX > x - 0.5 && mouseX < x + visibleWidth + 0.5 &&
|
||||||
|
mouseY > y - 0.5 && mouseY < y + height + 0.5)
|
||||||
|
this._controlsInitiallyHovered = true;
|
||||||
|
}
|
||||||
|
|
||||||
this._zoomOut = this._alwaysZoomOut;
|
this._zoomOut = this._alwaysZoomOut;
|
||||||
this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
|
this._zoomFraction = this._alwaysZoomOut ? 1 : 0;
|
||||||
this._updateZoom();
|
this._updateZoom();
|
||||||
@ -524,16 +564,7 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._controls.show();
|
this._controls.show();
|
||||||
this._thumbnailsBox.show();
|
this._thumbnailsBox.show();
|
||||||
|
|
||||||
this._workspaces = [];
|
this._updateWorkspacesViews();
|
||||||
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._monitorIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.workspacesView)
|
|
||||||
this.workspacesView.destroy();
|
|
||||||
this.workspacesView = new WorkspacesView(this._workspaces);
|
|
||||||
this._updateWorkspacesGeometry();
|
|
||||||
|
|
||||||
this._restackedNotifyId =
|
this._restackedNotifyId =
|
||||||
global.screen.connect('restacked',
|
global.screen.connect('restacked',
|
||||||
@ -564,10 +595,19 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._onRestacked();
|
this._onRestacked();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
zoomFromOverview: function() {
|
||||||
|
for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||||
|
this._workspacesViews[i].hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
this._controls.hide();
|
this._controls.hide();
|
||||||
this._thumbnailsBox.hide();
|
this._thumbnailsBox.hide();
|
||||||
|
|
||||||
|
if (!this._alwaysZoomOut)
|
||||||
|
this.zoomFraction = 0;
|
||||||
|
|
||||||
if (this._restackedNotifyId > 0){
|
if (this._restackedNotifyId > 0){
|
||||||
global.screen.disconnect(this._restackedNotifyId);
|
global.screen.disconnect(this._restackedNotifyId);
|
||||||
this._restackedNotifyId = 0;
|
this._restackedNotifyId = 0;
|
||||||
@ -597,12 +637,120 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._windowDragEndId = 0;
|
this._windowDragEndId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workspacesView.destroy();
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
this.workspacesView = null;
|
this._workspacesViews[i].destroy();
|
||||||
for (let w = 0; w < this._workspaces.length; w++) {
|
this._workspacesViews = null;
|
||||||
this._workspaces[w].disconnectAll();
|
|
||||||
this._workspaces[w].destroy();
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
|
for (let w = 0; w < this._workspaces[i].length; w++) {
|
||||||
|
this._workspaces[i][w].disconnectAll();
|
||||||
|
this._workspaces[i][w].destroy();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_setupSwipeScrolling: function() {
|
||||||
|
if (this._swipeScrollBeginId)
|
||||||
|
Main.overview.disconnect(this._swipeScrollBeginId);
|
||||||
|
this._swipeScrollBeginId = 0;
|
||||||
|
|
||||||
|
if (this._swipeScrollEndId)
|
||||||
|
Main.overview.disconnect(this._swipeScrollEndId);
|
||||||
|
this._swipeScrollEndId = 0;
|
||||||
|
|
||||||
|
if (!this.actor.mapped)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let direction = Overview.SwipeScrollDirection.VERTICAL;
|
||||||
|
Main.overview.setScrollAdjustment(this._scrollAdjustment,
|
||||||
|
direction);
|
||||||
|
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
|
this._workspacesViews[i].startSwipeScroll();
|
||||||
|
}));
|
||||||
|
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
|
||||||
|
Lang.bind(this, function(overview, result) {
|
||||||
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
|
this._workspacesViews[i].endSwipeScroll(result);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
_workspacesOnlyOnPrimaryChanged: function() {
|
||||||
|
this._workspacesOnlyOnPrimary = this._settings.get_boolean('workspaces-only-on-primary');
|
||||||
|
|
||||||
|
if (!Main.overview.visible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._updateWorkspacesViews();
|
||||||
|
},
|
||||||
|
|
||||||
|
_updateWorkspacesViews: function() {
|
||||||
|
if (this._workspacesViews)
|
||||||
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
|
this._workspacesViews[i].destroy();
|
||||||
|
|
||||||
|
if (this._workspaces)
|
||||||
|
for (let i = 0; i < this._workspaces.length; i++)
|
||||||
|
for (let w = 0; w < this._workspaces[i].length; w++)
|
||||||
|
this._workspaces[i][w].destroy();
|
||||||
|
|
||||||
|
this._workspacesViews = [];
|
||||||
|
this._workspaces = [];
|
||||||
|
let monitors = Main.layoutManager.monitors;
|
||||||
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
|
if (this._workspacesOnlyOnPrimary && i != this._primaryIndex)
|
||||||
|
continue; // we are only interested in the primary monitor
|
||||||
|
|
||||||
|
let monitorWorkspaces = [];
|
||||||
|
for (let w = 0; w < global.screen.n_workspaces; w++) {
|
||||||
|
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||||
|
monitorWorkspaces.push(new Workspace.Workspace(metaWorkspace, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._workspaces.push(monitorWorkspaces);
|
||||||
|
|
||||||
|
let view = new WorkspacesView(monitorWorkspaces);
|
||||||
|
if (this._workspacesOnlyOnPrimary || i == this._primaryIndex) {
|
||||||
|
this._scrollAdjustment = view.scrollAdjustment;
|
||||||
|
this._scrollAdjustment.connect('notify::value',
|
||||||
|
Lang.bind(this, this._scrollValueChanged));
|
||||||
|
this._setupSwipeScrolling();
|
||||||
|
}
|
||||||
|
this._workspacesViews.push(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._updateWorkspacesGeometry();
|
||||||
|
|
||||||
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
|
global.overlay_group.add_actor(this._workspacesViews[i].actor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_scrollValueChanged: function() {
|
||||||
|
if (this._workspacesOnlyOnPrimary)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||||
|
if (i == this._primaryIndex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
let adjustment = this._workspacesViews[i].scrollAdjustment;
|
||||||
|
// the adjustments work in terms of workspaces, so the
|
||||||
|
// values map directly
|
||||||
|
adjustment.value = this._scrollAdjustment.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPrimaryView: function() {
|
||||||
|
if (!this._workspacesViews)
|
||||||
|
return null;
|
||||||
|
if (this._workspacesOnlyOnPrimary)
|
||||||
|
return this._workspacesViews[0];
|
||||||
|
else
|
||||||
|
return this._workspacesViews[this._primaryIndex];
|
||||||
|
},
|
||||||
|
|
||||||
|
activeWorkspaceHasMaximizedWindows: function() {
|
||||||
|
return this._getPrimaryView().getActiveWorkspace().hasMaximizedWindows();
|
||||||
},
|
},
|
||||||
|
|
||||||
// zoomFraction property allows us to tween the controls sliding in and out
|
// zoomFraction property allows us to tween the controls sliding in and out
|
||||||
@ -659,7 +807,7 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
|
let controlsVisible = this._controls.get_theme_node().get_length('visible-width');
|
||||||
let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction;
|
let controlsReserved = controlsVisible * (1 - this._zoomFraction) + controlsNatural * this._zoomFraction;
|
||||||
|
|
||||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||||
if (rtl) {
|
if (rtl) {
|
||||||
childBox.x2 = controlsReserved;
|
childBox.x2 = controlsReserved;
|
||||||
childBox.x1 = childBox.x2 - controlsNatural;
|
childBox.x1 = childBox.x2 - controlsNatural;
|
||||||
@ -675,8 +823,37 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._updateWorkspacesGeometry();
|
this._updateWorkspacesGeometry();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_parentSet: function(actor, oldParent) {
|
||||||
|
if (oldParent && this._notifyOpacityId)
|
||||||
|
oldParent.disconnect(this._notifyOpacityId);
|
||||||
|
this._notifyOpacityId = 0;
|
||||||
|
|
||||||
|
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
let newParent = this.actor.get_parent();
|
||||||
|
if (!newParent)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// This is kinda hackish - we want the primary view to
|
||||||
|
// appear as parent of this.actor, though in reality it
|
||||||
|
// is added directly to overlay_group
|
||||||
|
this._notifyOpacityId = newParent.connect('notify::opacity',
|
||||||
|
Lang.bind(this, function() {
|
||||||
|
let opacity = this.actor.get_parent().opacity;
|
||||||
|
let primaryView = this._getPrimaryView();
|
||||||
|
if (!primaryView)
|
||||||
|
return;
|
||||||
|
primaryView.actor.opacity = opacity;
|
||||||
|
if (opacity == 0)
|
||||||
|
primaryView.actor.hide();
|
||||||
|
else
|
||||||
|
primaryView.actor.show();
|
||||||
|
}));
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
_updateWorkspacesGeometry: function() {
|
_updateWorkspacesGeometry: function() {
|
||||||
if (!this.workspacesView)
|
if (!this._workspacesViews)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
|
let fullWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
|
||||||
@ -690,15 +867,13 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
|
|
||||||
let [x, y] = this.actor.get_transformed_position();
|
let [x, y] = this.actor.get_transformed_position();
|
||||||
|
|
||||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||||
|
|
||||||
let clipWidth = width - controlsVisible;
|
let clipWidth = width - controlsVisible;
|
||||||
let clipHeight = (fullHeight / fullWidth) * clipWidth;
|
let clipHeight = (fullHeight / fullWidth) * clipWidth;
|
||||||
let clipX = rtl ? x + controlsVisible : x;
|
let clipX = rtl ? x + controlsVisible : x;
|
||||||
let clipY = y + (fullHeight - clipHeight) / 2;
|
let clipY = y + (fullHeight - clipHeight) / 2;
|
||||||
|
|
||||||
this.workspacesView.setClipRect(clipX, clipY, clipWidth, clipHeight);
|
|
||||||
|
|
||||||
if (this._zoomOut) {
|
if (this._zoomOut) {
|
||||||
width -= controlsNatural;
|
width -= controlsNatural;
|
||||||
if (rtl)
|
if (rtl)
|
||||||
@ -713,7 +888,28 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
let difference = fullHeight - height;
|
let difference = fullHeight - height;
|
||||||
y += difference / 2;
|
y += difference / 2;
|
||||||
|
|
||||||
this.workspacesView.setGeometry(x, y, width, height, difference);
|
|
||||||
|
let monitors = Main.layoutManager.monitors;
|
||||||
|
let m = 0;
|
||||||
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
|
if (i == this._primaryIndex) {
|
||||||
|
this._workspacesViews[m].setClipRect(clipX, clipY,
|
||||||
|
clipWidth, clipHeight);
|
||||||
|
this._workspacesViews[m].setGeometry(x, y, width, height,
|
||||||
|
difference);
|
||||||
|
m++;
|
||||||
|
} else if (!this._workspacesOnlyOnPrimary) {
|
||||||
|
this._workspacesViews[m].setClipRect(monitors[i].x,
|
||||||
|
monitors[i].y,
|
||||||
|
monitors[i].width,
|
||||||
|
monitors[i].height);
|
||||||
|
this._workspacesViews[m].setGeometry(monitors[i].x,
|
||||||
|
monitors[i].y,
|
||||||
|
monitors[i].width,
|
||||||
|
monitors[i].height, 0);
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onRestacked: function() {
|
_onRestacked: function() {
|
||||||
@ -725,12 +921,14 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
|
stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workspacesView.syncStacking(stackIndices);
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
|
this._workspacesViews[i].syncStacking(stackIndices);
|
||||||
|
|
||||||
this._thumbnailsBox.syncStacking(stackIndices);
|
this._thumbnailsBox.syncStacking(stackIndices);
|
||||||
},
|
},
|
||||||
|
|
||||||
_workspacesChanged: function() {
|
_workspacesChanged: function() {
|
||||||
let oldNumWorkspaces = this._workspaces.length;
|
let oldNumWorkspaces = this._workspaces[0].length;
|
||||||
let newNumWorkspaces = global.screen.n_workspaces;
|
let newNumWorkspaces = global.screen.n_workspaces;
|
||||||
let active = global.screen.get_active_workspace_index();
|
let active = global.screen.get_active_workspace_index();
|
||||||
|
|
||||||
@ -740,15 +938,24 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._updateAlwaysZoom();
|
this._updateAlwaysZoom();
|
||||||
this._updateZoom();
|
this._updateZoom();
|
||||||
|
|
||||||
if (this.workspacesView == null)
|
if (this._workspacesViews == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let lostWorkspaces = [];
|
let lostWorkspaces = [];
|
||||||
if (newNumWorkspaces > oldNumWorkspaces) {
|
if (newNumWorkspaces > oldNumWorkspaces) {
|
||||||
// Assume workspaces are only added at the end
|
let monitors = Main.layoutManager.monitors;
|
||||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
let m = 0;
|
||||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
for (let i = 0; i < monitors.length; i++) {
|
||||||
this._workspaces[w] = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
|
if (this._workspacesOnlyOnPrimaryChanged &&
|
||||||
|
i != this._primaryIndex)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 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[m++][w] =
|
||||||
|
new Workspace.Workspace(metaWorkspace, i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
|
this._thumbnailsBox.addThumbnails(oldNumWorkspaces, newNumWorkspaces - oldNumWorkspaces);
|
||||||
@ -759,25 +966,28 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
let removedNum = oldNumWorkspaces - newNumWorkspaces;
|
let removedNum = oldNumWorkspaces - newNumWorkspaces;
|
||||||
for (let w = 0; w < oldNumWorkspaces; w++) {
|
for (let w = 0; w < oldNumWorkspaces; w++) {
|
||||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||||
if (this._workspaces[w].metaWorkspace != metaWorkspace) {
|
if (this._workspaces[0][w].metaWorkspace != metaWorkspace) {
|
||||||
removedIndex = w;
|
removedIndex = w;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lostWorkspaces = this._workspaces.splice(removedIndex,
|
for (let i = 0; i < this._workspaces.length; i++) {
|
||||||
removedNum);
|
lostWorkspaces = this._workspaces[i].splice(removedIndex,
|
||||||
|
removedNum);
|
||||||
|
|
||||||
for (let l = 0; l < lostWorkspaces.length; l++) {
|
for (let l = 0; l < lostWorkspaces.length; l++) {
|
||||||
lostWorkspaces[l].disconnectAll();
|
lostWorkspaces[l].disconnectAll();
|
||||||
lostWorkspaces[l].destroy();
|
lostWorkspaces[l].destroy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
|
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.workspacesView.updateWorkspaces(oldNumWorkspaces,
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
newNumWorkspaces);
|
this._workspacesViews[i].updateWorkspaces(oldNumWorkspaces,
|
||||||
|
newNumWorkspaces);
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateZoom : function() {
|
_updateZoom : function() {
|
||||||
@ -789,7 +999,7 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
this._zoomOut = shouldZoom;
|
this._zoomOut = shouldZoom;
|
||||||
this._updateWorkspacesGeometry();
|
this._updateWorkspacesGeometry();
|
||||||
|
|
||||||
if (!this.workspacesView)
|
if (!this._workspacesViews)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Tweener.addTween(this,
|
Tweener.addTween(this,
|
||||||
@ -797,12 +1007,16 @@ const WorkspacesDisplay = new Lang.Class({
|
|||||||
time: WORKSPACE_SWITCH_TIME,
|
time: WORKSPACE_SWITCH_TIME,
|
||||||
transition: 'easeOutQuad' });
|
transition: 'easeOutQuad' });
|
||||||
|
|
||||||
this.workspacesView.updateWindowPositions();
|
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||||
|
this._workspacesViews[i].updateWindowPositions();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_onControlsHoverChanged: function() {
|
_onControlsHoverChanged: function() {
|
||||||
this._updateZoom();
|
if(!this._controls.hover)
|
||||||
|
this._controlsInitiallyHovered = false;
|
||||||
|
if(!this._controlsInitiallyHovered)
|
||||||
|
this._updateZoom();
|
||||||
},
|
},
|
||||||
|
|
||||||
_dragBegin: function() {
|
_dragBegin: function() {
|
||||||
|
@ -17,6 +17,7 @@ const XdndHandler = new Lang.Class({
|
|||||||
// Used as a drag actor in case we don't have a cursor window clone
|
// Used as a drag actor in case we don't have a cursor window clone
|
||||||
this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 });
|
this._dummy = new Clutter.Rectangle({ width: 1, height: 1, opacity: 0 });
|
||||||
global.stage.add_actor(this._dummy);
|
global.stage.add_actor(this._dummy);
|
||||||
|
Shell.util_set_hidden_from_pick(this._dummy, true);
|
||||||
this._dummy.hide();
|
this._dummy.hide();
|
||||||
|
|
||||||
// Mutter delays the creation of the output window as long
|
// Mutter delays the creation of the output window as long
|
||||||
@ -112,10 +113,11 @@ const XdndHandler = new Lang.Class({
|
|||||||
|
|
||||||
while (pickedActor) {
|
while (pickedActor) {
|
||||||
if (pickedActor._delegate && pickedActor._delegate.handleDragOver) {
|
if (pickedActor._delegate && pickedActor._delegate.handleDragOver) {
|
||||||
|
let [r, targX, targY] = pickedActor.transform_stage_point(x, y);
|
||||||
let result = pickedActor._delegate.handleDragOver(this,
|
let result = pickedActor._delegate.handleDragOver(this,
|
||||||
dragEvent.dragActor,
|
dragEvent.dragActor,
|
||||||
x,
|
targX,
|
||||||
y,
|
targY,
|
||||||
global.get_current_time());
|
global.get_current_time());
|
||||||
if (result != DND.DragMotionResult.CONTINUE)
|
if (result != DND.DragMotionResult.CONTINUE)
|
||||||
return;
|
return;
|
||||||
|
@ -30,11 +30,14 @@ hu
|
|||||||
id
|
id
|
||||||
it
|
it
|
||||||
ja
|
ja
|
||||||
ko
|
kk
|
||||||
kn
|
kn
|
||||||
|
ko
|
||||||
ku
|
ku
|
||||||
lt
|
lt
|
||||||
lv
|
lv
|
||||||
|
ml
|
||||||
|
mk
|
||||||
mr
|
mr
|
||||||
ms
|
ms
|
||||||
nb
|
nb
|
||||||
@ -47,6 +50,7 @@ pt
|
|||||||
pt_BR
|
pt_BR
|
||||||
ro
|
ro
|
||||||
ru
|
ru
|
||||||
|
si
|
||||||
sk
|
sk
|
||||||
sl
|
sl
|
||||||
sr
|
sr
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
data/gnome-shell.desktop.in.in
|
data/gnome-shell.desktop.in.in
|
||||||
|
data/gnome-shell-extension-prefs.desktop.in.in
|
||||||
data/org.gnome.shell.gschema.xml.in
|
data/org.gnome.shell.gschema.xml.in
|
||||||
|
js/extensionPrefs/main.js
|
||||||
js/gdm/loginDialog.js
|
js/gdm/loginDialog.js
|
||||||
js/gdm/powerMenu.js
|
js/gdm/powerMenu.js
|
||||||
js/misc/util.js
|
js/misc/util.js
|
||||||
@ -10,11 +12,12 @@ js/ui/calendar.js
|
|||||||
js/ui/contactDisplay.js
|
js/ui/contactDisplay.js
|
||||||
js/ui/dash.js
|
js/ui/dash.js
|
||||||
js/ui/dateMenu.js
|
js/ui/dateMenu.js
|
||||||
js/ui/docDisplay.js
|
|
||||||
js/ui/endSessionDialog.js
|
js/ui/endSessionDialog.js
|
||||||
js/ui/extensionSystem.js
|
js/ui/extensionSystem.js
|
||||||
js/ui/keyboard.js
|
js/ui/keyboard.js
|
||||||
|
js/ui/keyringPrompt.js
|
||||||
js/ui/lookingGlass.js
|
js/ui/lookingGlass.js
|
||||||
|
js/ui/main.js
|
||||||
js/ui/messageTray.js
|
js/ui/messageTray.js
|
||||||
js/ui/networkAgent.js
|
js/ui/networkAgent.js
|
||||||
js/ui/notificationDaemon.js
|
js/ui/notificationDaemon.js
|
||||||
@ -36,12 +39,14 @@ js/ui/status/volume.js
|
|||||||
js/ui/telepathyClient.js
|
js/ui/telepathyClient.js
|
||||||
js/ui/userMenu.js
|
js/ui/userMenu.js
|
||||||
js/ui/viewSelector.js
|
js/ui/viewSelector.js
|
||||||
|
js/ui/wanda.js
|
||||||
js/ui/windowAttentionHandler.js
|
js/ui/windowAttentionHandler.js
|
||||||
src/gvc/gvc-mixer-control.c
|
src/gvc/gvc-mixer-control.c
|
||||||
src/main.c
|
src/main.c
|
||||||
src/shell-app.c
|
src/shell-app.c
|
||||||
src/shell-app-system.c
|
src/shell-app-system.c
|
||||||
src/shell-global.c
|
src/shell-global.c
|
||||||
|
src/shell-keyring-prompt.c
|
||||||
src/shell-mobile-providers.c
|
src/shell-mobile-providers.c
|
||||||
src/shell-polkit-authentication-agent.c
|
src/shell-polkit-authentication-agent.c
|
||||||
src/shell-util.c
|
src/shell-util.c
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
data/gnome-shell.desktop.in
|
data/gnome-shell.desktop.in
|
||||||
data/gnome-shell-clock-preferences.desktop.in
|
data/gnome-shell-extension-prefs.desktop.in
|
||||||
|