Compare commits
380 Commits
Author | SHA1 | Date | |
---|---|---|---|
87c50eb495 | |||
be291ee4f9 | |||
e634b49859 | |||
4dddaefa41 | |||
cda60455f0 | |||
a42b8870b0 | |||
daa66a6de6 | |||
6c6aed84bc | |||
c59314acc1 | |||
dd3cc78be5 | |||
54b0b6eec5 | |||
41654b22b3 | |||
07cc60d65a | |||
a7f9dc5114 | |||
b5ae23d544 | |||
75347cb4f7 | |||
03a44b6ec2 | |||
17d2349c49 | |||
4e98c44052 | |||
0bef281d66 | |||
54af25ec24 | |||
86ab02f400 | |||
ae01cd143f | |||
2974b29f15 | |||
1b78dd662b | |||
c22264a0ca | |||
48c3e3f534 | |||
6ccc134ba6 | |||
9aa36d7851 | |||
3278f77739 | |||
5d24f48e3b | |||
573c1c86cc | |||
374c5967ba | |||
66b71a36ce | |||
e70fd5a57a | |||
4589ce4d78 | |||
d6197b0904 | |||
30fb2b0d99 | |||
5cdefc324d | |||
b222d0fe44 | |||
fe4fddf0d5 | |||
c675c93733 | |||
29485ff24b | |||
f6ed3d9f88 | |||
39a36cb510 | |||
ff5550c82b | |||
7d5ce1a159 | |||
c492415386 | |||
5616bbd45b | |||
e117aa5297 | |||
17ac1382df | |||
057a026ea4 | |||
6ce6e86318 | |||
492558a2d2 | |||
b78e00f372 | |||
c2cc504837 | |||
ac76940530 | |||
55d1c7e2ab | |||
fdf264ff64 | |||
e917b7ce0f | |||
ec6facb9e7 | |||
60f3c09f90 | |||
afdfd6cebc | |||
edd66c40d9 | |||
fc4bc5277a | |||
821768a414 | |||
522f3bf171 | |||
fb7400ab85 | |||
210128f22b | |||
78ae233823 | |||
8f25da7cea | |||
7f52fdb435 | |||
0ba05b29b9 | |||
ef8123e3a2 | |||
257e1f3096 | |||
6441ae77d9 | |||
3f0938072f | |||
2fe06a28aa | |||
38750ba798 | |||
b4c01f8905 | |||
104d70c88e | |||
133a350f2f | |||
496ab55357 | |||
a391758e31 | |||
eaf8ad4949 | |||
2f583bdcf3 | |||
db19012a41 | |||
62be46884e | |||
3f2e6a48a9 | |||
ff124e5f74 | |||
c07421c195 | |||
de8348d3b9 | |||
184df8a853 | |||
12768a147c | |||
94161cea37 | |||
52a4ef7cf7 | |||
3432f71500 | |||
8282aa6c24 | |||
59f9eaa1c9 | |||
4433b735c4 | |||
9cd30fa6b5 | |||
2c7bbfb500 | |||
51a1d23bf9 | |||
c02e6e82bc | |||
e37a3fa7e6 | |||
e23c2ffecc | |||
744f11d045 | |||
b7eb1f3e8b | |||
3f28091e52 | |||
b4ee86955d | |||
8b866efe92 | |||
fb61ab8df7 | |||
990956ece7 | |||
414b592d53 | |||
751154d9da | |||
29addc499c | |||
caa98de581 | |||
1fd1ec4312 | |||
f4607626e4 | |||
b494c15e4b | |||
3c0defa125 | |||
f2df4d95de | |||
fabcf20e06 | |||
b9510b9ab7 | |||
52a2ebad04 | |||
89a2dc71fc | |||
adb0de43d8 | |||
e2a811a720 | |||
5bcafc5c17 | |||
2d24536caf | |||
b088c4086b | |||
3c58f4abd3 | |||
e2a9b27b2b | |||
fcd5f06c09 | |||
6d93c8b3fd | |||
2663e1be5d | |||
0fa6be4614 | |||
46163a6607 | |||
645ef093f7 | |||
7551e134da | |||
5bec5fb6cb | |||
c176af4da5 | |||
2631f03108 | |||
525c71658b | |||
10e5778deb | |||
6512a5fd6b | |||
1af40b1345 | |||
0418b68051 | |||
a7283864e8 | |||
4950bad2a7 | |||
470ac0eae3 | |||
87abbf9b20 | |||
3e7e88cd5f | |||
b7e1539699 | |||
8492f2ba24 | |||
737f4eb1c1 | |||
58191ea66b | |||
1f786df462 | |||
fa4c481aed | |||
d555fd7883 | |||
fe7ece1f5a | |||
2bb3aed729 | |||
488a42696c | |||
f43ff45683 | |||
bde1451896 | |||
fff2ca6f26 | |||
bec57a6cee | |||
a012ca4fac | |||
3ba49b0a50 | |||
314aa024b5 | |||
598f750859 | |||
8057848458 | |||
e80c28a530 | |||
5d05b66902 | |||
59634b2cf5 | |||
7c3892f5a2 | |||
19406a238b | |||
d6146197dd | |||
38f241479c | |||
aa45999824 | |||
3b7593ed7f | |||
f959cafb36 | |||
e92d204d42 | |||
f543161234 | |||
9cc1017912 | |||
fc719c19f9 | |||
ad97fc6855 | |||
407dc74502 | |||
e5e764b402 | |||
65ad65fe52 | |||
8d09d20510 | |||
5a5b04b2b0 | |||
3113bac8e6 | |||
9217f2c916 | |||
32a49b7846 | |||
12ef034b7b | |||
e70e4a21f2 | |||
7826fb4f04 | |||
8f1b8909dc | |||
3f7a989d38 | |||
4d3fd7598d | |||
620e3cef20 | |||
812a61939e | |||
793c6c2f7b | |||
f8f4d0f646 | |||
3a92aa751f | |||
6882273aa0 | |||
3b0197620f | |||
f6240e114c | |||
0f3c129b95 | |||
6f87b01c47 | |||
32110a9866 | |||
ba459f4d20 | |||
d868e6bfaf | |||
9f3499a7c3 | |||
ccec7732a7 | |||
3b980a173f | |||
246139f90b | |||
4e85fb7d8d | |||
ab32411b0c | |||
477f28a6bd | |||
96ef0a178d | |||
ab603e7ef7 | |||
d52104a62a | |||
8d8d1cfdd6 | |||
5451751513 | |||
92ae26bb9f | |||
3c8ee0c8cb | |||
20f76b8118 | |||
d8eeeead18 | |||
5452162bc3 | |||
a4adcba405 | |||
66da594382 | |||
aa426842f2 | |||
ed53a45228 | |||
2ddbcb2369 | |||
61a58ff3c9 | |||
638aee65c0 | |||
f21c49f8da | |||
583d2cb4e4 | |||
aa70dcfc8f | |||
ffb61c425b | |||
858cf5e0c9 | |||
881dd4666e | |||
c4aeaf7fe8 | |||
ea1f5a8fc6 | |||
7f1e420a0a | |||
1272eaf07f | |||
2fe760cc4b | |||
df3a50bae8 | |||
0db3605f33 | |||
173fa92116 | |||
02ca58c1eb | |||
4a22fe58bf | |||
3fc478a14b | |||
203bc674fe | |||
a4a9f0a04c | |||
918e7fffeb | |||
e1648de661 | |||
f7c94e6343 | |||
2fba8e29e0 | |||
de1bb4e203 | |||
b4680a5c25 | |||
d44f40d105 | |||
8d5771e302 | |||
fb31f99aed | |||
b97f3a9ecf | |||
ac22172a6e | |||
57367380f5 | |||
7101cc3170 | |||
7051411be7 | |||
bb8397b9b1 | |||
bb8fa61cb4 | |||
10147ee331 | |||
3779ac2c8a | |||
bdad4db9ec | |||
36c69124f7 | |||
7c8c811134 | |||
ccfc9f3ab0 | |||
d163b92e0b | |||
887a21afb9 | |||
634adc9f71 | |||
974f01cef7 | |||
ef9ade3548 | |||
24fdb73b44 | |||
ba06a87ba8 | |||
e6be483755 | |||
a36bfced47 | |||
4faf421d5a | |||
a739455414 | |||
73f6e75d8d | |||
17e7f8057a | |||
b62c157680 | |||
816f5162f9 | |||
9d8f8277aa | |||
cca14053a4 | |||
427790f005 | |||
17845bf71e | |||
452f5ab3ba | |||
335744e78a | |||
c9e24439b2 | |||
61c697b6db | |||
3227d4f3ed | |||
7e27afb645 | |||
9ba4790b4d | |||
3a26f7f4d5 | |||
8b99617513 | |||
587655f063 | |||
7e9ecf4eb2 | |||
5413010c60 | |||
7d13cf1587 | |||
24cd13935a | |||
1ae7dbec67 | |||
2b0a2ab3bc | |||
4ed0f3e5f0 | |||
9cacc703dd | |||
9ae70c6519 | |||
02b38fed49 | |||
b2a65f809f | |||
2931869522 | |||
11d8640ba6 | |||
65ff947b5e | |||
2dd7db4808 | |||
1d7354696e | |||
cbceac4c8a | |||
297877fbe2 | |||
0d92451c49 | |||
c8a58dcb69 | |||
a4dea25d76 | |||
bfb0235fc6 | |||
6dcc3d637f | |||
9bb4d17e31 | |||
9df09db5fe | |||
d8e28ec274 | |||
d3905734c1 | |||
8fe7f923ec | |||
933f38390b | |||
a4e019442f | |||
d1c4e60636 | |||
765d0228c0 | |||
2d2020a20d | |||
03ab282f67 | |||
7f94cb1cad | |||
a2a303bd72 | |||
d34bf9a14d | |||
68faba6bde | |||
5c5b9cfd96 | |||
9d683f4767 | |||
f2912bad95 | |||
c8adfe0131 | |||
8b7e637e74 | |||
43cffd7c4a | |||
f3dad3765e | |||
70c25141fc | |||
b1b81a2672 | |||
46197bf262 | |||
58ec409e7f | |||
c2d68599de | |||
65f00f3af2 | |||
6544326ffd | |||
a23c206ccb | |||
1b152e6bd0 | |||
d9624d9882 | |||
178b8471cc | |||
719d2092a7 | |||
2f3a4675da | |||
9513be664b | |||
64d8b7853a | |||
4174e57c13 | |||
88b395599a | |||
b6d682c92c | |||
3b02894341 | |||
f3feb13dfe | |||
114d8d0aba | |||
503a843bb3 | |||
c4d91aff40 | |||
2ffe5faf6e | |||
5d2a03aa82 | |||
f4c83d1221 | |||
100e91714b |
41
COPYING
41
COPYING
@ -1,12 +1,12 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
@ -15,7 +15,7 @@ software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
@ -55,8 +55,8 @@ patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
@ -168,7 +168,7 @@ access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
@ -225,7 +225,7 @@ impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
||||
|
155
NEWS
155
NEWS
@ -1,3 +1,158 @@
|
||||
3.12.0
|
||||
======
|
||||
* gdm: Reset greeter when coming back to login screen [Jasper; #726989]
|
||||
|
||||
Contributors:
|
||||
Jasper St. Pierre
|
||||
|
||||
Translations:
|
||||
Daniel Martinez [an], Yuri Myasoedov [ru], Inaki Larranaga Murgoitio [eu],
|
||||
Abderrahim Kitouni [ar], Praveen Illa [te], Matej Urbančič [sl],
|
||||
Chao-Hsiung Liao [zh_HK, zh_TW], Frédéric Péters [fr],
|
||||
Мирослав Николић [sr, sr@latin], Ask H. Larsen [da], Kenneth Nielsen [da],
|
||||
Jiro Matsuzawa [ja], Dušan Kazik [sk]
|
||||
|
||||
3.11.92
|
||||
=======
|
||||
* calendar: Grab key focus after changing day [Volker; #725606]
|
||||
* gdm: Don't load user list if disabled [Florian; #725905]
|
||||
* Don't show network-offline in the top bar [Jasper; #725340]
|
||||
* Improve radial shade effect of modal dialogs [Giovanni; #725830]
|
||||
* Fix broken suspend-on-idle functionality [Giovanni; #712706]
|
||||
* Close wifi selection dialog when device disappears [Giovanni; #723935]
|
||||
* Don't close chats when pressing Escape [Giovanni; #724178]
|
||||
* Improve smartcard support in login/lock screen [Ray; #726262, #726263]
|
||||
* Wake up screen when resuming from suspend [Giovanni; #726378]
|
||||
* Make bluetooth and location items insensitive when locked [Florian; #726319]
|
||||
* Don't show bluetooth icon when there is no adapter [Giovanni; #725057]
|
||||
* Make sure to keep the OSK on top of modal dialogs [Rui; #719451]
|
||||
* Misc. bug fixes and cleanups [Giovanni, Ray, Adel, Daniel, Jasper, Florian;
|
||||
#725832, #725958, #722149, #724977, #724798, #725020, #723976, #726119,
|
||||
#726238, #585500, #704844, #726323, #726322, #726120, #726414]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Daniel Drake, Adel Gadllah, Rui Matos, Florian Müllner,
|
||||
Volker Sobek, Jasper St. Pierre, Ray Strode
|
||||
|
||||
Translations:
|
||||
Fabio Tomat [fur], Rafael Ferreira [pt_BR], Fran Diéguez [gl],
|
||||
Marek Černocký [cs], Baurzhan Muftakhidinov [kk], Andika Triwidada [id],
|
||||
A S Alam [pa], Rūdolfs Mazurs [lv], Wylmer Wang [zh_CN],
|
||||
Aurimas Černius [lt], Cheng-Chia Tseng [zh_TW], Stas Solovey [ru],
|
||||
Tiagosdot [pt], Benjamin Steinwender [de], Frédéric Peters [fr],
|
||||
Daniel Korostil [uk], Yaron Shahrabani [he], Ville-Pekka Vainio [fi],
|
||||
maria thukididu [el], Victor Ibragimov [tg], Kjartan Maraas [nb],
|
||||
Gábor Kelemen [hu], Ask H. Larsen [da]
|
||||
|
||||
3.11.91
|
||||
=======
|
||||
* Don't use network profile name in menu [Giovanni; #725586]
|
||||
* calendar: Make date label clickable to return to current date [Vit; #641366]
|
||||
* Misc. bug fixes [Florian, Zeeshan, Adel, Jasper, Dan, Volker; #724813,
|
||||
#724686, #725082, #724870, #724779, #725533]
|
||||
|
||||
Contributors:
|
||||
Zeeshan Ali (Khattak), Giovanni Campagna, Piotr Drąg, Adel Gadllah,
|
||||
Florian Müllner, Volker Sobek, Vit Stanislav, Jasper St. Pierre, Dan Williams
|
||||
|
||||
Translations:
|
||||
Victor Ibragimov [tg], Aurimas Černius [lt], Dimitris Spingos [el],
|
||||
Andika Triwidada [id], Rafael Ferreira [pt_BR], Daniel Mustieles [es],
|
||||
Baurzhan Muftakhidinov [kk], Marek Černocký [cs], Ihar Hrachyshka [be],
|
||||
eternalhui [zh_CN], Yosef Or Boczko [he], Fran Diéguez [gl],
|
||||
Khaled Hosny [ar], Ville-Pekka Vainio [fi], Piotr Drąg [pl],
|
||||
Kjartan Maraas [nb], Changwoo Ryu [ko]
|
||||
|
||||
3.11.90
|
||||
=======
|
||||
* Stop showing two bluetooth entries [Giovanni; #709353]
|
||||
* Improve styling of login/lock screen [Reda; #723833]
|
||||
* Fix magnifier crosshairs [Magdalen; #723709]
|
||||
* Make NetworkManager support optional [Michael; #669495]
|
||||
* Make middle-click open a new instance [Florian; #695010]
|
||||
* Scale the UI on high resolution displays [Cosimo, Adel; #705410, #724607]
|
||||
* Remove notification counter on screen shield [Carlos; #709275]
|
||||
* Improve app picker transition [Carlos; #722331]
|
||||
* Add geolocation indicator to status menu [Zeeshan; #723684]
|
||||
* Improve timestamps in chat notifications [Carlos; #708031, #715158]
|
||||
* Improve network menus [Giovanni; #723570]
|
||||
* Add "VPN Setting" item to VPN submenu [Giovanni; #709167]
|
||||
* Improve appearance of disclosure arrows [Carlos; #720206]
|
||||
* Add GSetting key to disable version validation of extensions [Adel; #724683]
|
||||
* Delay auto-removing empty workspaces [Florian; #709064]
|
||||
* Offer offline updates in the shutdown dialog [Kalev; #722898]
|
||||
* Animate tile previews [Florian; #665758]
|
||||
* Misc. bug fixes and cleanups [Giovanni, Ryan, Debarshi, Florian; #709128,
|
||||
#722342, #723661, #724184, #724256, #724293, #724305, #722554, #724282,
|
||||
#724690, #722928]
|
||||
|
||||
Contributors:
|
||||
Zeeshan Ali (Khattak), Magdalen Berns, Michael Biebl, Giovanni Campagna,
|
||||
Cosimo Cecchi, Adel Gadllah, Reda Lazri, Kalev Lember, Ryan Lortie,
|
||||
Florian Müllner, Debarshi Ray, Carlos Soriano, Jasper St. Pierre,
|
||||
Colin Walters
|
||||
|
||||
Translations:
|
||||
Victor Ibragimov [tg], Daniel Mustieles [es], Khaled Hosny [ar],
|
||||
Enrico Nicoletto [pt_BR], Yosef Or Boczko [he], Fran Diéguez [gl],
|
||||
Marek Černocký [cs], Baurzhan Muftakhidinov [kk], Jorge Pérez Pérez [an],
|
||||
Kjartan Maraas [nb], David Lüder [de], Daniel Korostil [uk], ngoswami [as],
|
||||
Rafael Ferreira [pt_BR]
|
||||
|
||||
3.11.5
|
||||
======
|
||||
* Fix extension preference tool [Florian; #722334]
|
||||
* Fix keyboard activation of legacy tray icons [Giovanni; #721267]
|
||||
* Add radial background shade for modal dialogs [Giovanni; #669798]
|
||||
* Show attached modal windows in the overview [Giovanni; #650843]
|
||||
* Add support for desktop actions [Giovanni; #669603]
|
||||
* Indicate in system status when location service is used [Zeeshan; #709372]
|
||||
* Add support for extended app folder schema [Jasper; #723179]
|
||||
* Show status icon for wired network connections [Jasper; #708966]
|
||||
* Indicate airplane mode in network selection dialog [Giovanni; #709128]
|
||||
* Misc bug fixes and cleanups [Florian, Sebastian, Giovanni, Tim, Matt, Jasper;
|
||||
#722417, #722494, #722547, #722593, #722434, #722787, #722690, #722840,
|
||||
#722660, #722812, #723197, #722927, #723306, #723308, #723523, #709685,
|
||||
#723570]
|
||||
|
||||
Contributors:
|
||||
Zeeshan Ali (Khattak), Magdalen Berns, Giovanni Campagna, William Jon McCann,
|
||||
Sebastian Keller, Tim Lunn, Florian Müllner, Carlos Soriano,
|
||||
Jasper St. Pierre, Rico Tzschichholz, Matt Watson
|
||||
|
||||
Translations:
|
||||
Marek Černocký [cs], Mattias Põldaru [et], Tong Hui [zh_CN],
|
||||
Victor Ibragimov [tg], Enrico Nicoletto [pt_BR], Daniel Mustieles [es],
|
||||
Fran Diéguez [gl], Kjartan Maraas [nb], Nilamdyuti Goswami [as],
|
||||
Aurimas Černius [lt], Stas Solovey [ru], Yosef Or Boczko [he],
|
||||
Jorge Pérez Pérez [an], Dimitris Spingos [el], Baurzhan Muftakhidinov [kk],
|
||||
Chao-Hsiung Liao [zh_HK, zh_TW], Shankar Prasad [kn], Yaron Shahrabani [he],
|
||||
Andika Triwidada [id]
|
||||
|
||||
3.11.4
|
||||
======
|
||||
* Fix removal of workspacaes that are not at the end [Giovanni; #721417]
|
||||
* Allow session mode to be specified in the environment [Ray; #720894]
|
||||
* Special-case launching of terminals [Debarshi; #695010]
|
||||
* Always show arrow if app switcher is scrollable [Jonh; #711467]
|
||||
* Implement new app folders system [Jasper; #722117]
|
||||
* Remove arrow from background menu [Tarun; #699608]
|
||||
* Misc bug fixes and cleanups [Giovanni, Andika, Florian, Ray; #721039,
|
||||
#721439, #721507, #721629, #721868, #722210]
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Piotr Drąg, Tarun Kumar Joshi, Florian Müllner,
|
||||
Debarshi Ray, Jasper St. Pierre, Ray Strode, Andika Triwidada, Jonh Wendell
|
||||
|
||||
Translations:
|
||||
Dušan Kazik [sk], Tong Hui [zh_CN], Benjamin Steinwender [de],
|
||||
Matej Urbančič [sl], Jorge Pérez Pérez [an], Kjartan Maraas [nb],
|
||||
Milo Casagrande [it], Rafael Ferreira [pt_BR], Marek Černocký [cs],
|
||||
Daniel Mustieles [es], Adorilson Bezerra [pt_BR], Christian Kirbach [de],
|
||||
Aurimas Černius [lt], Andika Triwidada [id], Baurzhan Muftakhidinov [kk],
|
||||
Victor Ibragimov [tg], Yosef Or Boczko [he], Dimitris Spingos [el],
|
||||
Fran Diéguez [gl]
|
||||
|
||||
3.11.3
|
||||
======
|
||||
* Fix fade effect of desktop icons [Florian; #707671]
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
|
||||
srcdir=`dirname $0`
|
||||
|
@ -13,9 +13,7 @@
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors:
|
||||
* Jasper St. Pierre <jstpierre@mecheye.net>
|
||||
@ -43,6 +41,8 @@
|
||||
|
||||
#define PLUGIN_API_VERSION 5
|
||||
|
||||
#define EXTENSION_DISABLE_VERSION_CHECK_KEY "disable-extension-version-validation"
|
||||
|
||||
typedef struct {
|
||||
GDBusProxy *proxy;
|
||||
} PluginData;
|
||||
@ -833,6 +833,16 @@ plugin_get_shell_version (PluginObject *obj,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plugin_get_version_validation_enabled (PluginObject *obj,
|
||||
NPVariant *result)
|
||||
{
|
||||
gboolean is_enabled = !g_settings_get_boolean (obj->settings, EXTENSION_DISABLE_VERSION_CHECK_KEY);
|
||||
BOOLEAN_TO_NPVARIANT(is_enabled, *result);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define METHODS \
|
||||
METHOD (list_extensions) \
|
||||
METHOD (get_info) \
|
||||
@ -852,6 +862,8 @@ static NPIdentifier api_version_id;
|
||||
static NPIdentifier shell_version_id;
|
||||
static NPIdentifier onextension_changed_id;
|
||||
static NPIdentifier onrestart_id;
|
||||
static NPIdentifier version_validation_enabled_id;
|
||||
|
||||
|
||||
static bool
|
||||
plugin_object_has_method (NPObject *npobj,
|
||||
@ -894,7 +906,8 @@ plugin_object_has_property (NPObject *npobj,
|
||||
return (name == onextension_changed_id ||
|
||||
name == onrestart_id ||
|
||||
name == api_version_id ||
|
||||
name == shell_version_id);
|
||||
name == shell_version_id ||
|
||||
name == version_validation_enabled_id);
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -912,6 +925,8 @@ plugin_object_get_property (NPObject *npobj,
|
||||
return plugin_get_api_version (obj, result);
|
||||
else if (name == shell_version_id)
|
||||
return plugin_get_shell_version (obj, result);
|
||||
else if (name == version_validation_enabled_id)
|
||||
return plugin_get_version_validation_enabled (obj, result);
|
||||
else if (name == onextension_changed_id)
|
||||
{
|
||||
if (obj->listener)
|
||||
@ -990,6 +1005,7 @@ init_methods_and_properties (void)
|
||||
/* this is the JS public API; it is manipulated through NPIdentifiers for speed */
|
||||
api_version_id = funcs.getstringidentifier ("apiVersion");
|
||||
shell_version_id = funcs.getstringidentifier ("shellVersion");
|
||||
version_validation_enabled_id = funcs.getstringidentifier ("versionValidationEnabled");
|
||||
|
||||
get_info_id = funcs.getstringidentifier ("getExtensionInfo");
|
||||
list_extensions_id = funcs.getstringidentifier ("listExtensions");
|
||||
|
54
configure.ac
54
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.11.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.12.0],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@ -73,10 +73,10 @@ AS_IF([test x$enable_systemd != xno], [
|
||||
|
||||
AC_MSG_RESULT($enable_systemd)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.13.4
|
||||
CLUTTER_MIN_VERSION=1.15.90
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=1.39.0
|
||||
MUTTER_MIN_VERSION=3.11.1
|
||||
MUTTER_MIN_VERSION=3.12.0
|
||||
GTK_MIN_VERSION=3.7.9
|
||||
GIO_MIN_VERSION=2.37.0
|
||||
LIBECAL_MIN_VERSION=3.5.3
|
||||
@ -105,9 +105,7 @@ SHARED_PCS="gio-unix-2.0 >= $GIO_MIN_VERSION
|
||||
libcanberra libcanberra-gtk3
|
||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||
polkit-agent-1 >= $POLKIT_MIN_VERSION
|
||||
libnm-glib libnm-util >= $NETWORKMANAGER_MIN_VERSION
|
||||
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
|
||||
libsecret-unstable gcr-base-3 >= $GCR_MIN_VERSION"
|
||||
gcr-base-3 >= $GCR_MIN_VERSION"
|
||||
if test x$have_systemd = xyes; then
|
||||
SHARED_PCS="${SHARED_PCS} libsystemd-journal"
|
||||
fi
|
||||
@ -182,6 +180,38 @@ if test "$langinfo_ok" = "yes"; then
|
||||
[Define if _NL_TIME_FIRST_WEEKDAY is available])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(networkmanager,
|
||||
AS_HELP_STRING([--disable-networkmanager],
|
||||
[disable NetworkManager support @<:@default=auto@:>@]),,
|
||||
[enable_networkmanager=auto])
|
||||
|
||||
if test "x$enable_networkmanager" != "xno"; then
|
||||
PKG_CHECK_MODULES(NETWORKMANAGER,
|
||||
[libnm-glib
|
||||
libnm-util >= $NETWORKMANAGER_MIN_VERSION
|
||||
libnm-gtk >= $NETWORKMANAGER_MIN_VERSION
|
||||
libsecret-unstable],
|
||||
[have_networkmanager=yes],
|
||||
[have_networkmanager=no])
|
||||
|
||||
GNOME_SHELL_CFLAGS="$GNOME_SHELL_CFLAGS $NETWORKMANAGER_CFLAGS"
|
||||
GNOME_SHELL_LIBS="$GNOME_SHELL_LIBS $NETWORKMANAGER_LIBS"
|
||||
else
|
||||
have_networkmanager="no (disabled)"
|
||||
fi
|
||||
|
||||
if test "x$have_networkmanager" = "xyes"; then
|
||||
AC_DEFINE(HAVE_NETWORKMANAGER, [1], [Define if we have NetworkManager])
|
||||
AC_SUBST([HAVE_NETWORKMANAGER], [1])
|
||||
else
|
||||
if test "x$enable_networkmanager" = "xyes"; then
|
||||
AC_MSG_ERROR([Couldn't find NetworkManager.])
|
||||
fi
|
||||
AC_SUBST([HAVE_NETWORKMANAGER], [0])
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(HAVE_NETWORKMANAGER, test "$have_networkmanager" = "yes")
|
||||
|
||||
# Sets GLIB_GENMARSHAL and GLIB_MKENUMS
|
||||
AM_PATH_GLIB_2_0()
|
||||
|
||||
@ -223,3 +253,15 @@ AC_CONFIG_FILES([
|
||||
man/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
||||
echo "
|
||||
Build configuration:
|
||||
|
||||
Prefix: ${prefix}
|
||||
Source code location: ${srcdir}
|
||||
Compiler: ${CC}
|
||||
Compiler Warnings: $enable_compile_warnings
|
||||
|
||||
Support for NetworkManager: $have_networkmanager
|
||||
Support for GStreamer recording: $build_recorder
|
||||
"
|
||||
|
@ -39,6 +39,7 @@ dist_theme_DATA = \
|
||||
theme/filter-selected-rtl.svg \
|
||||
theme/gnome-shell.css \
|
||||
theme/logged-in-indicator.svg \
|
||||
theme/menu-arrow-symbolic.svg \
|
||||
theme/message-tray-background.png \
|
||||
theme/more-results.svg \
|
||||
theme/noise-texture.png \
|
||||
|
@ -2,7 +2,7 @@
|
||||
Type=Application
|
||||
_Name=GNOME Shell (wayland compositor)
|
||||
_Comment=Window management and application launching
|
||||
Exec=@bindir@/mutter-launch -- gnome-shell-wayland --wayland
|
||||
Exec=@bindir@/mutter-launch -- gnome-shell-wayland --wayland --display-server
|
||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||
X-GNOME-Bugzilla-Product=gnome-shell
|
||||
X-GNOME-Bugzilla-Component=general
|
||||
|
@ -13,12 +13,21 @@
|
||||
</key>
|
||||
<key name="enabled-extensions" type="as">
|
||||
<default>[]</default>
|
||||
<_summary>Uuids of extensions to enable</_summary>
|
||||
<_summary>UUIDs of extensions to enable</_summary>
|
||||
<_description>
|
||||
GNOME Shell extensions have a uuid property; this key lists extensions
|
||||
GNOME Shell extensions have a UUID property; this key lists extensions
|
||||
which should be loaded. Any extension that wants to be loaded needs
|
||||
to be in this list. You can also manipulate this list with the
|
||||
EnableExtension and DisableExtension DBus methods on org.gnome.Shell.
|
||||
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="disable-extension-version-validation" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Disables the validation of extension version compatibility</_summary>
|
||||
<_description>
|
||||
GNOME Shell will only load extensions that claim to support the current
|
||||
running version. Enabling this option will disable this check and try to
|
||||
load all extensions regardless of the versions they claim to support.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="favorite-apps" type="as">
|
||||
@ -29,14 +38,6 @@
|
||||
will be displayed in the favorites area.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="app-folder-categories" type="as">
|
||||
<default>[ 'Utilities', 'Sundry' ]</default>
|
||||
<_summary>List of categories that should be displayed as folders</_summary>
|
||||
<_description>
|
||||
Each category name in this list will be represented as folder in the
|
||||
application view, rather than being displayed inline in the main view.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="app-picker-view" type="u">
|
||||
<default>0</default>
|
||||
<summary>App Picker View</summary>
|
||||
@ -54,10 +55,10 @@
|
||||
</key>
|
||||
<key name="always-show-log-out" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Always show the 'Log out' menuitem in the user menu.</_summary>
|
||||
<_summary>Always show the 'Log out' menu item in the user menu.</_summary>
|
||||
<_description>
|
||||
This key overrides the automatic hiding of the 'Log out'
|
||||
menuitem in single-user, single-session situations.
|
||||
menu item in single-user, single-session situations.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="remember-mount-password" type="b">
|
||||
@ -73,6 +74,7 @@
|
||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
||||
<child name="location" schema="org.gnome.shell.location"/>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
|
||||
@ -124,6 +126,11 @@
|
||||
Keybinding to focus the active notification.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="pause-resume-tweens" type="as">
|
||||
<default>[]</default>
|
||||
<summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</summary>
|
||||
<description></description>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
||||
@ -137,6 +144,32 @@
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<enum id="org.gnome.shell.geoclue.AccuracyLevel">
|
||||
<value value="0" nick="off"/>
|
||||
<value value="1" nick="country"/>
|
||||
<value value="4" nick="city"/>
|
||||
<value value="5" nick="neighborhood"/>
|
||||
<value value="6" nick="street"/>
|
||||
<value value="8" nick="exact"/>
|
||||
</enum>
|
||||
<schema id="org.gnome.shell.location"
|
||||
path="/org/gnome/shell/location/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="max-accuracy-level" enum="org.gnome.shell.geoclue.AccuracyLevel">
|
||||
<default>'exact'</default>
|
||||
<_summary>The maximum accuracy level of location.</_summary>
|
||||
<_description>
|
||||
Configures the maximum level of location accuracy applications are
|
||||
allowed to see. Valid options are 'off' (disable location tracking),
|
||||
'country', 'city', 'neighborhood', 'street', and 'exact' (typically
|
||||
requires GPS receiver). Please keep in mind that this only controls
|
||||
what GeoClue will allow applications to see and they can find user's
|
||||
location on their own using network resources (albeit with street-level
|
||||
accuracy at best).
|
||||
</_description>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.app-switcher"
|
||||
path="/org/gnome/shell/app-switcher/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
|
@ -157,8 +157,9 @@ StScrollBar StButton#vhandle:active {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.unicode-arrow {
|
||||
font-size: 120%;
|
||||
.popup-menu-arrow {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.popup-submenu-menu-item:open {
|
||||
@ -289,6 +290,20 @@ StScrollBar StButton#vhandle:active {
|
||||
spacing: 10px;
|
||||
}
|
||||
|
||||
.nm-dialog-airplane-box {
|
||||
spacing: 12px;
|
||||
}
|
||||
|
||||
.nm-dialog-airplane-headline {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.nm-dialog-airplane-text {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.nm-dialog-header-icon {
|
||||
icon-size: 32px;
|
||||
}
|
||||
@ -964,6 +979,8 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.app-folder-icon {
|
||||
padding: 5px;
|
||||
spacing-rows: 5px;
|
||||
spacing-columns: 5px;
|
||||
}
|
||||
|
||||
.dash-item-container > StButton {
|
||||
@ -1289,12 +1306,18 @@ StScrollBar StButton#vhandle:active {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: #eeeeec;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.datemenu-date-label:hover,
|
||||
.datemenu-date-label:focus {
|
||||
background-color: #999999;
|
||||
}
|
||||
|
||||
.datemenu-date-label:active {
|
||||
background-color: #aaaaaa;
|
||||
}
|
||||
|
||||
.calendar-day-base {
|
||||
font-size: 9pt;
|
||||
text-align: center;
|
||||
@ -1453,6 +1476,10 @@ StScrollBar StButton#vhandle:active {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.no-networks-box {
|
||||
spacing: 12px;
|
||||
}
|
||||
|
||||
.notification {
|
||||
border-radius: 10px 10px 0px 0px;
|
||||
background: rgba(0,0,0,0.9);
|
||||
@ -1630,8 +1657,8 @@ StScrollBar StButton#vhandle:active {
|
||||
color: #888888;
|
||||
}
|
||||
|
||||
.chat-group-sent, .chat-group-meta {
|
||||
padding: 8px 0;
|
||||
.chat-empty-line {
|
||||
font-size: 4px;
|
||||
}
|
||||
|
||||
.chat-received {
|
||||
@ -1656,6 +1683,7 @@ StScrollBar StButton#vhandle:active {
|
||||
.chat-meta-message {
|
||||
padding-left: 4px;
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
color: #bbbbbb;
|
||||
}
|
||||
|
||||
@ -1857,6 +1885,27 @@ StScrollBar StButton#vhandle:active {
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* Tile previews */
|
||||
.tile-preview {
|
||||
background-color: rgba(74, 144, 217, 0.35);
|
||||
border: 1px solid #4a90d9; /* Adwaita selected bg color */
|
||||
}
|
||||
|
||||
.tile-preview-left.on-primary {
|
||||
/* keep in sync with -panel-corner-radius */
|
||||
border-radius: 6px 0 0 0;
|
||||
}
|
||||
|
||||
.tile-preview-right.on-primary {
|
||||
/* keep in sync with -panel-corner-radius */
|
||||
border-radius: 0 6px 0 0;
|
||||
}
|
||||
|
||||
.tile-preview-left.tile-preview-right.on-primary {
|
||||
/* keep in sync with -panel-corner-radius */
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
/* Modal Dialogs */
|
||||
|
||||
/* Dialog Subject Text Style */
|
||||
@ -1927,45 +1976,57 @@ StScrollBar StButton#vhandle:active {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.end-session-dialog-subject {
|
||||
.end-session-dialog-layout {
|
||||
padding-left: 17px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.end-session-dialog-subject:rtl {
|
||||
padding-left: 0px;
|
||||
.end-session-dialog-layout:rtl {
|
||||
padding-right: 17px;
|
||||
}
|
||||
|
||||
.end-session-dialog-description {
|
||||
padding-left: 17px;
|
||||
width: 28em;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.end-session-dialog-description:rtl {
|
||||
padding-right: 17px;
|
||||
width: 28em;
|
||||
padding-bottom: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.end-session-dialog-warning {
|
||||
width: 28em;
|
||||
color: #f57900;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.end-session-dialog-warning:rtl {
|
||||
width: 28em;
|
||||
color: #f57900;
|
||||
padding-top: 6px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.end-session-dialog-logout-icon {
|
||||
border: 2px solid #8b8b8b;
|
||||
border-radius: 5px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.end-session-dialog-shutdown-icon {
|
||||
color: #bebebe;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
|
||||
.end-session-dialog-inhibitor-layout {
|
||||
spacing: 16px;
|
||||
max-height: 200px;
|
||||
padding-right: 50px;
|
||||
padding-left: 50px;
|
||||
padding-right: 65px;
|
||||
padding-left: 65px;
|
||||
}
|
||||
|
||||
.end-session-dialog-session-list,
|
||||
@ -2388,12 +2449,13 @@ StScrollBar StButton#vhandle:active {
|
||||
color: #E8E8E8;
|
||||
}
|
||||
|
||||
.login-dialog-username {
|
||||
.login-dialog-username,
|
||||
.user-widget-label {
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
padding-left: 15px;
|
||||
text-shadow: black 0px 4px 3px 0px;
|
||||
text-shadow: rgba(0, 0, 0, 0.5) 0px 2px 1px 0px;
|
||||
}
|
||||
|
||||
.login-dialog-prompt-layout {
|
||||
@ -2485,11 +2547,6 @@ StScrollBar StButton#vhandle:active {
|
||||
}
|
||||
|
||||
.user-widget-label {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
color:white;
|
||||
text-shadow: black 0px 4px 3px 0px;
|
||||
}
|
||||
|
||||
.user-widget-label:ltr {
|
||||
@ -2624,4 +2681,5 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
.background-menu {
|
||||
-boxpointer-gap: 4px;
|
||||
-arrow-rise: 0px;
|
||||
}
|
||||
|
90
data/theme/menu-arrow-symbolic.svg
Normal file
90
data/theme/menu-arrow-symbolic.svg
Normal file
@ -0,0 +1,90 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg3863"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="menu-arrow.svg">
|
||||
<defs
|
||||
id="defs3865" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="15.836083"
|
||||
inkscape:cx="-3.1641676"
|
||||
inkscape:cy="11.823817"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="702"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true">
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="15.996443,16.922964"
|
||||
id="guide3873" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="28.041217,3.1256134"
|
||||
id="guide3875" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-0.80372916,24.469088"
|
||||
id="guide3877" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="3.0363102,34.649657"
|
||||
id="guide3879" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="29.023553,28.577037"
|
||||
id="guide3881" />
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2988" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3868">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-16)">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 4,23 8,0 -4,5 z"
|
||||
id="path3883"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
@ -6,6 +6,7 @@ misc/config.js: misc/config.js.in Makefile
|
||||
sed -e "s|[@]PACKAGE_NAME@|$(PACKAGE_NAME)|g" \
|
||||
-e "s|[@]PACKAGE_VERSION@|$(PACKAGE_VERSION)|g" \
|
||||
-e "s|[@]HAVE_BLUETOOTH@|$(HAVE_BLUETOOTH)|g" \
|
||||
-e "s|[@]HAVE_NETWORKMANAGER@|$(HAVE_NETWORKMANAGER)|g" \
|
||||
-e "s|[@]GETTEXT_PACKAGE@|$(GETTEXT_PACKAGE)|g" \
|
||||
-e "s|[@]datadir@|$(datadir)|g" \
|
||||
-e "s|[@]libexecdir@|$(libexecdir)|g" \
|
||||
|
@ -450,8 +450,7 @@ const AuthPrompt = new Lang.Class({
|
||||
// respond to the request with the username
|
||||
beginRequestType = BeginRequestType.PROVIDE_USERNAME;
|
||||
} else if (this._userVerifier.serviceIsForeground(GdmUtil.OVIRT_SERVICE_NAME) ||
|
||||
(this.smartcardDetected &&
|
||||
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME))) {
|
||||
this._userVerifier.serviceIsForeground(GdmUtil.SMARTCARD_SERVICE_NAME)) {
|
||||
// We don't need to know the username if the user preempted the login screen
|
||||
// with a smartcard or with preauthenticated oVirt credentials
|
||||
beginRequestType = BeginRequestType.DONT_PROVIDE_USERNAME;
|
||||
|
@ -13,9 +13,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const Lang = imports.lang;
|
||||
|
@ -13,9 +13,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const AccountsService = imports.gi.AccountsService;
|
||||
@ -38,6 +36,7 @@ const BoxPointer = imports.ui.boxpointer;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const GdmUtil = imports.gdm.util;
|
||||
const Layout = imports.ui.layout;
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
const Main = imports.ui.main;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Realmd = imports.gdm.realmd;
|
||||
@ -456,18 +455,6 @@ const LoginDialog = new Lang.Class({
|
||||
this.actor.add_child(this._logoBin);
|
||||
this._updateLogo();
|
||||
|
||||
if (!this._userManager.is_loaded)
|
||||
this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
|
||||
Lang.bind(this, function() {
|
||||
if (this._userManager.is_loaded) {
|
||||
this._loadUserList();
|
||||
this._userManager.disconnect(this._userManagerLoadedId);
|
||||
this._userManagerLoadedId = 0;
|
||||
}
|
||||
}));
|
||||
else
|
||||
this._loadUserList();
|
||||
|
||||
this._userList.connect('activate',
|
||||
Lang.bind(this, function(userList, item) {
|
||||
this._onUserListActivated(item);
|
||||
@ -483,7 +470,31 @@ const LoginDialog = new Lang.Class({
|
||||
this._sessionMenuButton.actor.show();
|
||||
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
|
||||
|
||||
},
|
||||
this._disableUserList = undefined;
|
||||
this._userListLoaded = false;
|
||||
|
||||
LoginManager.getLoginManager().getCurrentSessionProxy(Lang.bind(this, this._gotGreeterSessionProxy));
|
||||
|
||||
// If the user list is enabled, it should take key focus; make sure the
|
||||
// screen shield is initialized first to prevent it from stealing the
|
||||
// focus later
|
||||
Main.layoutManager.connect('startup-complete',
|
||||
Lang.bind(this, this._updateDisableUserList));
|
||||
},
|
||||
|
||||
_ensureUserListLoaded: function() {
|
||||
if (!this._userManager.is_loaded)
|
||||
this._userManagerLoadedId = this._userManager.connect('notify::is-loaded',
|
||||
Lang.bind(this, function() {
|
||||
if (this._userManager.is_loaded) {
|
||||
this._loadUserList();
|
||||
this._userManager.disconnect(this._userManagerLoadedId);
|
||||
this._userManagerLoadedId = 0;
|
||||
}
|
||||
}));
|
||||
else
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, Lang.bind(this, this._loadUserList));
|
||||
},
|
||||
|
||||
_updateDisableUserList: function() {
|
||||
let disableUserList = this._settings.get_boolean(GdmUtil.DISABLE_USER_LIST_KEY);
|
||||
@ -627,6 +638,36 @@ const LoginDialog = new Lang.Class({
|
||||
this._showPrompt();
|
||||
},
|
||||
|
||||
_loginScreenSessionActivated: function() {
|
||||
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_SUCCEEDED)
|
||||
return;
|
||||
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: _FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onUpdate: function() {
|
||||
let children = Main.layoutManager.uiGroup.get_children();
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i] != Main.layoutManager.screenShieldGroup)
|
||||
children[i].opacity = this.actor.opacity;
|
||||
}
|
||||
},
|
||||
onUpdateScope: this,
|
||||
onComplete: function() {
|
||||
this._authPrompt.reset();
|
||||
},
|
||||
onCompleteScope: this });
|
||||
},
|
||||
|
||||
_gotGreeterSessionProxy: function(proxy) {
|
||||
proxy.connect('g-properties-changed', Lang.bind(this, function() {
|
||||
if (proxy.Active)
|
||||
this._loginScreenSessionActivated();
|
||||
}));
|
||||
},
|
||||
|
||||
_startSession: function(serviceName) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
@ -803,6 +844,7 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_showUserList: function() {
|
||||
this._ensureUserListLoaded();
|
||||
this._authPrompt.hide();
|
||||
this._sessionMenuButton.close();
|
||||
this._setUserListExpanded(true);
|
||||
@ -846,14 +888,17 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_loadUserList: function() {
|
||||
if (this._userListLoaded)
|
||||
return GLib.SOURCE_REMOVE;
|
||||
|
||||
this._userListLoaded = true;
|
||||
|
||||
let users = this._userManager.list_users();
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
this._userList.addUser(users[i]);
|
||||
}
|
||||
|
||||
this._updateDisableUserList();
|
||||
|
||||
this._userManager.connect('user-added',
|
||||
Lang.bind(this, function(userManager, user) {
|
||||
this._userList.addUser(user);
|
||||
@ -863,6 +908,8 @@ const LoginDialog = new Lang.Class({
|
||||
Lang.bind(this, function(userManager, user) {
|
||||
this._userList.removeUser(user);
|
||||
}));
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
|
||||
open: function() {
|
||||
|
@ -298,7 +298,7 @@ const ShellUserVerifier = new Lang.Class({
|
||||
|
||||
if (!this._settings.get_boolean(SMARTCARD_AUTHENTICATION_KEY))
|
||||
smartcardDetected = false;
|
||||
else if (this.reauthenticating)
|
||||
else if (this._reauthOnly)
|
||||
smartcardDetected = this._smartcardManager.hasInsertedLoginToken();
|
||||
else
|
||||
smartcardDetected = this._smartcardManager.hasInsertedTokens();
|
||||
|
@ -15,7 +15,6 @@
|
||||
<file>misc/extensionUtils.js</file>
|
||||
<file>misc/fileUtils.js</file>
|
||||
<file>misc/gnomeSession.js</file>
|
||||
<file>misc/hash.js</file>
|
||||
<file>misc/history.js</file>
|
||||
<file>misc/jsParse.js</file>
|
||||
<file>misc/loginManager.js</file>
|
||||
@ -102,6 +101,7 @@
|
||||
|
||||
<file>ui/status/accessibility.js</file>
|
||||
<file>ui/status/brightness.js</file>
|
||||
<file>ui/status/location.js</file>
|
||||
<file>ui/status/keyboard.js</file>
|
||||
<file>ui/status/network.js</file>
|
||||
<file>ui/status/power.js</file>
|
||||
|
@ -6,6 +6,8 @@ const PACKAGE_NAME = '@PACKAGE_NAME@';
|
||||
const PACKAGE_VERSION = '@PACKAGE_VERSION@';
|
||||
/* 1 if gnome-bluetooth is available, 0 otherwise */
|
||||
const HAVE_BLUETOOTH = @HAVE_BLUETOOTH@;
|
||||
/* 1 if networkmanager is available, 0 otherwise */
|
||||
const HAVE_NETWORKMANAGER = @HAVE_NETWORKMANAGER@;
|
||||
/* gettext package */
|
||||
const GETTEXT_PACKAGE = '@GETTEXT_PACKAGE@';
|
||||
/* locale dir */
|
||||
|
@ -5,26 +5,6 @@ const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
function listDirAsync(file, callback) {
|
||||
let allFiles = [];
|
||||
file.enumerate_children_async('standard::name,standard::type',
|
||||
Gio.FileQueryInfoFlags.NONE,
|
||||
GLib.PRIORITY_LOW, null, function (obj, res) {
|
||||
let enumerator = obj.enumerate_children_finish(res);
|
||||
function onNextFileComplete(obj, res) {
|
||||
let files = obj.next_files_finish(res);
|
||||
if (files.length) {
|
||||
allFiles = allFiles.concat(files);
|
||||
enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
|
||||
} else {
|
||||
enumerator.close(null);
|
||||
callback(allFiles);
|
||||
}
|
||||
}
|
||||
enumerator.next_files_async(100, GLib.PRIORITY_LOW, null, onNextFileComplete);
|
||||
});
|
||||
}
|
||||
|
||||
function collectFromDatadirs(subdir, includeUserDir, processFile) {
|
||||
let dataDirs = GLib.get_system_data_dirs();
|
||||
if (includeUserDir)
|
||||
|
144
js/misc/hash.js
144
js/misc/hash.js
@ -1,144 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const System = imports.system;
|
||||
|
||||
const Params = imports.misc.params;
|
||||
|
||||
// This is an implementation of EcmaScript SameValue algorithm,
|
||||
// which returns true if two values are not observably distinguishable.
|
||||
// It was taken from http://wiki.ecmascript.org/doku.php?id=harmony:egal
|
||||
//
|
||||
// In the future, we may want to use the 'is' operator instead.
|
||||
function _sameValue(x, y) {
|
||||
if (x === y) {
|
||||
// 0 === -0, but they are not identical
|
||||
return x !== 0 || 1 / x === 1 / y;
|
||||
}
|
||||
|
||||
// NaN !== NaN, but they are identical.
|
||||
// NaNs are the only non-reflexive value, i.e., if x !== x,
|
||||
// then x is a NaN.
|
||||
// isNaN is broken: it converts its argument to number, so
|
||||
// isNaN("foo") => true
|
||||
return x !== x && y !== y;
|
||||
}
|
||||
|
||||
const _hashers = {
|
||||
object: function(o) { return o ? System.addressOf(o) : 'null'; },
|
||||
function: function(f) { return System.addressOf(f); },
|
||||
string: function(s) { return s; },
|
||||
number: function(n) { return String(n); },
|
||||
undefined: function() { return 'undefined'; },
|
||||
};
|
||||
|
||||
/* Map is meant to be similar in usage to ES6 Map, which is
|
||||
described at http://wiki.ecmascript.org/doku.php?id=harmony:simple_maps_and_sets,
|
||||
without requiring more than ES5 + Gjs extensions.
|
||||
|
||||
Known differences from other implementations:
|
||||
Polyfills around the web usually implement HashMaps for
|
||||
primitive values and reversed WeakMaps for object keys,
|
||||
but we want real maps with real O(1) semantics in all cases,
|
||||
and the easiest way is to have different hashers for different
|
||||
types.
|
||||
|
||||
Known differences from the ES6 specification:
|
||||
- Map is a Lang.Class, not a ES6 class, so inheritance,
|
||||
prototype, sealing, etc. work differently.
|
||||
- items(), keys() and values() don't return iterators,
|
||||
they return actual arrays, so they incur a full copy everytime
|
||||
they're called, and they don't see changes if you mutate
|
||||
the table while iterating
|
||||
(admittedly, the ES6 spec is a bit unclear on this, and
|
||||
the reference code would just blow up)
|
||||
*/
|
||||
const Map = new Lang.Class({
|
||||
Name: 'Map',
|
||||
|
||||
_init: function(iterable) {
|
||||
this._pool = { };
|
||||
this._size = 0;
|
||||
|
||||
if (iterable) {
|
||||
for (let i = 0; i < iterable.length; i++) {
|
||||
let [key, value] = iterable[i];
|
||||
this.set(key, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_hashKey: function(key) {
|
||||
let type = typeof(key);
|
||||
return type + ':' + _hashers[type](key);
|
||||
},
|
||||
|
||||
_internalGet: function(key) {
|
||||
let hash = this._hashKey(key);
|
||||
let node = this._pool[hash];
|
||||
|
||||
if (node && _sameValue(node.key, key))
|
||||
return [true, node.value];
|
||||
else
|
||||
return [false, null];
|
||||
},
|
||||
|
||||
get: function(key) {
|
||||
return this._internalGet(key)[1];
|
||||
},
|
||||
|
||||
has: function(key) {
|
||||
return this._internalGet(key)[0];
|
||||
},
|
||||
|
||||
set: function(key, value) {
|
||||
let hash = this._hashKey(key);
|
||||
let node = this._pool[hash];
|
||||
|
||||
if (node) {
|
||||
node.key = key;
|
||||
node.value = value;
|
||||
} else {
|
||||
this._pool[hash] = { key: key, value: value };
|
||||
this._size++;
|
||||
}
|
||||
},
|
||||
|
||||
delete: function(key) {
|
||||
let hash = this._hashKey(key);
|
||||
let node = this._pool[hash];
|
||||
|
||||
if (node && _sameValue(node.key, key)) {
|
||||
delete this._pool[hash];
|
||||
this._size--;
|
||||
return [node.key, node.value];
|
||||
} else {
|
||||
return [null, null];
|
||||
}
|
||||
},
|
||||
|
||||
keys: function() {
|
||||
let pool = this._pool;
|
||||
return Object.getOwnPropertyNames(pool).map(function(hash) {
|
||||
return pool[hash].key;
|
||||
});
|
||||
},
|
||||
|
||||
values: function() {
|
||||
let pool = this._pool;
|
||||
return Object.getOwnPropertyNames(pool).map(function(hash) {
|
||||
return pool[hash].value;
|
||||
});
|
||||
},
|
||||
|
||||
items: function() {
|
||||
let pool = this._pool;
|
||||
return Object.getOwnPropertyNames(pool).map(function(hash) {
|
||||
return [pool[hash].key, pool[hash].value];
|
||||
});
|
||||
},
|
||||
|
||||
size: function() {
|
||||
return this._size;
|
||||
},
|
||||
});
|
@ -39,6 +39,7 @@ const SystemdLoginSessionIface = '<node> \
|
||||
<interface name="org.freedesktop.login1.Session"> \
|
||||
<signal name="Lock" /> \
|
||||
<signal name="Unlock" /> \
|
||||
<property name="Active" type="b" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
|
@ -89,7 +89,7 @@ function spawnApp(argv) {
|
||||
let app = Gio.AppInfo.create_from_commandline(argv.join(' '), null,
|
||||
Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION);
|
||||
|
||||
let context = global.create_app_launch_context();
|
||||
let context = global.create_app_launch_context(0, -1);
|
||||
app.launch([], context);
|
||||
} catch(err) {
|
||||
_handleSpawnError(argv[0], err);
|
||||
@ -153,7 +153,7 @@ function trySpawnCommandLine(command_line) {
|
||||
}
|
||||
|
||||
function _handleSpawnError(command, err) {
|
||||
let title = _("Execution of '%s' failed:").format(command);
|
||||
let title = _("Execution of “%s” failed:").format(command);
|
||||
Main.notifyError(title, err.message);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ const WINDOW_PREVIEW_SIZE = 128;
|
||||
const APP_ICON_SIZE = 96;
|
||||
const APP_ICON_SIZE_SMALL = 48;
|
||||
|
||||
const iconSizes = [96, 64, 48, 32, 22];
|
||||
const baseIconSizes = [96, 64, 48, 32, 22];
|
||||
|
||||
const AppIconMode = {
|
||||
THUMBNAIL_ONLY: 1,
|
||||
@ -430,7 +430,6 @@ const AppIcon = new Lang.Class({
|
||||
|
||||
set_size: function(size) {
|
||||
this.icon = this.app.create_icon_texture(size);
|
||||
this._iconBin.set_size(size, size);
|
||||
this._iconBin.child = this.icon;
|
||||
}
|
||||
});
|
||||
@ -460,9 +459,10 @@ const AppSwitcher = new Lang.Class({
|
||||
appIcon.cachedWindows = allWindows.filter(function(w) {
|
||||
return windowTracker.get_window_app (w) == appIcon.app;
|
||||
});
|
||||
if (workspace == null || appIcon.cachedWindows.length > 0) {
|
||||
if (appIcon.cachedWindows.length > 0)
|
||||
this._addIcon(appIcon);
|
||||
}
|
||||
else if (workspace == null)
|
||||
throw new Error('%s appears to be running, but doesn\'t have any windows'.format(appIcon.app.get_name()));
|
||||
}
|
||||
|
||||
this._curApp = -1;
|
||||
@ -478,12 +478,13 @@ const AppSwitcher = new Lang.Class({
|
||||
Mainloop.source_remove(this._mouseTimeOutId);
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
_setIconSize: function() {
|
||||
let j = 0;
|
||||
while(this._items.length > 1 && this._items[j].style_class != 'item-box') {
|
||||
j++;
|
||||
}
|
||||
let themeNode = this._items[j].get_theme_node();
|
||||
|
||||
let iconPadding = themeNode.get_horizontal_padding();
|
||||
let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT);
|
||||
let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
|
||||
@ -494,19 +495,22 @@ const AppSwitcher = new Lang.Class({
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
|
||||
let availWidth = primary.width - parentPadding - this.actor.get_theme_node().get_horizontal_padding();
|
||||
let height = 0;
|
||||
|
||||
for(let i = 0; i < iconSizes.length; i++) {
|
||||
this._iconSize = iconSizes[i];
|
||||
height = iconSizes[i] + iconSpacing;
|
||||
let w = height * this._items.length + totalSpacing;
|
||||
if (w <= availWidth)
|
||||
break;
|
||||
}
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
let iconSizes = baseIconSizes.map(function(s) {
|
||||
return s * scaleFactor;
|
||||
});
|
||||
|
||||
if (this._items.length == 1) {
|
||||
this._iconSize = iconSizes[0];
|
||||
height = iconSizes[0] + iconSpacing;
|
||||
this._iconSize = baseIconSizes[0];
|
||||
} else {
|
||||
for(let i = 0; i < baseIconSizes.length; i++) {
|
||||
this._iconSize = baseIconSizes[i];
|
||||
let height = iconSizes[i] + iconSpacing;
|
||||
let w = height * this._items.length + totalSpacing;
|
||||
if (w <= availWidth)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(let i = 0; i < this.icons.length; i++) {
|
||||
@ -514,9 +518,11 @@ const AppSwitcher = new Lang.Class({
|
||||
break;
|
||||
this.icons[i].set_size(this._iconSize);
|
||||
}
|
||||
},
|
||||
|
||||
alloc.min_size = height;
|
||||
alloc.natural_size = height;
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
this._setIconSize();
|
||||
this.parent(actor, forWidth, alloc);
|
||||
},
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
@ -649,17 +655,19 @@ const ThumbnailList = new Lang.Class({
|
||||
totalPadding += this.actor.get_theme_node().get_horizontal_padding() + this.actor.get_theme_node().get_vertical_padding();
|
||||
let [labelMinHeight, labelNaturalHeight] = this._labels[0].get_preferred_height(-1);
|
||||
let spacing = this._items[0].child.get_theme_node().get_length('spacing');
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
let thumbnailSize = THUMBNAIL_DEFAULT_SIZE * scaleFactor;
|
||||
|
||||
availHeight = Math.min(availHeight - labelNaturalHeight - totalPadding - spacing, THUMBNAIL_DEFAULT_SIZE);
|
||||
availHeight = Math.min(availHeight - labelNaturalHeight - totalPadding - spacing, thumbnailSize);
|
||||
let binHeight = availHeight + this._items[0].get_theme_node().get_vertical_padding() + this.actor.get_theme_node().get_vertical_padding() - spacing;
|
||||
binHeight = Math.min(THUMBNAIL_DEFAULT_SIZE, binHeight);
|
||||
binHeight = Math.min(thumbnailSize, binHeight);
|
||||
|
||||
for (let i = 0; i < this._thumbnailBins.length; i++) {
|
||||
let mutterWindow = this._windows[i].get_compositor_private();
|
||||
if (!mutterWindow)
|
||||
continue;
|
||||
|
||||
let clone = _createWindowClone(mutterWindow, THUMBNAIL_DEFAULT_SIZE);
|
||||
let clone = _createWindowClone(mutterWindow, thumbnailSize);
|
||||
this._thumbnailBins[i].set_height(binHeight);
|
||||
this._thumbnailBins[i].add_actor(clone);
|
||||
this._clones.push(clone);
|
||||
|
@ -5,7 +5,6 @@ const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const GMenu = imports.gi.GMenu;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
@ -47,24 +46,40 @@ const INDICATORS_ANIMATION_MAX_TIME = 0.75;
|
||||
const PAGE_SWITCH_TRESHOLD = 0.2;
|
||||
const PAGE_SWITCH_TIME = 0.3;
|
||||
|
||||
// Recursively load a GMenuTreeDirectory; we could put this in ShellAppSystem too
|
||||
function _loadCategory(dir, view) {
|
||||
let iter = dir.iter();
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
let nextType;
|
||||
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
|
||||
if (nextType == GMenu.TreeItemType.ENTRY) {
|
||||
let entry = iter.get_entry();
|
||||
let appInfo = entry.get_app_info();
|
||||
let app = appSystem.lookup_app(entry.get_desktop_file_id());
|
||||
if (appInfo.should_show())
|
||||
view.addApp(app);
|
||||
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
let itemDir = iter.get_directory();
|
||||
_loadCategory(itemDir, view);
|
||||
const VIEWS_SWITCH_TIME = 0.4;
|
||||
const VIEWS_SWITCH_ANIMATION_DELAY = 0.1;
|
||||
|
||||
function _getCategories(info) {
|
||||
let categoriesStr = info.get_categories();
|
||||
if (!categoriesStr)
|
||||
return [];
|
||||
return categoriesStr.split(';');
|
||||
}
|
||||
|
||||
function _listsIntersect(a, b) {
|
||||
for (let itemA of a)
|
||||
if (b.indexOf(itemA) >= 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
function _getFolderName(folder) {
|
||||
let name = folder.get_string('name');
|
||||
|
||||
if (folder.get_boolean('translate')) {
|
||||
let keyfile = new GLib.KeyFile();
|
||||
let path = 'desktop-directories/' + name;
|
||||
|
||||
try {
|
||||
keyfile.load_from_data_dirs(path, GLib.KeyFileFlags.NONE);
|
||||
name = keyfile.get_locale_string('Desktop Entry', 'Name', null);
|
||||
} catch(e) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
const BaseAppView = new Lang.Class({
|
||||
Name: 'BaseAppView',
|
||||
@ -97,40 +112,33 @@ const BaseAppView = new Lang.Class({
|
||||
this._allItems = [];
|
||||
},
|
||||
|
||||
_getItemId: function(item) {
|
||||
throw new Error('Not implemented');
|
||||
_redisplay: function() {
|
||||
this.removeAll();
|
||||
this._loadApps();
|
||||
},
|
||||
|
||||
_createItemIcon: function(item) {
|
||||
throw new Error('Not implemented');
|
||||
getAllItems: function() {
|
||||
return this._allItems;
|
||||
},
|
||||
|
||||
addItem: function(icon) {
|
||||
let id = icon.id;
|
||||
if (this._items[id] !== undefined)
|
||||
return;
|
||||
|
||||
this._allItems.push(icon);
|
||||
this._items[id] = icon;
|
||||
},
|
||||
|
||||
_compareItems: function(a, b) {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
_addItem: function(item) {
|
||||
let id = this._getItemId(item);
|
||||
if (this._items[id] !== undefined)
|
||||
return null;
|
||||
|
||||
let itemIcon = this._createItemIcon(item);
|
||||
this._allItems.push(item);
|
||||
this._items[id] = itemIcon;
|
||||
|
||||
return itemIcon;
|
||||
return a.name.localeCompare(b.name);
|
||||
},
|
||||
|
||||
loadGrid: function() {
|
||||
this._allItems.sort(Lang.bind(this, this._compareItems));
|
||||
|
||||
for (let i = 0; i < this._allItems.length; i++) {
|
||||
let id = this._getItemId(this._allItems[i]);
|
||||
if (!id)
|
||||
continue;
|
||||
this._grid.addItem(this._items[id]);
|
||||
}
|
||||
|
||||
this._allItems.sort(this._compareItems);
|
||||
this._allItems.forEach(Lang.bind(this, function(item) {
|
||||
this._grid.addItem(item);
|
||||
}));
|
||||
this.emit('view-loaded');
|
||||
},
|
||||
|
||||
@ -243,7 +251,8 @@ const PageIndicators = new Lang.Class({
|
||||
Tweener.addTween(children[i],
|
||||
{ translation_x: 0,
|
||||
time: INDICATORS_BASE_TIME + delay * i,
|
||||
transition: 'easeInOutQuad'
|
||||
transition: 'easeInOutQuad',
|
||||
delay: VIEWS_SWITCH_ANIMATION_DELAY
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -281,7 +290,7 @@ const AllView = new Lang.Class({
|
||||
this._pageIndicators.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
|
||||
this.actor.add_actor(this._pageIndicators.actor);
|
||||
|
||||
this._folderIcons = [];
|
||||
this.folderIcons = [];
|
||||
|
||||
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
@ -346,6 +355,76 @@ const AllView = new Lang.Class({
|
||||
this._keyPressEventId = 0;
|
||||
}
|
||||
}));
|
||||
|
||||
this._redisplayWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
|
||||
|
||||
Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._redisplayWorkId);
|
||||
}));
|
||||
this._folderSettings = new Gio.Settings({ schema: 'org.gnome.desktop.app-folders' });
|
||||
this._folderSettings.connect('changed::folder-children', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._redisplayWorkId);
|
||||
}));
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this.folderIcons = [];
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_itemNameChanged: function(item) {
|
||||
// If an item's name changed, we can pluck it out of where it's
|
||||
// supposed to be and reinsert it where it's sorted.
|
||||
let oldIdx = this._allItems.indexOf(item);
|
||||
this._allItems.splice(oldIdx, 1);
|
||||
let newIdx = Util.insertSorted(this._allItems, item, this._compareItems);
|
||||
|
||||
this._grid.removeItem(item);
|
||||
this._grid.addItem(item, newIdx);
|
||||
},
|
||||
|
||||
_refilterApps: function() {
|
||||
this._allItems.forEach(function(icon) {
|
||||
if (icon instanceof AppIcon)
|
||||
icon.actor.visible = true;
|
||||
});
|
||||
|
||||
this.folderIcons.forEach(Lang.bind(this, function(folder) {
|
||||
let folderApps = folder.getAppIds();
|
||||
folderApps.forEach(Lang.bind(this, function(appId) {
|
||||
let appIcon = this._items[appId];
|
||||
appIcon.actor.visible = false;
|
||||
}));
|
||||
}));
|
||||
},
|
||||
|
||||
_loadApps: function() {
|
||||
let apps = Gio.AppInfo.get_all().filter(function(appInfo) {
|
||||
return appInfo.should_show();
|
||||
}).map(function(app) {
|
||||
return app.get_id();
|
||||
});
|
||||
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
|
||||
let folders = this._folderSettings.get_strv('folder-children');
|
||||
folders.forEach(Lang.bind(this, function(id) {
|
||||
let path = this._folderSettings.path + 'folders/' + id + '/';
|
||||
let icon = new FolderIcon(id, path, this);
|
||||
icon.connect('name-changed', Lang.bind(this, this._itemNameChanged));
|
||||
icon.connect('apps-changed', Lang.bind(this, this._refilterApps));
|
||||
this.addItem(icon);
|
||||
this.folderIcons.push(icon);
|
||||
}));
|
||||
|
||||
apps.forEach(Lang.bind(this, function(appId) {
|
||||
let app = appSys.lookup_app(appId);
|
||||
let icon = new AppIcon(app);
|
||||
this.addItem(icon);
|
||||
}));
|
||||
|
||||
this.loadGrid();
|
||||
this._refilterApps();
|
||||
},
|
||||
|
||||
getCurrentPageY: function() {
|
||||
@ -467,52 +546,6 @@ const AllView = new Lang.Class({
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_getItemId: function(item) {
|
||||
if (item instanceof Shell.App)
|
||||
return item.get_id();
|
||||
else if (item instanceof GMenu.TreeDirectory)
|
||||
return item.get_menu_id();
|
||||
else
|
||||
return null;
|
||||
},
|
||||
|
||||
_createItemIcon: function(item) {
|
||||
if (item instanceof Shell.App)
|
||||
return new AppIcon(item);
|
||||
else if (item instanceof GMenu.TreeDirectory)
|
||||
return new FolderIcon(item, this);
|
||||
else
|
||||
return null;
|
||||
},
|
||||
|
||||
_compareItems: function(itemA, itemB) {
|
||||
// bit of a hack: rely on both ShellApp and GMenuTreeDirectory
|
||||
// having a get_name() method
|
||||
let nameA = GLib.utf8_collate_key(itemA.get_name(), -1);
|
||||
let nameB = GLib.utf8_collate_key(itemB.get_name(), -1);
|
||||
return (nameA > nameB) ? 1 : (nameA < nameB ? -1 : 0);
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this._folderIcons = [];
|
||||
this.parent();
|
||||
},
|
||||
|
||||
addApp: function(app) {
|
||||
let appIcon = this._addItem(app);
|
||||
if (appIcon)
|
||||
appIcon.actor.connect('key-focus-in',
|
||||
Lang.bind(this, this._ensureIconVisible));
|
||||
},
|
||||
|
||||
addFolder: function(dir) {
|
||||
let folderIcon = this._addItem(dir);
|
||||
this._folderIcons.push(folderIcon);
|
||||
if (folderIcon)
|
||||
folderIcon.actor.connect('key-focus-in',
|
||||
Lang.bind(this, this._ensureIconVisible));
|
||||
},
|
||||
|
||||
addFolderPopup: function(popup) {
|
||||
this._stack.add_actor(popup.actor);
|
||||
popup.connect('open-state-changed', Lang.bind(this,
|
||||
@ -577,8 +610,8 @@ const AllView = new Lang.Class({
|
||||
this._availWidth = availWidth;
|
||||
this._availHeight = availHeight;
|
||||
// Update folder views
|
||||
for (let i = 0; i < this._folderIcons.length; i++)
|
||||
this._folderIcons[i].adaptToSize(availWidth, availHeight);
|
||||
for (let i = 0; i < this.folderIcons.length; i++)
|
||||
this.folderIcons[i].adaptToSize(availWidth, availHeight);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(AllView.prototype);
|
||||
@ -607,17 +640,18 @@ const FrequentView = new Lang.Class({
|
||||
this._noFrequentAppsLabel.hide();
|
||||
|
||||
this._usage = Shell.AppUsage.get_default();
|
||||
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, function() {
|
||||
if (this.actor.mapped)
|
||||
this._redisplay();
|
||||
}));
|
||||
},
|
||||
|
||||
hasUsefulData: function() {
|
||||
return this._usage.get_most_used("").length >= MIN_FREQUENT_APPS_COUNT;
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
this._grid.destroyAll();
|
||||
},
|
||||
|
||||
loadApps: function() {
|
||||
_loadApps: function() {
|
||||
let mostUsed = this._usage.get_most_used ("");
|
||||
let hasUsefulData = this.hasUsefulData();
|
||||
this._noFrequentAppsLabel.visible = !hasUsefulData;
|
||||
@ -695,15 +729,6 @@ const AppDisplay = new Lang.Class({
|
||||
Name: 'AppDisplay',
|
||||
|
||||
_init: function() {
|
||||
Shell.AppSystem.get_default().connect('installed-changed', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._allAppsWorkId);
|
||||
}));
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._frequentAppsWorkId);
|
||||
}));
|
||||
global.settings.connect('changed::app-folder-categories', Lang.bind(this, function() {
|
||||
Main.queueDeferredWork(this._allAppsWorkId);
|
||||
}));
|
||||
this._privacySettings = new Gio.Settings({ schema: 'org.gnome.desktop.privacy' });
|
||||
this._privacySettings.connect('changed::remember-app-usage',
|
||||
Lang.bind(this, this._updateFrequentVisibility));
|
||||
@ -757,22 +782,15 @@ const AppDisplay = new Lang.Class({
|
||||
initialView = Views.ALL;
|
||||
this._showView(initialView);
|
||||
this._updateFrequentVisibility();
|
||||
|
||||
// We need a dummy actor to catch the keyboard focus if the
|
||||
// user Ctrl-Alt-Tabs here before the deferred work creates
|
||||
// our real contents
|
||||
this._focusDummy = new St.Bin({ can_focus: true });
|
||||
this._viewStack.add_actor(this._focusDummy);
|
||||
|
||||
this._allAppsWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplayAllApps));
|
||||
this._frequentAppsWorkId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplayFrequentApps));
|
||||
},
|
||||
|
||||
_showView: function(activeIndex) {
|
||||
for (let i = 0; i < this._views.length; i++) {
|
||||
let actor = this._views[i].view.actor;
|
||||
let params = { time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
opacity: (i == activeIndex) ? 255 : 0 };
|
||||
|
||||
let params = { time: VIEWS_SWITCH_TIME,
|
||||
opacity: (i == activeIndex) ? 255 : 0,
|
||||
delay: (i == activeIndex) ? VIEWS_SWITCH_ANIMATION_DELAY : 0 };
|
||||
if (i == activeIndex)
|
||||
actor.visible = true;
|
||||
else
|
||||
@ -799,51 +817,6 @@ const AppDisplay = new Lang.Class({
|
||||
this._showView(Views.ALL);
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this._redisplayFrequentApps();
|
||||
this._redisplayAllApps();
|
||||
},
|
||||
|
||||
_redisplayFrequentApps: function() {
|
||||
let view = this._views[Views.FREQUENT].view;
|
||||
|
||||
view.removeAll();
|
||||
view.loadApps();
|
||||
},
|
||||
|
||||
_redisplayAllApps: function() {
|
||||
let view = this._views[Views.ALL].view;
|
||||
|
||||
view.removeAll();
|
||||
|
||||
let tree = new GMenu.Tree({ menu_basename: "applications.menu" });
|
||||
tree.load_sync();
|
||||
let root = tree.get_root_directory();
|
||||
|
||||
let iter = root.iter();
|
||||
let nextType;
|
||||
let folderCategories = global.settings.get_strv('app-folder-categories');
|
||||
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
|
||||
if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
let dir = iter.get_directory();
|
||||
|
||||
if (folderCategories.indexOf(dir.get_menu_id()) != -1)
|
||||
view.addFolder(dir);
|
||||
else
|
||||
_loadCategory(dir, view);
|
||||
}
|
||||
}
|
||||
view.loadGrid();
|
||||
|
||||
if (this._focusDummy) {
|
||||
let focused = this._focusDummy.has_key_focus();
|
||||
this._focusDummy.destroy();
|
||||
this._focusDummy = null;
|
||||
if (focused)
|
||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
}
|
||||
},
|
||||
|
||||
selectApp: function(id) {
|
||||
this._showView(Views.ALL);
|
||||
this._views[Views.ALL].view.selectApp(id);
|
||||
@ -956,36 +929,23 @@ const FolderView = new Lang.Class({
|
||||
this.actor.add_action(action);
|
||||
},
|
||||
|
||||
_getItemId: function(item) {
|
||||
return item.get_id();
|
||||
},
|
||||
|
||||
_createItemIcon: function(item) {
|
||||
return new AppIcon(item);
|
||||
},
|
||||
|
||||
_compareItems: function(a, b) {
|
||||
return a.compare_by_name(b);
|
||||
},
|
||||
|
||||
addApp: function(app) {
|
||||
this._addItem(app);
|
||||
},
|
||||
|
||||
createFolderIcon: function(size) {
|
||||
let icon = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||
style_class: 'app-folder-icon',
|
||||
width: size, height: size });
|
||||
let layout = new Clutter.TableLayout();
|
||||
let icon = new St.Widget({ layout_manager: layout,
|
||||
style_class: 'app-folder-icon' });
|
||||
layout.hookup_style(icon);
|
||||
let subSize = Math.floor(FOLDER_SUBICON_FRACTION * size);
|
||||
|
||||
let aligns = [ Clutter.ActorAlign.START, Clutter.ActorAlign.END ];
|
||||
for (let i = 0; i < Math.min(this._allItems.length, 4); i++) {
|
||||
let texture = this._allItems[i].create_icon_texture(subSize);
|
||||
let bin = new St.Bin({ child: texture,
|
||||
x_expand: true, y_expand: true });
|
||||
bin.set_x_align(aligns[i % 2]);
|
||||
bin.set_y_align(aligns[Math.floor(i / 2)]);
|
||||
icon.add_actor(bin);
|
||||
let numItems = this._allItems.length;
|
||||
for (let i = 0; i < 4; i++) {
|
||||
let bin;
|
||||
if (i < numItems) {
|
||||
let texture = this._allItems[i].app.create_icon_texture(subSize);
|
||||
bin = new St.Bin({ child: texture });
|
||||
} else {
|
||||
bin = new St.Bin({ width: subSize, height: subSize });
|
||||
}
|
||||
layout.pack(bin, i % 2, Math.floor(i / 2));
|
||||
}
|
||||
|
||||
return icon;
|
||||
@ -1057,10 +1017,12 @@ const FolderView = new Lang.Class({
|
||||
const FolderIcon = new Lang.Class({
|
||||
Name: 'FolderIcon',
|
||||
|
||||
_init: function(dir, parentView) {
|
||||
this._dir = dir;
|
||||
_init: function(id, path, parentView) {
|
||||
this.id = id;
|
||||
this._parentView = parentView;
|
||||
|
||||
this._folder = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders.folder',
|
||||
path: path });
|
||||
this.actor = new St.Button({ style_class: 'app-well-app app-folder',
|
||||
button_mask: St.ButtonMask.ONE,
|
||||
toggle_mode: true,
|
||||
@ -1071,15 +1033,11 @@ const FolderIcon = new Lang.Class({
|
||||
// whether we need to update arrow side, position etc.
|
||||
this._popupInvalidated = false;
|
||||
|
||||
let label = this._dir.get_name();
|
||||
this.icon = new IconGrid.BaseIcon(label,
|
||||
{ createIcon: Lang.bind(this, this._createIcon), setSizeManually: true });
|
||||
this.icon = new IconGrid.BaseIcon('', { createIcon: Lang.bind(this, this._createIcon), setSizeManually: true });
|
||||
this.actor.set_child(this.icon.actor);
|
||||
this.actor.label_actor = this.icon.label;
|
||||
|
||||
this.view = new FolderView();
|
||||
_loadCategory(dir, this.view);
|
||||
this.view.loadGrid();
|
||||
|
||||
this.actor.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
@ -1092,6 +1050,63 @@ const FolderIcon = new Lang.Class({
|
||||
if (!this.actor.mapped && this._popup)
|
||||
this._popup.popdown();
|
||||
}));
|
||||
|
||||
this._folder.connect('changed', Lang.bind(this, this._redisplay));
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
getAppIds: function() {
|
||||
return this.view.getAllItems().map(function(item) {
|
||||
return item.id;
|
||||
});
|
||||
},
|
||||
|
||||
_updateName: function() {
|
||||
let name = _getFolderName(this._folder);
|
||||
if (this.name == name)
|
||||
return;
|
||||
|
||||
this.name = name;
|
||||
this.icon.label.text = this.name;
|
||||
this.emit('name-changed');
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this._updateName();
|
||||
|
||||
this.view.removeAll();
|
||||
|
||||
let excludedApps = this._folder.get_strv('excluded-apps');
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let addAppId = (function addAppId(appId) {
|
||||
if (excludedApps.indexOf(appId) >= 0)
|
||||
return;
|
||||
|
||||
let app = appSys.lookup_app(appId);
|
||||
if (!app)
|
||||
return;
|
||||
|
||||
if (!app.get_app_info().should_show())
|
||||
return;
|
||||
|
||||
let icon = new AppIcon(app);
|
||||
this.view.addItem(icon);
|
||||
}).bind(this);
|
||||
|
||||
let folderApps = this._folder.get_strv('apps');
|
||||
folderApps.forEach(addAppId);
|
||||
|
||||
let folderCategories = this._folder.get_strv('categories');
|
||||
Gio.AppInfo.get_all().forEach(function(appInfo) {
|
||||
let appCategories = _getCategories(appInfo);
|
||||
if (!_listsIntersect(folderCategories, appCategories))
|
||||
return;
|
||||
|
||||
addAppId(appInfo.get_id());
|
||||
});
|
||||
|
||||
this.view.loadGrid();
|
||||
this.emit('apps-changed');
|
||||
},
|
||||
|
||||
_createIcon: function(iconSize) {
|
||||
@ -1170,6 +1185,7 @@ const FolderIcon = new Lang.Class({
|
||||
this._popupInvalidated = true;
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(FolderIcon.prototype);
|
||||
|
||||
const AppFolderPopup = new Lang.Class({
|
||||
Name: 'AppFolderPopup',
|
||||
@ -1288,6 +1304,9 @@ const AppIcon = new Lang.Class({
|
||||
|
||||
_init : function(app, iconParams) {
|
||||
this.app = app;
|
||||
this.id = app.get_id();
|
||||
this.name = app.get_name();
|
||||
|
||||
this.actor = new St.Button({ style_class: 'app-well-app',
|
||||
reactive: true,
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
|
||||
@ -1385,9 +1404,6 @@ const AppIcon = new Lang.Class({
|
||||
if (button == 1) {
|
||||
this._onActivate(Clutter.get_current_event());
|
||||
} else if (button == 2) {
|
||||
// Last workspace is always empty
|
||||
let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
|
||||
launchWorkspace.activate(global.get_current_time());
|
||||
this.app.open_new_window(-1);
|
||||
Main.overview.hide();
|
||||
}
|
||||
@ -1497,8 +1513,6 @@ const AppIconMenu = new Lang.Class({
|
||||
|
||||
this._source = source;
|
||||
|
||||
this.connect('activate', Lang.bind(this, this._onActivate));
|
||||
|
||||
this.actor.add_style_class_name('app-well-menu');
|
||||
|
||||
// Chain our visibility and lifecycle to that of the source
|
||||
@ -1515,7 +1529,7 @@ const AppIconMenu = new Lang.Class({
|
||||
this.removeAll();
|
||||
|
||||
let windows = this._source.app.get_windows().filter(function(w) {
|
||||
return Shell.WindowTracker.is_window_interesting(w);
|
||||
return !w.skip_taskbar;
|
||||
});
|
||||
|
||||
// Display the app windows menu items and the separator between windows
|
||||
@ -1524,25 +1538,54 @@ const AppIconMenu = new Lang.Class({
|
||||
let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace;
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (!separatorShown && windows[i].get_workspace() != activeWorkspace) {
|
||||
let window = windows[i];
|
||||
if (!separatorShown && window.get_workspace() != activeWorkspace) {
|
||||
this._appendSeparator();
|
||||
separatorShown = true;
|
||||
}
|
||||
let item = this._appendMenuItem(windows[i].title);
|
||||
item._window = windows[i];
|
||||
let item = this._appendMenuItem(window.title);
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
this.emit('activate-window', window);
|
||||
}));
|
||||
}
|
||||
|
||||
if (!this._source.app.is_window_backed()) {
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
this._appendSeparator();
|
||||
|
||||
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
|
||||
this._newWindowMenuItem.connect('activate', Lang.bind(this, function() {
|
||||
this._source.app.open_new_window(-1);
|
||||
this.emit('activate-window', null);
|
||||
}));
|
||||
this._appendSeparator();
|
||||
|
||||
let appInfo = this._source.app.get_app_info();
|
||||
let actions = appInfo.list_actions();
|
||||
for (let i = 0; i < actions.length; i++) {
|
||||
let action = actions[i];
|
||||
let item = this._appendMenuItem(appInfo.get_action_name(action));
|
||||
item.connect('activate', Lang.bind(this, function(emitter, event) {
|
||||
this._source.app.launch_action(action, event.get_time(), -1);
|
||||
this.emit('activate-window', null);
|
||||
}));
|
||||
}
|
||||
this._appendSeparator();
|
||||
|
||||
let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
|
||||
|
||||
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
|
||||
this._appendSeparator();
|
||||
|
||||
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
|
||||
: _("Add to Favorites"));
|
||||
if (isFavorite) {
|
||||
let item = this._appendMenuItem(_("Remove from Favorites"));
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
let favs = AppFavorites.getAppFavorites();
|
||||
favs.removeFavorite(this._source.app.get_id());
|
||||
}));
|
||||
} else {
|
||||
let item = this._appendMenuItem(_("Add to Favorites"));
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
let favs = AppFavorites.getAppFavorites();
|
||||
favs.addFavorite(this._source.app.get_id());
|
||||
}));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -1561,24 +1604,6 @@ const AppIconMenu = new Lang.Class({
|
||||
popup: function(activatingButton) {
|
||||
this._redisplay();
|
||||
this.open();
|
||||
},
|
||||
|
||||
_onActivate: function (actor, child) {
|
||||
if (child._window) {
|
||||
let metaWindow = child._window;
|
||||
this.emit('activate-window', metaWindow);
|
||||
} else if (child == this._newWindowMenuItem) {
|
||||
this._source.app.open_new_window(-1);
|
||||
this.emit('activate-window', null);
|
||||
} else if (child == this._toggleFavoriteMenuItem) {
|
||||
let favs = AppFavorites.getAppFavorites();
|
||||
let isFavorite = favs.isFavorite(this._source.app.get_id());
|
||||
if (isFavorite)
|
||||
favs.removeFavorite(this._source.app.get_id());
|
||||
else
|
||||
favs.addFavorite(this._source.app.get_id());
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(AppIconMenu.prototype);
|
||||
|
@ -132,6 +132,25 @@ const BackgroundCache = new Lang.Class({
|
||||
this._removeContent(this._images, content);
|
||||
},
|
||||
|
||||
_attachCallerToFileLoad: function(caller, fileLoad) {
|
||||
fileLoad.callers.push(caller);
|
||||
|
||||
if (!caller.cancellable)
|
||||
return;
|
||||
|
||||
caller.cancellable.connect(Lang.bind(this, function() {
|
||||
let idx = fileLoad.callers.indexOf(caller);
|
||||
fileLoad.callers.splice(idx, 1);
|
||||
|
||||
if (fileLoad.callers.length == 0) {
|
||||
fileLoad.cancellable.cancel();
|
||||
|
||||
let idx = this._pendingFileLoads.indexOf(fileLoad);
|
||||
this._pendingFileLoads.splice(idx, 1);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_loadImageContent: function(params) {
|
||||
params = Params.parse(params, { monitorIndex: 0,
|
||||
style: null,
|
||||
@ -140,27 +159,28 @@ const BackgroundCache = new Lang.Class({
|
||||
cancellable: null,
|
||||
onFinished: null });
|
||||
|
||||
let caller = { monitorIndex: params.monitorIndex,
|
||||
effects: params.effects,
|
||||
cancellable: params.cancellable,
|
||||
onFinished: params.onFinished };
|
||||
|
||||
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
||||
if (this._pendingFileLoads[i].filename == params.filename &&
|
||||
this._pendingFileLoads[i].style == params.style) {
|
||||
this._pendingFileLoads[i].callers.push({ shouldCopy: true,
|
||||
monitorIndex: params.monitorIndex,
|
||||
effects: params.effects,
|
||||
onFinished: params.onFinished });
|
||||
let fileLoad = this._pendingFileLoads[i];
|
||||
|
||||
if (fileLoad.filename == params.filename &&
|
||||
fileLoad.style == params.style) {
|
||||
this._attachCallerToFileLoad(caller, fileLoad);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._pendingFileLoads.push({ filename: params.filename,
|
||||
style: params.style,
|
||||
callers: [{ shouldCopy: false,
|
||||
monitorIndex: params.monitorIndex,
|
||||
effects: params.effects,
|
||||
onFinished: params.onFinished }] });
|
||||
let fileLoad = { filename: params.filename,
|
||||
style: params.style,
|
||||
cancellable: new Gio.Cancellable(),
|
||||
callers: [] };
|
||||
this._attachCallerToFileLoad(caller, fileLoad);
|
||||
|
||||
let content = new Meta.Background({ meta_screen: global.screen,
|
||||
monitor: params.monitorIndex,
|
||||
effects: params.effects });
|
||||
let content = new Meta.Background({ meta_screen: global.screen });
|
||||
|
||||
content.load_file_async(params.filename,
|
||||
params.style,
|
||||
@ -171,35 +191,26 @@ const BackgroundCache = new Lang.Class({
|
||||
content.load_file_finish(result);
|
||||
|
||||
this._monitorFile(params.filename);
|
||||
this._images.push(content);
|
||||
} catch(e) {
|
||||
content = null;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._pendingFileLoads.length; i++) {
|
||||
let pendingLoad = this._pendingFileLoads[i];
|
||||
if (pendingLoad.filename != params.filename ||
|
||||
pendingLoad.style != params.style)
|
||||
continue;
|
||||
for (let i = 0; i < fileLoad.callers.length; i++) {
|
||||
let caller = fileLoad.callers[i];
|
||||
if (caller.onFinished) {
|
||||
let newContent;
|
||||
|
||||
for (let j = 0; j < pendingLoad.callers.length; j++) {
|
||||
if (pendingLoad.callers[j].onFinished) {
|
||||
let newContent;
|
||||
|
||||
if (content && pendingLoad.callers[j].shouldCopy) {
|
||||
newContent = content.copy(pendingLoad.callers[j].monitorIndex,
|
||||
pendingLoad.callers[j].effects);
|
||||
this._images.push(newContent);
|
||||
} else {
|
||||
newContent = content;
|
||||
}
|
||||
|
||||
pendingLoad.callers[j].onFinished(newContent);
|
||||
if (content) {
|
||||
newContent = content.copy(caller.monitorIndex, caller.effects);
|
||||
this._images.push(newContent);
|
||||
}
|
||||
}
|
||||
|
||||
this._pendingFileLoads.splice(i, 1);
|
||||
caller.onFinished(newContent);
|
||||
}
|
||||
}
|
||||
|
||||
let idx = this._pendingFileLoads.indexOf(fileLoad);
|
||||
this._pendingFileLoads.splice(idx, 1);
|
||||
}));
|
||||
},
|
||||
|
||||
@ -565,7 +576,7 @@ const Background = new Lang.Class({
|
||||
_load: function () {
|
||||
this._cache = getBackgroundCache();
|
||||
|
||||
this._loadPattern(this._cache);
|
||||
this._loadPattern();
|
||||
|
||||
this._style = this._settings.get_enum(BACKGROUND_STYLE_KEY);
|
||||
if (this._style == GDesktopEnums.BackgroundStyle.NONE) {
|
||||
@ -733,29 +744,31 @@ const BackgroundManager = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_updateBackground: function(background) {
|
||||
_updateBackground: function() {
|
||||
let newBackground = this._createBackground();
|
||||
newBackground.vignetteSharpness = background.vignetteSharpness;
|
||||
newBackground.brightness = background.brightness;
|
||||
newBackground.visible = background.visible;
|
||||
newBackground.vignetteSharpness = this.background.vignetteSharpness;
|
||||
newBackground.brightness = this.background.brightness;
|
||||
newBackground.visible = this.background.visible;
|
||||
|
||||
newBackground.loadedSignalId = newBackground.connect('loaded',
|
||||
Lang.bind(this, function() {
|
||||
newBackground.disconnect(newBackground.loadedSignalId);
|
||||
newBackground.loadedSignalId = 0;
|
||||
Tweener.addTween(background.actor,
|
||||
|
||||
if (this._newBackground != newBackground) {
|
||||
/* Not interesting, we queued another load */
|
||||
newBackground.actor.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
Tweener.addTween(this.background.actor,
|
||||
{ opacity: 0,
|
||||
time: FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
if (this._newBackground == newBackground) {
|
||||
this.background = newBackground;
|
||||
this._newBackground = null;
|
||||
} else {
|
||||
newBackground.actor.destroy();
|
||||
}
|
||||
|
||||
background.actor.destroy();
|
||||
this.background.actor.destroy();
|
||||
this.background = newBackground;
|
||||
this._newBackground = null;
|
||||
|
||||
this.emit('changed');
|
||||
})
|
||||
@ -783,7 +796,7 @@ const BackgroundManager = new Lang.Class({
|
||||
background.changeSignalId = background.connect('changed', Lang.bind(this, function() {
|
||||
background.disconnect(background.changeSignalId);
|
||||
background.changeSignalId = 0;
|
||||
this._updateBackground(background);
|
||||
this._updateBackground();
|
||||
}));
|
||||
|
||||
background.actor.connect('destroy', Lang.bind(this, function() {
|
||||
|
@ -13,8 +13,8 @@ const BackgroundMenu = new Lang.Class({
|
||||
Name: 'BackgroundMenu',
|
||||
Extends: PopupMenu.PopupMenu,
|
||||
|
||||
_init: function(source, layoutManager) {
|
||||
this.parent(source, 0, St.Side.TOP);
|
||||
_init: function(layoutManager) {
|
||||
this.parent(layoutManager.dummyCursor, 0, St.Side.TOP);
|
||||
|
||||
this.addSettingsAction(_("Settings"), 'gnome-control-center.desktop');
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
@ -28,17 +28,14 @@ const BackgroundMenu = new Lang.Class({
|
||||
});
|
||||
|
||||
function addBackgroundMenu(actor, layoutManager) {
|
||||
let cursor = new St.Bin({ opacity: 0 });
|
||||
layoutManager.uiGroup.add_actor(cursor);
|
||||
|
||||
actor.reactive = true;
|
||||
actor._backgroundMenu = new BackgroundMenu(cursor, layoutManager);
|
||||
actor._backgroundMenu = new BackgroundMenu(layoutManager);
|
||||
actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
|
||||
actor._backgroundManager.addMenu(actor._backgroundMenu);
|
||||
|
||||
function openMenu() {
|
||||
let [x, y] = global.get_pointer();
|
||||
cursor.set_position(x, y);
|
||||
Main.layoutManager.setDummyCursorPosition(x, y);
|
||||
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
|
||||
}
|
||||
|
||||
@ -59,10 +56,8 @@ function addBackgroundMenu(actor, layoutManager) {
|
||||
actor.add_action(clickAction);
|
||||
|
||||
actor.connect('destroy', function() {
|
||||
actor._backgroundMenu.destroy();
|
||||
actor._backgroundMenu = null;
|
||||
actor._backgroundManager = null;
|
||||
|
||||
cursor.destroy();
|
||||
});
|
||||
actor._backgroundMenu.destroy();
|
||||
actor._backgroundMenu = null;
|
||||
actor._backgroundManager = null;
|
||||
});
|
||||
}
|
||||
|
@ -287,38 +287,40 @@ const BoxPointer = new Lang.Class({
|
||||
let skipBottomLeft = false;
|
||||
let skipBottomRight = false;
|
||||
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
if (this._arrowOrigin == x1)
|
||||
skipTopLeft = true;
|
||||
else if (this._arrowOrigin == x2)
|
||||
skipTopRight = true;
|
||||
break;
|
||||
if (rise) {
|
||||
switch (this._arrowSide) {
|
||||
case St.Side.TOP:
|
||||
if (this._arrowOrigin == x1)
|
||||
skipTopLeft = true;
|
||||
else if (this._arrowOrigin == x2)
|
||||
skipTopRight = true;
|
||||
break;
|
||||
|
||||
case St.Side.RIGHT:
|
||||
if (this._arrowOrigin == y1)
|
||||
skipTopRight = true;
|
||||
else if (this._arrowOrigin == y2)
|
||||
skipBottomRight = true;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
if (this._arrowOrigin == y1)
|
||||
skipTopRight = true;
|
||||
else if (this._arrowOrigin == y2)
|
||||
skipBottomRight = true;
|
||||
break;
|
||||
|
||||
case St.Side.BOTTOM:
|
||||
if (this._arrowOrigin == x1)
|
||||
skipBottomLeft = true;
|
||||
else if (this._arrowOrigin == x2)
|
||||
skipBottomRight = true;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
if (this._arrowOrigin == x1)
|
||||
skipBottomLeft = true;
|
||||
else if (this._arrowOrigin == x2)
|
||||
skipBottomRight = true;
|
||||
break;
|
||||
|
||||
case St.Side.LEFT:
|
||||
if (this._arrowOrigin == y1)
|
||||
skipTopLeft = true;
|
||||
else if (this._arrowOrigin == y2)
|
||||
skipBottomLeft = true;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
if (this._arrowOrigin == y1)
|
||||
skipTopLeft = true;
|
||||
else if (this._arrowOrigin == y2)
|
||||
skipBottomLeft = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cr.moveTo(x1 + borderRadius, y1);
|
||||
if (this._arrowSide == St.Side.TOP) {
|
||||
if (this._arrowSide == St.Side.TOP && rise) {
|
||||
if (skipTopLeft) {
|
||||
cr.moveTo(x1, y2 - borderRadius);
|
||||
cr.lineTo(x1, y1 - rise);
|
||||
@ -340,7 +342,7 @@ const BoxPointer = new Lang.Class({
|
||||
3*Math.PI/2, Math.PI*2);
|
||||
}
|
||||
|
||||
if (this._arrowSide == St.Side.RIGHT) {
|
||||
if (this._arrowSide == St.Side.RIGHT && rise) {
|
||||
if (skipTopRight) {
|
||||
cr.lineTo(x2 + rise, y1);
|
||||
cr.lineTo(x2 + rise, y1 + halfBase);
|
||||
@ -361,7 +363,7 @@ const BoxPointer = new Lang.Class({
|
||||
0, Math.PI/2);
|
||||
}
|
||||
|
||||
if (this._arrowSide == St.Side.BOTTOM) {
|
||||
if (this._arrowSide == St.Side.BOTTOM && rise) {
|
||||
if (skipBottomLeft) {
|
||||
cr.lineTo(x1 + halfBase, y2);
|
||||
cr.lineTo(x1, y2 + rise);
|
||||
@ -382,7 +384,7 @@ const BoxPointer = new Lang.Class({
|
||||
Math.PI/2, Math.PI);
|
||||
}
|
||||
|
||||
if (this._arrowSide == St.Side.LEFT) {
|
||||
if (this._arrowSide == St.Side.LEFT && rise) {
|
||||
if (skipTopLeft) {
|
||||
cr.lineTo(x1, y1 + halfBase);
|
||||
cr.lineTo(x1 - rise, y1);
|
||||
|
@ -403,6 +403,8 @@ const Calendar = new Lang.Class({
|
||||
// Start off with the current date
|
||||
this._selectedDate = new Date();
|
||||
|
||||
this._shouldDateGrabFocus = false;
|
||||
|
||||
this.actor = new St.Table({ homogeneous: false,
|
||||
style_class: 'calendar',
|
||||
reactive: true });
|
||||
@ -418,8 +420,10 @@ const Calendar = new Lang.Class({
|
||||
setEventSource: function(eventSource) {
|
||||
this._eventSource = eventSource;
|
||||
this._eventSource.connect('changed', Lang.bind(this, function() {
|
||||
this._rebuildCalendar();
|
||||
this._update();
|
||||
}));
|
||||
this._rebuildCalendar();
|
||||
this._update();
|
||||
},
|
||||
|
||||
@ -548,6 +552,7 @@ const Calendar = new Lang.Class({
|
||||
_onSettingsChange: function() {
|
||||
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
|
||||
this._buildHeader();
|
||||
this._rebuildCalendar();
|
||||
this._update();
|
||||
},
|
||||
|
||||
@ -607,7 +612,9 @@ const Calendar = new Lang.Class({
|
||||
|
||||
button._date = new Date(iter);
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
this._shouldDateGrabFocus = true;
|
||||
this.setDate(button._date);
|
||||
this._shouldDateGrabFocus = false;
|
||||
}));
|
||||
|
||||
let hasEvents = this._eventSource.hasEvents(iter);
|
||||
@ -673,8 +680,11 @@ const Calendar = new Lang.Class({
|
||||
this._rebuildCalendar();
|
||||
|
||||
this._buttons.forEach(Lang.bind(this, function(button) {
|
||||
if (_sameDay(button._date, this._selectedDate))
|
||||
if (_sameDay(button._date, this._selectedDate)) {
|
||||
button.add_style_pseudo_class('active');
|
||||
if (this._shouldDateGrabFocus)
|
||||
button.grab_key_focus();
|
||||
}
|
||||
else
|
||||
button.remove_style_pseudo_class('active');
|
||||
}));
|
||||
|
@ -64,7 +64,7 @@ function startAppForMount(app, mount) {
|
||||
|
||||
try {
|
||||
retval = app.launch(files,
|
||||
global.create_app_launch_context())
|
||||
global.create_app_launch_context(0, -1))
|
||||
} catch (e) {
|
||||
log('Unable to launch the application ' + app.get_name()
|
||||
+ ': ' + e.toString());
|
||||
|
@ -309,7 +309,7 @@ const NetworkSecretDialog = new Lang.Class({
|
||||
wirelessSetting = this._connection.get_setting_wireless();
|
||||
ssid = NetworkManager.utils_ssid_to_utf8(wirelessSetting.get_ssid());
|
||||
content.title = _("Authentication required by wireless network");
|
||||
content.message = _("Passwords or encryption keys are required to access the wireless network '%s'.").format(ssid);
|
||||
content.message = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
|
||||
this._getWirelessSecrets(content.secrets, wirelessSetting);
|
||||
break;
|
||||
case '802-3-ethernet':
|
||||
@ -336,7 +336,7 @@ const NetworkSecretDialog = new Lang.Class({
|
||||
case 'cdma':
|
||||
case 'bluetooth':
|
||||
content.title = _("Mobile broadband network password");
|
||||
content.message = _("A password is required to connect to '%s'.").format(connectionSetting.get_id());
|
||||
content.message = _("A password is required to connect to “%s”.").format(connectionSetting.get_id());
|
||||
this._getMobileSecrets(content.secrets, connectionType);
|
||||
break;
|
||||
default:
|
||||
|
@ -1,5 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
@ -28,6 +29,8 @@ const SCROLLBACK_HISTORY_LINES = 10;
|
||||
// See Notification._onEntryChanged
|
||||
const COMPOSING_STOP_TIMEOUT = 5;
|
||||
|
||||
const CLOCK_FORMAT_KEY = 'clock-format';
|
||||
|
||||
const NotificationDirection = {
|
||||
SENT: 'chat-sent',
|
||||
RECEIVED: 'chat-received'
|
||||
@ -621,7 +624,11 @@ const ChatSource = new Lang.Class({
|
||||
this.notify();
|
||||
},
|
||||
|
||||
_channelClosed: function() {
|
||||
destroy: function(reason) {
|
||||
if (this._destroyed)
|
||||
return;
|
||||
|
||||
this._destroyed = true;
|
||||
this._channel.disconnect(this._closedId);
|
||||
this._channel.disconnect(this._receivedId);
|
||||
this._channel.disconnect(this._pendingId);
|
||||
@ -631,7 +638,14 @@ const ChatSource = new Lang.Class({
|
||||
this._contact.disconnect(this._notifyAvatarId);
|
||||
this._contact.disconnect(this._presenceChangedId);
|
||||
|
||||
this.destroy();
|
||||
if (this._timestampTimeoutId)
|
||||
Mainloop.source_remove(this._timestampTimeoutId);
|
||||
|
||||
this.parent(reason);
|
||||
},
|
||||
|
||||
_channelClosed: function() {
|
||||
this.destroy(MessageTray.NotificationDestroyedReason.SOURCE_CLOSED);
|
||||
},
|
||||
|
||||
/* All messages are new messages for Telepathy sources */
|
||||
@ -894,14 +908,14 @@ const ChatNotification = new Lang.Class({
|
||||
|
||||
let group = props.group;
|
||||
if (group != this._lastGroup) {
|
||||
let style = 'chat-group-' + group;
|
||||
this._lastGroup = group;
|
||||
this._lastGroupActor = new St.BoxLayout({ style_class: style,
|
||||
vertical: true });
|
||||
this.addActor(this._lastGroupActor);
|
||||
let emptyLine = new St.Label({ style_class: 'chat-empty-line' });
|
||||
this.addActor(emptyLine);
|
||||
}
|
||||
|
||||
this._lastGroupActor.add(body, props.childProps);
|
||||
this._lastMessageBox = new St.BoxLayout({ vertical: false });
|
||||
this._lastMessageBox.add(body, props.childProps);
|
||||
this.addActor(this._lastMessageBox);
|
||||
|
||||
this.updated();
|
||||
|
||||
@ -930,32 +944,81 @@ const ChatNotification = new Lang.Class({
|
||||
|
||||
let format;
|
||||
|
||||
// Show only the hour if date is on today
|
||||
if(daysAgo < 1){
|
||||
format = "<b>%H:%M</b>";
|
||||
}
|
||||
// Show the word "Yesterday" and time if date is on yesterday
|
||||
else if(daysAgo <2){
|
||||
/* Translators: this is the word "Yesterday" followed by a time string. i.e. "Yesterday, 14:30"*/
|
||||
// xgettext:no-c-format
|
||||
format = _("<b>Yesterday</b>, <b>%H:%M</b>");
|
||||
}
|
||||
// Show a week day and time if date is in the last week
|
||||
else if (daysAgo < 7) {
|
||||
/* Translators: this is the week day name followed by a time string. i.e. "Monday, 14:30*/
|
||||
// xgettext:no-c-format
|
||||
format = _("<b>%A</b>, <b>%H:%M</b>");
|
||||
let desktopSettings = new Gio.Settings({ schema: 'org.gnome.desktop.interface' });
|
||||
let clockFormat = desktopSettings.get_string(CLOCK_FORMAT_KEY);
|
||||
|
||||
} else if (date.getYear() == now.getYear()) {
|
||||
/* Translators: this is the month name and day number followed by a time string. i.e. "May 25, 14:30"*/
|
||||
// xgettext:no-c-format
|
||||
format = _("<b>%B</b> <b>%d</b>, <b>%H:%M</b>");
|
||||
} else {
|
||||
/* Translators: this is the month name, day number, year number followed by a time string. i.e. "May 25 2012, 14:30"*/
|
||||
// xgettext:no-c-format
|
||||
format = _("<b>%B</b> <b>%d</b> <b>%Y</b>, <b>%H:%M</b> ");
|
||||
}
|
||||
switch (clockFormat) {
|
||||
case '24h':
|
||||
// Show only the time if date is on today
|
||||
if(daysAgo < 1){
|
||||
/* Translators: Time in 24h format */
|
||||
format = _("%H\u2236%M");
|
||||
}
|
||||
// Show the word "Yesterday" and time if date is on yesterday
|
||||
else if(daysAgo <2){
|
||||
/* Translators: this is the word "Yesterday" followed by a
|
||||
time string in 24h format. i.e. "Yesterday, 14:30" */
|
||||
// xgettext:no-c-format
|
||||
format = _("Yesterday, %H\u2236%M");
|
||||
}
|
||||
// Show a week day and time if date is in the last week
|
||||
else if (daysAgo < 7) {
|
||||
/* Translators: this is the week day name followed by a time
|
||||
string in 24h format. i.e. "Monday, 14:30" */
|
||||
// xgettext:no-c-format
|
||||
format = _("%A, %H\u2236%M");
|
||||
|
||||
} else if (date.getYear() == now.getYear()) {
|
||||
/* Translators: this is the month name and day number
|
||||
followed by a time string in 24h format.
|
||||
i.e. "May 25, 14:30" */
|
||||
// xgettext:no-c-format
|
||||
format = _("%B %d, %H\u2236%M");
|
||||
} else {
|
||||
/* Translators: this is the month name, day number, year
|
||||
number followed by a time string in 24h format.
|
||||
i.e. "May 25 2012, 14:30" */
|
||||
// xgettext:no-c-format
|
||||
format = _("%B %d %Y, %H\u2236%M");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* explicit fall-through */
|
||||
case '12h':
|
||||
// Show only the time if date is on today
|
||||
if(daysAgo < 1){
|
||||
/* Translators: Time in 24h format */
|
||||
format = _("%l\u2236%M %p");
|
||||
}
|
||||
// Show the word "Yesterday" and time if date is on yesterday
|
||||
else if(daysAgo <2){
|
||||
/* Translators: this is the word "Yesterday" followed by a
|
||||
time string in 12h format. i.e. "Yesterday, 2:30 pm" */
|
||||
// xgettext:no-c-format
|
||||
format = _("Yesterday, %l\u2236%M %p");
|
||||
}
|
||||
// Show a week day and time if date is in the last week
|
||||
else if (daysAgo < 7) {
|
||||
/* Translators: this is the week day name followed by a time
|
||||
string in 12h format. i.e. "Monday, 2:30 pm" */
|
||||
// xgettext:no-c-format
|
||||
format = _("%A, %l\u2236%M %p");
|
||||
|
||||
} else if (date.getYear() == now.getYear()) {
|
||||
/* Translators: this is the month name and day number
|
||||
followed by a time string in 12h format.
|
||||
i.e. "May 25, 2:30 pm" */
|
||||
// xgettext:no-c-format
|
||||
format = _("%B %d, %l\u2236%M %p");
|
||||
} else {
|
||||
/* Translators: this is the month name, day number, year
|
||||
number followed by a time string in 12h format.
|
||||
i.e. "May 25 2012, 2:30 pm"*/
|
||||
// xgettext:no-c-format
|
||||
format = _("%B %d %Y, %l\u2236%M %p");
|
||||
}
|
||||
break;
|
||||
}
|
||||
return date.toLocaleFormat(format);
|
||||
},
|
||||
|
||||
@ -965,13 +1028,14 @@ const ChatNotification = new Lang.Class({
|
||||
let lastMessageTime = this._history[0].time;
|
||||
let lastMessageDate = new Date(lastMessageTime * 1000);
|
||||
|
||||
let timeLabel = this._append({ body: this._formatTimestamp(lastMessageDate),
|
||||
group: 'meta',
|
||||
styles: ['chat-meta-message'],
|
||||
childProps: { expand: true, x_fill: false,
|
||||
x_align: St.Align.END },
|
||||
noTimestamp: true,
|
||||
timestamp: lastMessageTime });
|
||||
let timeLabel = new St.Label({ text: this._formatTimestamp(lastMessageDate),
|
||||
style_class: 'chat-meta-message',
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
x_align: Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.END });
|
||||
|
||||
this._lastMessageBox.add_actor(timeLabel);
|
||||
|
||||
this._filterMessages();
|
||||
|
||||
@ -1339,7 +1403,7 @@ const AccountNotification = new Lang.Class({
|
||||
let cmd = 'empathy-accounts --select-account=' +
|
||||
account.get_path_suffix();
|
||||
let app_info = Gio.app_info_create_from_commandline(cmd, null, 0);
|
||||
app_info.launch([], global.create_app_launch_context());
|
||||
app_info.launch([], global.create_app_launch_context(0, -1));
|
||||
}));
|
||||
|
||||
this._enabledId = account.connect('notify::enabled',
|
||||
@ -1357,7 +1421,12 @@ const AccountNotification = new Lang.Class({
|
||||
if (status == Tp.ConnectionStatus.CONNECTED) {
|
||||
this.destroy();
|
||||
} else if (status == Tp.ConnectionStatus.DISCONNECTED) {
|
||||
this.update(this.title, this._getMessage(account.connection_error));
|
||||
let connectionError = account.connection_error;
|
||||
|
||||
if (connectionError == Tp.error_get_dbus_name(Tp.Error.CANCELLED))
|
||||
this.destroy();
|
||||
else
|
||||
this.update(this.title, this._getMessage(connectionError));
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
@ -381,6 +381,8 @@ const DashActor = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const baseIconSizes = [ 16, 22, 24, 32, 48, 64 ];
|
||||
|
||||
const Dash = new Lang.Class({
|
||||
Name: 'Dash',
|
||||
|
||||
@ -632,25 +634,24 @@ const Dash = new Lang.Class({
|
||||
let minHeight, natHeight;
|
||||
|
||||
// Enforce the current icon size during the size request
|
||||
let [currentWidth, currentHeight] = firstIcon.icon.get_size();
|
||||
|
||||
firstIcon.icon.set_size(this.iconSize, this.iconSize);
|
||||
firstIcon.setIconSize(this.iconSize);
|
||||
[minHeight, natHeight] = firstButton.get_preferred_height(-1);
|
||||
|
||||
firstIcon.icon.set_size(currentWidth, currentHeight);
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
let iconSizes = baseIconSizes.map(function(s) {
|
||||
return s * scaleFactor;
|
||||
});
|
||||
|
||||
// Subtract icon padding and box spacing from the available height
|
||||
availHeight -= iconChildren.length * (natHeight - this.iconSize) +
|
||||
availHeight -= iconChildren.length * (natHeight - this.iconSize * scaleFactor) +
|
||||
(iconChildren.length - 1) * spacing;
|
||||
|
||||
let availSize = availHeight / iconChildren.length;
|
||||
|
||||
let iconSizes = [ 16, 22, 24, 32, 48, 64 ];
|
||||
|
||||
let newIconSize = 16;
|
||||
let newIconSize = baseIconSizes[0];
|
||||
for (let i = 0; i < iconSizes.length; i++) {
|
||||
if (iconSizes[i] < availSize)
|
||||
newIconSize = iconSizes[i];
|
||||
newIconSize = baseIconSizes[i];
|
||||
}
|
||||
|
||||
if (newIconSize == this.iconSize)
|
||||
|
@ -63,9 +63,14 @@ const DateMenuButton = new Lang.Class({
|
||||
hbox.add(vbox);
|
||||
|
||||
// Date
|
||||
this._date = new St.Label({ style_class: 'datemenu-date-label',
|
||||
can_focus: true });
|
||||
vbox.add(this._date);
|
||||
this._date = new St.Button({ style_class: 'datemenu-date-label',
|
||||
can_focus: true,
|
||||
});
|
||||
this._date.connect('clicked',
|
||||
Lang.bind(this, function() {
|
||||
this._calendar.setDate(new Date(), false);
|
||||
}));
|
||||
vbox.add(this._date, { x_fill: false });
|
||||
|
||||
this._eventList = new Calendar.EventsList();
|
||||
this._calendar = new Calendar.Calendar();
|
||||
@ -186,7 +191,7 @@ const DateMenuButton = new Lang.Class({
|
||||
*/
|
||||
let dateFormat = _("%A %B %e, %Y");
|
||||
let displayDate = new Date();
|
||||
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
|
||||
this._date.set_label(displayDate.toLocaleFormat(dateFormat));
|
||||
},
|
||||
|
||||
_getCalendarApp: function() {
|
||||
@ -202,7 +207,7 @@ const DateMenuButton = new Lang.Class({
|
||||
},
|
||||
|
||||
_getClockApp: function() {
|
||||
return Shell.AppSystem.get_default().lookup_app('gnome-clocks.desktop');
|
||||
return Shell.AppSystem.get_default().lookup_app('org.gnome.clocks.desktop');
|
||||
},
|
||||
|
||||
_onOpenCalendarActivate: function() {
|
||||
@ -211,7 +216,7 @@ const DateMenuButton = new Lang.Class({
|
||||
let app = this._getCalendarApp();
|
||||
if (app.get_id() == 'evolution.desktop')
|
||||
app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
|
||||
app.launch([], global.create_app_launch_context());
|
||||
app.launch([], global.create_app_launch_context(0, -1));
|
||||
},
|
||||
|
||||
_onOpenClocksActivate: function() {
|
||||
|
@ -13,9 +13,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
* 02111-1307, USA.
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const Lang = imports.lang;
|
||||
@ -27,9 +25,11 @@ const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Polkit = imports.gi.Polkit;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const CheckBox = imports.ui.checkBox;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
@ -38,8 +38,10 @@ const UserWidget = imports.ui.userWidget;
|
||||
|
||||
let _endSessionDialog = null;
|
||||
|
||||
const TRIGGER_OFFLINE_UPDATE = '/usr/libexec/pk-trigger-offline-update';
|
||||
|
||||
const _ITEM_ICON_SIZE = 48;
|
||||
const _DIALOG_ICON_SIZE = 32;
|
||||
const _DIALOG_ICON_SIZE = 48;
|
||||
|
||||
const GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
|
||||
|
||||
@ -73,6 +75,7 @@ const logoutDialogContent = {
|
||||
"You will be logged out automatically in %d seconds.",
|
||||
seconds).format(seconds);
|
||||
},
|
||||
showBatteryWarning: false,
|
||||
confirmButtons: [{ signal: 'ConfirmedLogout',
|
||||
label: C_("button", "Log Out") }],
|
||||
iconStyleClass: 'end-session-dialog-logout-icon',
|
||||
@ -81,11 +84,14 @@ const logoutDialogContent = {
|
||||
|
||||
const shutdownDialogContent = {
|
||||
subject: C_("title", "Power Off"),
|
||||
subjectWithUpdates: C_("title", "Install Updates & Power Off"),
|
||||
description: function(seconds) {
|
||||
return ngettext("The system will power off automatically in %d second.",
|
||||
"The system will power off automatically in %d seconds.",
|
||||
seconds).format(seconds);
|
||||
},
|
||||
checkBoxText: C_("checkbox", "Install pending software updates"),
|
||||
showBatteryWarning: true,
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: C_("button", "Restart") },
|
||||
{ signal: 'ConfirmedShutdown',
|
||||
@ -102,6 +108,7 @@ const restartDialogContent = {
|
||||
"The system will restart automatically in %d seconds.",
|
||||
seconds).format(seconds);
|
||||
},
|
||||
showBatteryWarning: false,
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: C_("button", "Restart") }],
|
||||
iconName: 'view-refresh-symbolic',
|
||||
@ -117,8 +124,11 @@ const restartInstallDialogContent = {
|
||||
"The system will automatically restart and install updates in %d seconds.",
|
||||
seconds).format(seconds);
|
||||
},
|
||||
showBatteryWarning: true,
|
||||
confirmButtons: [{ signal: 'ConfirmedReboot',
|
||||
label: C_("button", "Restart & Install") }],
|
||||
label: C_("button", "Restart & Install") }],
|
||||
unusedFutureButtonForTranslation: C_("button", "Install & Power Off"),
|
||||
unusedFutureCheckBoxForTranslation: C_("checkbox", "Power off after updates are installed"),
|
||||
iconName: 'view-refresh-symbolic',
|
||||
iconStyleClass: 'end-session-dialog-shutdown-icon',
|
||||
showOtherSessions: true,
|
||||
@ -145,6 +155,14 @@ const LogindSessionIface = '<node> \
|
||||
|
||||
const LogindSession = Gio.DBusProxy.makeProxyWrapper(LogindSessionIface);
|
||||
|
||||
const UPowerIface = '<node> \
|
||||
<interface name="org.freedesktop.UPower"> \
|
||||
<property name="OnBattery" type="b" access="read"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const UPowerProxy = Gio.DBusProxy.makeProxyWrapper(UPowerIface);
|
||||
|
||||
function findAppFromInhibitor(inhibitor) {
|
||||
let desktopFile;
|
||||
try {
|
||||
@ -197,6 +215,18 @@ function _setLabelText(label, text) {
|
||||
}
|
||||
}
|
||||
|
||||
function _setCheckBoxLabel(checkBox, text) {
|
||||
let label = checkBox.getLabelActor();
|
||||
|
||||
if (text) {
|
||||
label.set_text(text);
|
||||
checkBox.actor.show();
|
||||
} else {
|
||||
label.set_text('');
|
||||
checkBox.actor.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function init() {
|
||||
// This always returns the same singleton object
|
||||
// By instantiating it initially, we register the
|
||||
@ -216,6 +246,20 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
this._user = this._userManager.get_user(GLib.get_user_name());
|
||||
this._updatesFile = Gio.File.new_for_path('/system-update');
|
||||
this._preparedUpdateFile = Gio.File.new_for_path('/var/lib/PackageKit/prepared-update');
|
||||
|
||||
this._powerProxy = new UPowerProxy(Gio.DBus.system,
|
||||
'org.freedesktop.UPower',
|
||||
'/org/freedesktop/UPower',
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._powerProxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
this._sync();
|
||||
}));
|
||||
|
||||
this._secondsLeft = 0;
|
||||
this._totalSecondsToStayOpen = 0;
|
||||
@ -242,7 +286,8 @@ const EndSessionDialog = new Lang.Class({
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let messageLayout = new St.BoxLayout({ vertical: true });
|
||||
let messageLayout = new St.BoxLayout({ vertical: true,
|
||||
style_class: 'end-session-dialog-layout' });
|
||||
mainContentLayout.add(messageLayout,
|
||||
{ y_align: St.Align.START });
|
||||
|
||||
@ -262,6 +307,16 @@ const EndSessionDialog = new Lang.Class({
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this._checkBox = new CheckBox.CheckBox();
|
||||
this._checkBox.actor.connect('clicked', Lang.bind(this, this._sync));
|
||||
messageLayout.add(this._checkBox.actor);
|
||||
|
||||
this._batteryWarning = new St.Label({ style_class: 'end-session-dialog-warning',
|
||||
text: _("Running on battery power: please plug in before installing updates.") });
|
||||
this._batteryWarning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._batteryWarning.clutter_text.line_wrap = true;
|
||||
messageLayout.add(this._batteryWarning);
|
||||
|
||||
this._scrollView = new St.ScrollView({ style_class: 'end-session-dialog-list' });
|
||||
this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this.contentLayout.add(this._scrollView,
|
||||
@ -287,6 +342,12 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._inhibitorSection.add_actor(this._sessionHeader);
|
||||
this._inhibitorSection.add_actor(this._sessionList);
|
||||
|
||||
try {
|
||||
this._updatesPermission = Polkit.Permission.new_sync("org.freedesktop.packagekit.trigger-offline-update", null, null);
|
||||
} catch(e) {
|
||||
log('No permission to trigger offline updates: %s'.format(e.toString()));
|
||||
}
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
|
||||
},
|
||||
@ -301,13 +362,22 @@ const EndSessionDialog = new Lang.Class({
|
||||
if (!open)
|
||||
return;
|
||||
|
||||
if (this._type == 2 && this._updatesFile.query_exists(null))
|
||||
this._type = 3;
|
||||
|
||||
let dialogContent = DialogContent[this._type];
|
||||
|
||||
let subject = dialogContent.subject;
|
||||
|
||||
// Use different title when we are installing updates
|
||||
if (dialogContent.subjectWithUpdates && this._checkBox.actor.checked)
|
||||
subject = dialogContent.subjectWithUpdates;
|
||||
|
||||
if (dialogContent.showBatteryWarning) {
|
||||
// Warn when running on battery power
|
||||
if (this._powerProxy.OnBattery && this._checkBox.actor.checked)
|
||||
this._batteryWarning.opacity = 255;
|
||||
else
|
||||
this._batteryWarning.opacity = 0;
|
||||
}
|
||||
|
||||
let description;
|
||||
let displayTime = _roundSecondsToInterval(this._totalSecondsToStayOpen,
|
||||
this._secondsLeft,
|
||||
@ -390,15 +460,75 @@ const EndSessionDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_confirm: function(signal) {
|
||||
this._fadeOutDialog();
|
||||
this._stopTimer();
|
||||
this._dbusImpl.emit_signal(signal, null);
|
||||
let callback = Lang.bind(this, function() {
|
||||
this._fadeOutDialog();
|
||||
this._stopTimer();
|
||||
this._dbusImpl.emit_signal(signal, null);
|
||||
});
|
||||
|
||||
// Offline update not available; just emit the signal
|
||||
if (!this._checkBox.actor.visible) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// Trigger the offline update as requested
|
||||
if (this._checkBox.actor.checked) {
|
||||
switch (signal) {
|
||||
case "ConfirmedReboot":
|
||||
this._triggerOfflineUpdateReboot(callback);
|
||||
break;
|
||||
case "ConfirmedShutdown":
|
||||
// To actually trigger the offline update, we need to
|
||||
// reboot to do the upgrade. When the upgrade is complete,
|
||||
// the computer will shut down automatically.
|
||||
signal = "ConfirmedReboot";
|
||||
this._triggerOfflineUpdateShutdown(callback);
|
||||
break;
|
||||
default:
|
||||
callback();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this._triggerOfflineUpdateCancel(callback);
|
||||
}
|
||||
},
|
||||
|
||||
_onOpened: function() {
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_triggerOfflineUpdateReboot: function(callback) {
|
||||
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, 'reboot'], callback);
|
||||
},
|
||||
|
||||
_triggerOfflineUpdateShutdown: function(callback) {
|
||||
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, 'power-off'], callback);
|
||||
},
|
||||
|
||||
_triggerOfflineUpdateCancel: function(callback) {
|
||||
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, '--cancel'], callback);
|
||||
},
|
||||
|
||||
_pkexecSpawn: function(argv, callback) {
|
||||
let ret, pid;
|
||||
try {
|
||||
[ret, pid] = GLib.spawn_async(null, ['pkexec'].concat(argv), null,
|
||||
GLib.SpawnFlags.DO_NOT_REAP_CHILD | GLib.SpawnFlags.SEARCH_PATH,
|
||||
null);
|
||||
} catch (e) {
|
||||
log('Error spawning "pkexec %s": %s'.format(argv.join(' '), e.toString()));
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
|
||||
GLib.spawn_close_pid(pid);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
_startTimer: function() {
|
||||
let startTime = GLib.get_monotonic_time();
|
||||
this._secondsLeft = this._totalSecondsToStayOpen;
|
||||
@ -546,6 +676,9 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
||||
this._type = type;
|
||||
|
||||
if (this._type == 2 && this._updatesFile.query_exists(null))
|
||||
this._type = 3;
|
||||
|
||||
this._applications = [];
|
||||
this._applicationList.destroy_all_children();
|
||||
|
||||
@ -558,6 +691,8 @@ const EndSessionDialog = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
let dialogContent = DialogContent[this._type];
|
||||
|
||||
for (let i = 0; i < inhibitorObjectPaths.length; i++) {
|
||||
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], Lang.bind(this, function(proxy, error) {
|
||||
this._onInhibitorLoaded(proxy);
|
||||
@ -566,9 +701,23 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._applications.push(inhibitor);
|
||||
}
|
||||
|
||||
if (DialogContent[type].showOtherSessions)
|
||||
if (dialogContent.showOtherSessions)
|
||||
this._loadSessions();
|
||||
|
||||
let preparedUpdate = this._preparedUpdateFile.query_exists(null);
|
||||
let updateAlreadyTriggered = this._updatesFile.query_exists(null);
|
||||
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
|
||||
|
||||
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText);
|
||||
this._checkBox.actor.visible = (dialogContent.checkBoxText && preparedUpdate && updatesAllowed);
|
||||
this._checkBox.actor.checked = (preparedUpdate && updateAlreadyTriggered);
|
||||
|
||||
// We show the warning either together with the checkbox, or when
|
||||
// updates have already been triggered, but the user doesn't have
|
||||
// enough permissions to cancel them.
|
||||
this._batteryWarning.visible = (dialogContent.showBatteryWarning &&
|
||||
(this._checkBox.actor.visible || preparedUpdate && updateAlreadyTriggered && !updatesAllowed));
|
||||
|
||||
this._updateButtons();
|
||||
|
||||
if (!this.open(timestamp)) {
|
||||
|
@ -201,7 +201,7 @@ const InstallExtensionDialog = new Lang.Class({
|
||||
default: true
|
||||
}]);
|
||||
|
||||
let message = _("Download and install '%s' from extensions.gnome.org?").format(info.name);
|
||||
let message = _("Download and install “%s” from extensions.gnome.org?").format(info.name);
|
||||
|
||||
let box = new St.BoxLayout();
|
||||
this.contentLayout.add(box);
|
||||
|
@ -38,6 +38,7 @@ const connect = Lang.bind(_signals, _signals.connect);
|
||||
const disconnect = Lang.bind(_signals, _signals.disconnect);
|
||||
|
||||
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
|
||||
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
|
||||
|
||||
var initted = false;
|
||||
var enabled;
|
||||
@ -156,7 +157,9 @@ function loadExtension(extension) {
|
||||
// Default to error, we set success as the last step
|
||||
extension.state = ExtensionState.ERROR;
|
||||
|
||||
if (ExtensionUtils.isOutOfDate(extension)) {
|
||||
let checkVersion = !global.settings.get_boolean(EXTENSION_DISABLE_VERSION_CHECK_KEY);
|
||||
|
||||
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
|
||||
extension.state = ExtensionState.OUT_OF_DATE;
|
||||
} else {
|
||||
let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
|
||||
@ -267,8 +270,19 @@ function onEnabledExtensionsChanged() {
|
||||
enabledExtensions = newEnabledExtensions;
|
||||
}
|
||||
|
||||
function _onVersionValidationChanged() {
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
enabledExtensions.forEach(function(uuid) {
|
||||
if (ExtensionUtils.extensions[uuid])
|
||||
reloadExtension(ExtensionUtils.extensions[uuid]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function _loadExtensions() {
|
||||
global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
|
||||
global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged);
|
||||
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
||||
let finder = new ExtensionUtils.ExtensionFinder();
|
||||
|
@ -34,7 +34,11 @@ const FocusCaretTracker = new Lang.Class({
|
||||
_init: function() {
|
||||
Atspi.init();
|
||||
Atspi.set_timeout(250, 250);
|
||||
|
||||
this._atspiListener = Atspi.EventListener.new(Lang.bind(this, this._onChanged));
|
||||
|
||||
this._focusListenerRegistered = false;
|
||||
this._caretListenerRegistered = false;
|
||||
},
|
||||
|
||||
_onChanged: function(event) {
|
||||
@ -45,21 +49,39 @@ const FocusCaretTracker = new Lang.Class({
|
||||
},
|
||||
|
||||
registerFocusListener: function() {
|
||||
return this._atspiListener.register(STATECHANGED + ':focused') &&
|
||||
this._atspiListener.register(STATECHANGED + ':selected');
|
||||
if (this._focusListenerRegistered)
|
||||
return;
|
||||
|
||||
// Ignore the return value, we get an exception if they fail
|
||||
// And they should never fail
|
||||
this._atspiListener.register(STATECHANGED + ':focused');
|
||||
this._atspiListener.register(STATECHANGED + ':selected');
|
||||
this._focusListenerRegistered = true;
|
||||
},
|
||||
|
||||
registerCaretListener: function() {
|
||||
return this._atspiListener.register(CARETMOVED);
|
||||
if (this._caretListenerRegistered)
|
||||
return;
|
||||
|
||||
this._atspiListener.register(CARETMOVED);
|
||||
this._caretListenerRegistered = true;
|
||||
},
|
||||
|
||||
deregisterFocusListener: function() {
|
||||
return this._atspiListener.deregister(STATECHANGED + ':focused') &&
|
||||
this._atspiListener.deregister(STATECHANGED + ':selected');
|
||||
if (!this._focusListenerRegistered)
|
||||
return;
|
||||
|
||||
this._atspiListener.deregister(STATECHANGED + ':focused');
|
||||
this._atspiListener.deregister(STATECHANGED + ':selected');
|
||||
this._focusListenerRegistered = false;
|
||||
},
|
||||
|
||||
deregisterCaretListener: function() {
|
||||
return this._atspiListener.deregister(CARETMOVED);
|
||||
if (!this._caretListenerRegistered)
|
||||
return;
|
||||
|
||||
this._atspiListener.deregister(CARETMOVED);
|
||||
this._caretListenerRegistered = false;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(FocusCaretTracker.prototype);
|
||||
|
@ -115,9 +115,6 @@ const CandidatePopup = new Lang.Class({
|
||||
Name: 'CandidatePopup',
|
||||
|
||||
_init: function() {
|
||||
this._cursor = new St.Bin({ opacity: 0 });
|
||||
Main.uiGroup.add_actor(this._cursor);
|
||||
|
||||
this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
|
||||
this._boxPointer.actor.visible = false;
|
||||
this._boxPointer.actor.style_class = 'candidate-popup-boxpointer';
|
||||
@ -158,10 +155,9 @@ const CandidatePopup = new Lang.Class({
|
||||
|
||||
panelService.connect('set-cursor-location',
|
||||
Lang.bind(this, function(ps, x, y, w, h) {
|
||||
this._cursor.set_position(x, y);
|
||||
this._cursor.set_size(w, h);
|
||||
Main.layoutManager.setDummyCursorPosition(x, y);
|
||||
if (this._boxPointer.actor.visible)
|
||||
this._boxPointer.setPosition(this._cursor, 0);
|
||||
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
|
||||
}));
|
||||
panelService.connect('update-preedit-text',
|
||||
Lang.bind(this, function(ps, text, cursorPosition, visible) {
|
||||
@ -253,7 +249,7 @@ const CandidatePopup = new Lang.Class({
|
||||
this._candidateArea.actor.visible);
|
||||
|
||||
if (isVisible) {
|
||||
this._boxPointer.setPosition(this._cursor, 0);
|
||||
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
|
||||
this._boxPointer.show(BoxPointer.PopupAnimation.NONE);
|
||||
this._boxPointer.actor.raise_top();
|
||||
} else {
|
||||
|
@ -143,11 +143,6 @@ const BaseIcon = new Lang.Class({
|
||||
this.icon = this.createIcon(this.iconSize);
|
||||
|
||||
this._iconBin.child = this.icon;
|
||||
|
||||
// The icon returned by createIcon() might actually be smaller than
|
||||
// the requested icon size (for instance StTextureCache does this
|
||||
// for fallback icons), so set the size explicitly.
|
||||
this._iconBin.set_size(this.iconSize, this.iconSize);
|
||||
},
|
||||
|
||||
_onStyleChanged: function() {
|
||||
@ -433,6 +428,10 @@ const IconGrid = new Lang.Class({
|
||||
this._grid.add_actor(item.actor);
|
||||
},
|
||||
|
||||
removeItem: function(item) {
|
||||
this._grid.remove_child(item.actor);
|
||||
},
|
||||
|
||||
getItemAtIndex: function(index) {
|
||||
return this._grid.get_child_at_index(index);
|
||||
},
|
||||
|
@ -4,7 +4,6 @@ const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
@ -213,12 +212,21 @@ const LayoutManager = new Lang.Class({
|
||||
this.addChrome(this.trayBox);
|
||||
this._setupTrayPressure();
|
||||
|
||||
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
|
||||
layout_manager: new Clutter.BinLayout() });
|
||||
this.uiGroup.add_actor(this.modalDialogGroup);
|
||||
|
||||
this.keyboardBox = new St.BoxLayout({ name: 'keyboardBox',
|
||||
reactive: true,
|
||||
track_hover: true });
|
||||
this.addChrome(this.keyboardBox);
|
||||
this._keyboardHeightNotifyId = 0;
|
||||
|
||||
// A dummy actor that tracks the mouse or text cursor, based on the
|
||||
// position set in setDummyCursorPosition.
|
||||
this.dummyCursor = new St.Widget({ width: 0, height: 0 });
|
||||
this.uiGroup.add_actor(this.dummyCursor);
|
||||
|
||||
global.stage.remove_actor(global.top_window_group);
|
||||
this.uiGroup.add_actor(global.top_window_group);
|
||||
|
||||
@ -720,6 +728,20 @@ const LayoutManager = new Lang.Class({
|
||||
this._updateRegions();
|
||||
},
|
||||
|
||||
// setDummyCursorPosition:
|
||||
//
|
||||
// The cursor dummy is a standard widget commonly used for popup
|
||||
// menus and box pointers to track, as the box pointer API only
|
||||
// tracks actors. If you want to pop up a menu based on where the
|
||||
// user clicked, or where the text cursor is, the cursor dummy
|
||||
// is what you should use. Given that the menu should not track
|
||||
// the actual mouse pointer as it moves, you need to call this
|
||||
// function before you show the menu to ensure it is at the right
|
||||
// position.
|
||||
setDummyCursorPosition: function(x, y) {
|
||||
this.dummyCursor.set_position(Math.round(x), Math.round(y));
|
||||
},
|
||||
|
||||
// addChrome:
|
||||
// @actor: an actor to add to the chrome
|
||||
// @params: (optional) additional params
|
||||
@ -811,13 +833,12 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
let actorData = Params.parse(params, defaultParams);
|
||||
actorData.actor = actor;
|
||||
actorData.isToplevel = actor.get_parent() == this.uiGroup;
|
||||
actorData.visibleId = actor.connect('notify::visible',
|
||||
Lang.bind(this, this._queueUpdateRegions));
|
||||
actorData.allocationId = actor.connect('notify::allocation',
|
||||
Lang.bind(this, this._queueUpdateRegions));
|
||||
actorData.parentSetId = actor.connect('parent-set',
|
||||
Lang.bind(this, this._actorReparented));
|
||||
actorData.destroyId = actor.connect('destroy',
|
||||
Lang.bind(this, this._untrackActor));
|
||||
// Note that destroying actor will unset its parent, so we don't
|
||||
// need to connect to 'destroy' too.
|
||||
|
||||
@ -835,22 +856,11 @@ const LayoutManager = new Lang.Class({
|
||||
this._trackedActors.splice(i, 1);
|
||||
actor.disconnect(actorData.visibleId);
|
||||
actor.disconnect(actorData.allocationId);
|
||||
actor.disconnect(actorData.parentSetId);
|
||||
actor.disconnect(actorData.destroyId);
|
||||
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_actorReparented: function(actor, oldParent) {
|
||||
let newParent = actor.get_parent();
|
||||
if (!newParent) {
|
||||
this._untrackActor(actor);
|
||||
} else {
|
||||
let i = this._findActor(actor);
|
||||
let actorData = this._trackedActors[i];
|
||||
actorData.isToplevel = (newParent == this.uiGroup);
|
||||
}
|
||||
},
|
||||
|
||||
_updateVisibility: function() {
|
||||
let windowsVisible = Main.sessionMode.hasWindows && !this._inOverview;
|
||||
|
||||
@ -861,8 +871,6 @@ const LayoutManager = new Lang.Class({
|
||||
let actorData = this._trackedActors[i], visible;
|
||||
if (!actorData.trackFullscreen)
|
||||
continue;
|
||||
if (!actorData.isToplevel)
|
||||
continue;
|
||||
|
||||
if (!windowsVisible)
|
||||
visible = true;
|
||||
@ -902,8 +910,8 @@ const LayoutManager = new Lang.Class({
|
||||
return;
|
||||
|
||||
if (!this._updateRegionIdle)
|
||||
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
|
||||
Meta.PRIORITY_BEFORE_REDRAW);
|
||||
this._updateRegionIdle = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this, this._updateRegions));
|
||||
},
|
||||
|
||||
_getWindowActorsForWorkspace: function(workspace) {
|
||||
@ -934,7 +942,7 @@ const LayoutManager = new Lang.Class({
|
||||
let rects = [], struts = [], i;
|
||||
|
||||
if (this._updateRegionIdle) {
|
||||
Mainloop.source_remove(this._updateRegionIdle);
|
||||
Meta.later_remove(this._updateRegionIdle);
|
||||
delete this._updateRegionIdle;
|
||||
}
|
||||
|
||||
|
@ -5,11 +5,67 @@ const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const DEFAULT_FADE_FACTOR = 0.4;
|
||||
const VIGNETTE_BRIGHTNESS = 0.8;
|
||||
const VIGNETTE_SHARPNESS = 0.7;
|
||||
|
||||
const VIGNETTE_DECLARATIONS = '\
|
||||
uniform float brightness;\n\
|
||||
uniform float vignette_sharpness;\n';
|
||||
|
||||
const VIGNETTE_CODE = '\
|
||||
cogl_color_out.a = cogl_color_in.a;\n\
|
||||
cogl_color_out.rgb = vec3(0.0, 0.0, 0.0);\n\
|
||||
vec2 position = cogl_tex_coord_in[0].xy - 0.5;\n\
|
||||
float t = length(2.0 * position);\n\
|
||||
t = clamp(t, 0.0, 1.0);\n\
|
||||
float pixel_brightness = mix(1.0, 1.0 - vignette_sharpness, t);\n\
|
||||
cogl_color_out.a = cogl_color_out.a * (1 - pixel_brightness * brightness);';
|
||||
|
||||
const RadialShaderQuad = new Lang.Class({
|
||||
Name: 'RadialShaderQuad',
|
||||
Extends: Shell.GLSLQuad,
|
||||
|
||||
_init: function(params) {
|
||||
this.parent(params);
|
||||
|
||||
this._brightnessLocation = this.get_uniform_location('brightness');
|
||||
this._sharpnessLocation = this.get_uniform_location('vignette_sharpness');
|
||||
|
||||
this.brightness = 1.0;
|
||||
this.vignetteSharpness = 0.0;
|
||||
},
|
||||
|
||||
vfunc_build_pipeline: function() {
|
||||
this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT,
|
||||
VIGNETTE_DECLARATIONS, VIGNETTE_CODE, true);
|
||||
},
|
||||
|
||||
get brightness() {
|
||||
return this._brightness;
|
||||
},
|
||||
|
||||
set brightness(v) {
|
||||
this._brightness = v;
|
||||
this.set_uniform_float(this._brightnessLocation,
|
||||
1, [this._brightness]);
|
||||
},
|
||||
|
||||
get vignetteSharpness() {
|
||||
return this._sharpness;
|
||||
},
|
||||
|
||||
set vignetteSharpness(v) {
|
||||
this._sharpness = v;
|
||||
this.set_uniform_float(this._sharpnessLocation,
|
||||
1, [this._sharpness]);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Lightbox:
|
||||
@ -43,15 +99,23 @@ const Lightbox = new Lang.Class({
|
||||
width: null,
|
||||
height: null,
|
||||
fadeFactor: DEFAULT_FADE_FACTOR,
|
||||
radialEffect: false,
|
||||
});
|
||||
|
||||
this._container = container;
|
||||
this._children = container.get_children();
|
||||
this._fadeFactor = params.fadeFactor;
|
||||
this.actor = new St.Bin({ x: 0,
|
||||
y: 0,
|
||||
style_class: 'lightbox',
|
||||
reactive: params.inhibitEvents });
|
||||
this._radialEffect = params.radialEffect;
|
||||
if (params.radialEffect)
|
||||
this.actor = new RadialShaderQuad({ x: 0,
|
||||
y: 0,
|
||||
reactive: params.inhibitEvents });
|
||||
else
|
||||
this.actor = new St.Bin({ x: 0,
|
||||
y: 0,
|
||||
opacity: 0,
|
||||
style_class: 'lightbox',
|
||||
reactive: params.inhibitEvents });
|
||||
|
||||
container.add_actor(this.actor);
|
||||
this.actor.raise_top();
|
||||
@ -101,9 +165,18 @@ const Lightbox = new Lang.Class({
|
||||
fadeInTime = fadeInTime || 0;
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
if (fadeInTime != 0) {
|
||||
this.shown = false;
|
||||
this.actor.opacity = 0;
|
||||
if (this._radialEffect) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ brightness: VIGNETTE_BRIGHTNESS,
|
||||
vignetteSharpness: VIGNETTE_SHARPNESS,
|
||||
time: fadeInTime,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.shown = true;
|
||||
this.emit('shown');
|
||||
})
|
||||
});
|
||||
} else {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255 * this._fadeFactor,
|
||||
time: fadeInTime,
|
||||
@ -113,11 +186,8 @@ const Lightbox = new Lang.Class({
|
||||
this.emit('shown');
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this.actor.opacity = 255 * this._fadeFactor;
|
||||
this.shown = true;
|
||||
this.emit('shown');
|
||||
}
|
||||
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
@ -126,7 +196,18 @@ const Lightbox = new Lang.Class({
|
||||
|
||||
this.shown = false;
|
||||
Tweener.removeTweens(this.actor);
|
||||
if (fadeOutTime != 0) {
|
||||
if (this._radialEffect) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ brightness: 1.0,
|
||||
vignetteSharpness: 0.0,
|
||||
opacity: 0,
|
||||
time: fadeOutTime,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this.actor.hide();
|
||||
})
|
||||
});
|
||||
} else {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: fadeOutTime,
|
||||
@ -135,8 +216,6 @@ const Lightbox = new Lang.Class({
|
||||
this.actor.hide();
|
||||
})
|
||||
});
|
||||
} else {
|
||||
this.actor.hide();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -27,6 +27,8 @@ const CHEVRON = '>>> ';
|
||||
/* Imports...feel free to add here as needed */
|
||||
var commandHeader = 'const Clutter = imports.gi.Clutter; ' +
|
||||
'const GLib = imports.gi.GLib; ' +
|
||||
'const GObject = imports.gi.GObject; ' +
|
||||
'const Gio = imports.gi.Gio; ' +
|
||||
'const Gtk = imports.gi.Gtk; ' +
|
||||
'const Mainloop = imports.mainloop; ' +
|
||||
'const Meta = imports.gi.Meta; ' +
|
||||
@ -670,13 +672,13 @@ const Extensions = new Lang.Class({
|
||||
_onViewSource: function (actor) {
|
||||
let extension = actor._extension;
|
||||
let uri = extension.dir.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(0, -1));
|
||||
this._lookingGlass.close();
|
||||
},
|
||||
|
||||
_onWebPage: function (actor) {
|
||||
let extension = actor._extension;
|
||||
Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context());
|
||||
Gio.app_info_launch_default_for_uri(extension.metadata.url, global.create_app_launch_context(0, -1));
|
||||
this._lookingGlass.close();
|
||||
},
|
||||
|
||||
|
@ -11,6 +11,7 @@ const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Background = imports.ui.background;
|
||||
const FocusCaretTracker = imports.ui.focusCaretTracker;
|
||||
const Main = imports.ui.main;
|
||||
const MagnifierDBus = imports.ui.magnifierDBus;
|
||||
@ -57,20 +58,6 @@ const Magnifier = new Lang.Class({
|
||||
// Magnifier is a manager of ZoomRegions.
|
||||
this._zoomRegions = [];
|
||||
|
||||
// Export to dbus.
|
||||
magDBusService = new MagnifierDBus.ShellMagnifier();
|
||||
|
||||
let showAtLaunch = this._settingsInit();
|
||||
this.setActive(showAtLaunch);
|
||||
},
|
||||
|
||||
_initialize: function() {
|
||||
if (this._initialized)
|
||||
return;
|
||||
this._initialized = true;
|
||||
|
||||
this._settingsInitLate();
|
||||
|
||||
// Create small clutter tree for the magnified mouse.
|
||||
let cursorTracker = Meta.CursorTracker.get_for_screen(global.screen);
|
||||
this._mouseSprite = new Clutter.Texture();
|
||||
@ -86,11 +73,15 @@ const Magnifier = new Lang.Class({
|
||||
|
||||
let aZoomRegion = new ZoomRegion(this, this._cursorRoot);
|
||||
this._zoomRegions.push(aZoomRegion);
|
||||
this._settingsInitRegion(aZoomRegion);
|
||||
let showAtLaunch = this._settingsInit(aZoomRegion);
|
||||
aZoomRegion.scrollContentsTo(this.xMouse, this.yMouse);
|
||||
|
||||
cursorTracker.connect('cursor-changed', Lang.bind(this, this._updateMouseSprite));
|
||||
this._cursorTracker = cursorTracker;
|
||||
|
||||
// Export to dbus.
|
||||
magDBusService = new MagnifierDBus.ShellMagnifier();
|
||||
this.setActive(showAtLaunch);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -115,20 +106,21 @@ const Magnifier = new Lang.Class({
|
||||
* @activate: Boolean to activate or de-activate the magnifier.
|
||||
*/
|
||||
setActive: function(activate) {
|
||||
if (activate == this.isActive())
|
||||
return;
|
||||
|
||||
if (activate)
|
||||
this._initialize();
|
||||
let isActive = this.isActive();
|
||||
|
||||
this._zoomRegions.forEach (function(zoomRegion, index, array) {
|
||||
zoomRegion.setActive(activate);
|
||||
});
|
||||
|
||||
if (activate)
|
||||
this.startTrackingMouse();
|
||||
else
|
||||
this.stopTrackingMouse();
|
||||
if (isActive != activate) {
|
||||
if (activate) {
|
||||
Meta.disable_unredirect_for_screen(global.screen);
|
||||
this.startTrackingMouse();
|
||||
} else {
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
this.stopTrackingMouse();
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure system mouse pointer is shown when all zoom regions are
|
||||
// invisible.
|
||||
@ -448,68 +440,64 @@ const Magnifier = new Lang.Class({
|
||||
this._mouseSprite.set_anchor_point(xHot, yHot);
|
||||
},
|
||||
|
||||
_settingsInitRegion: function(zoomRegion) {
|
||||
// Mag factor is accurate to two decimal places.
|
||||
let aPref = parseFloat(this._settings.get_double(MAG_FACTOR_KEY).toFixed(2));
|
||||
if (aPref != 0.0)
|
||||
zoomRegion.setMagFactor(aPref, aPref);
|
||||
|
||||
aPref = this._settings.get_enum(SCREEN_POSITION_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setScreenPosition(aPref);
|
||||
|
||||
zoomRegion.setLensMode(this._settings.get_boolean(LENS_MODE_KEY));
|
||||
zoomRegion.setClampScrollingAtEdges(!this._settings.get_boolean(CLAMP_MODE_KEY));
|
||||
|
||||
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setMouseTrackingMode(aPref);
|
||||
|
||||
aPref = this._settings.get_enum(FOCUS_TRACKING_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setFocusTrackingMode(aPref);
|
||||
|
||||
aPref = this._settings.get_enum(CARET_TRACKING_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setCaretTrackingMode(aPref);
|
||||
|
||||
aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setInvertLightness(aPref);
|
||||
|
||||
aPref = this._settings.get_double(COLOR_SATURATION_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setColorSaturation(aPref);
|
||||
|
||||
let bc = {};
|
||||
bc.r = this._settings.get_double(BRIGHT_RED_KEY);
|
||||
bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
|
||||
bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
|
||||
zoomRegion.setBrightness(bc);
|
||||
|
||||
bc.r = this._settings.get_double(CONTRAST_RED_KEY);
|
||||
bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
|
||||
bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
|
||||
zoomRegion.setContrast(bc);
|
||||
},
|
||||
|
||||
_settingsInit: function() {
|
||||
_settingsInit: function(zoomRegion) {
|
||||
this._appSettings = new Gio.Settings({ schema: APPLICATIONS_SCHEMA });
|
||||
this._settings = new Gio.Settings({ schema: MAGNIFIER_SCHEMA });
|
||||
|
||||
this._appSettings.connect('changed::' + SHOW_KEY, Lang.bind(this, function() {
|
||||
let active = this._appSettings.get_boolean(SHOW_KEY);
|
||||
this.setActive(active);
|
||||
}));
|
||||
if (zoomRegion) {
|
||||
// Mag factor is accurate to two decimal places.
|
||||
let aPref = parseFloat(this._settings.get_double(MAG_FACTOR_KEY).toFixed(2));
|
||||
if (aPref != 0.0)
|
||||
zoomRegion.setMagFactor(aPref, aPref);
|
||||
|
||||
return this._appSettings.get_boolean(SHOW_KEY);
|
||||
},
|
||||
aPref = this._settings.get_enum(SCREEN_POSITION_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setScreenPosition(aPref);
|
||||
|
||||
zoomRegion.setLensMode(this._settings.get_boolean(LENS_MODE_KEY));
|
||||
zoomRegion.setClampScrollingAtEdges(!this._settings.get_boolean(CLAMP_MODE_KEY));
|
||||
|
||||
aPref = this._settings.get_enum(MOUSE_TRACKING_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setMouseTrackingMode(aPref);
|
||||
|
||||
aPref = this._settings.get_enum(FOCUS_TRACKING_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setFocusTrackingMode(aPref);
|
||||
|
||||
aPref = this._settings.get_enum(CARET_TRACKING_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setCaretTrackingMode(aPref);
|
||||
|
||||
aPref = this._settings.get_boolean(INVERT_LIGHTNESS_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setInvertLightness(aPref);
|
||||
|
||||
aPref = this._settings.get_double(COLOR_SATURATION_KEY);
|
||||
if (aPref)
|
||||
zoomRegion.setColorSaturation(aPref);
|
||||
|
||||
let bc = {};
|
||||
bc.r = this._settings.get_double(BRIGHT_RED_KEY);
|
||||
bc.g = this._settings.get_double(BRIGHT_GREEN_KEY);
|
||||
bc.b = this._settings.get_double(BRIGHT_BLUE_KEY);
|
||||
zoomRegion.setBrightness(bc);
|
||||
|
||||
bc.r = this._settings.get_double(CONTRAST_RED_KEY);
|
||||
bc.g = this._settings.get_double(CONTRAST_GREEN_KEY);
|
||||
bc.b = this._settings.get_double(CONTRAST_BLUE_KEY);
|
||||
zoomRegion.setContrast(bc);
|
||||
}
|
||||
|
||||
_settingsInitLate: function() {
|
||||
let showCrosshairs = this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY);
|
||||
this.addCrosshairs();
|
||||
this.setCrosshairsVisible(showCrosshairs);
|
||||
|
||||
this._appSettings.connect('changed::' + SHOW_KEY,
|
||||
Lang.bind(this, function() {
|
||||
this.setActive(this._appSettings.get_boolean(SHOW_KEY));
|
||||
}));
|
||||
|
||||
this._settings.connect('changed::' + SCREEN_POSITION_KEY,
|
||||
Lang.bind(this, this._updateScreenPosition));
|
||||
this._settings.connect('changed::' + MAG_FACTOR_KEY,
|
||||
@ -573,6 +561,7 @@ const Magnifier = new Lang.Class({
|
||||
Lang.bind(this, function() {
|
||||
this.setCrosshairsClip(this._settings.get_boolean(CROSS_HAIRS_CLIP_KEY));
|
||||
}));
|
||||
return this._appSettings.get_boolean(SHOW_KEY);
|
||||
},
|
||||
|
||||
_updateScreenPosition: function() {
|
||||
@ -731,8 +720,16 @@ const ZoomRegion = new Lang.Class({
|
||||
let component = event.source.get_component_iface();
|
||||
if (!component || event.detail1 != 1)
|
||||
return;
|
||||
let extents = component.get_extents(Atspi.CoordType.SCREEN);
|
||||
[this._xFocus, this._yFocus] = [extents.x, extents.y]
|
||||
let extents;
|
||||
try {
|
||||
extents = component.get_extents(Atspi.CoordType.SCREEN);
|
||||
} catch(e) {
|
||||
log('Failed to read extents of focused component: ' + e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
[this._xFocus, this._yFocus] = [extents.x + (extents.width / 2),
|
||||
extents.y + (extents.height / 2)];
|
||||
this._centerFromFocusPosition();
|
||||
},
|
||||
|
||||
@ -740,7 +737,14 @@ const ZoomRegion = new Lang.Class({
|
||||
let text = event.source.get_text_iface();
|
||||
if (!text)
|
||||
return;
|
||||
let extents = text.get_character_extents(text.get_caret_offset(), 0);
|
||||
let extents;
|
||||
try {
|
||||
extents = text.get_character_extents(text.get_caret_offset(), 0);
|
||||
} catch(e) {
|
||||
log('Failed to read extents of text caret: ' + e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
[this._xCaret, this._yCaret] = [extents.x, extents.y];
|
||||
this._centerFromCaretPosition();
|
||||
},
|
||||
@ -763,6 +767,9 @@ const ZoomRegion = new Lang.Class({
|
||||
} else {
|
||||
this._destroyActors();
|
||||
}
|
||||
|
||||
this._syncCaretTracking();
|
||||
this._syncFocusTracking();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -822,10 +829,7 @@ const ZoomRegion = new Lang.Class({
|
||||
*/
|
||||
setFocusTrackingMode: function(mode) {
|
||||
this._focusTrackingMode = mode;
|
||||
if (this._focusTrackingMode == GDesktopEnums.MagnifierFocusTrackingMode.NONE)
|
||||
this._focusCaretTracker.deregisterFocusListener();
|
||||
else
|
||||
this._focusCaretTracker.registerFocusListener();
|
||||
this._syncFocusTracking();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -834,10 +838,27 @@ const ZoomRegion = new Lang.Class({
|
||||
*/
|
||||
setCaretTrackingMode: function(mode) {
|
||||
this._caretTrackingMode = mode;
|
||||
if (this._caretTrackingMode == GDesktopEnums.MagnifierCaretTrackingMode.NONE)
|
||||
this._focusCaretTracker.deregisterCaretListener();
|
||||
this._syncCaretTracking();
|
||||
},
|
||||
|
||||
_syncFocusTracking: function() {
|
||||
let enabled = this._focusTrackingMode != GDesktopEnums.MagnifierFocusTrackingMode.NONE &&
|
||||
this.isActive();
|
||||
|
||||
if (enabled)
|
||||
this._focusCaretTracker.registerFocusListener();
|
||||
else
|
||||
this._focusCaretTracker.deregisterFocusListener();
|
||||
},
|
||||
|
||||
_syncCaretTracking: function() {
|
||||
let enabled = this._caretTrackingMode != GDesktopEnums.MagnifierCaretTrackingMode.NONE &&
|
||||
this.isActive();
|
||||
|
||||
if (enabled)
|
||||
this._focusCaretTracker.registerCaretListener();
|
||||
else
|
||||
this._focusCaretTracker.deregisterCaretListener();
|
||||
},
|
||||
|
||||
/**
|
||||
@ -1178,13 +1199,17 @@ const ZoomRegion = new Lang.Class({
|
||||
// Add a background for when the magnified uiGroup is scrolled
|
||||
// out of view (don't want to see desktop showing through).
|
||||
this._background = new Clutter.Actor({ background_color: Main.DEFAULT_BACKGROUND_COLOR,
|
||||
layout_manager: new Clutter.BinLayout(),
|
||||
width: global.screen_width,
|
||||
height: global.screen_height });
|
||||
let noiseTexture = (new Background.SystemBackground()).actor;
|
||||
this._background.add_actor(noiseTexture);
|
||||
mainGroup.add_actor(this._background);
|
||||
|
||||
// Clone the group that contains all of UI on the screen. This is the
|
||||
// chrome, the windows, etc.
|
||||
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup });
|
||||
this._uiGroupClone = new Clutter.Clone({ source: Main.uiGroup,
|
||||
clip_to_allocation: true });
|
||||
mainGroup.add_actor(this._uiGroupClone);
|
||||
|
||||
// Add either the given mouseSourceActor to the ZoomRegion, or a clone of
|
||||
|
@ -19,7 +19,6 @@ const BoxPointer = imports.ui.boxpointer;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const GrabHelper = imports.ui.grabHelper;
|
||||
const Hash = imports.misc.hash;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const PointerWatcher = imports.ui.pointerWatcher;
|
||||
@ -204,7 +203,7 @@ const URLHighlighter = new Lang.Class({
|
||||
if (url.indexOf(':') == -1)
|
||||
url = 'http://' + url;
|
||||
|
||||
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context());
|
||||
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
@ -1002,6 +1001,9 @@ const Notification = new Lang.Class({
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
if (this._destroyed)
|
||||
return false;
|
||||
|
||||
if (this._canExpandContent()) {
|
||||
this._addBannerBody();
|
||||
this._table.add_style_class_name('multi-line-notification');
|
||||
@ -1160,32 +1162,12 @@ const SourceActor = new Lang.Class({
|
||||
}));
|
||||
this._actorDestroyed = false;
|
||||
|
||||
this._counterLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
|
||||
x_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
y_expand: true });
|
||||
|
||||
this._counterBin = new St.Bin({ style_class: 'summary-source-counter',
|
||||
child: this._counterLabel,
|
||||
layout_manager: new Clutter.BinLayout() });
|
||||
this._counterBin.hide();
|
||||
|
||||
this._counterBin.connect('style-changed', Lang.bind(this, function() {
|
||||
let themeNode = this._counterBin.get_theme_node();
|
||||
this._counterBin.translation_x = themeNode.get_length('-shell-counter-overlap-x');
|
||||
this._counterBin.translation_y = themeNode.get_length('-shell-counter-overlap-y');
|
||||
}));
|
||||
|
||||
this._iconBin = new St.Bin({ width: size,
|
||||
height: size,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
let scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._iconBin = new St.Bin({ x_fill: true,
|
||||
height: size * scale_factor,
|
||||
width: size * scale_factor });
|
||||
|
||||
this.actor.add_actor(this._iconBin);
|
||||
this.actor.add_actor(this._counterBin);
|
||||
|
||||
this._source.connect('count-updated', Lang.bind(this, this._updateCount));
|
||||
this._updateCount();
|
||||
|
||||
this._source.connect('icon-updated', Lang.bind(this, this._updateIcon));
|
||||
this._updateIcon();
|
||||
@ -1209,6 +1191,48 @@ const SourceActor = new Lang.Class({
|
||||
_allocate: function(actor, box, flags) {
|
||||
// the iconBin should fill our entire box
|
||||
this._iconBin.allocate(box, flags);
|
||||
},
|
||||
|
||||
_updateIcon: function() {
|
||||
if (this._actorDestroyed)
|
||||
return;
|
||||
|
||||
if (!this._iconSet)
|
||||
this._iconBin.child = this._source.createIcon(this._size);
|
||||
}
|
||||
});
|
||||
|
||||
const SourceActorWithLabel = new Lang.Class({
|
||||
Name: 'SourceActorWithLabel',
|
||||
Extends: SourceActor,
|
||||
|
||||
_init: function(source, size) {
|
||||
this.parent(source, size);
|
||||
|
||||
this._counterLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
|
||||
x_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
y_expand: true });
|
||||
|
||||
this._counterBin = new St.Bin({ style_class: 'summary-source-counter',
|
||||
child: this._counterLabel,
|
||||
layout_manager: new Clutter.BinLayout() });
|
||||
this._counterBin.hide();
|
||||
|
||||
this._counterBin.connect('style-changed', Lang.bind(this, function() {
|
||||
let themeNode = this._counterBin.get_theme_node();
|
||||
this._counterBin.translation_x = themeNode.get_length('-shell-counter-overlap-x');
|
||||
this._counterBin.translation_y = themeNode.get_length('-shell-counter-overlap-y');
|
||||
}));
|
||||
|
||||
this.actor.add_actor(this._counterBin);
|
||||
|
||||
this._source.connect('count-updated', Lang.bind(this, this._updateCount));
|
||||
this._updateCount();
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
this.parent(actor, box, flags);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
@ -1231,14 +1255,6 @@ const SourceActor = new Lang.Class({
|
||||
this._counterBin.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
_updateIcon: function() {
|
||||
if (this._actorDestroyed)
|
||||
return;
|
||||
|
||||
if (!this._iconSet)
|
||||
this._iconBin.child = this._source.createIcon(this._size);
|
||||
},
|
||||
|
||||
_updateCount: function() {
|
||||
if (this._actorDestroyed)
|
||||
return;
|
||||
@ -1351,7 +1367,7 @@ const Source = new Lang.Class({
|
||||
if (this._mainIcon)
|
||||
return;
|
||||
|
||||
this._mainIcon = new SourceActor(this, this.SOURCE_ICON_SIZE);
|
||||
this._mainIcon = new SourceActorWithLabel(this, this.SOURCE_ICON_SIZE);
|
||||
},
|
||||
|
||||
// Unlike createIcon, this always returns the same actor;
|
||||
@ -1899,7 +1915,7 @@ const MessageTray = new Lang.Class({
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
Lang.bind(this, this._expandActiveNotification));
|
||||
|
||||
this._sources = new Hash.Map();
|
||||
this._sources = new Map();
|
||||
this._chatSummaryItemsCount = 0;
|
||||
|
||||
this._trayDwellTimeoutId = 0;
|
||||
@ -1936,7 +1952,7 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateNoMessagesLabel: function() {
|
||||
this._noMessages.visible = this._sources.size() == 0;
|
||||
this._noMessages.visible = this._sources.size == 0;
|
||||
},
|
||||
|
||||
_sessionUpdated: function() {
|
||||
@ -2011,13 +2027,18 @@ const MessageTray = new Lang.Class({
|
||||
|
||||
_onNotificationKeyRelease: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.KEY_Escape && event.get_state() == 0) {
|
||||
this._closeNotification();
|
||||
this._expireNotification();
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_expireNotification: function() {
|
||||
this._notificationExpired = true;
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
_closeNotification: function() {
|
||||
if (this._notificationState == State.SHOWN) {
|
||||
this._closeButton.hide();
|
||||
@ -2099,7 +2120,8 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
_removeSource: function(source) {
|
||||
let [, obj] = this._sources.delete(source);
|
||||
let obj = this._sources.get(source);
|
||||
this._sources.delete(source);
|
||||
let summaryItem = obj.summaryItem;
|
||||
|
||||
if (source.isChat)
|
||||
@ -2120,7 +2142,7 @@ const MessageTray = new Lang.Class({
|
||||
},
|
||||
|
||||
getSources: function() {
|
||||
return this._sources.keys();
|
||||
return [k for (k of this._sources.keys())];
|
||||
},
|
||||
|
||||
_onSourceEnableChanged: function(policy, source) {
|
||||
@ -2381,7 +2403,7 @@ const MessageTray = new Lang.Class({
|
||||
this._notificationTimeoutId == 0 &&
|
||||
this._notification.urgency != Urgency.CRITICAL &&
|
||||
!this._notification.focused &&
|
||||
!this._pointerInNotification);
|
||||
!this._pointerInNotification) || this._notificationExpired;
|
||||
let mustClose = (this._notificationRemoved || !hasNotifications || expired || this._traySummoned);
|
||||
|
||||
if (mustClose) {
|
||||
@ -2442,6 +2464,10 @@ const MessageTray = new Lang.Class({
|
||||
this._hideDesktopClone();
|
||||
|
||||
this._updatingState = false;
|
||||
|
||||
// Clean transient variables that are used to communicate actions
|
||||
// to updateState()
|
||||
this._notificationExpired = false;
|
||||
},
|
||||
|
||||
_tween: function(actor, statevar, value, params) {
|
||||
@ -2764,7 +2790,12 @@ const MessageTray = new Lang.Class({
|
||||
{ y: expandedY,
|
||||
opacity: 255,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
transition: 'easeOutQuad',
|
||||
// HACK: Drive the state machine here better,
|
||||
// instead of overwriting tweens
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this._notificationState = State.SHOWN;
|
||||
}),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -41,7 +41,6 @@ const ModalDialog = new Lang.Class({
|
||||
_init: function(params) {
|
||||
params = Params.parse(params, { shellReactive: false,
|
||||
styleClass: null,
|
||||
parentActor: Main.uiGroup,
|
||||
keybindingMode: Shell.KeyBindingMode.SYSTEM_MODAL,
|
||||
shouldFadeIn: true,
|
||||
destroyOnClose: true });
|
||||
@ -57,7 +56,7 @@ const ModalDialog = new Lang.Class({
|
||||
x: 0,
|
||||
y: 0,
|
||||
accessible_role: Atk.Role.DIALOG });
|
||||
params.parentActor.add_actor(this._group);
|
||||
Main.layoutManager.modalDialogGroup.add_actor(this._group);
|
||||
|
||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||
coordinate: Clutter.BindCoordinate.ALL });
|
||||
@ -89,7 +88,8 @@ const ModalDialog = new Lang.Class({
|
||||
|
||||
if (!this._shellReactive) {
|
||||
this._lightbox = new Lightbox.Lightbox(this._group,
|
||||
{ inhibitEvents: true });
|
||||
{ inhibitEvents: true,
|
||||
radialEffect: true });
|
||||
this._lightbox.highlight(this._backgroundBin);
|
||||
|
||||
this._eventBlocker = new Clutter.Actor({ reactive: true });
|
||||
|
@ -66,6 +66,7 @@ const LevelBar = new Lang.Class({
|
||||
cr.arc(radius, h - radius, radius, 0.5 * Math.PI, Math.PI);
|
||||
cr.arc(radius, radius, radius, Math.PI, 1.5 * Math.PI);
|
||||
cr.fill();
|
||||
cr.$dispose();
|
||||
}
|
||||
});
|
||||
|
||||
@ -124,13 +125,15 @@ const OsdWindow = new Lang.Class({
|
||||
|
||||
setLevel: function(level) {
|
||||
this._level.actor.visible = (level != undefined);
|
||||
if (this.actor.visible)
|
||||
Tweener.addTween(this._level,
|
||||
{ level: level,
|
||||
time: LEVEL_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
else
|
||||
this._level.level = level;
|
||||
if (level) {
|
||||
if (this.actor.visible)
|
||||
Tweener.addTween(this._level,
|
||||
{ level: level,
|
||||
time: LEVEL_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
else
|
||||
this._level.level = level;
|
||||
}
|
||||
},
|
||||
|
||||
show: function() {
|
||||
@ -197,8 +200,9 @@ const OsdWindow = new Lang.Class({
|
||||
let scale = Math.min(scalew, scaleh);
|
||||
this._popupSize = 110 * Math.max(1, scale);
|
||||
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._icon.icon_size = this._popupSize / (2 * scaleFactor);
|
||||
this._box.translation_y = monitor.height / 4;
|
||||
this._icon.icon_size = this._popupSize / 2;
|
||||
this._box.style_changed();
|
||||
},
|
||||
|
||||
@ -214,7 +218,10 @@ const OsdWindow = new Lang.Class({
|
||||
let minWidth = this._popupSize - verticalPadding - leftBorder - rightBorder;
|
||||
let minHeight = this._popupSize - horizontalPadding - topBorder - bottomBorder;
|
||||
|
||||
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight));
|
||||
// minWidth/minHeight here are in real pixels,
|
||||
// but the theme takes measures in unscaled dimensions
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._box.style = 'min-height: %dpx;'.format(Math.max(minWidth, minHeight) / scaleFactor);
|
||||
},
|
||||
|
||||
setMonitor: function(index) {
|
||||
|
@ -14,6 +14,7 @@ const Gdk = imports.gi.Gdk;
|
||||
const Background = imports.ui.background;
|
||||
const DND = imports.ui.dnd;
|
||||
const LayoutManager = imports.ui.layout;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const OverviewControls = imports.ui.overviewControls;
|
||||
@ -131,7 +132,7 @@ const Overview = new Lang.Class({
|
||||
Main.layoutManager.overviewGroup.add_child(this._backgroundGroup);
|
||||
this._bgManagers = [];
|
||||
|
||||
this._desktopFade = new St.Bin();
|
||||
this._desktopFade = new St.Widget();
|
||||
Main.layoutManager.overviewGroup.add_child(this._desktopFade);
|
||||
|
||||
this._activationTime = 0;
|
||||
@ -196,11 +197,7 @@ const Overview = new Lang.Class({
|
||||
|
||||
Tweener.addTween(background,
|
||||
{ brightness: 1.0,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
Tweener.addTween(background,
|
||||
{ vignetteSharpness: 0.0,
|
||||
vignetteSharpness: 0.0,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
@ -213,12 +210,8 @@ const Overview = new Lang.Class({
|
||||
let background = backgrounds[i]._delegate;
|
||||
|
||||
Tweener.addTween(background,
|
||||
{ brightness: 0.8,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
Tweener.addTween(background,
|
||||
{ vignetteSharpness: 0.7,
|
||||
{ brightness: Lightbox.VIGNETTE_BRIGHTNESS,
|
||||
vignetteSharpness: Lightbox.VIGNETTE_SHARPNESS,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
@ -493,8 +486,13 @@ const Overview = new Lang.Class({
|
||||
},
|
||||
|
||||
fadeOutDesktop: function() {
|
||||
if (!this._desktopFade.child)
|
||||
this._desktopFade.child = this._getDesktopClone();
|
||||
if (!this._desktopFade.get_n_children()) {
|
||||
let clone = this._getDesktopClone();
|
||||
if (!clone)
|
||||
return;
|
||||
|
||||
this._desktopFade.add_child(clone);
|
||||
}
|
||||
|
||||
this._desktopFade.opacity = 255;
|
||||
this._desktopFade.show();
|
||||
|
@ -213,7 +213,7 @@ const AppMenuButton = new Lang.Class({
|
||||
this._label = new TextShadower();
|
||||
this._label.actor.y_align = Clutter.ActorAlign.CENTER;
|
||||
this._hbox.add_actor(this._label.actor);
|
||||
this._arrow = PopupMenu.unicodeArrow(St.Side.BOTTOM);
|
||||
this._arrow = PopupMenu.arrowIcon(St.Side.BOTTOM);
|
||||
this._hbox.add_actor(this._arrow);
|
||||
|
||||
this._iconBottomClip = 0;
|
||||
@ -812,7 +812,11 @@ const AggregateMenu = new Lang.Class({
|
||||
this._indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box' });
|
||||
this.actor.add_child(this._indicators);
|
||||
|
||||
this._network = new imports.ui.status.network.NMApplet();
|
||||
if (Config.HAVE_NETWORKMANAGER) {
|
||||
this._network = new imports.ui.status.network.NMApplet();
|
||||
} else {
|
||||
this._network = null;
|
||||
}
|
||||
if (Config.HAVE_BLUETOOTH) {
|
||||
this._bluetooth = new imports.ui.status.bluetooth.Indicator();
|
||||
} else {
|
||||
@ -825,24 +829,31 @@ const AggregateMenu = new Lang.Class({
|
||||
this._brightness = new imports.ui.status.brightness.Indicator();
|
||||
this._system = new imports.ui.status.system.Indicator();
|
||||
this._screencast = new imports.ui.status.screencast.Indicator();
|
||||
this._location = new imports.ui.status.location.Indicator();
|
||||
|
||||
this._indicators.add_child(this._screencast.indicators);
|
||||
this._indicators.add_child(this._network.indicators);
|
||||
this._indicators.add_child(this._location.indicators);
|
||||
if (this._network) {
|
||||
this._indicators.add_child(this._network.indicators);
|
||||
}
|
||||
if (this._bluetooth) {
|
||||
this._indicators.add_child(this._bluetooth.indicators);
|
||||
}
|
||||
this._indicators.add_child(this._rfkill.indicators);
|
||||
this._indicators.add_child(this._volume.indicators);
|
||||
this._indicators.add_child(this._power.indicators);
|
||||
this._indicators.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
|
||||
this._indicators.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
|
||||
|
||||
this.menu.addMenuItem(this._volume.menu);
|
||||
this.menu.addMenuItem(this._brightness.menu);
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addMenuItem(this._network.menu);
|
||||
if (this._network) {
|
||||
this.menu.addMenuItem(this._network.menu);
|
||||
}
|
||||
if (this._bluetooth) {
|
||||
this.menu.addMenuItem(this._bluetooth.menu);
|
||||
}
|
||||
this.menu.addMenuItem(this._location.menu);
|
||||
this.menu.addMenuItem(this._rfkill.menu);
|
||||
this.menu.addMenuItem(this._power.menu);
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
@ -45,28 +45,35 @@ function isPopupMenuItemVisible(child) {
|
||||
/**
|
||||
* @side Side to which the arrow points.
|
||||
*/
|
||||
function unicodeArrow(side) {
|
||||
let arrowChar;
|
||||
function arrowIcon(side) {
|
||||
let rotation;
|
||||
switch (side) {
|
||||
case St.Side.TOP:
|
||||
arrowChar = '\u25B4';
|
||||
rotation = 180;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
arrowChar = '\u25B8';
|
||||
rotation = - 90;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
arrowChar = '\u25BE';
|
||||
rotation = 0;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
arrowChar = '\u25C2';
|
||||
rotation = 90;
|
||||
break;
|
||||
}
|
||||
|
||||
return new St.Label({ text: arrowChar,
|
||||
style_class: 'unicode-arrow',
|
||||
accessible_role: Atk.Role.ARROW,
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_path(global.datadir +
|
||||
'/theme/menu-arrow-symbolic.svg') });
|
||||
|
||||
let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
|
||||
gicon: gicon,
|
||||
accessible_role: Atk.Role.ARROW,
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
|
||||
arrow.rotation_angle_z = rotation;
|
||||
|
||||
return arrow;
|
||||
}
|
||||
|
||||
const PopupBaseMenuItem = new Lang.Class({
|
||||
@ -111,6 +118,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
||||
|
||||
this.actor.connect('key-focus-in', Lang.bind(this, this._onKeyFocusIn));
|
||||
this.actor.connect('key-focus-out', Lang.bind(this, this._onKeyFocusOut));
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
},
|
||||
|
||||
_getTopMenu: function() {
|
||||
@ -192,6 +200,9 @@ const PopupBaseMenuItem = new Lang.Class({
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this.emit('destroy');
|
||||
},
|
||||
|
||||
@ -868,14 +879,14 @@ const PopupSubMenu = new Lang.Class({
|
||||
if (animate) {
|
||||
let [minHeight, naturalHeight] = this.actor.get_preferred_height(-1);
|
||||
this.actor.height = 0;
|
||||
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
|
||||
this.actor._arrowRotation = this._arrow.rotation_angle_z;
|
||||
Tweener.addTween(this.actor,
|
||||
{ _arrow_rotation: 90,
|
||||
{ _arrowRotation: this.actor._arrowRotation + 90,
|
||||
height: naturalHeight,
|
||||
time: 0.25,
|
||||
onUpdateScope: this,
|
||||
onUpdate: function() {
|
||||
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
|
||||
this._arrow.rotation_angle_z = this.actor._arrowRotation;
|
||||
},
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
@ -883,7 +894,7 @@ const PopupSubMenu = new Lang.Class({
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._arrow.rotation_angle_z = 90;
|
||||
this._arrow.rotation_angle_z = this.actor._arrowRotation + 90;
|
||||
}
|
||||
},
|
||||
|
||||
@ -901,14 +912,14 @@ const PopupSubMenu = new Lang.Class({
|
||||
animate = false;
|
||||
|
||||
if (animate) {
|
||||
this.actor._arrow_rotation = this._arrow.rotation_angle_z;
|
||||
this.actor._arrowRotation = this._arrow.rotation_angle_z;
|
||||
Tweener.addTween(this.actor,
|
||||
{ _arrow_rotation: 0,
|
||||
{ _arrowRotation: this.actor._arrowRotation - 90,
|
||||
height: 0,
|
||||
time: 0.25,
|
||||
onUpdateScope: this,
|
||||
onUpdate: function() {
|
||||
this._arrow.rotation_angle_z = this.actor._arrow_rotation;
|
||||
this._arrow.rotation_angle_z = this.actor._arrowRotation;
|
||||
},
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
@ -917,7 +928,7 @@ const PopupSubMenu = new Lang.Class({
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this._arrow.rotation_angle_z = 0;
|
||||
this._arrow.rotation_angle_z = this.actor._arrowRotation - 90;
|
||||
this.actor.hide();
|
||||
}
|
||||
},
|
||||
@ -989,7 +1000,7 @@ const PopupSubMenuMenuItem = new Lang.Class({
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this.actor.add_child(this.status);
|
||||
|
||||
this._triangle = unicodeArrow(St.Side.RIGHT);
|
||||
this._triangle = arrowIcon(St.Side.RIGHT);
|
||||
this._triangle.pivot_point = new Clutter.Point({ x: 0.5, y: 0.6 });
|
||||
|
||||
this._triangleBin = new St.Widget({ y_expand: true,
|
||||
|
@ -283,7 +283,7 @@ const RemoteSearchProvider = new Lang.Class({
|
||||
// the provider is not compatible with the new version of the interface, launch
|
||||
// the app itself but warn so we can catch the error in logs
|
||||
log('Search provider ' + this.appInfo.get_id() + ' does not implement LaunchSearch');
|
||||
this.appInfo.launch([], global.create_app_launch_context());
|
||||
this.appInfo.launch([], global.create_app_launch_context(0, -1));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -233,7 +233,7 @@ const RunDialog = new Lang.Class({
|
||||
let file = Gio.file_new_for_path(path);
|
||||
try {
|
||||
Gio.app_info_launch_default_for_uri(file.get_uri(),
|
||||
global.create_app_launch_context());
|
||||
global.create_app_launch_context(0, -1));
|
||||
} catch (e) {
|
||||
// The exception from gjs contains an error string like:
|
||||
// Error invoking Gio.app_info_launch_default_for_uri: No application
|
||||
|
@ -17,7 +17,6 @@ const TweenerEquations = imports.tweener.equations;
|
||||
|
||||
const Background = imports.ui.background;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Hash = imports.misc.hash;
|
||||
const Layout = imports.ui.layout;
|
||||
const OVirt = imports.gdm.oVirt;
|
||||
const LoginManager = imports.misc.loginManager;
|
||||
@ -115,7 +114,7 @@ const NotificationsBox = new Lang.Class({
|
||||
this.actor.add(this._musicBin);
|
||||
this.actor.add(this._scrollView, { x_fill: true, x_align: St.Align.START });
|
||||
|
||||
this._sources = new Hash.Map();
|
||||
this._sources = new Map();
|
||||
Main.messageTray.getSources().forEach(Lang.bind(this, function(source) {
|
||||
this._sourceAdded(Main.messageTray, source, true);
|
||||
}));
|
||||
@ -130,9 +129,8 @@ const NotificationsBox = new Lang.Class({
|
||||
this._sourceAddedId = 0;
|
||||
}
|
||||
|
||||
let items = this._sources.items();
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let [source, obj] = items[i];
|
||||
let items = this._sources.entries();
|
||||
for (let [source, obj] of items) {
|
||||
this._removeSource(source, obj);
|
||||
}
|
||||
|
||||
@ -303,7 +301,7 @@ const NotificationsBox = new Lang.Class({
|
||||
});
|
||||
|
||||
this._updateVisibility();
|
||||
Shell.util_wake_up_screen();
|
||||
this.emit('wake-up-screen');
|
||||
}
|
||||
},
|
||||
|
||||
@ -329,7 +327,7 @@ const NotificationsBox = new Lang.Class({
|
||||
|
||||
this._updateVisibility();
|
||||
if (obj.sourceBox.visible)
|
||||
Shell.util_wake_up_screen();
|
||||
this.emit('wake-up-screen');
|
||||
},
|
||||
|
||||
_visibleChanged: function(source, obj) {
|
||||
@ -344,7 +342,7 @@ const NotificationsBox = new Lang.Class({
|
||||
|
||||
this._updateVisibility();
|
||||
if (obj.sourceBox.visible)
|
||||
Shell.util_wake_up_screen();
|
||||
this.emit('wake-up-screen');
|
||||
},
|
||||
|
||||
_detailedChanged: function(source, obj) {
|
||||
@ -382,6 +380,7 @@ const NotificationsBox = new Lang.Class({
|
||||
this._sources.delete(source);
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(NotificationsBox.prototype);
|
||||
|
||||
const Arrow = new Lang.Class({
|
||||
Name: 'Arrow',
|
||||
@ -415,6 +414,7 @@ const Arrow = new Lang.Class({
|
||||
cr.lineTo(w/2, thickness);
|
||||
cr.lineTo(w - thickness / 2, h - thickness / 2);
|
||||
cr.stroke();
|
||||
cr.$dispose();
|
||||
},
|
||||
|
||||
vfunc_style_changed: function() {
|
||||
@ -537,7 +537,7 @@ const ScreenShield = new Lang.Class({
|
||||
|
||||
this._smartcardManager = SmartcardManager.getSmartcardManager();
|
||||
this._smartcardManager.connect('smartcard-inserted',
|
||||
Lang.bind(this, function(token) {
|
||||
Lang.bind(this, function(manager, token) {
|
||||
if (this._isLocked && token.UsedToLogin)
|
||||
this._liftShield(true, 0);
|
||||
}));
|
||||
@ -729,7 +729,7 @@ const ScreenShield = new Lang.Class({
|
||||
} else {
|
||||
this._inhibitSuspend();
|
||||
|
||||
this._onUserBecameActive();
|
||||
this._wakeUpScreen();
|
||||
}
|
||||
},
|
||||
|
||||
@ -1152,6 +1152,7 @@ const ScreenShield = new Lang.Class({
|
||||
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
|
||||
|
||||
this._notificationsBox = new NotificationsBox();
|
||||
this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', Lang.bind(this, this._wakeUpScreen));
|
||||
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
|
||||
y_fill: true,
|
||||
expand: true });
|
||||
@ -1159,11 +1160,17 @@ const ScreenShield = new Lang.Class({
|
||||
this._hasLockScreen = true;
|
||||
},
|
||||
|
||||
_wakeUpScreen: function() {
|
||||
this._onUserBecameActive();
|
||||
this.emit('wake-up-screen');
|
||||
},
|
||||
|
||||
_clearLockScreen: function() {
|
||||
this._clock.destroy();
|
||||
this._clock = null;
|
||||
|
||||
if (this._notificationsBox) {
|
||||
this._notificationsBox.disconnect(this._wakeUpScreenId);
|
||||
this._notificationsBox.destroy();
|
||||
this._notificationsBox = null;
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Hash = imports.misc.hash;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const ScreencastIface = '<node> \
|
||||
@ -42,13 +41,13 @@ const ScreencastService = new Lang.Class({
|
||||
|
||||
Gio.DBus.session.own_name('org.gnome.Shell.Screencast', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||
|
||||
this._recorders = new Hash.Map();
|
||||
this._recorders = new Map();
|
||||
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
},
|
||||
|
||||
get isRecording() {
|
||||
return this._recorders.size() > 0;
|
||||
return this._recorders.size > 0;
|
||||
},
|
||||
|
||||
_ensureRecorderForSender: function(sender) {
|
||||
@ -69,8 +68,7 @@ const ScreencastService = new Lang.Class({
|
||||
if (Main.sessionMode.allowScreencast)
|
||||
return;
|
||||
|
||||
for (let sender in this._recorders.keys())
|
||||
this._recorders.delete(sender);
|
||||
this._recorders.clear();
|
||||
this.emit('updated');
|
||||
},
|
||||
|
||||
|
@ -315,6 +315,8 @@ const SearchResultsBase = new Lang.Class({
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
for (let resultId in this._resultDisplays)
|
||||
this._resultDisplays[resultId].actor.destroy();
|
||||
this._resultDisplays = {};
|
||||
this._clearResultDisplay();
|
||||
this.actor.hide();
|
||||
@ -338,12 +340,22 @@ const SearchResultsBase = new Lang.Class({
|
||||
}));
|
||||
|
||||
if (metasNeeded.length === 0) {
|
||||
callback();
|
||||
callback(true);
|
||||
} else {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
|
||||
this.provider.getResultMetas(metasNeeded, Lang.bind(this, function(metas) {
|
||||
if (metas.length == 0) {
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
if (metas.length != metasNeeded.length) {
|
||||
log('Wrong number of result metas returned by search provider');
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
metasNeeded.forEach(Lang.bind(this, function(resultId, i) {
|
||||
let meta = metas[i];
|
||||
let display = this._createResultDisplay(meta);
|
||||
@ -351,7 +363,7 @@ const SearchResultsBase = new Lang.Class({
|
||||
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._resultDisplays[resultId] = display;
|
||||
}));
|
||||
callback();
|
||||
callback(true);
|
||||
}), this._cancellable);
|
||||
}
|
||||
},
|
||||
@ -368,8 +380,10 @@ const SearchResultsBase = new Lang.Class({
|
||||
let results = this.provider.filterResults(providerResults, maxResults);
|
||||
let hasMoreResults = results.length < providerResults.length;
|
||||
|
||||
this._ensureResultActors(results, Lang.bind(this, function() {
|
||||
this._ensureResultActors(results, Lang.bind(this, function(successful) {
|
||||
this._clearResultDisplay();
|
||||
if (!successful)
|
||||
return;
|
||||
|
||||
// To avoid CSS transitions causing flickering when
|
||||
// the first search result stays the same, we hide the
|
||||
|
@ -10,6 +10,8 @@ const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
|
||||
const DEFAULT_MODE = 'restrictive';
|
||||
|
||||
const _modes = {
|
||||
@ -92,8 +94,12 @@ const _modes = {
|
||||
isLocked: false,
|
||||
isPrimary: true,
|
||||
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
|
||||
components: ['networkAgent', 'polkitAgent', 'telepathyClient',
|
||||
components: Config.HAVE_NETWORKMANAGER ?
|
||||
['networkAgent', 'polkitAgent', 'telepathyClient',
|
||||
'keyring', 'autorunManager', 'automountManager'] :
|
||||
['polkitAgent', 'telepathyClient',
|
||||
'keyring', 'autorunManager', 'automountManager'],
|
||||
|
||||
panel: {
|
||||
left: ['activities', 'appMenu'],
|
||||
center: ['dateMenu'],
|
||||
|
@ -10,7 +10,6 @@ const Config = imports.misc.config;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const ExtensionDownloader = imports.ui.extensionDownloader;
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Hash = imports.misc.hash;
|
||||
const Main = imports.ui.main;
|
||||
const Screenshot = imports.ui.screenshot;
|
||||
const ViewSelector = imports.ui.viewSelector;
|
||||
@ -70,6 +69,7 @@ const ScreenSaverIface = '<node> \
|
||||
<signal name="ActiveChanged"> \
|
||||
<arg name="new_value" type="b" /> \
|
||||
</signal> \
|
||||
<signal name="WakeUpScreen" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
@ -83,8 +83,8 @@ const GnomeShell = new Lang.Class({
|
||||
this._extensionsService = new GnomeShellExtensions();
|
||||
this._screenshotService = new Screenshot.ScreenshotService();
|
||||
|
||||
this._grabbedAccelerators = new Hash.Map();
|
||||
this._grabbers = new Hash.Map();
|
||||
this._grabbedAccelerators = new Map();
|
||||
this._grabbers = new Map();
|
||||
|
||||
global.display.connect('accelerator-activated', Lang.bind(this,
|
||||
function(display, action, deviceid, timestamp) {
|
||||
@ -228,9 +228,8 @@ const GnomeShell = new Lang.Class({
|
||||
},
|
||||
|
||||
_onGrabberBusNameVanished: function(connection, name) {
|
||||
let grabs = this._grabbedAccelerators.items();
|
||||
for (let i = 0; i < grabs.length; i++) {
|
||||
let [action, sender] = grabs[i];
|
||||
let grabs = this._grabbedAccelerators.entries();
|
||||
for (let [action, sender] of grabs) {
|
||||
if (sender == name)
|
||||
this._ungrabAccelerator(action);
|
||||
}
|
||||
@ -373,8 +372,10 @@ const GnomeShellExtensions = new Lang.Class({
|
||||
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);
|
||||
let info = app.get_app_info();
|
||||
let timestamp = global.display.get_current_time_roundtrip();
|
||||
info.launch_uris(['extension:///' + uuid],
|
||||
global.create_app_launch_context(timestamp, -1));
|
||||
},
|
||||
|
||||
ReloadExtension: function(uuid) {
|
||||
@ -407,6 +408,9 @@ const ScreenSaverDBus = new Lang.Class({
|
||||
screenShield.connect('active-changed', Lang.bind(this, function(shield) {
|
||||
this._dbusImpl.emit_signal('ActiveChanged', GLib.Variant.new('(b)', [shield.active]));
|
||||
}));
|
||||
screenShield.connect('wake-up-screen', Lang.bind(this, function(shield) {
|
||||
this._dbusImpl.emit_signal('WakeUpScreen', null);
|
||||
}));
|
||||
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenSaverIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/ScreenSaver');
|
||||
|
@ -1,11 +1,11 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Atk = imports.gi.Atk;
|
||||
const Cairo = imports.cairo;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Atk = imports.gi.Atk;
|
||||
|
||||
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
|
||||
|
||||
|
@ -44,7 +44,7 @@ const ATIndicator = new Lang.Class({
|
||||
this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
||||
this._hbox.add_child(new St.Icon({ style_class: 'system-status-icon',
|
||||
icon_name: 'preferences-desktop-accessibility-symbolic' }));
|
||||
this._hbox.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
|
||||
this._hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
|
||||
|
||||
this.actor.add_child(this._hbox);
|
||||
|
||||
|
@ -17,6 +17,7 @@ const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
|
||||
const RfkillManagerInterface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
|
||||
<property name="BluetoothAirplaneMode" type="b" access="readwrite" /> \
|
||||
<property name="BluetoothHasAirplaneMode" type="b" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
@ -38,7 +39,10 @@ const Indicator = new Lang.Class({
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
|
||||
this._sync();
|
||||
}));
|
||||
this._proxy.connect('g-properties-changed', Lang.bind(this, this._sync));
|
||||
|
||||
// The Bluetooth menu only appears when Bluetooth is in use,
|
||||
// so just statically build it with a "Turn Off" menu item.
|
||||
@ -55,6 +59,7 @@ const Indicator = new Lang.Class({
|
||||
this._model.connect('row-changed', Lang.bind(this, this._sync));
|
||||
this._model.connect('row-deleted', Lang.bind(this, this._sync));
|
||||
this._model.connect('row-inserted', Lang.bind(this, this._sync));
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sync));
|
||||
this._sync();
|
||||
},
|
||||
|
||||
@ -89,12 +94,15 @@ const Indicator = new Lang.Class({
|
||||
|
||||
_sync: function() {
|
||||
let nDevices = this._getNConnectedDevices();
|
||||
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||
|
||||
let on = nDevices > 0;
|
||||
this._indicator.visible = on;
|
||||
this._item.actor.visible = on;
|
||||
this.menu.setSensitive(sensitive);
|
||||
this._indicator.visible = nDevices > 0;
|
||||
this._item.actor.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
|
||||
|
||||
if (on)
|
||||
if (nDevices > 0)
|
||||
this._item.status.text = ngettext("%d Connected Device", "%d Connected Devices", nDevices).format(nDevices);
|
||||
else
|
||||
this._item.status.text = _("Not Connected");
|
||||
},
|
||||
});
|
||||
|
@ -341,7 +341,7 @@ const InputSourceIndicator = new Lang.Class({
|
||||
|
||||
this._hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
||||
this._hbox.add_child(this._container);
|
||||
this._hbox.add_child(PopupMenu.unicodeArrow(St.Side.BOTTOM));
|
||||
this._hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
|
||||
|
||||
this.actor.add_child(this._hbox);
|
||||
this.actor.add_style_class_name('panel-status-button');
|
||||
|
201
js/ui/status/location.js
Normal file
201
js/ui/status/location.js
Normal file
@ -0,0 +1,201 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const LOCATION_SCHEMA = 'org.gnome.shell.location';
|
||||
const MAX_ACCURACY_LEVEL = 'max-accuracy-level';
|
||||
|
||||
var GeoclueIface = '<node> \
|
||||
<interface name="org.freedesktop.GeoClue2.Manager"> \
|
||||
<property name="InUse" type="b" access="read"/> \
|
||||
<property name="AvailableAccuracyLevel" type="u" access="read"/> \
|
||||
<method name="AddAgent"> \
|
||||
<arg name="id" type="s" direction="in"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const GeoclueManager = Gio.DBusProxy.makeProxyWrapper(GeoclueIface);
|
||||
|
||||
var AgentIface = '<node> \
|
||||
<interface name="org.freedesktop.GeoClue2.Agent"> \
|
||||
<property name="MaxAccuracyLevel" type="u" access="read"/> \
|
||||
<method name="AuthorizeApp"> \
|
||||
<arg name="desktop_id" type="s" direction="in"/> \
|
||||
<arg name="req_accuracy_level" type="u" direction="in"/> \
|
||||
<arg name="authorized" type="b" direction="out"/> \
|
||||
<arg name="allowed_accuracy_level" type="u" direction="out"/> \
|
||||
</method> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'LocationIndicator',
|
||||
Extends: PanelMenu.SystemIndicator,
|
||||
|
||||
_init: function() {
|
||||
this.parent();
|
||||
|
||||
this._settings = new Gio.Settings({ schema: LOCATION_SCHEMA });
|
||||
this._settings.connect('changed::' + MAX_ACCURACY_LEVEL,
|
||||
Lang.bind(this, this._onMaxAccuracyLevelChanged));
|
||||
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.icon_name = 'find-location-symbolic';
|
||||
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Location"), true);
|
||||
this._item.icon.icon_name = 'find-location-symbolic';
|
||||
|
||||
this._agent = Gio.DBusExportedObject.wrapJSObject(AgentIface, this);
|
||||
this._agent.export(Gio.DBus.system, '/org/freedesktop/GeoClue2/Agent');
|
||||
|
||||
this._item.status.text = _("On");
|
||||
this._onOffAction = this._item.menu.addAction(_("Turn Off"), Lang.bind(this, this._onOnOffAction));
|
||||
|
||||
this.menu.addMenuItem(this._item);
|
||||
|
||||
this._watchId = Gio.bus_watch_name(Gio.BusType.SYSTEM,
|
||||
'org.freedesktop.GeoClue2',
|
||||
0,
|
||||
Lang.bind(this, this._connectToGeoclue),
|
||||
Lang.bind(this, this._onGeoclueVanished));
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._onSessionUpdated));
|
||||
this._onSessionUpdated();
|
||||
this._onMaxAccuracyLevelChanged();
|
||||
this._connectToGeoclue();
|
||||
},
|
||||
|
||||
get MaxAccuracyLevel() {
|
||||
return this._getMaxAccuracyLevel();
|
||||
},
|
||||
|
||||
// We (and geoclue) have currently no way to reliably identifying apps so
|
||||
// for now, lets just authorize all apps as long as they provide a valid
|
||||
// desktop ID. We also ensure they don't get more accuracy than global max.
|
||||
AuthorizeApp: function(desktop_id, reqAccuracyLevel) {
|
||||
var appSystem = Shell.AppSystem.get_default();
|
||||
var app = appSystem.lookup_app(desktop_id + ".desktop");
|
||||
if (app == null) {
|
||||
return [false, 0];
|
||||
}
|
||||
|
||||
let allowedAccuracyLevel = clamp(reqAccuracyLevel, 0, this._getMaxAccuracyLevel());
|
||||
return [true, allowedAccuracyLevel];
|
||||
},
|
||||
|
||||
_syncIndicator: function() {
|
||||
if (this._proxy == null) {
|
||||
this._indicator.visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this._indicator.visible = this._proxy.InUse;
|
||||
},
|
||||
|
||||
_connectToGeoclue: function() {
|
||||
if (this._proxy != null || this._connecting)
|
||||
return false;
|
||||
|
||||
this._connecting = true;
|
||||
new GeoclueManager(Gio.DBus.system,
|
||||
'org.freedesktop.GeoClue2',
|
||||
'/org/freedesktop/GeoClue2/Manager',
|
||||
Lang.bind(this, this._onProxyReady));
|
||||
return true;
|
||||
},
|
||||
|
||||
_onProxyReady: function(proxy, error) {
|
||||
if (error != null) {
|
||||
log(error.message);
|
||||
this._connecting = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this._proxy = proxy;
|
||||
this._propertiesChangedId = this._proxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._onGeocluePropsChanged));
|
||||
|
||||
this._updateMenu();
|
||||
this._syncIndicator();
|
||||
|
||||
this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
|
||||
},
|
||||
|
||||
_onAgentRegistered: function(result, error) {
|
||||
this._connecting = false;
|
||||
this._notifyMaxAccuracyLevel();
|
||||
|
||||
if (error != null)
|
||||
log(error.message);
|
||||
},
|
||||
|
||||
_onGeoclueVanished: function() {
|
||||
if (this._propertiesChangedId) {
|
||||
this._proxy.disconnect(this._propertiesChangedId);
|
||||
this._propertiesChangedId = 0;
|
||||
}
|
||||
this._proxy = null;
|
||||
|
||||
this._syncIndicator();
|
||||
},
|
||||
|
||||
_onOnOffAction: function() {
|
||||
if (this._getMaxAccuracyLevel() == 0)
|
||||
this._settings.set_enum(MAX_ACCURACY_LEVEL, this._availableAccuracyLevel);
|
||||
else
|
||||
this._settings.set_enum(MAX_ACCURACY_LEVEL, 0);
|
||||
},
|
||||
|
||||
_onSessionUpdated: function() {
|
||||
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||
this.menu.setSensitive(sensitive);
|
||||
},
|
||||
|
||||
_onMaxAccuracyLevelChanged: function() {
|
||||
if (this._getMaxAccuracyLevel() == 0) {
|
||||
this._item.status.text = _("Off");
|
||||
this._onOffAction.label.text = _("Turn On");
|
||||
} else {
|
||||
this._item.status.text = _("On");
|
||||
this._onOffAction.label.text = _("Turn Off");
|
||||
}
|
||||
|
||||
// Gotta ensure geoclue is up and we are registered as agent to it
|
||||
// before we emit the notify for this property change.
|
||||
if (!this._connectToGeoclue())
|
||||
this._notifyMaxAccuracyLevel();
|
||||
},
|
||||
|
||||
_getMaxAccuracyLevel: function() {
|
||||
return this._settings.get_enum(MAX_ACCURACY_LEVEL);
|
||||
},
|
||||
|
||||
_notifyMaxAccuracyLevel: function() {
|
||||
let variant = new GLib.Variant('u', this._getMaxAccuracyLevel());
|
||||
this._agent.emit_property_changed('MaxAccuracyLevel', variant);
|
||||
},
|
||||
|
||||
_updateMenu: function() {
|
||||
this._availableAccuracyLevel = this._proxy.AvailableAccuracyLevel;
|
||||
this.menu.actor.visible = (this._availableAccuracyLevel != 0);
|
||||
},
|
||||
|
||||
_onGeocluePropsChanged: function(proxy, properties) {
|
||||
let unpacked = properties.deep_unpack();
|
||||
if ("InUse" in unpacked)
|
||||
this._syncIndicator();
|
||||
if ("AvailableAccuracyLevel" in unpacked)
|
||||
this._updateMenu();
|
||||
}
|
||||
});
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
@ -9,19 +9,22 @@ const NetworkManager = imports.gi.NetworkManager;
|
||||
const NMClient = imports.gi.NMClient;
|
||||
const NMGtk = imports.gi.NMGtk;
|
||||
const Signals = imports.signals;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Hash = imports.misc.hash;
|
||||
const Animation = imports.ui.animation;
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const ModemManager = imports.misc.modemManager;
|
||||
const Rfkill = imports.ui.status.rfkill;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const NMConnectionCategory = {
|
||||
INVALID: 'invalid',
|
||||
WIRED: 'wired',
|
||||
WIRELESS: 'wireless',
|
||||
WWAN: 'wwan',
|
||||
VPN: 'vpn'
|
||||
@ -102,18 +105,34 @@ const NMConnectionItem = new Lang.Class({
|
||||
this._activeConnection = null;
|
||||
this._activeConnectionChangedId = 0;
|
||||
|
||||
this._buildUI();
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_buildUI: function() {
|
||||
this.labelItem = new PopupMenu.PopupMenuItem('');
|
||||
this.labelItem.connect('activate', Lang.bind(this, this._toggle));
|
||||
|
||||
this.switchItem = new PopupMenu.PopupSwitchMenuItem(connection.get_id(), false);
|
||||
this.switchItem.connect('toggled', Lang.bind(this, this._toggle));
|
||||
|
||||
this._sync();
|
||||
this.radioItem = new PopupMenu.PopupMenuItem(this._connection.get_id(), false);
|
||||
this.radioItem.connect('activate', Lang.bind(this, this._activate));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.labelItem.destroy();
|
||||
this.switchItem.destroy();
|
||||
this.radioItem.destroy();
|
||||
},
|
||||
|
||||
updateForConnection: function(connection) {
|
||||
// connection should always be the same object
|
||||
// (and object path) as this._connection, but
|
||||
// this can be false if NetworkManager was restarted
|
||||
// and picked up connections in a different order
|
||||
// Just to be safe, we set it here again
|
||||
|
||||
this._connection = connection;
|
||||
this.radioItem.label.text = connection.get_id();
|
||||
this._sync();
|
||||
this.emit('name-changed');
|
||||
},
|
||||
|
||||
getName: function() {
|
||||
@ -129,9 +148,8 @@ const NMConnectionItem = new Lang.Class({
|
||||
|
||||
_sync: function() {
|
||||
let isActive = this.isActive();
|
||||
this.labelItem.label.text = isActive ? _("Turn Off") : _("Connect");
|
||||
this.switchItem.setToggleState(isActive);
|
||||
this.switchItem.setStatus(this._getStatus());
|
||||
this.labelItem.label.text = isActive ? _("Turn Off") : this._section.getConnectLabel();
|
||||
this.radioItem.setOrnament(isActive ? PopupMenu.Ornament.DOT : PopupMenu.Ornament.NONE);
|
||||
this.emit('icon-changed');
|
||||
},
|
||||
|
||||
@ -144,8 +162,11 @@ const NMConnectionItem = new Lang.Class({
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_getStatus: function() {
|
||||
return null;
|
||||
_activate: function() {
|
||||
if (this._activeConnection == null)
|
||||
this._section.activateConnection(this._connection);
|
||||
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_connectionStateChanged: function(ac, newstate, reason) {
|
||||
@ -176,15 +197,15 @@ const NMConnectionSection = new Lang.Class({
|
||||
_init: function(client) {
|
||||
this._client = client;
|
||||
|
||||
this._connectionItems = new Hash.Map();
|
||||
this._connectionItems = new Map();
|
||||
this._connections = [];
|
||||
|
||||
this._labelSection = new PopupMenu.PopupMenuSection();
|
||||
this._switchSection = new PopupMenu.PopupMenuSection();
|
||||
this._radioSection = new PopupMenu.PopupMenuSection();
|
||||
|
||||
this.item = new PopupMenu.PopupSubMenuMenuItem('', true);
|
||||
this.item.menu.addMenuItem(this._labelSection);
|
||||
this.item.menu.addMenuItem(this._switchSection);
|
||||
this.item.menu.addMenuItem(this._radioSection);
|
||||
|
||||
this.connect('icon-changed', Lang.bind(this, this._sync));
|
||||
},
|
||||
@ -194,9 +215,9 @@ const NMConnectionSection = new Lang.Class({
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let nItems = this._connectionItems.size();
|
||||
let nItems = this._connectionItems.size;
|
||||
|
||||
this._switchSection.actor.visible = (nItems > 1);
|
||||
this._radioSection.actor.visible = (nItems > 1);
|
||||
this._labelSection.actor.visible = (nItems == 1);
|
||||
|
||||
this.item.status.text = this._getStatus();
|
||||
@ -211,19 +232,12 @@ const NMConnectionSection = new Lang.Class({
|
||||
this.item.label.text = '';
|
||||
},
|
||||
|
||||
_getStatus: function() {
|
||||
let values = this._connectionItems.values();
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let item = values[i];
|
||||
if (item.isActive())
|
||||
return item.getName();
|
||||
}
|
||||
|
||||
return _("Off");
|
||||
_getMenuIcon: function() {
|
||||
return this.getIndicatorIcon();
|
||||
},
|
||||
|
||||
_hasConnection: function(connection) {
|
||||
return this._connectionItems.has(connection.get_uuid());
|
||||
getConnectLabel: function() {
|
||||
return _("Connect");
|
||||
},
|
||||
|
||||
_connectionValid: function(connection) {
|
||||
@ -231,10 +245,7 @@ const NMConnectionSection = new Lang.Class({
|
||||
},
|
||||
|
||||
_connectionSortFunction: function(one, two) {
|
||||
if (one._timestamp == two._timestamp)
|
||||
return GLib.utf8_collate(one.get_id(), two.get_id());
|
||||
|
||||
return two._timestamp - one._timestamp;
|
||||
return GLib.utf8_collate(one.get_id(), two.get_id());
|
||||
},
|
||||
|
||||
_makeConnectionItem: function(connection) {
|
||||
@ -245,10 +256,20 @@ const NMConnectionSection = new Lang.Class({
|
||||
if (!this._connectionValid(connection))
|
||||
return;
|
||||
|
||||
if (this._hasConnection(connection))
|
||||
return;
|
||||
// This function is called everytime connection is added or updated
|
||||
// In the usual case, we already added this connection and UUID
|
||||
// didn't change. So we need to check if we already have an item,
|
||||
// and update it for properties in the connection that changed
|
||||
// (the only one we care about is the name)
|
||||
// But it's also possible we didn't know about this connection
|
||||
// (eg, during coldplug, or because it was updated and suddenly
|
||||
// it's valid for this device), in which case we add a new item
|
||||
|
||||
this._addConnection(connection);
|
||||
let item = this._connectionItems.get(connection.get_uuid());
|
||||
if (item)
|
||||
item.updateForConnection(connection);
|
||||
else
|
||||
this._addConnection(connection);
|
||||
},
|
||||
|
||||
_addConnection: function(connection) {
|
||||
@ -262,17 +283,23 @@ const NMConnectionSection = new Lang.Class({
|
||||
item.connect('activation-failed', Lang.bind(this, function(item, reason) {
|
||||
this.emit('activation-failed', reason);
|
||||
}));
|
||||
item.connect('name-changed', Lang.bind(this, this._sync));
|
||||
|
||||
let pos = Util.insertSorted(this._connections, connection, Lang.bind(this, this._connectionSortFunction));
|
||||
this._labelSection.addMenuItem(item.labelItem, pos);
|
||||
this._switchSection.addMenuItem(item.switchItem, pos);
|
||||
this._radioSection.addMenuItem(item.radioItem, pos);
|
||||
this._connectionItems.set(connection.get_uuid(), item);
|
||||
this._sync();
|
||||
},
|
||||
|
||||
removeConnection: function(connection) {
|
||||
this._connectionItems.get(connection.get_uuid()).destroy();
|
||||
this._connectionItems.delete(connection.get_uuid());
|
||||
let uuid = connection.get_uuid();
|
||||
let item = this._connectionItems.get(uuid);
|
||||
if (item == undefined)
|
||||
return;
|
||||
|
||||
item.destroy();
|
||||
this._connectionItems.delete(uuid);
|
||||
|
||||
let pos = this._connections.indexOf(connection);
|
||||
this._connections.splice(pos, 1);
|
||||
@ -293,11 +320,24 @@ const NMConnectionDevice = new Lang.Class({
|
||||
this._settings = settings;
|
||||
|
||||
this._autoConnectItem = this.item.menu.addAction(_("Connect"), Lang.bind(this, this._autoConnect));
|
||||
this._deactivateItem = this._radioSection.addAction(_("Turn Off"), Lang.bind(this, this.deactivateConnection));
|
||||
|
||||
this._stateChangedId = this._device.connect('state-changed', Lang.bind(this, this._deviceStateChanged));
|
||||
this._activeConnectionChangedId = this._device.connect('notify::active-connection', Lang.bind(this, this._activeConnectionChanged));
|
||||
},
|
||||
|
||||
_canReachInternet: function() {
|
||||
if (this._client.primary_connection != this._device.active_connection)
|
||||
return true;
|
||||
|
||||
return this._client.connectivity == NetworkManager.ConnectivityState.FULL;
|
||||
},
|
||||
|
||||
_autoConnect: function() {
|
||||
let connection = new NetworkManager.Connection();
|
||||
this._client.add_and_activate_connection(connection, this._device, null, null);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._stateChangedId) {
|
||||
GObject.Object.prototype.disconnect.call(this._device, this._stateChangedId);
|
||||
@ -305,7 +345,7 @@ const NMConnectionDevice = new Lang.Class({
|
||||
}
|
||||
if (this._activeConnectionChangedId) {
|
||||
GObject.Object.prototype.disconnect.call(this._device, this._activeConnectionChangedId);
|
||||
this._stateChangedId = 0;
|
||||
this._activeConnectionChangedId = 0;
|
||||
}
|
||||
|
||||
this.parent();
|
||||
@ -365,8 +405,9 @@ const NMConnectionDevice = new Lang.Class({
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let nItems = this._connectionItems.size();
|
||||
let nItems = this._connectionItems.size;
|
||||
this._autoConnectItem.actor.visible = (nItems == 0);
|
||||
this._deactivateItem.actor.visible = this._device.state > NetworkManager.DeviceState.DISCONNECTED;
|
||||
this.parent();
|
||||
},
|
||||
|
||||
@ -378,7 +419,7 @@ const NMConnectionDevice = new Lang.Class({
|
||||
case NetworkManager.DeviceState.DISCONNECTED:
|
||||
return _("Off");
|
||||
case NetworkManager.DeviceState.ACTIVATED:
|
||||
return this.parent();
|
||||
return _("Connected");
|
||||
case NetworkManager.DeviceState.UNMANAGED:
|
||||
/* Translators: this is for network devices that are physically present but are not
|
||||
under NetworkManager's control (and thus cannot be used in the menu) */
|
||||
@ -415,6 +456,48 @@ const NMConnectionDevice = new Lang.Class({
|
||||
},
|
||||
});
|
||||
|
||||
const NMDeviceWired = new Lang.Class({
|
||||
Name: 'NMDeviceWired',
|
||||
Extends: NMConnectionDevice,
|
||||
category: NMConnectionCategory.WIRED,
|
||||
|
||||
_init: function(client, device, settings) {
|
||||
this.parent(client, device, settings);
|
||||
|
||||
this.item.menu.addMenuItem(createSettingsAction(_("Wired Settings"), device));
|
||||
},
|
||||
|
||||
_hasCarrier: function() {
|
||||
if (this._device instanceof NMClient.DeviceEthernet)
|
||||
return this._device.carrier;
|
||||
else
|
||||
return true;
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
this.item.actor.visible = this._hasCarrier();
|
||||
this.parent();
|
||||
},
|
||||
|
||||
getIndicatorIcon: function() {
|
||||
if (this._device.active_connection) {
|
||||
let state = this._device.active_connection.state;
|
||||
|
||||
if (state == NetworkManager.ActiveConnectionState.ACTIVATING) {
|
||||
return 'network-wired-acquiring-symbolic';
|
||||
} else if (state == NetworkManager.ActiveConnectionState.ACTIVATED) {
|
||||
if (this._canReachInternet())
|
||||
return 'network-wired-symbolic';
|
||||
else
|
||||
return 'network-wired-no-route-symbolic';
|
||||
} else {
|
||||
return 'network-wired-disconnected-symbolic';
|
||||
}
|
||||
} else
|
||||
return 'network-wired-disconnected-symbolic';
|
||||
}
|
||||
});
|
||||
|
||||
const NMDeviceModem = new Lang.Class({
|
||||
Name: 'NMDeviceModem',
|
||||
Extends: NMConnectionDevice,
|
||||
@ -477,28 +560,20 @@ const NMDeviceModem = new Lang.Class({
|
||||
return this.parent();
|
||||
},
|
||||
|
||||
_getMenuIcon: function() {
|
||||
if (this._device.active_connection)
|
||||
return this.getIndicatorIcon();
|
||||
else
|
||||
getIndicatorIcon: function() {
|
||||
if (this._device.active_connection) {
|
||||
if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
return 'network-cellular-acquiring-symbolic';
|
||||
|
||||
return this._getSignalIcon();
|
||||
} else {
|
||||
return 'network-cellular-signal-none-symbolic';
|
||||
}
|
||||
},
|
||||
|
||||
_getSignalIcon: function() {
|
||||
return 'network-cellular-signal-' + signalToIcon(this._mobileDevice.signal_quality) + '-symbolic';
|
||||
},
|
||||
|
||||
getIndicatorIcon: function() {
|
||||
if (this._device.active_connection.state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
return 'network-cellular-acquiring-symbolic';
|
||||
|
||||
if (!this._mobileDevice) {
|
||||
// this can happen for bluetooth in PAN mode
|
||||
return 'network-cellular-connected-symbolic';
|
||||
}
|
||||
|
||||
return this._getSignalIcon();
|
||||
}
|
||||
});
|
||||
|
||||
const NMDeviceBluetooth = new Lang.Class({
|
||||
@ -512,33 +587,26 @@ const NMDeviceBluetooth = new Lang.Class({
|
||||
this.item.menu.addMenuItem(createSettingsAction(_("Mobile Broadband Settings"), device));
|
||||
},
|
||||
|
||||
_autoConnect: function() {
|
||||
// FIXME: DUN devices are configured like modems, so
|
||||
// We need to spawn the mobile wizard
|
||||
// but the network panel doesn't support bluetooth at the moment
|
||||
// so we just create an empty connection and hope
|
||||
// that this phone supports PAN
|
||||
|
||||
let connection = new NetworkManager.Connection();
|
||||
this._client.add_and_activate_connection(connection, this._device, null, null);
|
||||
return true;
|
||||
_getDescription: function() {
|
||||
return this._device.name;
|
||||
},
|
||||
|
||||
_getMenuIcon: function() {
|
||||
if (this._device.active_connection)
|
||||
return this.getIndicatorIcon();
|
||||
else
|
||||
return 'network-cellular-signal-none-symbolic';
|
||||
getConnectLabel: function() {
|
||||
return _("Use as Internet connection");
|
||||
},
|
||||
|
||||
getIndicatorIcon: function() {
|
||||
let state = this._device.active_connection.state;
|
||||
if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
return 'network-cellular-acquiring-symbolic';
|
||||
else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
|
||||
return 'network-cellular-connected-symbolic';
|
||||
else
|
||||
if (this._device.active_connection) {
|
||||
let state = this._device.active_connection.state;
|
||||
if (state == NetworkManager.ActiveConnectionState.ACTIVATING)
|
||||
return 'network-cellular-acquiring-symbolic';
|
||||
else if (state == NetworkManager.ActiveConnectionState.ACTIVATED)
|
||||
return 'network-cellular-connected-symbolic';
|
||||
else
|
||||
return 'network-cellular-signal-none-symbolic';
|
||||
} else {
|
||||
return 'network-cellular-signal-none-symbolic';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -617,6 +685,13 @@ const NMWirelessDialog = new Lang.Class({
|
||||
this._client = client;
|
||||
this._device = device;
|
||||
|
||||
this._wirelessEnabledChangedId = this._client.connect('notify::wireless-enabled',
|
||||
Lang.bind(this, this._syncView));
|
||||
|
||||
this._rfkill = Rfkill.getRfkillManager();
|
||||
this._airplaneModeChangedId = this._rfkill.connect('airplane-mode-changed',
|
||||
Lang.bind(this, this._syncView));
|
||||
|
||||
this._networks = [];
|
||||
this._buildLayout();
|
||||
|
||||
@ -638,6 +713,12 @@ const NMWirelessDialog = new Lang.Class({
|
||||
this._selectedNetwork = null;
|
||||
this._activeApChanged();
|
||||
this._updateSensitivity();
|
||||
this._syncView();
|
||||
|
||||
if (accessPoints.length == 0) {
|
||||
/* If there are no visible access points, request a scan */
|
||||
this._device.request_scan_simple(null);
|
||||
}
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
@ -653,6 +734,14 @@ const NMWirelessDialog = new Lang.Class({
|
||||
GObject.Object.prototype.disconnect.call(this._device, this._activeApChangedId);
|
||||
this._activeApChangedId = 0;
|
||||
}
|
||||
if (this._wirelessEnabledChangedId) {
|
||||
this._client.disconnect(this._wirelessEnabledChangedId);
|
||||
this._wirelessEnabledChangedId = 0;
|
||||
}
|
||||
if (this._airplaneModeChangedId) {
|
||||
this._rfkill.disconnect(this._airplaneModeChangedId);
|
||||
this._airplaneModeChangedId = 0;
|
||||
}
|
||||
|
||||
this.parent();
|
||||
},
|
||||
@ -674,13 +763,44 @@ const NMWirelessDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateSensitivity: function() {
|
||||
let connectSensitive = this._selectedNetwork && (this._selectedNetwork != this._activeNetwork);
|
||||
let connectSensitive = this._client.wireless_enabled && this._selectedNetwork && (this._selectedNetwork != this._activeNetwork);
|
||||
this._connectButton.reactive = connectSensitive;
|
||||
this._connectButton.can_focus = connectSensitive;
|
||||
},
|
||||
|
||||
_updateVisibility: function() {
|
||||
this._noNetworksLabel.visible = (this._networks.length == 0);
|
||||
_syncView: function() {
|
||||
if (this._rfkill.airplaneMode) {
|
||||
this._airplaneBox.show();
|
||||
|
||||
this._airplaneIcon.icon_name = 'airplane-mode-symbolic';
|
||||
this._airplaneHeadline.text = _("Airplane Mode is On");
|
||||
this._airplaneText.text = _("Wi-Fi is disabled when airplane mode is on.");
|
||||
this._airplaneButton.label = _("Turn Off Airplane Mode");
|
||||
|
||||
this._airplaneButton.visible = !this._rfkill.hwAirplaneMode;
|
||||
this._airplaneInactive.visible = this._rfkill.hwAirplaneMode;
|
||||
this._noNetworksBox.hide();
|
||||
} else if (!this._client.wireless_enabled) {
|
||||
this._airplaneBox.show();
|
||||
|
||||
this._airplaneIcon.icon_name = 'dialog-information-symbolic';
|
||||
this._airplaneHeadline.text = _("Wi-Fi is Off");
|
||||
this._airplaneText.text = _("Wi-Fi needs to be turned on in order to connect to a network.");
|
||||
this._airplaneButton.label = _("Turn On Wi-Fi");
|
||||
|
||||
this._airplaneButton.show();
|
||||
this._airplaneInactive.hide();
|
||||
this._noNetworksBox.hide();
|
||||
} else {
|
||||
this._airplaneBox.hide();
|
||||
|
||||
this._noNetworksBox.visible = (this._networks.length == 0);
|
||||
}
|
||||
|
||||
if (this._noNetworksBox.visible)
|
||||
this._noNetworksSpinner.play();
|
||||
else
|
||||
this._noNetworksSpinner.stop();
|
||||
},
|
||||
|
||||
_buildLayout: function() {
|
||||
@ -714,11 +834,43 @@ const NMWirelessDialog = new Lang.Class({
|
||||
this._scrollView.add_actor(this._itemBox);
|
||||
this._stack.add_child(this._scrollView);
|
||||
|
||||
this._noNetworksLabel = new St.Label({ style_class: 'no-networks-label',
|
||||
this._noNetworksBox = new St.BoxLayout({ vertical: true,
|
||||
style_class: 'no-networks-box',
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
|
||||
this._noNetworksSpinner = new Animation.AnimatedIcon(global.datadir + '/theme/process-working.svg', 24, 24);
|
||||
this._noNetworksBox.add_actor(this._noNetworksSpinner.actor);
|
||||
this._noNetworksBox.add_actor(new St.Label({ style_class: 'no-networks-label',
|
||||
text: _("No Networks") }));
|
||||
this._stack.add_child(this._noNetworksBox);
|
||||
|
||||
this._airplaneBox = new St.BoxLayout({ vertical: true,
|
||||
style_class: 'nm-dialog-airplane-box',
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
text: _("No Networks") });
|
||||
this._stack.add_child(this._noNetworksLabel);
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this._airplaneIcon = new St.Icon({ icon_size: 48 });
|
||||
this._airplaneHeadline = new St.Label({ style_class: 'nm-dialog-airplane-headline' });
|
||||
this._airplaneText = new St.Label({ style_class: 'nm-dialog-airplane-text' });
|
||||
|
||||
let airplaneSubStack = new St.Widget({ layout_manager: new Clutter.BinLayout });
|
||||
this._airplaneButton = new St.Button({ style_class: 'modal-dialog-button' });
|
||||
this._airplaneButton.connect('clicked', Lang.bind(this, function() {
|
||||
if (this._rfkill.airplaneMode)
|
||||
this._rfkill.airplaneMode = false;
|
||||
else
|
||||
this._client.wireless_enabled = true;
|
||||
}));
|
||||
airplaneSubStack.add_actor(this._airplaneButton);
|
||||
this._airplaneInactive = new St.Label({ style_class: 'nm-dialog-airplane-text',
|
||||
text: _("Use hardware switch to turn off") });
|
||||
airplaneSubStack.add_actor(this._airplaneInactive);
|
||||
|
||||
this._airplaneBox.add(this._airplaneIcon, { x_align: St.Align.MIDDLE });
|
||||
this._airplaneBox.add(this._airplaneHeadline, { x_align: St.Align.MIDDLE });
|
||||
this._airplaneBox.add(this._airplaneText, { x_align: St.Align.MIDDLE });
|
||||
this._airplaneBox.add(airplaneSubStack, { x_align: St.Align.MIDDLE });
|
||||
this._stack.add_child(this._airplaneBox);
|
||||
|
||||
this.contentLayout.add(this._stack, { expand: true });
|
||||
|
||||
@ -735,16 +887,11 @@ const NMWirelessDialog = new Lang.Class({
|
||||
|
||||
_connect: function() {
|
||||
let network = this._selectedNetwork;
|
||||
let accessPoints = network.accessPoints;
|
||||
if (network.connections.length > 0) {
|
||||
let connection = network.connections[0];
|
||||
for (let i = 0; i < accessPoints.length; i++) {
|
||||
if (accessPoints[i].connection_valid(connection)) {
|
||||
this._client.activate_connection(connection, this._device, accessPoints[i].dbus_path, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
this._client.activate_connection(connection, this._device, null, null);
|
||||
} else {
|
||||
let accessPoints = network.accessPoints;
|
||||
if ((accessPoints[0]._secType == NMAccessPointSecurity.WPA2_ENT)
|
||||
|| (accessPoints[0]._secType == NMAccessPointSecurity.WPA_ENT)) {
|
||||
// 802.1x-enabled APs require further configuration, so they're
|
||||
@ -916,7 +1063,7 @@ const NMWirelessDialog = new Lang.Class({
|
||||
this._itemBox.insert_child_at_index(network.item.actor, newPos);
|
||||
}
|
||||
|
||||
this._updateVisibility();
|
||||
this._syncView();
|
||||
},
|
||||
|
||||
_accessPointRemoved: function(device, accessPoint) {
|
||||
@ -931,14 +1078,14 @@ const NMWirelessDialog = new Lang.Class({
|
||||
network.accessPoints.splice(res.ap, 1);
|
||||
|
||||
if (network.accessPoints.length == 0) {
|
||||
network.item.destroy();
|
||||
network.item.actor.destroy();
|
||||
this._networks.splice(res.network, 1);
|
||||
} else {
|
||||
network.item.updateBestAP(network.accessPoints[0]);
|
||||
this._resortItems();
|
||||
}
|
||||
|
||||
this._updateVisibility();
|
||||
this._syncView();
|
||||
},
|
||||
|
||||
_resortItems: function() {
|
||||
@ -1023,6 +1170,10 @@ const NMDeviceWireless = new Lang.Class({
|
||||
this._client.disconnect(this._wirelessHwEnabledChangedId);
|
||||
this._wirelessHwEnabledChangedId = 0;
|
||||
}
|
||||
if (this._dialog) {
|
||||
this._dialog.destroy();
|
||||
this._dialog = null;
|
||||
}
|
||||
|
||||
this.item.destroy();
|
||||
},
|
||||
@ -1096,7 +1247,12 @@ const NMDeviceWireless = new Lang.Class({
|
||||
_getStatus: function() {
|
||||
let ap = this._device.active_access_point;
|
||||
|
||||
if (ap)
|
||||
if (this._isHotSpotMaster())
|
||||
return _("Hotspot Active");
|
||||
else if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
|
||||
this._device.state < NetworkManager.DeviceState.ACTIVATED)
|
||||
return _("Connecting");
|
||||
else if (ap)
|
||||
return ssidToLabel(ap.get_ssid());
|
||||
else if (!this._client.wireless_hardware_enabled)
|
||||
return _("Hardware Disabled");
|
||||
@ -1115,20 +1271,52 @@ const NMDeviceWireless = new Lang.Class({
|
||||
return 'network-wireless-signal-none-symbolic';
|
||||
},
|
||||
|
||||
_canReachInternet: function() {
|
||||
if (this._client.primary_connection != this._device.active_connection)
|
||||
return true;
|
||||
|
||||
return this._client.connectivity == NetworkManager.ConnectivityState.FULL;
|
||||
},
|
||||
|
||||
_isHotSpotMaster: function() {
|
||||
if (!this._device.active_connection)
|
||||
return false;
|
||||
|
||||
let connection = this._settings.get_connection_by_path(this._device.active_connection.connection);
|
||||
if (!connection)
|
||||
return false;
|
||||
|
||||
let ip4config = connection.get_setting_ip4_config();
|
||||
if (!ip4config)
|
||||
return false;
|
||||
|
||||
return ip4config.get_method() == NetworkManager.SETTING_IP4_CONFIG_METHOD_SHARED;
|
||||
},
|
||||
|
||||
getIndicatorIcon: function() {
|
||||
if (this._device.state >= NetworkManager.DeviceState.PREPARE &&
|
||||
this._device.state < NetworkManager.DeviceState.ACTIVATED)
|
||||
if (this._device.state < NetworkManager.DeviceState.PREPARE)
|
||||
return 'network-wireless-disconnected-symbolic';
|
||||
if (this._device.state < NetworkManager.DeviceState.ACTIVATED)
|
||||
return 'network-wireless-acquiring-symbolic';
|
||||
|
||||
if (this._isHotSpotMaster())
|
||||
return 'network-wireless-hotspot-symbolic';
|
||||
|
||||
let ap = this._device.active_access_point;
|
||||
if (!ap) {
|
||||
if (this._device.mode != NM80211Mode.ADHOC)
|
||||
log('An active wireless connection, in infrastructure mode, involves no access point?');
|
||||
|
||||
return 'network-wireless-connected-symbolic';
|
||||
if (this._canReachInternet())
|
||||
return 'network-wireless-connected-symbolic';
|
||||
else
|
||||
return 'network-wireless-no-route-symbolic';
|
||||
}
|
||||
|
||||
return 'network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic';
|
||||
if (this._canReachInternet())
|
||||
return 'network-wireless-signal-' + signalToIcon(ap.strength) + '-symbolic';
|
||||
else
|
||||
return 'network-wireless-no-route-symbolic';
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(NMDeviceWireless.prototype);
|
||||
@ -1144,6 +1332,22 @@ const NMVPNConnectionItem = new Lang.Class({
|
||||
return this._activeConnection.vpn_state != NetworkManager.VPNConnectionState.DISCONNECTED;
|
||||
},
|
||||
|
||||
_buildUI: function() {
|
||||
this.labelItem = new PopupMenu.PopupMenuItem('');
|
||||
this.labelItem.connect('activate', Lang.bind(this, this._toggle));
|
||||
|
||||
this.radioItem = new PopupMenu.PopupSwitchMenuItem(this._connection.get_id(), false);
|
||||
this.radioItem.connect('toggled', Lang.bind(this, this._toggle));
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let isActive = this.isActive();
|
||||
this.labelItem.label.text = isActive ? _("Turn Off") : this._section.getConnectLabel();
|
||||
this.radioItem.setToggleState(isActive);
|
||||
this.radioItem.setStatus(this._getStatus());
|
||||
this.emit('icon-changed');
|
||||
},
|
||||
|
||||
_getStatus: function() {
|
||||
if (this._activeConnection == null)
|
||||
return null;
|
||||
@ -1213,19 +1417,53 @@ const NMVPNSection = new Lang.Class({
|
||||
|
||||
_init: function(client) {
|
||||
this.parent(client);
|
||||
|
||||
this._vpnSettings = new PopupMenu.PopupMenuItem('');
|
||||
this.item.menu.addMenuItem(this._vpnSettings);
|
||||
this._vpnSettings.connect('activate', Lang.bind(this, this._onSettingsActivate));
|
||||
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let nItems = this._connectionItems.size();
|
||||
let nItems = this._connectionItems.size;
|
||||
this.item.actor.visible = (nItems > 0);
|
||||
|
||||
if (nItems > 1)
|
||||
this._vpnSettings.label.text = _("Network Settings");
|
||||
else
|
||||
this._vpnSettings.label.text = _("VPN Settings");
|
||||
|
||||
this.parent();
|
||||
},
|
||||
|
||||
_onSettingsActivate: function() {
|
||||
let nItems = this._connectionItems.size;
|
||||
if (nItems > 1) {
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let app = appSys.lookup_app('gnome-network-panel.desktop');
|
||||
app.launch(0, -1);
|
||||
} else {
|
||||
let connection = this._connections[0];
|
||||
Util.spawnApp(['gnome-control-center', 'network', 'show-device',
|
||||
connection.get_path()]);
|
||||
}
|
||||
},
|
||||
|
||||
_getDescription: function() {
|
||||
return _("VPN");
|
||||
},
|
||||
|
||||
_getStatus: function() {
|
||||
let values = this._connectionItems.values();
|
||||
for (let item of values) {
|
||||
if (item.isActive())
|
||||
return item.getName();
|
||||
}
|
||||
|
||||
return _("Off");
|
||||
},
|
||||
|
||||
_getMenuIcon: function() {
|
||||
return this.getIndicatorIcon() || 'network-vpn-symbolic';
|
||||
},
|
||||
@ -1239,9 +1477,10 @@ const NMVPNSection = new Lang.Class({
|
||||
},
|
||||
|
||||
setActiveConnections: function(vpnConnections) {
|
||||
this._connectionItems.values().forEach(function(item) {
|
||||
let connections = this._connectionItems.values();
|
||||
for (let item of connections) {
|
||||
item.setActiveConnection(null);
|
||||
});
|
||||
}
|
||||
vpnConnections.forEach(Lang.bind(this, function(a) {
|
||||
let item = this._connectionItems.get(a._connection.get_uuid());
|
||||
item.setActiveConnection(a);
|
||||
@ -1254,8 +1493,7 @@ const NMVPNSection = new Lang.Class({
|
||||
|
||||
getIndicatorIcon: function() {
|
||||
let items = this._connectionItems.values();
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
let item = items[i];
|
||||
for (let item of items) {
|
||||
let icon = item.getIndicatorIcon();
|
||||
if (icon)
|
||||
return icon;
|
||||
@ -1277,6 +1515,7 @@ const NMApplet = new Lang.Class({
|
||||
|
||||
// Device types
|
||||
this._dtypes = { };
|
||||
this._dtypes[NetworkManager.DeviceType.ETHERNET] = NMDeviceWired;
|
||||
this._dtypes[NetworkManager.DeviceType.WIFI] = NMDeviceWireless;
|
||||
this._dtypes[NetworkManager.DeviceType.MODEM] = NMDeviceModem;
|
||||
this._dtypes[NetworkManager.DeviceType.BT] = NMDeviceBluetooth;
|
||||
@ -1284,6 +1523,7 @@ const NMApplet = new Lang.Class({
|
||||
|
||||
// Connection types
|
||||
this._ctypes = { };
|
||||
this._ctypes[NetworkManager.SETTING_WIRED_SETTING_NAME] = NMConnectionCategory.WIRED;
|
||||
this._ctypes[NetworkManager.SETTING_WIRELESS_SETTING_NAME] = NMConnectionCategory.WIRELESS;
|
||||
this._ctypes[NetworkManager.SETTING_BLUETOOTH_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
this._ctypes[NetworkManager.SETTING_CDMA_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||
@ -1306,6 +1546,15 @@ const NMApplet = new Lang.Class({
|
||||
this._tryLateInit();
|
||||
},
|
||||
|
||||
_createDeviceCategory: function() {
|
||||
let category = {
|
||||
section: new PopupMenu.PopupMenuSection(),
|
||||
devices: [ ],
|
||||
};
|
||||
this.menu.addMenuItem(category.section);
|
||||
return category;
|
||||
},
|
||||
|
||||
_tryLateInit: function() {
|
||||
if (!this._client || !this._settings)
|
||||
return;
|
||||
@ -1321,17 +1570,9 @@ const NMApplet = new Lang.Class({
|
||||
this._nmDevices = [];
|
||||
this._devices = { };
|
||||
|
||||
this._devices.wireless = {
|
||||
section: new PopupMenu.PopupMenuSection(),
|
||||
devices: [ ],
|
||||
};
|
||||
this.menu.addMenuItem(this._devices.wireless.section);
|
||||
|
||||
this._devices.wwan = {
|
||||
section: new PopupMenu.PopupMenuSection(),
|
||||
devices: [ ],
|
||||
};
|
||||
this.menu.addMenuItem(this._devices.wwan.section);
|
||||
this._devices.wired = this._createDeviceCategory();
|
||||
this._devices.wireless = this._createDeviceCategory();
|
||||
this._devices.wwan = this._createDeviceCategory();
|
||||
|
||||
this._vpnSection = new NMVPNSection(this._client);
|
||||
this._vpnSection.connect('activation-failed', Lang.bind(this, this._onActivationFailed));
|
||||
@ -1601,7 +1842,6 @@ const NMApplet = new Lang.Class({
|
||||
let connectionSettings = connection.get_setting_by_name(NetworkManager.SETTING_CONNECTION_SETTING_NAME);
|
||||
connection._type = connectionSettings.type;
|
||||
connection._section = this._ctypes[connection._type] || NMConnectionCategory.INVALID;
|
||||
connection._timestamp = connectionSettings.timestamp;
|
||||
|
||||
let section = connection._section;
|
||||
|
||||
@ -1626,8 +1866,7 @@ const NMApplet = new Lang.Class({
|
||||
|
||||
_updateIcon: function() {
|
||||
if (!this._client.networking_enabled || !this._mainConnection) {
|
||||
this._primaryIndicator.icon_name = 'network-offline-symbolic';
|
||||
this._primaryIndicator.visible = true;
|
||||
this._primaryIndicator.visible = false;
|
||||
} else {
|
||||
let dev = this._mainConnection._primaryDevice;
|
||||
this._primaryIndicator.visible = (dev != null);
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
@ -12,11 +13,55 @@ const OBJECT_PATH = '/org/gnome/SettingsDaemon/Rfkill';
|
||||
const RfkillManagerInterface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Rfkill"> \
|
||||
<property name="AirplaneMode" type="b" access="readwrite" /> \
|
||||
<property name="HardwareAirplaneMode" type="b" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface);
|
||||
|
||||
const RfkillManager = new Lang.Class({
|
||||
Name: 'RfkillManager',
|
||||
|
||||
_init: function() {
|
||||
this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._proxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._changed));
|
||||
this._changed();
|
||||
}));
|
||||
},
|
||||
|
||||
get airplaneMode() {
|
||||
return this._proxy.AirplaneMode;
|
||||
},
|
||||
|
||||
set airplaneMode(v) {
|
||||
this._proxy.AirplaneMode = v;
|
||||
},
|
||||
|
||||
get hwAirplaneMode() {
|
||||
return this._proxy.HardwareAirplaneMode;
|
||||
},
|
||||
|
||||
_changed: function() {
|
||||
this.emit('airplane-mode-changed');
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(RfkillManager.prototype);
|
||||
|
||||
var _manager;
|
||||
function getRfkillManager() {
|
||||
if (_manager != null)
|
||||
return _manager;
|
||||
|
||||
_manager = new RfkillManager();
|
||||
return _manager;
|
||||
}
|
||||
|
||||
const Indicator = new Lang.Class({
|
||||
Name: 'RfkillIndicator',
|
||||
Extends: PanelMenu.SystemIndicator,
|
||||
@ -24,16 +69,8 @@ const Indicator = new Lang.Class({
|
||||
_init: function() {
|
||||
this.parent();
|
||||
|
||||
this._proxy = new RfkillManagerProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._proxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
this._sync();
|
||||
}));
|
||||
this._manager = getRfkillManager();
|
||||
this._manager.connect('airplane-mode-changed', Lang.bind(this, this._sync));
|
||||
|
||||
this._indicator = this._addIndicator();
|
||||
this._indicator.icon_name = 'airplane-mode-symbolic';
|
||||
@ -45,7 +82,7 @@ const Indicator = new Lang.Class({
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Airplane Mode"), true);
|
||||
this._item.icon.icon_name = 'airplane-mode-symbolic';
|
||||
this._item.status.text = _("On");
|
||||
this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
|
||||
this._offItem = this._item.menu.addAction(_("Turn Off"), Lang.bind(this, function() {
|
||||
this._proxy.AirplaneMode = false;
|
||||
}));
|
||||
this._item.menu.addSettingsAction(_("Network Settings"), 'gnome-network-panel.desktop');
|
||||
@ -53,8 +90,18 @@ const Indicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let airplaneMode = this._proxy.AirplaneMode;
|
||||
let airplaneMode = this._manager.airplaneMode;
|
||||
let hwAirplaneMode = this._manager.hwAirplaneMode;
|
||||
let changed = (airplaneMode != this._indicator.visible) ||
|
||||
(hwAirplaneMode != this._offItem.actor.visible);
|
||||
|
||||
this._indicator.visible = airplaneMode;
|
||||
this._item.actor.visible = airplaneMode;
|
||||
this._offItem.setSensitive(!hwAirplaneMode);
|
||||
|
||||
if (hwAirplaneMode)
|
||||
this._offItem.label.text = _("Use hardware switch to turn off");
|
||||
else
|
||||
this._offItem.label.text = _("Turn Off");
|
||||
},
|
||||
});
|
||||
|
@ -452,10 +452,9 @@ const SwitcherList = new Lang.Class({
|
||||
time: POPUP_SCROLL_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function () {
|
||||
if (this._highlighted == 0) {
|
||||
if (this._highlighted == 0)
|
||||
this._scrollableLeft = false;
|
||||
this.actor.queue_relayout();
|
||||
}
|
||||
this.actor.queue_relayout();
|
||||
})
|
||||
});
|
||||
},
|
||||
@ -477,10 +476,9 @@ const SwitcherList = new Lang.Class({
|
||||
time: POPUP_SCROLL_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function () {
|
||||
if (this._highlighted == this._items.length - 1) {
|
||||
if (this._highlighted == this._items.length - 1)
|
||||
this._scrollableRight = false;
|
||||
this.actor.queue_relayout();
|
||||
}
|
||||
this.actor.queue_relayout();
|
||||
})
|
||||
});
|
||||
},
|
||||
@ -515,7 +513,7 @@ const SwitcherList = new Lang.Class({
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
let [maxChildMin, maxChildNat] = this._maxChildWidth(forHeight);
|
||||
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
let totalSpacing = Math.max(this._list.spacing * (this._items.length - 1), 0);
|
||||
alloc.min_size = this._items.length * maxChildMin + totalSpacing;
|
||||
alloc.natural_size = alloc.min_size;
|
||||
this._minSize = alloc.min_size;
|
||||
@ -545,7 +543,7 @@ const SwitcherList = new Lang.Class({
|
||||
let childHeight = box.y2 - box.y1;
|
||||
|
||||
let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight);
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
let totalSpacing = Math.max(this._list.spacing * (this._items.length - 1), 0);
|
||||
|
||||
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing) / this._items.length);
|
||||
|
||||
|
@ -187,7 +187,6 @@ const ViewSelector = new Lang.Class({
|
||||
params = Params.parse(params, { a11yFocus: null });
|
||||
|
||||
let page = new St.Bin({ child: actor,
|
||||
visible: false,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START,
|
||||
x_fill: true,
|
||||
@ -212,7 +211,7 @@ const ViewSelector = new Lang.Class({
|
||||
oldPage.hide();
|
||||
|
||||
this.emit('page-empty');
|
||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
|
||||
this._activePage.show();
|
||||
Tweener.addTween(this._activePage,
|
||||
{ opacity: 255,
|
||||
@ -283,6 +282,14 @@ const ViewSelector = new Lang.Class({
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (this._shouldTriggerSearch(symbol)) {
|
||||
this.startSearch(event);
|
||||
} else if (!this._searchActive) {
|
||||
if (symbol == Clutter.Tab || symbol == Clutter.Down) {
|
||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
return true;
|
||||
} else if (symbol == Clutter.ISO_Left_Tab) {
|
||||
this._activePage.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
@ -475,13 +482,6 @@ const ViewSelector = new Lang.Class({
|
||||
return ViewPage.SEARCH;
|
||||
},
|
||||
|
||||
setActivePage: function(page) {
|
||||
if (page == ViewPage.WINDOWS)
|
||||
this._showPage(this._workspacesPage);
|
||||
else
|
||||
this._showPage(this._appsPage);
|
||||
},
|
||||
|
||||
fadeIn: function() {
|
||||
let actor = this._activePage;
|
||||
Tweener.addTween(actor, { opacity: 255,
|
||||
|
@ -16,7 +16,7 @@ const WindowAttentionHandler = new Lang.Class({
|
||||
|
||||
_getTitleAndBanner: function(app, window) {
|
||||
let title = app.get_name();
|
||||
let banner = _("'%s' is ready").format(window.get_title());
|
||||
let banner = _("“%s” is ready").format(window.get_title());
|
||||
return [title, banner]
|
||||
},
|
||||
|
||||
|
@ -191,6 +191,7 @@ const WorkspaceTracker = new Lang.Class({
|
||||
tracker.connect('startup-sequence-changed', Lang.bind(this, this._queueCheckWorkspaces));
|
||||
|
||||
global.screen.connect('notify::n-workspaces', Lang.bind(this, this._nWorkspacesChanged));
|
||||
global.window_manager.connect('switch-workspace', Lang.bind(this, this._queueCheckWorkspaces));
|
||||
|
||||
global.screen.connect('window-entered-monitor', Lang.bind(this, this._windowEnteredMonitor));
|
||||
global.screen.connect('window-left-monitor', Lang.bind(this, this._windowLeftMonitor));
|
||||
@ -249,13 +250,7 @@ const WorkspaceTracker = new Lang.Class({
|
||||
}
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let removingCurrentWorkspace = (emptyWorkspaces[activeWorkspaceIndex] &&
|
||||
activeWorkspaceIndex < emptyWorkspaces.length - 1);
|
||||
|
||||
if (removingCurrentWorkspace) {
|
||||
// "Merge" the empty workspace we are removing with the one at the end
|
||||
this._wm.blockAnimations();
|
||||
}
|
||||
emptyWorkspaces[activeWorkspaceIndex] = false;
|
||||
|
||||
// Delete other empty workspaces; do it from the end to avoid index changes
|
||||
for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
|
||||
@ -263,11 +258,6 @@ const WorkspaceTracker = new Lang.Class({
|
||||
global.screen.remove_workspace(this._workspaces[i], global.get_current_time());
|
||||
}
|
||||
|
||||
if (removingCurrentWorkspace) {
|
||||
global.screen.get_workspace_by_index(global.screen.n_workspaces - 1).activate(global.get_current_time());
|
||||
this._wm.unblockAnimations();
|
||||
}
|
||||
|
||||
this._checkWorkspacesId = 0;
|
||||
return false;
|
||||
},
|
||||
@ -368,6 +358,93 @@ const WorkspaceTracker = new Lang.Class({
|
||||
}
|
||||
});
|
||||
|
||||
const TilePreview = new Lang.Class({
|
||||
Name: 'TilePreview',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.Widget();
|
||||
global.window_group.add_actor(this.actor);
|
||||
|
||||
this._reset();
|
||||
this._showing = false;
|
||||
},
|
||||
|
||||
show: function(window, tileRect, monitorIndex) {
|
||||
let windowActor = window.get_compositor_private();
|
||||
if (!windowActor)
|
||||
return;
|
||||
|
||||
global.window_group.set_child_below_sibling(this.actor, windowActor);
|
||||
|
||||
if (this._rect && this._rect.equal(tileRect))
|
||||
return;
|
||||
|
||||
let changeMonitor = (this._monitorIndex == -1 ||
|
||||
this._monitorIndex != monitorIndex);
|
||||
|
||||
this._monitorIndex = monitorIndex;
|
||||
this._rect = tileRect;
|
||||
|
||||
let monitor = Main.layoutManager.monitors[monitorIndex];
|
||||
|
||||
this._updateStyle(monitor);
|
||||
|
||||
if (!this._showing || changeMonitor) {
|
||||
let monitorRect = new Meta.Rectangle({ x: monitor.x,
|
||||
y: monitor.y,
|
||||
width: monitor.width,
|
||||
height: monitor.height });
|
||||
let [, rect] = window.get_outer_rect().intersect(monitorRect);
|
||||
this.actor.set_size(rect.width, rect.height);
|
||||
this.actor.set_position(rect.x, rect.y);
|
||||
this.actor.opacity = 0;
|
||||
}
|
||||
|
||||
this._showing = true;
|
||||
this.actor.show();
|
||||
Tweener.addTween(this.actor,
|
||||
{ x: tileRect.x,
|
||||
y: tileRect.y,
|
||||
width: tileRect.width,
|
||||
height: tileRect.height,
|
||||
opacity: 255,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (!this._showing)
|
||||
return;
|
||||
|
||||
this._showing = false;
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, this._reset)
|
||||
});
|
||||
},
|
||||
|
||||
_reset: function() {
|
||||
this.actor.hide();
|
||||
this._rect = null;
|
||||
this._monitorIndex = -1;
|
||||
},
|
||||
|
||||
_updateStyle: function(monitor) {
|
||||
let styles = ['tile-preview'];
|
||||
if (this._monitorIndex == Main.layoutManager.primaryIndex)
|
||||
styles.push('on-primary');
|
||||
if (this._rect.x == monitor.x)
|
||||
styles.push('tile-preview-left');
|
||||
if (this._rect.x + this._rect.width == monitor.x + monitor.width)
|
||||
styles.push('tile-preview-right');
|
||||
|
||||
this.actor.style_class = styles.join(' ');
|
||||
}
|
||||
});
|
||||
|
||||
const WindowManager = new Lang.Class({
|
||||
Name: 'WindowManager',
|
||||
|
||||
@ -398,6 +475,8 @@ const WindowManager = new Lang.Class({
|
||||
}));
|
||||
|
||||
this._shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
|
||||
this._shellwm.connect('show-tile-preview', Lang.bind(this, this._showTilePreview));
|
||||
this._shellwm.connect('hide-tile-preview', Lang.bind(this, this._hideTilePreview));
|
||||
this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
|
||||
this._shellwm.connect('maximize', Lang.bind(this, this._maximizeWindow));
|
||||
this._shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
|
||||
@ -407,6 +486,8 @@ const WindowManager = new Lang.Class({
|
||||
this._shellwm.connect('confirm-display-change', Lang.bind(this, this._confirmDisplayChange));
|
||||
|
||||
this._workspaceSwitcherPopup = null;
|
||||
this._tilePreview = null;
|
||||
|
||||
this.setCustomKeybindingHandler('switch-to-workspace-left',
|
||||
Shell.KeyBindingMode.NORMAL |
|
||||
Shell.KeyBindingMode.OVERVIEW,
|
||||
@ -556,6 +637,12 @@ const WindowManager = new Lang.Class({
|
||||
Shell.KeyBindingMode.LOGIN_SCREEN,
|
||||
Lang.bind(this, this._startA11ySwitcher));
|
||||
|
||||
this.addKeybinding('pause-resume-tweens',
|
||||
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
Shell.KeyBindingMode.ALL,
|
||||
Lang.bind(this, this._toggleTweens));
|
||||
|
||||
this.addKeybinding('open-application-menu',
|
||||
new Gio.Settings({ schema: SHELL_KEYBINDINGS_SCHEMA }),
|
||||
Meta.KeyBindingFlags.NONE,
|
||||
@ -743,15 +830,13 @@ const WindowManager = new Lang.Class({
|
||||
if (shouldDim && !window._dimmed) {
|
||||
window._dimmed = true;
|
||||
this._dimmedWindows.push(window);
|
||||
if (!Main.overview.visible)
|
||||
this._dimWindow(window);
|
||||
this._dimWindow(window);
|
||||
} else if (!shouldDim && window._dimmed) {
|
||||
window._dimmed = false;
|
||||
this._dimmedWindows = this._dimmedWindows.filter(function(win) {
|
||||
return win != window;
|
||||
});
|
||||
if (!Main.overview.visible)
|
||||
this._undimWindow(window);
|
||||
this._undimWindow(window);
|
||||
}
|
||||
},
|
||||
|
||||
@ -1052,6 +1137,18 @@ const WindowManager = new Lang.Class({
|
||||
shellwm.completed_switch_workspace();
|
||||
},
|
||||
|
||||
_showTilePreview: function(shellwm, window, tileRect, monitorIndex) {
|
||||
if (!this._tilePreview)
|
||||
this._tilePreview = new TilePreview();
|
||||
this._tilePreview.show(window, tileRect, monitorIndex);
|
||||
},
|
||||
|
||||
_hideTilePreview: function(shellwm) {
|
||||
if (!this._tilePreview)
|
||||
return;
|
||||
this._tilePreview.hide();
|
||||
},
|
||||
|
||||
_startAppSwitcher : function(display, screen, window, binding) {
|
||||
/* prevent a corner case where both popups show up at once */
|
||||
if (this._workspaceSwitcherPopup != null)
|
||||
@ -1088,6 +1185,15 @@ const WindowManager = new Lang.Class({
|
||||
Main.panel.toggleAppMenu();
|
||||
},
|
||||
|
||||
_toggleTweens: function() {
|
||||
this._tweensPaused = !this._tweensPaused;
|
||||
const OrigTweener = imports.tweener.tweener;
|
||||
if (this._tweensPaused)
|
||||
OrigTweener.pauseAllTweens();
|
||||
else
|
||||
OrigTweener.resumeAllTweens();
|
||||
},
|
||||
|
||||
_showWorkspaceSwitcher : function(display, screen, window, binding) {
|
||||
if (!Main.sessionMode.hasWorkspaces)
|
||||
return;
|
||||
|
@ -14,6 +14,7 @@ const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
|
||||
const WINDOW_DND_SIZE = 256;
|
||||
|
||||
@ -35,6 +36,68 @@ function _interpolate(start, end, step) {
|
||||
return start + (end - start) * step;
|
||||
}
|
||||
|
||||
const WindowCloneLayout = new Lang.Class({
|
||||
Name: 'WindowCloneLayout',
|
||||
Extends: Clutter.LayoutManager,
|
||||
|
||||
_init: function(boundingBox) {
|
||||
this.parent();
|
||||
|
||||
this._boundingBox = boundingBox;
|
||||
},
|
||||
|
||||
get boundingBox() {
|
||||
return this._boundingBox;
|
||||
},
|
||||
|
||||
set boundingBox(b) {
|
||||
this._boundingBox = b;
|
||||
this.layout_changed();
|
||||
},
|
||||
|
||||
_makeBoxForWindow: function(window) {
|
||||
// We need to adjust the position of the actor because of the
|
||||
// consequences of invisible borders -- in reality, the texture
|
||||
// has an extra set of "padding" around it that we need to trim
|
||||
// down.
|
||||
|
||||
// The outer rect (from which we compute the bounding box)
|
||||
// paradoxically is the smaller rectangle, containing the positions
|
||||
// of the visible frame. The input rect contains everything,
|
||||
// including the invisible border padding.
|
||||
let inputRect = window.get_input_rect();
|
||||
|
||||
let box = new Clutter.ActorBox();
|
||||
|
||||
box.set_origin(inputRect.x - this._boundingBox.x,
|
||||
inputRect.y - this._boundingBox.y);
|
||||
box.set_size(inputRect.width, inputRect.height);
|
||||
|
||||
return box;
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(container, forWidth) {
|
||||
return [this._boundingBox.height, this._boundingBox.height];
|
||||
},
|
||||
|
||||
vfunc_get_preferred_width: function(container, forHeight) {
|
||||
return [this._boundingBox.width, this._boundingBox.width];
|
||||
},
|
||||
|
||||
vfunc_allocate: function(container, box, flags) {
|
||||
let clone = container.get_children().forEach(function (child) {
|
||||
let realWindow;
|
||||
if (child == container._delegate._windowClone)
|
||||
realWindow = container._delegate.realWindow;
|
||||
else
|
||||
realWindow = child.source;
|
||||
|
||||
child.allocate(this._makeBoxForWindow(realWindow.meta_window),
|
||||
flags);
|
||||
}, this);
|
||||
},
|
||||
});
|
||||
|
||||
const WindowClone = new Lang.Class({
|
||||
Name: 'WindowClone',
|
||||
|
||||
@ -44,10 +107,7 @@ const WindowClone = new Lang.Class({
|
||||
this.metaWindow._delegate = this;
|
||||
this._workspace = workspace;
|
||||
|
||||
let [borderX, borderY] = this._getInvisibleBorderPadding();
|
||||
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture(),
|
||||
x: -borderX,
|
||||
y: -borderY });
|
||||
this._windowClone = new Clutter.Clone({ source: realWindow.get_texture() });
|
||||
// We expect this.actor to be used for all interaction rather than
|
||||
// this._windowClone; as the former is reactive and the latter
|
||||
// is not, this just works for most cases. However, for DND all
|
||||
@ -55,21 +115,13 @@ const WindowClone = new Lang.Class({
|
||||
// To avoid this, we hide it from pick.
|
||||
Shell.util_set_hidden_from_pick(this._windowClone, true);
|
||||
|
||||
this.origX = realWindow.x + borderX;
|
||||
this.origY = realWindow.y + borderY;
|
||||
|
||||
let outerRect = realWindow.meta_window.get_outer_rect();
|
||||
|
||||
// The MetaShapedTexture that we clone has a size that includes
|
||||
// the invisible border; this is inconvenient; rather than trying
|
||||
// to compensate all over the place we insert a ClutterActor into
|
||||
// the hierarchy that is sized to only the visible portion.
|
||||
this.actor = new St.Widget({ reactive: true,
|
||||
can_focus: true,
|
||||
x: this.origX,
|
||||
y: this.origY,
|
||||
width: outerRect.width,
|
||||
height: outerRect.height });
|
||||
layout_manager: new WindowCloneLayout() });
|
||||
|
||||
this.actor.add_child(this._windowClone);
|
||||
|
||||
@ -79,10 +131,19 @@ const WindowClone = new Lang.Class({
|
||||
this._dragSlot = [0, 0, 0, 0];
|
||||
this._stackAbove = null;
|
||||
|
||||
this._sizeChangedId = this.realWindow.connect('size-changed',
|
||||
this._windowClone._updateId = this.metaWindow.connect('size-changed',
|
||||
Lang.bind(this, this._onRealWindowSizeChanged));
|
||||
this._realWindowDestroyId = this.realWindow.connect('destroy',
|
||||
Lang.bind(this, this._disconnectRealWindowSignals));
|
||||
this._windowClone._destroyId = this.realWindow.connect('destroy', Lang.bind(this, function() {
|
||||
// First destroy the clone and then destroy everything
|
||||
// This will ensure that we never see it in the _disconnectSignals loop
|
||||
this._windowClone.destroy();
|
||||
this.destroy();
|
||||
}));
|
||||
|
||||
this._updateAttachedDialogs();
|
||||
this._computeBoundingBox();
|
||||
this.actor.x = this._boundingBox.x;
|
||||
this.actor.y = this._boundingBox.y;
|
||||
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
@ -116,6 +177,83 @@ const WindowClone = new Lang.Class({
|
||||
return this._slot;
|
||||
},
|
||||
|
||||
deleteAll: function() {
|
||||
// Delete all windows, starting from the bottom-most (most-modal) one
|
||||
|
||||
let windows = this.actor.get_children();
|
||||
for (let i = windows.length - 1; i >= 1; i--) {
|
||||
let realWindow = windows[i].source;
|
||||
let metaWindow = realWindow.meta_window;
|
||||
|
||||
metaWindow.delete(global.get_current_time());
|
||||
}
|
||||
|
||||
this.metaWindow.delete(global.get_current_time());
|
||||
},
|
||||
|
||||
addAttachedDialog: function(win) {
|
||||
this._doAddAttachedDialog(win, win.get_compositor_private());
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
},
|
||||
|
||||
_doAddAttachedDialog: function(metaWin, realWin) {
|
||||
let clone = new Clutter.Clone({ source: realWin });
|
||||
clone._updateId = metaWin.connect('size-changed', Lang.bind(this, function() {
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
}));
|
||||
clone._destroyId = realWin.connect('destroy', Lang.bind(this, function() {
|
||||
clone.destroy();
|
||||
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
}));
|
||||
this.actor.add_child(clone);
|
||||
},
|
||||
|
||||
_updateAttachedDialogs: function() {
|
||||
let iter = Lang.bind(this, function(win) {
|
||||
let actor = win.get_compositor_private();
|
||||
|
||||
if (!actor)
|
||||
return false;
|
||||
if (!win.is_attached_dialog())
|
||||
return false;
|
||||
|
||||
this._doAddAttachedDialog(win, actor);
|
||||
win.foreach_transient(iter);
|
||||
return true;
|
||||
});
|
||||
this.metaWindow.foreach_transient(iter);
|
||||
},
|
||||
|
||||
get boundingBox() {
|
||||
return this._boundingBox;
|
||||
},
|
||||
|
||||
getOriginalPosition: function() {
|
||||
return [this._boundingBox.x, this._boundingBox.y];
|
||||
},
|
||||
|
||||
_computeBoundingBox: function() {
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
|
||||
this.actor.get_children().forEach(function (child) {
|
||||
let realWindow;
|
||||
if (child == this._windowClone)
|
||||
realWindow = this.realWindow;
|
||||
else
|
||||
realWindow = child.source;
|
||||
|
||||
let metaWindow = realWindow.meta_window;
|
||||
rect = rect.union(metaWindow.get_outer_rect());
|
||||
}, this);
|
||||
|
||||
this._boundingBox = rect;
|
||||
this.actor.layout_manager.boundingBox = rect;
|
||||
},
|
||||
|
||||
// Find the actor just below us, respecting reparenting done
|
||||
// by DND code
|
||||
getActualStackAbove: function() {
|
||||
@ -149,44 +287,26 @@ const WindowClone = new Lang.Class({
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_disconnectRealWindowSignals: function() {
|
||||
if (this._sizeChangedId > 0)
|
||||
this.realWindow.disconnect(this._sizeChangedId);
|
||||
this._sizeChangedId = 0;
|
||||
_disconnectSignals: function() {
|
||||
this.actor.get_children().forEach(Lang.bind(this, function (child) {
|
||||
let realWindow;
|
||||
if (child == this._windowClone)
|
||||
realWindow = this.realWindow;
|
||||
else
|
||||
realWindow = child.source;
|
||||
|
||||
if (this._realWindowDestroyId > 0)
|
||||
this.realWindow.disconnect(this._realWindowDestroyId);
|
||||
this._realWindowDestroyId = 0;
|
||||
},
|
||||
|
||||
_getInvisibleBorderPadding: function() {
|
||||
// We need to adjust the position of the actor because of the
|
||||
// consequences of invisible borders -- in reality, the texture
|
||||
// has an extra set of "padding" around it that we need to trim
|
||||
// down.
|
||||
|
||||
// The outer rect paradoxically is the smaller rectangle,
|
||||
// containing the positions of the visible frame. The input
|
||||
// rect contains everything, including the invisible border
|
||||
// padding.
|
||||
let outerRect = this.metaWindow.get_outer_rect();
|
||||
let inputRect = this.metaWindow.get_input_rect();
|
||||
let [borderX, borderY] = [outerRect.x - inputRect.x,
|
||||
outerRect.y - inputRect.y];
|
||||
|
||||
return [borderX, borderY];
|
||||
realWindow.meta_window.disconnect(child._updateId);
|
||||
realWindow.disconnect(child._destroyId);
|
||||
}));
|
||||
},
|
||||
|
||||
_onRealWindowSizeChanged: function() {
|
||||
let [borderX, borderY] = this._getInvisibleBorderPadding();
|
||||
let outerRect = this.metaWindow.get_outer_rect();
|
||||
this.actor.set_size(outerRect.width, outerRect.height);
|
||||
this._windowClone.set_position(-borderX, -borderY);
|
||||
this._computeBoundingBox();
|
||||
this.emit('size-changed');
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._disconnectRealWindowSignals();
|
||||
this._disconnectSignals();
|
||||
|
||||
this.metaWindow._delegate = null;
|
||||
this.actor._delegate = null;
|
||||
@ -454,7 +574,7 @@ const WindowOverlay = new Lang.Class({
|
||||
Lang.bind(this,
|
||||
this._onWindowAdded));
|
||||
|
||||
metaWindow.delete(global.get_current_time());
|
||||
this._windowClone.deleteAll();
|
||||
},
|
||||
|
||||
_windowCanClose: function() {
|
||||
@ -1321,9 +1441,29 @@ const Workspace = new Lang.Class({
|
||||
if (this._lookupIndex (metaWin) != -1)
|
||||
return;
|
||||
|
||||
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
||||
if (!this._isMyWindow(win))
|
||||
return;
|
||||
|
||||
if (!this._isOverviewWindow(win)) {
|
||||
if (metaWin.is_attached_dialog()) {
|
||||
let parent = metaWin.get_transient_for();
|
||||
while (parent.is_attached_dialog())
|
||||
parent = metaWin.get_transient_for();
|
||||
|
||||
let idx = this._lookupIndex (parent);
|
||||
if (idx < 0) {
|
||||
// parent was not created yet, it will take care
|
||||
// of the dialog when created
|
||||
return;
|
||||
}
|
||||
|
||||
let clone = this._windows[idx];
|
||||
clone.addAttachedDialog(metaWin);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let [clone, overlay] = this._addWindowClone(win, false);
|
||||
|
||||
if (win._overviewHint) {
|
||||
@ -1411,9 +1551,11 @@ const Workspace = new Lang.Class({
|
||||
overlay.hide();
|
||||
|
||||
if (clone.metaWindow.showing_on_its_workspace()) {
|
||||
let [origX, origY] = clone.getOriginalPosition();
|
||||
|
||||
Tweener.addTween(clone.actor,
|
||||
{ x: clone.origX,
|
||||
y: clone.origY,
|
||||
{ x: origX,
|
||||
y: origY,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
@ -1477,8 +1619,7 @@ const Workspace = new Lang.Class({
|
||||
|
||||
// Tests if @win should be shown in the Overview
|
||||
_isOverviewWindow : function (win) {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
return tracker.is_window_interesting(win.get_meta_window());
|
||||
return !win.get_meta_window().skip_taskbar;
|
||||
},
|
||||
|
||||
// Create a clone of a (non-desktop) window and add it to the window list
|
||||
|
@ -14,6 +14,7 @@ const Background = imports.ui.background;
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
const Workspace = imports.ui.workspace;
|
||||
const WorkspacesView = imports.ui.workspacesView;
|
||||
|
||||
@ -32,20 +33,49 @@ const WORKSPACE_KEEP_ALIVE_TIME = 100;
|
||||
|
||||
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
|
||||
|
||||
/* A layout manager that requests size only for primary_actor, but then allocates
|
||||
all using a fixed layout */
|
||||
const PrimaryActorLayout = new Lang.Class({
|
||||
Name: 'PrimaryActorLayout',
|
||||
Extends: Clutter.FixedLayout,
|
||||
|
||||
_init: function(primaryActor) {
|
||||
this.parent();
|
||||
|
||||
this.primaryActor = primaryActor;
|
||||
},
|
||||
|
||||
vfunc_get_preferred_width: function(forHeight) {
|
||||
return this.primaryActor.get_preferred_width(forHeight);
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(forWidth) {
|
||||
return this.primaryActor.get_preferred_height(forWidth);
|
||||
},
|
||||
});
|
||||
|
||||
const WindowClone = new Lang.Class({
|
||||
Name: 'WindowClone',
|
||||
|
||||
_init : function(realWindow) {
|
||||
this.actor = new Clutter.Clone({ source: realWindow.get_texture(),
|
||||
this.clone = new Clutter.Clone({ source: realWindow });
|
||||
|
||||
/* Can't use a Shell.GenericContainer because of DND and reparenting... */
|
||||
this.actor = new Clutter.Actor({ layout_manager: new PrimaryActorLayout(this.clone),
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.add_child(this.clone);
|
||||
this.realWindow = realWindow;
|
||||
this.metaWindow = realWindow.meta_window;
|
||||
|
||||
this._positionChangedId = this.realWindow.connect('position-changed',
|
||||
Lang.bind(this, this._onPositionChanged));
|
||||
this._realWindowDestroyedId = this.realWindow.connect('destroy',
|
||||
Lang.bind(this, this._disconnectRealWindowSignals));
|
||||
this.clone._updateId = this.metaWindow.connect('position-changed',
|
||||
Lang.bind(this, this._onPositionChanged));
|
||||
this.clone._destroyId = this.realWindow.connect('destroy', Lang.bind(this, function() {
|
||||
// First destroy the clone and then destroy everything
|
||||
// This will ensure that we never see it in the _disconnectSignals loop
|
||||
this.clone.destroy();
|
||||
this.destroy();
|
||||
}));
|
||||
this._onPositionChanged();
|
||||
|
||||
this.actor.connect('button-release-event',
|
||||
@ -61,6 +91,21 @@ const WindowClone = new Lang.Class({
|
||||
this._draggable.connect('drag-cancelled', Lang.bind(this, this._onDragCancelled));
|
||||
this._draggable.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||
this.inDrag = false;
|
||||
|
||||
let iter = Lang.bind(this, function(win) {
|
||||
let actor = win.get_compositor_private();
|
||||
|
||||
if (!actor)
|
||||
return false;
|
||||
if (!win.is_attached_dialog())
|
||||
return false;
|
||||
|
||||
this._doAddAttachedDialog(win, actor);
|
||||
win.foreach_transient(iter);
|
||||
|
||||
return true;
|
||||
});
|
||||
this.metaWindow.foreach_transient(iter);
|
||||
},
|
||||
|
||||
// Find the actor just below us, respecting reparenting done
|
||||
@ -98,25 +143,46 @@ const WindowClone = new Lang.Class({
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
addAttachedDialog: function(win) {
|
||||
this._doAddAttachedDialog(win, win.get_compositor_private());
|
||||
},
|
||||
|
||||
_doAddAttachedDialog: function(metaDialog, realDialog) {
|
||||
let clone = new Clutter.Clone({ source: realDialog });
|
||||
this._updateDialogPosition(realDialog, clone);
|
||||
|
||||
clone._updateId = metaDialog.connect('position-changed',
|
||||
Lang.bind(this, this._updateDialogPosition, clone));
|
||||
clone._destroyId = realDialog.connect('destroy', Lang.bind(this, function() {
|
||||
clone.destroy();
|
||||
}));
|
||||
this.actor.add_child(clone);
|
||||
},
|
||||
|
||||
_updateDialogPosition: function(realDialog, cloneDialog) {
|
||||
let metaDialog = realDialog.meta_window;
|
||||
let dialogRect = metaDialog.get_outer_rect();
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
|
||||
cloneDialog.set_position(dialogRect.x - rect.x, dialogRect.y - rect.y);
|
||||
},
|
||||
|
||||
_onPositionChanged: function() {
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
this.actor.set_position(this.realWindow.x, this.realWindow.y);
|
||||
},
|
||||
|
||||
_disconnectRealWindowSignals: function() {
|
||||
if (this._positionChangedId != 0) {
|
||||
this.realWindow.disconnect(this._positionChangedId);
|
||||
this._positionChangedId = 0;
|
||||
}
|
||||
_disconnectSignals: function() {
|
||||
this.actor.get_children().forEach(function(child) {
|
||||
let realWindow = child.source;
|
||||
|
||||
if (this._realWindowDestroyedId != 0) {
|
||||
this.realWindow.disconnect(this._realWindowDestroyedId);
|
||||
this._realWindowDestroyedId = 0;
|
||||
}
|
||||
realWindow.meta_window.disconnect(child._updateId);
|
||||
realWindow.disconnect(child._destroyId);
|
||||
});
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._disconnectRealWindowSignals();
|
||||
this._disconnectSignals();
|
||||
|
||||
this.actor._delegate = null;
|
||||
|
||||
@ -344,10 +410,26 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
if (this._lookupIndex (metaWin) != -1)
|
||||
return;
|
||||
|
||||
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
||||
if (!this._isMyWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._addWindowClone(win);
|
||||
if (this._isOverviewWindow(win)) {
|
||||
this._addWindowClone(win);
|
||||
} else if (metaWin.is_attached_dialog()) {
|
||||
let parent = metaWin.get_transient_for();
|
||||
while (parent.is_attached_dialog())
|
||||
parent = metaWin.get_transient_for();
|
||||
|
||||
let idx = this._lookupIndex (parent);
|
||||
if (idx < 0) {
|
||||
// parent was not created yet, it will take care
|
||||
// of the dialog when created
|
||||
return;
|
||||
}
|
||||
|
||||
let clone = this._windows[idx];
|
||||
clone.addAttachedDialog(metaWin);
|
||||
}
|
||||
},
|
||||
|
||||
_windowAdded : function(metaWorkspace, metaWin) {
|
||||
@ -425,8 +507,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
|
||||
// Tests if @win should be shown in the Overview
|
||||
_isOverviewWindow : function (win) {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
return tracker.is_window_interesting(win.get_meta_window()) &&
|
||||
return !win.get_meta_window().skip_taskbar &&
|
||||
win.get_meta_window().showing_on_its_workspace();
|
||||
},
|
||||
|
||||
@ -723,22 +804,25 @@ const ThumbnailsBox = new Lang.Class({
|
||||
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
|
||||
|
||||
// Nab all the windows below us.
|
||||
let windows = global.get_window_actors().filter(function(win) {
|
||||
let windows = global.get_window_actors().filter(function(winActor) {
|
||||
// If the window is attached to an ancestor, we don't need/want to move it
|
||||
if (!!win.meta_window.get_transient_for())
|
||||
let window = winActor.meta_window;
|
||||
|
||||
if (window.get_transient_for() != null)
|
||||
return false;
|
||||
|
||||
if (isWindow)
|
||||
return win.get_workspace() >= newWorkspaceIndex && win != source;
|
||||
return window.get_workspace().index() >= newWorkspaceIndex && winActor != source;
|
||||
else
|
||||
return win.get_workspace() >= newWorkspaceIndex;
|
||||
return window.get_workspace().index() >= newWorkspaceIndex;
|
||||
});
|
||||
|
||||
this._spliceIndex = newWorkspaceIndex;
|
||||
|
||||
// ... move them down one.
|
||||
windows.forEach(function(win) {
|
||||
win.meta_window.change_workspace_by_index(win.get_workspace() + 1, true);
|
||||
windows.forEach(function(winActor) {
|
||||
let window = winActor.meta_window;
|
||||
window.change_workspace_by_index(window.get_workspace().index() + 1, true);
|
||||
});
|
||||
|
||||
if (isWindow)
|
||||
|
@ -237,29 +237,32 @@ const WorkspacesView = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateWorkspaces: function() {
|
||||
let oldNumWorkspaces = this._workspaces.length;
|
||||
let newNumWorkspaces = global.screen.n_workspaces;
|
||||
|
||||
this.scrollAdjustment.upper = newNumWorkspaces;
|
||||
|
||||
if (newNumWorkspaces > oldNumWorkspaces) {
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(w);
|
||||
let workspace = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
|
||||
this._workspaces.push(workspace);
|
||||
this.actor.add_actor(workspace.actor);
|
||||
}
|
||||
let needsUpdate = false;
|
||||
for (let j = 0; j < newNumWorkspaces; j++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(j);
|
||||
let workspace;
|
||||
|
||||
if (this._fullGeometry)
|
||||
this._updateWorkspaceActors(false);
|
||||
} else if (newNumWorkspaces < oldNumWorkspaces) {
|
||||
let nRemoved = (newNumWorkspaces - oldNumWorkspaces);
|
||||
let removed = this._workspaces.splice(oldNumWorkspaces, nRemoved);
|
||||
removed.forEach(function(workspace) {
|
||||
workspace.destroy();
|
||||
});
|
||||
if (j >= this._workspaces.length) { /* added */
|
||||
workspace = new Workspace.Workspace(metaWorkspace, this._monitorIndex);
|
||||
this.actor.add_actor(workspace.actor);
|
||||
this._workspaces[j] = workspace;
|
||||
} else {
|
||||
workspace = this._workspaces[j];
|
||||
|
||||
if (workspace.metaWorkspace != metaWorkspace) { /* removed */
|
||||
workspace.destroy();
|
||||
this._workspaces.splice(j, 1);
|
||||
} /* else kept */
|
||||
}
|
||||
}
|
||||
|
||||
if (this._fullGeometry)
|
||||
this._updateWorkspaceActors(false);
|
||||
|
||||
this._syncGeometry();
|
||||
},
|
||||
|
||||
@ -402,7 +405,7 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
Main.overview.addAction(clickAction);
|
||||
this.actor.bind_property('mapped', clickAction, 'enabled', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
let panAction = new Clutter.PanAction();
|
||||
let panAction = new Clutter.PanAction({ threshold_trigger_edge: Clutter.GestureTriggerEdge.AFTER });
|
||||
panAction.connect('pan', Lang.bind(this, this._onPan));
|
||||
panAction.connect('gesture-begin', Lang.bind(this, function() {
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
@ -410,7 +413,6 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
return true;
|
||||
}));
|
||||
panAction.connect('gesture-cancel', Lang.bind(this, function() {
|
||||
clickAction.release();
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].endSwipeScroll();
|
||||
}));
|
||||
|
@ -45,6 +45,7 @@ js/ui/status/accessibility.js
|
||||
js/ui/status/bluetooth.js
|
||||
js/ui/status/brightness.js
|
||||
js/ui/status/keyboard.js
|
||||
js/ui/status/location.js
|
||||
js/ui/status/network.js
|
||||
js/ui/status/power.js
|
||||
js/ui/status/rfkill.js
|
||||
|
114
po/et.po
114
po/et.po
@ -13,8 +13,8 @@ msgstr ""
|
||||
"Project-Id-Version: gnome-shell MASTER\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&keywords=I18N+L10N&component=general\n"
|
||||
"POT-Creation-Date: 2013-11-22 21:44+0000\n"
|
||||
"PO-Revision-Date: 2013-11-18 13:56+0300\n"
|
||||
"POT-Creation-Date: 2014-01-14 01:18+0000\n"
|
||||
"PO-Revision-Date: 2014-01-14 13:33+0300\n"
|
||||
"Last-Translator: Mattias Põldaru <mahfiaz@gmail.com>\n"
|
||||
"Language-Team: Estonian <>\n"
|
||||
"Language: et\n"
|
||||
@ -68,14 +68,14 @@ msgstr ""
|
||||
"Lubab ligipääsu sisemistele silumise ja monitoorimise tööriistadele Alt-F2 "
|
||||
"dialoogi kaudu."
|
||||
|
||||
msgid "Uuids of extensions to enable"
|
||||
msgid "UUIDs of extensions to enable"
|
||||
msgstr "Lubatavate laienduste UUID-d"
|
||||
|
||||
msgid ""
|
||||
"GNOME Shell extensions have a uuid property; this key lists extensions which "
|
||||
"GNOME Shell extensions have a UUID property; this key lists extensions which "
|
||||
"should be loaded. Any extension that wants to be loaded needs to be in this "
|
||||
"list. You can also manipulate this list with the EnableExtension and "
|
||||
"DisableExtension DBus methods on org.gnome.Shell."
|
||||
"DisableExtension D-Bus methods on org.gnome.Shell."
|
||||
msgstr ""
|
||||
"GNOME Shelli laiendustel on UUID omadus; selles võtmes loetletud laiendused "
|
||||
"tuleks laadida. Seda loendit saab muuta kasutades EnableExtension ja "
|
||||
@ -106,11 +106,11 @@ msgstr "Käsudialoogi (Alt-F2) ajalugu"
|
||||
msgid "History for the looking glass dialog"
|
||||
msgstr "Otsingudialoogi ajalugu"
|
||||
|
||||
msgid "Always show the 'Log out' menuitem in the user menu."
|
||||
msgid "Always show the 'Log out' menu item in the user menu."
|
||||
msgstr "Kasutajamenüüs näidatakse alati 'Logi välja' menüükirjet."
|
||||
|
||||
msgid ""
|
||||
"This key overrides the automatic hiding of the 'Log out' menuitem in single-"
|
||||
"This key overrides the automatic hiding of the 'Log out' menu item in single-"
|
||||
"user, single-session situations."
|
||||
msgstr ""
|
||||
"See võti keelab automaatse 'Logi välja' menüükirje peitmise, kui arvutis on "
|
||||
@ -1030,60 +1030,6 @@ msgid_plural "%d Connected Devices"
|
||||
msgstr[0] "%d ühendatud seade"
|
||||
msgstr[1] "%d ühendatud seadet"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Authorization request from %s"
|
||||
msgstr "Autoriseerimise päring seadmelt %s"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Device %s wants to pair with this computer"
|
||||
msgstr "Seade '%s' tahab selle arvutiga paarduda"
|
||||
|
||||
msgid "Allow"
|
||||
msgstr "Luba"
|
||||
|
||||
msgid "Deny"
|
||||
msgstr "Keela"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Device %s wants access to the service '%s'"
|
||||
msgstr "Seade %s soovib ligipääsu teenusele '%s'"
|
||||
|
||||
msgid "Always grant access"
|
||||
msgstr "Luba alati"
|
||||
|
||||
msgid "Grant this time only"
|
||||
msgstr "Luba ainult seekord"
|
||||
|
||||
msgid "Reject"
|
||||
msgstr "Lükka tagasi"
|
||||
|
||||
#. Translators: argument is the device short name */
|
||||
#, javascript-format
|
||||
msgid "Pairing confirmation for %s"
|
||||
msgstr "Paardumise kinnitus seadmele %s"
|
||||
|
||||
#, javascript-format
|
||||
msgid ""
|
||||
"Please confirm whether the Passkey '%06d' matches the one on the device."
|
||||
msgstr "Palun kontrolli, kas parool '%06d' kattub seadme parooliga."
|
||||
|
||||
#. Translators: this is the verb, not the noun */
|
||||
msgid "Matches"
|
||||
msgstr "Kattub"
|
||||
|
||||
msgid "Does not match"
|
||||
msgstr "Ei kattu"
|
||||
|
||||
#, javascript-format
|
||||
msgid "Pairing request for %s"
|
||||
msgstr "Seadmega %s paardumise päring"
|
||||
|
||||
msgid "Please enter the PIN mentioned on the device."
|
||||
msgstr "Palun sisesta seadme poolt öeldav PIN-kood."
|
||||
|
||||
msgid "OK"
|
||||
msgstr "Olgu"
|
||||
|
||||
msgid "Brightness"
|
||||
msgstr "Heledus"
|
||||
|
||||
@ -1300,6 +1246,52 @@ msgstr "Parool ei saa olla tühi"
|
||||
msgid "Authentication dialog was dismissed by the user"
|
||||
msgstr "Kasutaja katkestas autentimisdialoogi"
|
||||
|
||||
#~ msgid "Authorization request from %s"
|
||||
#~ msgstr "Autoriseerimise päring seadmelt %s"
|
||||
|
||||
#~ msgid "Device %s wants to pair with this computer"
|
||||
#~ msgstr "Seade '%s' tahab selle arvutiga paarduda"
|
||||
|
||||
#~ msgid "Allow"
|
||||
#~ msgstr "Luba"
|
||||
|
||||
#~ msgid "Deny"
|
||||
#~ msgstr "Keela"
|
||||
|
||||
#~ msgid "Device %s wants access to the service '%s'"
|
||||
#~ msgstr "Seade %s soovib ligipääsu teenusele '%s'"
|
||||
|
||||
#~ msgid "Always grant access"
|
||||
#~ msgstr "Luba alati"
|
||||
|
||||
#~ msgid "Grant this time only"
|
||||
#~ msgstr "Luba ainult seekord"
|
||||
|
||||
#~ msgid "Reject"
|
||||
#~ msgstr "Lükka tagasi"
|
||||
|
||||
#~ msgid "Pairing confirmation for %s"
|
||||
#~ msgstr "Paardumise kinnitus seadmele %s"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Please confirm whether the Passkey '%06d' matches the one on the device."
|
||||
#~ msgstr "Palun kontrolli, kas parool '%06d' kattub seadme parooliga."
|
||||
|
||||
#~ msgid "Matches"
|
||||
#~ msgstr "Kattub"
|
||||
|
||||
#~ msgid "Does not match"
|
||||
#~ msgstr "Ei kattu"
|
||||
|
||||
#~ msgid "Pairing request for %s"
|
||||
#~ msgstr "Seadmega %s paardumise päring"
|
||||
|
||||
#~ msgid "Please enter the PIN mentioned on the device."
|
||||
#~ msgstr "Palun sisesta seadme poolt öeldav PIN-kood."
|
||||
|
||||
#~ msgid "OK"
|
||||
#~ msgstr "Olgu"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Sorry, no wisdom for you today:\n"
|
||||
#~ "%s"
|
||||
|
997
po/pt_BR.po
997
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user