Compare commits
344 Commits
Author | SHA1 | Date | |
---|---|---|---|
fff607e1a4 | |||
3cc27eaabe | |||
601b081bf3 | |||
4405d993c9 | |||
361308eb1b | |||
d894dedaf6 | |||
d12dd1491f | |||
1625591598 | |||
a50c30a4fd | |||
02bfc74c1e | |||
a012dd838d | |||
e2b634e59a | |||
80b98d8787 | |||
bf2ba83cd5 | |||
727c43dbab | |||
203dedfb3a | |||
8d5d4159a3 | |||
cecba0269f | |||
3c878793b5 | |||
0549f42030 | |||
50f248ec5b | |||
544bdb4fb1 | |||
88b295ff9f | |||
602326bb57 | |||
31857cf05f | |||
896d8e830c | |||
5f86e29830 | |||
579ae59eca | |||
90db743cc9 | |||
fe82897064 | |||
0f49f36519 | |||
a92b7342ba | |||
86818e9c52 | |||
7a8a00c705 | |||
c8d5e0a51c | |||
524a7ff6fb | |||
5f6ac33d59 | |||
b4f5e4206d | |||
5133c3e010 | |||
0b77ea422a | |||
5c1dd4ea18 | |||
e1c687184e | |||
297d1356a2 | |||
98327b0c13 | |||
6786aee5ed | |||
0b9c726b4e | |||
436dd6ee8c | |||
acc053302d | |||
534b371d42 | |||
6004e3d2e1 | |||
c632074ba7 | |||
664245d2a6 | |||
fda4fc674d | |||
bf28c24c82 | |||
32df0e80ca | |||
297eab738f | |||
5819dd3a5a | |||
a007b1bb2d | |||
5cb43b6bae | |||
f524138a64 | |||
0aa626b2fb | |||
3ae1050f67 | |||
67736642f3 | |||
09f3c87d20 | |||
9deca75de8 | |||
5bc1dede81 | |||
6d53d43766 | |||
325462d9bf | |||
ee4ae62946 | |||
153768ef7f | |||
7249a218ba | |||
de348a4c49 | |||
fda8ffd9ef | |||
6cb707cc4f | |||
998c5f17fc | |||
c34b357051 | |||
40f4e92461 | |||
c727da823b | |||
8d1b7962d8 | |||
a6dfe20348 | |||
ed46390bbc | |||
80eb5bf535 | |||
7596fdb460 | |||
8db1ff8aef | |||
1dfffdbc4e | |||
64b2b4a7d4 | |||
ae35d0e43c | |||
b22c5eb167 | |||
6d5e414863 | |||
3e74dfb66d | |||
1245628521 | |||
c567690004 | |||
2feff4207b | |||
8c40b6f9a7 | |||
fc759bff77 | |||
3581c1d5b4 | |||
64e7459d1c | |||
f71afa9248 | |||
1ebca2e6d5 | |||
6222796b6a | |||
dcecf41d18 | |||
9d1fbffe75 | |||
6a6ba94bb9 | |||
ef5de3a5c0 | |||
f042e43990 | |||
620330db8f | |||
3765acc0a5 | |||
2e8654b96c | |||
cc5c5e7e8a | |||
9c849b0290 | |||
ad314b362e | |||
737a4f2816 | |||
96e4128e3e | |||
6f515f2327 | |||
cbb9a7ab96 | |||
e2e3b29ed1 | |||
82a8ac1976 | |||
bfec396ec2 | |||
d0e7f880d7 | |||
ff81659b9e | |||
6b2b3475c8 | |||
ed8acefc00 | |||
737f395d6c | |||
ab0a5d4a53 | |||
9412ac2027 | |||
c8670819dc | |||
4132ccae33 | |||
c450120409 | |||
6ce07abf50 | |||
e39e539ee9 | |||
9563a8f8a0 | |||
d5f37fa280 | |||
5c6e5ef6d0 | |||
42adc38609 | |||
e5fadb3b42 | |||
4c5f3aa971 | |||
6fc49b79a4 | |||
9e804b082f | |||
1fb220beb7 | |||
1fc1282fad | |||
8834a7df10 | |||
a34071e1c3 | |||
52a342300a | |||
b9456caeb0 | |||
26aa4333a5 | |||
04d2b0d282 | |||
7def1a4aa5 | |||
001b9868fb | |||
59a3e393f9 | |||
b846354787 | |||
2674d96e54 | |||
0c98fe8546 | |||
f18ed3c6ae | |||
644acf7018 | |||
96dca48b3b | |||
1309b64c33 | |||
1301dee744 | |||
efc194e36c | |||
60f41a109f | |||
890efa787a | |||
60c88612f7 | |||
82648bc86c | |||
ea1e5a5210 | |||
aa03734d39 | |||
bb0f76f562 | |||
8c2a290d09 | |||
8e661c3780 | |||
a03b6c419a | |||
fb55dd677f | |||
408790a630 | |||
08371f073d | |||
e7289378b7 | |||
31bde574de | |||
5aacfe4e6e | |||
5cf7bdabfd | |||
2021edd1fb | |||
45c1a9eafb | |||
0ae1556b94 | |||
c0739bd1e3 | |||
af51e8df7b | |||
22ef63cc44 | |||
03a5133e8c | |||
7f2456c00d | |||
aa4dbee362 | |||
7b65735cc9 | |||
7ef35fbec7 | |||
8b10d85fee | |||
d99b1e6c09 | |||
57ab7aec5b | |||
29a221bf62 | |||
671c569a9e | |||
492c033760 | |||
33a3b8046d | |||
88df183450 | |||
6a9080c3d6 | |||
019670b5ab | |||
4cab0c95d3 | |||
d51e79d483 | |||
69a27911a7 | |||
dd48514b24 | |||
eb54662098 | |||
545f0432c8 | |||
fdefb317cb | |||
4e0c8bfe67 | |||
dbd629d5d2 | |||
619a44a499 | |||
c5ca4e3ff0 | |||
55771b437b | |||
8727680983 | |||
ab9f21351f | |||
0055cabc62 | |||
fc70c2246b | |||
f7b6acaff8 | |||
91caa8e59f | |||
4c44bb7f52 | |||
df8a735aa9 | |||
82aea3e8d6 | |||
a8baf4a2a2 | |||
bfd344cdec | |||
a0fd4e195d | |||
4b3fbc4c9b | |||
63b1699a35 | |||
48acc41698 | |||
17672accfe | |||
986d72d9de | |||
ffd461cdb4 | |||
71dfab9711 | |||
c4f5274d74 | |||
4bfc3bafcb | |||
898b2b903d | |||
7921954a31 | |||
0e42de9149 | |||
8e4a5f1ac5 | |||
61577e176e | |||
4b008b1ada | |||
bee37b5bc4 | |||
b5ab8b6ed5 | |||
4d6bd91d16 | |||
5428db5385 | |||
6e6b1e6052 | |||
bc2b47974d | |||
2244b6ff1b | |||
fb384fc291 | |||
73cae8ce9a | |||
dcd07eb23f | |||
fa24448489 | |||
c975740f92 | |||
1e0187fa57 | |||
cbdf060bca | |||
19a8dff975 | |||
72f9f482d6 | |||
88de26138a | |||
57bd964cb3 | |||
74a39ae57c | |||
5090a4ccce | |||
ae0652d13f | |||
101a07a3d7 | |||
b012e93121 | |||
c31109800b | |||
c0dc363a3d | |||
739bb28220 | |||
aab2794e05 | |||
75c8c1bfb6 | |||
6f8bd96195 | |||
25f0d098bd | |||
56d584b7c6 | |||
20bf53add1 | |||
0d440bb0a2 | |||
8ec62ce46b | |||
79927faaec | |||
e4c7f1f3c4 | |||
68710c4647 | |||
7d7cbde1f3 | |||
bafd9c777a | |||
42a5531f15 | |||
227da25776 | |||
2028f33e38 | |||
145bf19636 | |||
d1675c44e2 | |||
6934e4db26 | |||
cae3414854 | |||
90d061edaf | |||
2e02918323 | |||
e77a1fd33b | |||
dd01c24c34 | |||
f88fbee80d | |||
fe08edbe2b | |||
d2a16bca10 | |||
a87f51487e | |||
76fce94b66 | |||
d104f9210a | |||
d0780d1622 | |||
9d5906dae3 | |||
07a0960265 | |||
72bee6d7ca | |||
249f26d23c | |||
7813c5b93f | |||
e38d83fd44 | |||
d97657b151 | |||
7e857dede3 | |||
c3218f6b03 | |||
1060d0db60 | |||
b8925a091c | |||
79cca07a41 | |||
c1d189c9ad | |||
b1a973ee5a | |||
93ef560779 | |||
c28d35ad86 | |||
9c654a6ab5 | |||
64a54e379c | |||
8f4ec8583b | |||
f4852d7264 | |||
092e1a691d | |||
16ac42421d | |||
1d2eadb9c0 | |||
35c85d9fac | |||
f0622c1896 | |||
6d11247417 | |||
59c3e3a179 | |||
42e26a8682 | |||
db6caac9cc | |||
ba4a57ba0b | |||
018e3bc35f | |||
a56bc9d933 | |||
5b93525ce8 | |||
6abb86dff6 | |||
6a27d5ed80 | |||
8232684672 | |||
2d855ce5cf | |||
b2b685e46d | |||
ef552846d1 | |||
c7dfd0894e | |||
5b1a76aeff | |||
529b6ca935 | |||
625a4c0766 | |||
3c3ea2f575 | |||
57a332bb08 | |||
73ac98b193 | |||
59e3cbb36b | |||
fb019a7cbf | |||
09607f6aa7 | |||
1c4a33eb78 | |||
b7513097ea | |||
a35677a9bf |
8
.gitignore
vendored
@ -3,6 +3,7 @@
|
||||
*.o
|
||||
.deps
|
||||
.libs
|
||||
ABOUT-NLS
|
||||
ChangeLog
|
||||
INSTALL
|
||||
Makefile
|
||||
@ -29,8 +30,13 @@ m4/
|
||||
omf.make
|
||||
po/*.gmo
|
||||
po/gnome-shell.pot
|
||||
po/*.header
|
||||
po/*.sed
|
||||
po/*.sin
|
||||
po/Makefile.in.in
|
||||
po/Makevars.template
|
||||
po/POTFILES
|
||||
po/Rules-quot
|
||||
po/stamp-it
|
||||
scripts/launcher.pyc
|
||||
src/*.gir
|
||||
@ -43,9 +49,11 @@ src/calendar-server/org.gnome.Shell.CalendarServer.service
|
||||
src/gnome-shell
|
||||
src/gnome-shell-calendar-server
|
||||
src/gnome-shell-extension-tool
|
||||
src/gnome-shell-hotplug-sniffer
|
||||
src/gnome-shell-jhbuild
|
||||
src/gnome-shell-perf-helper
|
||||
src/gnome-shell-real
|
||||
src/hotplug-sniffer/org.gnome.Shell.HotplugSniffer.service
|
||||
src/run-js-test
|
||||
src/test-recorder
|
||||
src/test-recorder.ogg
|
||||
|
@ -3,5 +3,5 @@ E-mail: otaylor@redhat.com
|
||||
Userid: otaylor
|
||||
|
||||
Colin Walters
|
||||
E-mail: walters@redhat.com
|
||||
E-mail: walters@verbum.org
|
||||
Userid: walters
|
||||
|
192
NEWS
@ -1,3 +1,195 @@
|
||||
3.1.3
|
||||
=====
|
||||
* Fix problem with "user theme extension" breaking the CSS for other
|
||||
extensions [Giovanni; #650971]
|
||||
* Telepathy IM framework integration
|
||||
- Switch to using telepathy-glib rather than talking to
|
||||
Telepathy via D-Bus [Guillaume, Jasper; #645585, #649633, #651138, #651227]
|
||||
- Acknowledge messages when the user clicks on them [Guillaume, #647893]
|
||||
- Fix problem with telepathy icon blinking for incoming messages
|
||||
even though the user has been notified of them [Guillaume; #643594]
|
||||
* Networking
|
||||
- keep wirelesss networks in predictable order [Giovanni; #646580, #652313]
|
||||
- Show unmanaged devices in the menu [Giovanni; #646946]
|
||||
- Fix overflow when too many VPN connections [Giovanni; #651602]
|
||||
* Bluetooth
|
||||
- Show "hardware disabled" when disabled by rfkill [Giovanni; #648048]
|
||||
- Fix bug updating status of devices [Giovanni; #647565]
|
||||
* LookingGlass console:
|
||||
- Add a "Memory" tab [Colin; #650692]
|
||||
- Make escape work from any page [Dan Winship; #647303]
|
||||
- Provide a way to refer to panel items as, e.g.,
|
||||
Main.panel._activities [Dan Winship; #646915]
|
||||
* User menu
|
||||
- Fix problem with suspend menu option locking the screen even when the user
|
||||
disabled that. [Florian; #652327]
|
||||
- Hide "power off..." option if shutdown is disabled via PolicyKit
|
||||
[Florian; #652038]
|
||||
* Track changes to WM_CLASS (fixes problems with LibreOffice tracking)
|
||||
[Colin; #649315]
|
||||
* Remove app tracking workarounds for Firefox and LibreOffice [Colin; #651015]
|
||||
* Use upstream gettext autoconfigury rather than glib version [Javier; #631576]
|
||||
* Show messages in the message tray when an application is fullscreen
|
||||
[Dan Winship; #608667]
|
||||
* Don't autohide the workspace pager if there is more than one workspace
|
||||
[Florian; #652714, #653078, #653142]
|
||||
* Don't always slide out the workspace pager at drag begin [Florian; #652730]
|
||||
* Only offer to remove a favorite app when dragging it's icon [Owen; #642895]
|
||||
* Allow dropping an icon anywhere on a workspace [Adel; #652079]
|
||||
* st-scroll-view: Make the fade effect and offset themable [Jasper; #651813]
|
||||
* Obey the user's preference when running an application in a terminal
|
||||
from the run dialog [Florian; #648422]
|
||||
* Consistently exit overview when launching external applications
|
||||
[Colin; #653095]
|
||||
* Adapt to changes in GJS for how GObject APIs are bound
|
||||
[Alex, Colin, Florian, Jasper, Marc-Antoine; #649981, #652597]
|
||||
* Fix problems with scrolling in overflow for alt-Tab switcher
|
||||
[Dan Winship, Adel; #647807]
|
||||
* Mark relationships between labels and actors for accessibility [Alejandro]
|
||||
* Add org.gnome.shell.enabled-extensions complementing disabled-extensions
|
||||
GSetting [Tassilo; #651088]
|
||||
* Visual tweaks [Jakub, Jasper; #646261, #652715]
|
||||
* Switch to building against clutter-1.7 with independent Cogl [Adel; #653397]
|
||||
* Code cleanups [Colin, Dan Winship, Florian; #633620, #645031, #648755, #648758,
|
||||
#648760, #649203, #649517, #650317, #652730]
|
||||
* Memory leak fixes [Colin, Maxim; #649508, #650934]
|
||||
* Build Fixes [Colin, Dan Winship, Florian, Ionut, Morten, Owen, Sean; #647395,
|
||||
#648006, #650869, #653199, #653275
|
||||
* Miscellaneous bug fixes [Adam, Adel, Dan Williams, Dan Winship, Florian,
|
||||
Ionut, Jasper, Maxim, Ray; #620105, #639459, #641570, #642793, #643513,
|
||||
#645848, #646919, #647186, #648305, #648410, #648562, #648894, #649001,
|
||||
#645990, #647893, #647907, #651012, #651086, #651606, #651569, #651866,
|
||||
#652388, #653511]
|
||||
|
||||
Contributors:
|
||||
Ionut Biru, Giovanni Campagna, Guillaume Desmottes, Adam Dingle,
|
||||
Maxim Ermilov, Adel Gadllah, Tassilo Horn, Javier Jardón, Jonny Lamb,
|
||||
Alexander Larsson, Rui Matos, Morten Mjelva, Florian Müllner,
|
||||
Marc-Antoine Perennou, Alejandro Piñeiro, Jasper St. Pierre, Jakub Steiner,
|
||||
Ray Strode, Owen Taylor, Colin Walters, Dan Williams, Sean Wilson, Dan Winship
|
||||
|
||||
Translations:
|
||||
Daniel Martinez Cucalon [ar], Ihar Hrachyshka [be], Carles Ferrando,
|
||||
Gil Forcada, Sílvia Miranda [ca], Kristjan Schmidt [eo], Jorge González,
|
||||
Daniel Mustieles [es], Seán de Búrca [ga], Fran Diéguez [gl],
|
||||
Yaron Shahrabani [he], Kjartan Maraas [nb], Misha Shnurapet,
|
||||
Yuri Myasoedov [ru], Daniel Nylander [se], Peter Mráz [sk],
|
||||
Matej Urbančič [sl], Krishnababu Krothapalli [te], Daniel Korostil [uk],
|
||||
Aron Xu [zh_CN]
|
||||
|
||||
3.0.2
|
||||
=====
|
||||
* Network Menu [Dan Williams]
|
||||
- Fix connecting to WPA2 Enterprise access points
|
||||
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=648171
|
||||
- Show the mobile broadband wizard when selecting 3G network
|
||||
Fixes https://bugzilla.gnome.org/show_bug.cgi?id=649318
|
||||
- Miscellaneous bug fixes
|
||||
648648, 650124
|
||||
* Fix duplicate icons in the application browser [Owen]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=648739
|
||||
* Make clicking anywhere on the volume icon slider work [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646660
|
||||
* Fix a case where activating and clicking the hot corner
|
||||
at the same time could result in immediately leaving the
|
||||
overview [Rui]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=649427
|
||||
* Fix a case where applications became misordered in Alt-Tab [Jasper]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=643302
|
||||
* Fix a bug where messages you send could show up in
|
||||
notifications as if someone else sent them [Jonny]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=650219
|
||||
* Memory leak fixes [Colin, Maxim]
|
||||
642652, 649508, 649497
|
||||
* Miscellaneous minor bug fixes [Adel, Christopher, Jasper]
|
||||
649596, 648765, 648983, 649632
|
||||
|
||||
Contributors:
|
||||
Christopher Aillon, Giovanni Campagna, Maxim Ermilov,
|
||||
Adel Gadllah, Jonny Lamb, Rui Matos, Jasper St. Pierre,
|
||||
Owen Taylor, Colin Walters, Dan Williams
|
||||
|
||||
Translations:
|
||||
Arash Mousavi [fa], Seán de Búrca [ga], Timo Jyrinki [fi],
|
||||
Sigurd Gartmann [nb], Daniel Nylander [se], Peter Mráz [sl],
|
||||
Abduxukur Abdurixit [ug], Nguyễn Thái Ngọc Duy [vi]
|
||||
|
||||
3.0.1
|
||||
=====
|
||||
|
||||
* Network menu
|
||||
- Fix problems updating the menu for mobile broadband devices [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646395
|
||||
- Fix missing device descriptions with multiple devices of the
|
||||
same type [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646074
|
||||
- Label ad-hoc neworks with an appropriate icon [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646141
|
||||
- Fix displaying some devices states as "invalid" [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646946
|
||||
- Fix problems with access points that don't report a SSID [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=647040
|
||||
- Miscellaneous minor bug fixes [Dan, Giovanni, Owen]
|
||||
645981, 646558, 646443, 646708, 646968
|
||||
* Application menu and icon
|
||||
- Fix bug where application menu icon was missing at GNOME Shell
|
||||
startup. [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=644122
|
||||
- Fix missing application menu for dialog windows [Colin]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=647082
|
||||
- When launching an application through an alternate launcher
|
||||
(like for a System Settings pane), association the windows with
|
||||
the application, not the launcher. [Colin]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646689
|
||||
* Activities overview
|
||||
- Load the applications view incrementally to avoid potentially freezing
|
||||
for multiple seconds [Colin]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=647778
|
||||
- Fix bug where package installation while the overview
|
||||
was up could result in a corrupted application display. [Giovanni]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=645801
|
||||
- Fix dragging from the search results to launch apps and docs [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=645990
|
||||
- Fix flickering of selection when searching in the overview [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646019
|
||||
- Fix bug when typing into the search box when text was already
|
||||
selected [Nohemi]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=636341
|
||||
* Fix layout of notifications for right-to-left languages [Florian]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646921
|
||||
* Remove a confusing special case where Alt-Tab sometimes switched
|
||||
to a different window of the same application rather than to
|
||||
a different application. [Rui]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=648132
|
||||
* Fix a crash that could happen when a window was opened on a
|
||||
workspace that was immediately removed [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=648132
|
||||
* Fix keyboard navigation in logout/reboot dialogs [Dan]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646740
|
||||
* Fix missing inspector icon in Looking Glass console [Dan]
|
||||
* Miscellaneous minor bug fixes [Adel, Colin, Dan, Florian, Nohemi]
|
||||
645648, 646205, 646257, 646855, 647098, 646730
|
||||
|
||||
Contributors:
|
||||
Giovanni Campagna, Nohemi Fernandez, Adel Gadllah, Rui Matos, Florian Müllner,
|
||||
Owen Taylor, Colin Walters, Dan Winship
|
||||
|
||||
Translations:
|
||||
Hendrik Richter [de], Jorge González [es], Arash Mousavi [fa],
|
||||
Fran Diéguez [gl], Jiro Matsuzawa [ja], Piotr Drąg [pl], Daniel Nylander [sv],
|
||||
Sira Nokyoongtong [th], Muhammet Kara [tr], Nguyễn Thái Ngọc Duy [vi],
|
||||
Aron Xu [zh_CN], Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||
|
||||
3.0.0.2
|
||||
=======
|
||||
|
||||
* Fix missing import that was preventing extensions from loading.
|
||||
[Maxim Ermilov]
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=646333
|
||||
|
||||
Translations:
|
||||
Timo Jyrinki [fi]
|
||||
|
||||
3.0.0.1
|
||||
=======
|
||||
|
||||
|
46
configure.ac
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.0.0.1],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.1.3],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@ -23,12 +23,16 @@ AM_PROG_CC_C_O
|
||||
LT_PREREQ([2.2.6])
|
||||
LT_INIT([disable-static])
|
||||
|
||||
# i18n
|
||||
IT_PROG_INTLTOOL([0.40])
|
||||
|
||||
AM_GNU_GETTEXT([external])
|
||||
AM_GNU_GETTEXT_VERSION([0.17])
|
||||
|
||||
GETTEXT_PACKAGE=gnome-shell
|
||||
AC_SUBST(GETTEXT_PACKAGE)
|
||||
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
|
||||
[The prefix for our gettext translation domains.])
|
||||
IT_PROG_INTLTOOL(0.26)
|
||||
AM_GLIB_GNU_GETTEXT
|
||||
|
||||
PKG_PROG_PKG_CONFIG([0.22])
|
||||
|
||||
@ -60,7 +64,7 @@ fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
CLUTTER_MIN_VERSION=1.5.15
|
||||
CLUTTER_MIN_VERSION=1.7.5
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=0.7.11
|
||||
MUTTER_MIN_VERSION=3.0.0
|
||||
@ -68,11 +72,11 @@ GTK_MIN_VERSION=3.0.0
|
||||
GIO_MIN_VERSION=2.25.9
|
||||
LIBECAL_MIN_VERSION=2.32.0
|
||||
LIBEDATASERVER_MIN_VERSION=1.2.0
|
||||
LIBEDATASERVERUI2_MIN_VERSION=1.2.0
|
||||
LIBEDATASERVERUI3_MIN_VERSION=2.91.6
|
||||
TELEPATHY_GLIB_MIN_VERSION=0.13.12
|
||||
LIBEDATASERVERUI_MIN_VERSION=2.91.6
|
||||
TELEPATHY_GLIB_MIN_VERSION=0.15.3
|
||||
TELEPATHY_LOGGER_MIN_VERSION=0.2.4
|
||||
POLKIT_MIN_VERSION=0.100
|
||||
STARTUP_NOTIFICATION_MIN_VERSION=0.11
|
||||
|
||||
# Collect more than 20 libraries for a prize!
|
||||
PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
|
||||
@ -81,10 +85,10 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
|
||||
libmutter >= $MUTTER_MIN_VERSION
|
||||
gjs-internals-1.0 >= $GJS_MIN_VERSION
|
||||
libgnome-menu $recorder_modules gconf-2.0
|
||||
gdk-x11-3.0
|
||||
gdk-x11-3.0 libsoup-2.4
|
||||
clutter-x11-1.0 >= $CLUTTER_MIN_VERSION
|
||||
clutter-glx-1.0 >= $CLUTTER_MIN_VERSION
|
||||
libstartup-notification-1.0
|
||||
libstartup-notification-1.0 >= $STARTUP_NOTIFICATION_MIN_VERSION
|
||||
gobject-introspection-1.0 >= $GOBJECT_INTROSPECTION_MIN_VERSION
|
||||
libcanberra
|
||||
telepathy-glib >= $TELEPATHY_GLIB_MIN_VERSION
|
||||
@ -93,6 +97,8 @@ PKG_CHECK_MODULES(GNOME_SHELL, gio-2.0 >= $GIO_MIN_VERSION
|
||||
|
||||
PKG_CHECK_MODULES(SHELL_PERF_HELPER, gtk+-3.0 gio-2.0)
|
||||
|
||||
PKG_CHECK_MODULES(SHELL_HOTPLUG_SNIFFER, gio-2.0 gdk-pixbuf-2.0)
|
||||
|
||||
GJS_VERSION=`$PKG_CONFIG --modversion gjs-internals-1.0`
|
||||
AC_DEFINE_UNQUOTED([GJS_VERSION], ["$GJS_VERSION"], [The version of GJS we're linking to])
|
||||
AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
|
||||
@ -100,7 +106,7 @@ AC_SUBST([GJS_VERSION], ["$GJS_VERSION"])
|
||||
GOBJECT_INTROSPECTION_CHECK([$GOBJECT_INTROSPECTION_MIN_VERSION])
|
||||
JHBUILD_TYPELIBDIR="$INTROSPECTION_TYPELIBDIR"
|
||||
# NM is the only typelib we use that we don't jhbuild
|
||||
PKG_CHECK_EXISTS([libnm-glib >= 0.8.995],
|
||||
PKG_CHECK_EXISTS([libnm-glib >= 0.8.999],
|
||||
[NM_TYPELIBDIR=`$PKG_CONFIG --variable=libdir libnm-glib`/girepository-1.0
|
||||
if test "$INTROSPECTION_TYPELIBDIR" != "$NM_TYPELIBDIR"; then
|
||||
JHBUILD_TYPELIBDIR="$JHBUILD_TYPELIBDIR:$NM_TYPELIBDIR"
|
||||
@ -111,22 +117,20 @@ saved_CFLAGS=$CFLAGS
|
||||
saved_LIBS=$LIBS
|
||||
CFLAGS=$GNOME_SHELL_CFLAGS
|
||||
LIBS=$GNOME_SHELL_LIBS
|
||||
# sn_startup_sequence_get_application_id, we can replace with a version check later
|
||||
AC_CHECK_FUNCS(JS_NewGlobalObject sn_startup_sequence_get_application_id XFixesCreatePointerBarrier)
|
||||
AC_CHECK_FUNCS(JS_NewGlobalObject XFixesCreatePointerBarrier)
|
||||
CFLAGS=$saved_CFLAGS
|
||||
LIBS=$saved_LIBS
|
||||
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 gnome-desktop-3.0 >= 2.90.0 x11)
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-3.0 libcroco-0.6 >= 0.6.2 gnome-desktop-3.0 >= 2.90.0 x11)
|
||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-3.0)
|
||||
PKG_CHECK_MODULES(TRAY, gtk+-3.0)
|
||||
PKG_CHECK_MODULES(GVC, libpulse libpulse-mainloop-glib gobject-2.0)
|
||||
PKG_CHECK_MODULES(JS_TEST, clutter-x11-1.0 gjs-1.0 gobject-introspection-1.0 gtk+-3.0)
|
||||
PKG_CHECK_MODULES(DESKTOP_SCHEMAS, gsettings-desktop-schemas >= 0.1.7)
|
||||
|
||||
AC_MSG_CHECKING([for bluetooth support])
|
||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
|
||||
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=libdir gnome-bluetooth-1.0`/gnome-bluetooth
|
||||
BLUETOOTH_LIBS="-L'$BLUETOOTH_DIR' -lgnome-bluetooth-applet"
|
||||
PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 3.1.0],
|
||||
[BLUETOOTH_DIR=`$PKG_CONFIG --variable=applet_libdir gnome-bluetooth-1.0`
|
||||
BLUETOOTH_LIBS=`$PKG_CONFIG --variable=applet_libs gnome-bluetooth-1.0`
|
||||
AC_SUBST([BLUETOOTH_LIBS],["$BLUETOOTH_LIBS"])
|
||||
AC_DEFINE_UNQUOTED([BLUETOOTH_DIR],["$BLUETOOTH_DIR"],[Path to installed GnomeBluetooth typelib and library])
|
||||
AC_DEFINE([HAVE_BLUETOOTH],[1],[Define if you have libgnome-bluetooth-applet])
|
||||
@ -136,13 +140,7 @@ PKG_CHECK_EXISTS([gnome-bluetooth-1.0 >= 2.90.0],
|
||||
AC_SUBST([HAVE_BLUETOOTH],[0])
|
||||
AC_MSG_RESULT([no])])
|
||||
|
||||
# Default to libedataserverui-3.0, but allow falling back to 1.2
|
||||
PKG_CHECK_EXISTS(libedataserverui-3.0,
|
||||
[EDS_API=3.0
|
||||
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI3_MIN_VERSION],
|
||||
[EDS_API=1.2
|
||||
LIBEDATASERVERUI_MIN_VERSION=$LIBEDATASERVERUI2_MIN_VERSION])
|
||||
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-$EDS_API >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
|
||||
PKG_CHECK_MODULES(CALENDAR_SERVER, libecal-1.2 >= $LIBECAL_MIN_VERSION libedataserver-1.2 >= $LIBEDATASERVER_MIN_VERSION libedataserverui-3.0 >= $LIBEDATASERVERUI_MIN_VERSION gio-2.0)
|
||||
AC_SUBST(CALENDAR_SERVER_CFLAGS)
|
||||
AC_SUBST(CALENDAR_SERVER_LIBS)
|
||||
|
||||
|
@ -30,26 +30,14 @@ dist_theme_DATA = \
|
||||
theme/filter-selected-ltr.svg \
|
||||
theme/filter-selected-rtl.svg \
|
||||
theme/gnome-shell.css \
|
||||
theme/mosaic-view-active.svg \
|
||||
theme/mosaic-view.svg \
|
||||
theme/move-window-on-new.svg \
|
||||
theme/panel-border.svg \
|
||||
theme/panel-button-border.svg \
|
||||
theme/panel-button-highlight-narrow.svg \
|
||||
theme/panel-button-highlight-wide.svg \
|
||||
theme/process-working.svg \
|
||||
theme/running-indicator.svg \
|
||||
theme/scroll-button-down-hover.png \
|
||||
theme/scroll-button-down.png \
|
||||
theme/scroll-button-up-hover.png \
|
||||
theme/scroll-button-up.png \
|
||||
theme/scroll-hhandle.svg \
|
||||
theme/scroll-vhandle.svg \
|
||||
theme/section-more.svg \
|
||||
theme/section-more-open.svg \
|
||||
theme/separator-white.png \
|
||||
theme/single-view-active.svg \
|
||||
theme/single-view.svg \
|
||||
theme/source-button-border.svg \
|
||||
theme/toggle-off-us.svg \
|
||||
theme/toggle-off-intl.svg \
|
||||
|
@ -15,8 +15,18 @@
|
||||
<default>[]</default>
|
||||
<_summary>Uuids of extensions to disable</_summary>
|
||||
<_description>
|
||||
GNOME Shell extensions have a uuid property;
|
||||
this key lists extensions which should not be loaded.
|
||||
GNOME Shell extensions have a uuid property; this key lists extensions
|
||||
which should not be loaded. This setting overrides enabled-extensions
|
||||
for extensions that appear in both lists.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="enabled-extensions" type="as">
|
||||
<default>[]</default>
|
||||
<_summary>Uuids of extensions to enable</_summary>
|
||||
<_description>
|
||||
GNOME Shell extensions have a uuid property; this key lists extensions
|
||||
which should be loaded. disabled-extensions overrides this setting for
|
||||
extensions that appear in both lists.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="enable-app-monitoring" type="b">
|
||||
@ -52,6 +62,7 @@
|
||||
<child name="clock" schema="org.gnome.shell.clock"/>
|
||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||
<child name="recorder" schema="org.gnome.shell.recorder"/>
|
||||
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
|
||||
@ -65,6 +76,38 @@
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="show-keyboard" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Show the onscreen keyboard</_summary>
|
||||
<_description>
|
||||
If true, display onscreen keyboard.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="keyboard-type" type="s">
|
||||
<default>'touch'</default>
|
||||
<_summary>Which keyboard to use</_summary>
|
||||
<_description>
|
||||
The type of keyboard to use.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="enable-drag" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Enable keyboard dragging</_summary>
|
||||
<_description>
|
||||
If true, enable keyboard dragging.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="enable-float" type="b">
|
||||
<default>false</default>
|
||||
<_summary>Enable floating keyboard</_summary>
|
||||
<_description>
|
||||
If true, enable floating keyboard.
|
||||
</_description>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.clock" path="/org/gnome/shell/clock/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="show-seconds" type="b">
|
||||
|
@ -39,6 +39,11 @@ StScrollBar
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
StScrollView.vfade
|
||||
{
|
||||
-st-vfade-offset: 68px;
|
||||
}
|
||||
|
||||
StScrollView StScrollBar
|
||||
{
|
||||
min-width: 16px;
|
||||
@ -182,6 +187,7 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.popup-inactive-menu-item {
|
||||
font-weight: normal;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@ -258,7 +264,7 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.panel-corner:active,
|
||||
.panel-corner:checked,
|
||||
.panel-corner:overview,
|
||||
.panel-corner:focus {
|
||||
-panel-corner-inner-border-color: rgba(255,255,255,0.8);
|
||||
}
|
||||
@ -295,7 +301,7 @@ StTooltip StLabel {
|
||||
}
|
||||
|
||||
.panel-button:active,
|
||||
.panel-button:checked,
|
||||
.panel-button:overview,
|
||||
.panel-button:focus {
|
||||
border-image: url("panel-button-border.svg") 10 10 0 2;
|
||||
background-image: url("panel-button-highlight-wide.svg");
|
||||
@ -458,6 +464,7 @@ StTooltip StLabel {
|
||||
background-gradient-start: rgba(5,5,6,0.1);
|
||||
background-gradient-end: rgba(254,254,254,0.1);
|
||||
background-gradient-direction: vertical;
|
||||
selected-color: black;
|
||||
caret-color: rgb(128, 128, 128);
|
||||
caret-size: 1px;
|
||||
width: 250px;
|
||||
@ -718,6 +725,8 @@ StTooltip StLabel {
|
||||
.lg-dialog StEntry
|
||||
{
|
||||
color: #88ff66;
|
||||
selection-background-color: #88ff66;
|
||||
selected-color: black;
|
||||
}
|
||||
|
||||
.lg-obj-inspector-title
|
||||
@ -1130,6 +1139,83 @@ StTooltip StLabel {
|
||||
icon-size: 36px;
|
||||
}
|
||||
|
||||
.hotplug-transient-box {
|
||||
spacing: 6px;
|
||||
padding: 2px 72px 2px 12px;
|
||||
}
|
||||
|
||||
.hotplug-notification-item {
|
||||
background-color: #3c3c3c;
|
||||
padding: 0px 10px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #181818;
|
||||
}
|
||||
|
||||
.hotplug-notification-item:hover {
|
||||
border: 1px solid #a1a1a1;
|
||||
}
|
||||
|
||||
.hotplug-notification-item:focus {
|
||||
background-color: #666666;
|
||||
}
|
||||
|
||||
.hotplug-notification-item:active {
|
||||
border: 1px solid #a1a1a1;
|
||||
background-color: #2b2b2b;
|
||||
}
|
||||
|
||||
.hotplug-notification-item-icon {
|
||||
icon-size: 24px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
||||
.hotplug-resident-box {
|
||||
spacing: 8px;
|
||||
}
|
||||
|
||||
.hotplug-resident-mount {
|
||||
spacing: 8px;
|
||||
border-radius: 4px;
|
||||
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.hotplug-resident-mount:hover {
|
||||
background-gradient-direction: horizontal;
|
||||
background-gradient-start: rgba(255, 255, 255, 0.1);
|
||||
background-gradient-end: rgba(255, 255, 255, 0);
|
||||
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.hotplug-resident-mount-label {
|
||||
color: inherit;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.hotplug-resident-mount-icon {
|
||||
icon-size: 24px;
|
||||
padding-left: 6px;
|
||||
}
|
||||
|
||||
.hotplug-resident-eject-icon {
|
||||
icon-size: 16px;
|
||||
}
|
||||
|
||||
.hotplug-resident-eject-button {
|
||||
padding: 2px;
|
||||
border: 1px solid #2b2b2b;
|
||||
border-radius: 5px;
|
||||
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.hotplug-resident-eject-button:hover {
|
||||
color: #fff;
|
||||
background-color: #2b2b2b;
|
||||
border: 1px solid #a1a1a1;
|
||||
}
|
||||
|
||||
.chat-log-message {
|
||||
color: #888888;
|
||||
}
|
||||
@ -1189,6 +1275,8 @@ StTooltip StLabel {
|
||||
color: #545454;
|
||||
background-color: #e8e8e8;
|
||||
caret-color: #545454;
|
||||
selection-background-color: #bcbcbc;
|
||||
selected-color: #323232;
|
||||
box-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
|
||||
}
|
||||
|
||||
@ -1255,6 +1343,16 @@ StTooltip StLabel {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.summary-source-counter {
|
||||
color: white;
|
||||
background-color: #3465A4;
|
||||
text-shadow: black 1px 1px 0;
|
||||
font-size: 9pt;
|
||||
border-radius: 1em;
|
||||
min-height: 1em;
|
||||
min-width: 1em;
|
||||
}
|
||||
|
||||
.source-title {
|
||||
font-size: 9pt;
|
||||
font-weight: bold;
|
||||
@ -1470,6 +1568,8 @@ StTooltip StLabel {
|
||||
font-weight: bold;
|
||||
width: 23em;
|
||||
color: white;
|
||||
selection-background-color: white;
|
||||
selected-color: black;
|
||||
}
|
||||
|
||||
.run-dialog {
|
||||
@ -1573,6 +1673,90 @@ StTooltip StLabel {
|
||||
color: #444444;
|
||||
}
|
||||
|
||||
/* ShellMountOperation Dialogs */
|
||||
.shell-mount-operation-icon {
|
||||
icon-size: 48px;
|
||||
}
|
||||
|
||||
.mount-password-reask {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.show-processes-dialog,
|
||||
.mount-question-dialog {
|
||||
spacing: 24px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-subject,
|
||||
.mount-question-dialog-subject {
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
color: #666666;
|
||||
padding-top: 10px;
|
||||
padding-left: 17px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-subject:rtl,
|
||||
.mount-question-dialog-subject:rtl {
|
||||
padding-left: 0px;
|
||||
padding-right: 17px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-description,
|
||||
.mount-question-dialog-description {
|
||||
font-size: 10pt;
|
||||
color: white;
|
||||
padding-left: 17px;
|
||||
width: 28em;
|
||||
}
|
||||
|
||||
.show-processes-dialog-description:rtl,
|
||||
.mount-question-dialog-description:rtl {
|
||||
padding-right: 17px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list {
|
||||
font-size: 10pt;
|
||||
max-height: 200px;
|
||||
padding-top: 24px;
|
||||
padding-left: 49px;
|
||||
padding-right: 32px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list:rtl {
|
||||
padding-right: 49px;
|
||||
padding-left: 32px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list-item {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list-item:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list-item:ltr {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list-item:rtl {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list-item-icon:ltr {
|
||||
padding-right: 17px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list-item-icon:rtl {
|
||||
padding-left: 17px;
|
||||
}
|
||||
|
||||
.show-processes-dialog-app-list-item-name {
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
/* PolicyKit Authentication Dialog */
|
||||
.polkit-dialog {
|
||||
/* this is the width of the entire modal popup */
|
||||
@ -1655,3 +1839,57 @@ StTooltip StLabel {
|
||||
.magnifier-zoom-region.full-screen {
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
/* On-screen Keyboard */
|
||||
|
||||
#keyboard {
|
||||
background: rgba(0,0,0,0.8);
|
||||
}
|
||||
|
||||
.keyboard-layout {
|
||||
spacing: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.keyboard-row {
|
||||
spacing: 15px;
|
||||
}
|
||||
|
||||
.keyboard-key {
|
||||
min-height: 30px;
|
||||
min-width: 30px;
|
||||
background-gradient-start: rgba(255,245,245,0.4);
|
||||
background-gradient-end: rgba(105,105,105,0.1);
|
||||
background-gradient-direction: vertical;
|
||||
font-size: 14pt;
|
||||
font-weight: bold;
|
||||
border-radius: 10px;
|
||||
border: 2px solid #a0a0a0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.keyboard-key:grayed {
|
||||
color: #808080;
|
||||
border-color: #808080;
|
||||
}
|
||||
|
||||
.keyboard-key:checked,
|
||||
.keyboard-key:hover {
|
||||
background: #303030;
|
||||
border: 3px solid white;
|
||||
}
|
||||
|
||||
.keyboard-key:active {
|
||||
background: #808080;
|
||||
}
|
||||
|
||||
.keyboard-subkeys {
|
||||
color: white;
|
||||
padding: 5px;
|
||||
-arrow-border-radius: 10px;
|
||||
-arrow-background-color: #090909;
|
||||
-arrow-border-width: 2px;
|
||||
-arrow-border-color: white;
|
||||
-arrow-base: 20px;
|
||||
-arrow-rise: 10px;
|
||||
}
|
||||
|
@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6503"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="mosaic-view-active.svg">
|
||||
<defs
|
||||
id="defs6505">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6511" />
|
||||
<inkscape:perspective
|
||||
id="perspective6494"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="-15.97056"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6508">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-16)">
|
||||
<g
|
||||
style="display:inline;fill:#cbcbcb;fill-opacity:1"
|
||||
transform="translate(-449.85476,-685.85869)"
|
||||
id="g5306">
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none"
|
||||
id="rect5308"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
|
||||
id="rect5310"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999976000000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
|
||||
id="rect5312"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
|
||||
id="rect5314"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.7 KiB |
@ -1,113 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6503"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="New document 19">
|
||||
<defs
|
||||
id="defs6505">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6511" />
|
||||
<inkscape:perspective
|
||||
id="perspective6494"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="16"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6508">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-16)">
|
||||
<g
|
||||
style="display:inline"
|
||||
transform="translate(-449.85476,-685.85869)"
|
||||
id="g5306">
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none"
|
||||
id="rect5308"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
|
||||
id="rect5310"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
|
||||
id="rect5312"
|
||||
width="11"
|
||||
height="7"
|
||||
x="450.5"
|
||||
y="702.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
<rect
|
||||
style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
|
||||
id="rect5314"
|
||||
width="11"
|
||||
height="7"
|
||||
x="462.5"
|
||||
y="710.5"
|
||||
rx="0.99999958"
|
||||
ry="1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.6 KiB |
@ -1,89 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="98"
|
||||
height="98"
|
||||
id="svg6375"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="add-workspace.svg">
|
||||
<defs
|
||||
id="defs6377">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6383" />
|
||||
<inkscape:perspective
|
||||
id="perspective6366"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.9590209"
|
||||
inkscape:cx="56.650687"
|
||||
inkscape:cy="20.635343"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6380">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,66)">
|
||||
<g
|
||||
id="g2824"
|
||||
transform="matrix(11.568551,0,0,11.698271,-78.828159,-304.81518)">
|
||||
<path
|
||||
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
|
||||
d="m 11.07363,21.36834 0,6.43903"
|
||||
id="path5322" />
|
||||
<path
|
||||
style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
d="m 14.29314,24.58786 -6.43902,0"
|
||||
id="path5324" />
|
||||
</g>
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:0.98823529"
|
||||
d="m 48.239516,97.908047 c -0.41677,-0.05102 -1.269253,-0.222408 -1.894408,-0.380859 -4.088493,-1.036262 -7.520781,-4.753234 -8.330163,-9.021094 -0.154947,-0.817026 -0.257819,-6.68112 -0.257819,-14.696556 l 0,-13.337088 -13.829177,-0.08909 C 10.802042,60.298796 10.026884,60.268266 8.6851548,59.783022 3.6288503,57.954375 0.62673331,53.828648 0.62673331,48.708554 c 0,-5.625522 4.25936019,-10.425065 9.97721469,-11.242548 0.987903,-0.141242 7.368912,-0.254994 14.460646,-0.257791 l 12.692532,-0.005 0,-13.586668 c 0,-14.6441583 0.03287,-15.0698926 1.364686,-17.6753047 2.185477,-4.2754229 6.938193,-6.75739913 11.687647,-6.10355607 3.382776,0.46569661 6.737962,2.72496967 8.414081,5.66577137 1.480816,2.5981315 1.519067,3.0522448 1.519067,18.0333334 l 0,13.666424 12.692533,0.005 c 7.091733,0.0028 13.472742,0.116549 14.460646,0.257791 6.395303,0.914337 10.804785,6.623716 9.941157,12.871766 -0.698243,5.051565 -4.792685,9.104635 -9.941157,9.840713 -0.987904,0.141242 -7.368913,0.254995 -14.460646,0.257791 l -12.692533,0.005 0,13.801945 c 0,13.031417 -0.02798,13.895893 -0.501177,15.484801 -1.526902,5.127058 -6.919246,8.802262 -12.001914,8.18002 z"
|
||||
id="path2828"
|
||||
transform="translate(0,-66)" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 4.0 KiB |
@ -2,24 +2,62 @@
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="119.97824"
|
||||
height="119.97824"
|
||||
id="svg7355"
|
||||
version="1.1">
|
||||
version="1.1"
|
||||
inkscape:version="0.48.1 r9760"
|
||||
sodipodi:docname="running-indicator.svg">
|
||||
<metadata
|
||||
id="metadata4175">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#2c1cff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1141"
|
||||
id="namedview4173"
|
||||
showgrid="false"
|
||||
inkscape:zoom="8.1348081"
|
||||
inkscape:cx="81.120662"
|
||||
inkscape:cy="58.117986"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g30864" />
|
||||
<defs
|
||||
id="defs7357">
|
||||
<radialGradient
|
||||
xlink:href="#linearGradient36429"
|
||||
id="radialGradient7461"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0525552,0,0,1.0525552,-2.5162753,-9.0000838)"
|
||||
cx="47.878681"
|
||||
cy="171.25"
|
||||
fx="47.878681"
|
||||
fy="171.25"
|
||||
gradientTransform="matrix(1.011539,0,0,0.57582113,-0.39262194,71.83807)"
|
||||
cx="47.428951"
|
||||
cy="167.16817"
|
||||
fx="47.428951"
|
||||
fy="167.16817"
|
||||
r="37" />
|
||||
<linearGradient
|
||||
id="linearGradient36429">
|
||||
@ -59,7 +97,7 @@
|
||||
fx="49.067139"
|
||||
cy="242.50381"
|
||||
cx="49.067139"
|
||||
gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
|
||||
gradientTransform="matrix(1.1891549,0,0,0.15252127,-9.281289,132.52772)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient7488"
|
||||
xlink:href="#linearGradient36471" />
|
||||
@ -72,19 +110,21 @@
|
||||
id="g30864"
|
||||
transform="translate(255.223,70.118091)">
|
||||
<rect
|
||||
ry="3.5996203"
|
||||
rx="3.5996203"
|
||||
y="98"
|
||||
x="11"
|
||||
height="74"
|
||||
width="74"
|
||||
ry="3.4593496"
|
||||
rx="3.4593496"
|
||||
y="99.596962"
|
||||
x="12.596948"
|
||||
height="71.116341"
|
||||
width="71.116341"
|
||||
id="rect14000"
|
||||
style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
|
||||
style="opacity:0.37187500000000001;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
id="rect34520"
|
||||
d="m 84.506708,167.95508 c 6e-6,1.96759 -1.584022,3.55162 -3.551629,3.55163 l -65.910146,0 c -1.967608,-1e-5 -3.551648,-1.58402 -3.551643,-3.55164"
|
||||
style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1"
|
||||
inkscape:connector-curvature="0" />
|
||||
d="m 83.273151,166.72152 c 0,1.96759 -1.584022,3.55163 -3.551629,3.55163 l -63.443032,0 c -1.967608,0 -3.551648,-1.58402 -3.551643,-3.55164 0,-5.85318 0,-5.85318 0,0"
|
||||
style="opacity:0.35;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1"
|
||||
connector-curvature="0"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccscc" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 225 B |
Before Width: | Height: | Size: 225 B |
Before Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 211 B |
@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="5.8600588"
|
||||
height="9"
|
||||
id="svg3647"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="section-more.svg">
|
||||
<defs
|
||||
id="defs3649">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3655" />
|
||||
<inkscape:perspective
|
||||
id="perspective3603"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="82.777778"
|
||||
inkscape:cx="2.9300294"
|
||||
inkscape:cy="5.466443"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata3652">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-262.78425,-490.71933)">
|
||||
<path
|
||||
transform="matrix(0,-0.98149546,0.71467449,0,25.404986,578.15569)"
|
||||
d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="1.5707963"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="5"
|
||||
sodipodi:cy="337.5"
|
||||
sodipodi:cx="84.5"
|
||||
sodipodi:sides="3"
|
||||
id="path5497-5"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
sodipodi:type="star" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.8 KiB |
@ -1,87 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="5.8600588"
|
||||
height="9"
|
||||
id="svg3647"
|
||||
version="1.1"
|
||||
inkscape:version="0.46+devel"
|
||||
sodipodi:docname="New document 6">
|
||||
<defs
|
||||
id="defs3649">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
id="perspective3655" />
|
||||
<inkscape:perspective
|
||||
id="perspective3603"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="112.21575"
|
||||
inkscape:cy="-32.642856"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="609"
|
||||
inkscape:window-height="501"
|
||||
inkscape:window-x="164"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata3652">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-262.78425,-490.71933)">
|
||||
<path
|
||||
transform="matrix(0,0.98149546,-0.71467449,0,506.02358,412.28296)"
|
||||
d="M 88.830127,340 80.169873,340 84.5,332.5 88.830127,340 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:arg2="1.5707963"
|
||||
sodipodi:arg1="0.52359878"
|
||||
sodipodi:r2="2.5"
|
||||
sodipodi:r1="5"
|
||||
sodipodi:cy="337.5"
|
||||
sodipodi:cx="84.5"
|
||||
sodipodi:sides="3"
|
||||
id="path5497-5"
|
||||
style="fill:#5f5f5f;fill-opacity:1;stroke:#5f5f5f;stroke-width:0.59699643;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
sodipodi:type="star" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 531 B |
@ -1,81 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6446"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="single-view-active.svg">
|
||||
<defs
|
||||
id="defs6448">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6454" />
|
||||
<inkscape:perspective
|
||||
id="perspective6441"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="0.014720032"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6451">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-17)">
|
||||
<rect
|
||||
ry="0.5"
|
||||
rx="0.49999979"
|
||||
y="17.483809"
|
||||
x="0.53483802"
|
||||
height="15"
|
||||
width="23"
|
||||
id="rect5304"
|
||||
style="fill:#cccccc;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.4 KiB |
@ -1,81 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="16"
|
||||
id="svg6446"
|
||||
version="1.1"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
sodipodi:docname="single-view.svg">
|
||||
<defs
|
||||
id="defs6448">
|
||||
<inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 16 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="32 : 16 : 1"
|
||||
inkscape:persp3d-origin="16 : 10.666667 : 1"
|
||||
id="perspective6454" />
|
||||
<inkscape:perspective
|
||||
id="perspective6441"
|
||||
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
|
||||
inkscape:vp_z="1 : 0.5 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 0.5 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="11.197802"
|
||||
inkscape:cx="0.014720032"
|
||||
inkscape:cy="16"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:window-height="997"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata6451">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
transform="translate(0,-17)">
|
||||
<rect
|
||||
ry="0.5"
|
||||
rx="0.49999979"
|
||||
y="17.483809"
|
||||
x="0.53483802"
|
||||
height="15"
|
||||
width="23"
|
||||
id="rect5304"
|
||||
style="fill:#626262;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 2.4 KiB |
@ -13,8 +13,8 @@
|
||||
height="22"
|
||||
id="svg3199"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="New document 11">
|
||||
inkscape:version="0.48.1 r9760"
|
||||
sodipodi:docname="toggle-on-intl.svg">
|
||||
<defs
|
||||
id="defs3201">
|
||||
<inkscape:perspective
|
||||
@ -39,14 +39,14 @@
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.35"
|
||||
inkscape:cx="32.500004"
|
||||
inkscape:cy="10.999997"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="49.147112"
|
||||
inkscape:cy="17.532036"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="609"
|
||||
inkscape:window-height="501"
|
||||
inkscape:window-width="1412"
|
||||
inkscape:window-height="1067"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="0" />
|
||||
@ -58,7 +58,7 @@
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
@ -72,7 +72,7 @@
|
||||
transform="translate(-453.5,448.36218)"
|
||||
id="g16453">
|
||||
<rect
|
||||
style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
style="color:#000000;fill:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect16256-9-4"
|
||||
width="63.000004"
|
||||
height="19"
|
||||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
@ -13,8 +13,8 @@
|
||||
height="22"
|
||||
id="svg2857"
|
||||
version="1.1"
|
||||
inkscape:version="0.47 r22583"
|
||||
sodipodi:docname="New document 2">
|
||||
inkscape:version="0.48.1 r9760"
|
||||
sodipodi:docname="toggle-on-us.svg">
|
||||
<defs
|
||||
id="defs2859">
|
||||
<inkscape:perspective
|
||||
@ -40,16 +40,18 @@
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="-69.642856"
|
||||
inkscape:cy="42.428569"
|
||||
inkscape:cx="19.689855"
|
||||
inkscape:cy="2.0517979"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="609"
|
||||
inkscape:window-height="501"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:window-maximized="0" />
|
||||
inkscape:window-width="941"
|
||||
inkscape:window-height="751"
|
||||
inkscape:window-x="2577"
|
||||
inkscape:window-y="206"
|
||||
inkscape:window-maximized="0"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false" />
|
||||
<metadata
|
||||
id="metadata2862">
|
||||
<rdf:RDF>
|
||||
@ -58,7 +60,7 @@
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
@ -72,7 +74,7 @@
|
||||
transform="translate(-351.35714,708.36218)"
|
||||
id="g16453">
|
||||
<rect
|
||||
style="color:#000000;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
style="color:#000000;fill:#4a90d9;fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
|
||||
id="rect16256-9-4"
|
||||
width="63.000004"
|
||||
height="19"
|
||||
|
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.8 KiB |
@ -10,11 +10,14 @@ nobase_dist_js_DATA = \
|
||||
misc/history.js \
|
||||
misc/modemManager.js \
|
||||
misc/params.js \
|
||||
misc/screenSaver.js \
|
||||
misc/util.js \
|
||||
perf/core.js \
|
||||
ui/altTab.js \
|
||||
ui/appDisplay.js \
|
||||
ui/appFavorites.js \
|
||||
ui/automountManager.js \
|
||||
ui/autorunManager.js \
|
||||
ui/boxpointer.js \
|
||||
ui/calendar.js \
|
||||
ui/chrome.js \
|
||||
@ -27,6 +30,8 @@ nobase_dist_js_DATA = \
|
||||
ui/environment.js \
|
||||
ui/extensionSystem.js \
|
||||
ui/iconGrid.js \
|
||||
ui/keyboard.js \
|
||||
ui/layout.js \
|
||||
ui/lightbox.js \
|
||||
ui/link.js \
|
||||
ui/lookingGlass.js \
|
||||
@ -35,6 +40,7 @@ nobase_dist_js_DATA = \
|
||||
ui/main.js \
|
||||
ui/messageTray.js \
|
||||
ui/modalDialog.js \
|
||||
ui/shellMountOperation.js \
|
||||
ui/notificationDaemon.js \
|
||||
ui/overview.js \
|
||||
ui/panel.js \
|
||||
|
@ -109,7 +109,8 @@ const SessionManagerIface = {
|
||||
name: 'org.gnome.SessionManager',
|
||||
methods: [
|
||||
{ name: 'Logout', inSignature: 'u', outSignature: '' },
|
||||
{ name: 'Shutdown', inSignature: '', outSignature: '' }
|
||||
{ name: 'Shutdown', inSignature: '', outSignature: '' },
|
||||
{ name: 'CanShutdown', inSignature: '', outSignature: 'b' }
|
||||
]
|
||||
};
|
||||
|
||||
|
@ -77,9 +77,9 @@ HistoryManager.prototype = {
|
||||
this._history[this._history.length - 1] != input) {
|
||||
|
||||
this._history.push(input);
|
||||
this._historyIndex = this._history.length;
|
||||
this._save();
|
||||
}
|
||||
}
|
||||
this._historyIndex = this._history.length;
|
||||
},
|
||||
|
||||
_onEntryKeyPress: function(entry, event) {
|
||||
|
53
js/misc/screenSaver.js
Normal file
@ -0,0 +1,53 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const ScreenSaverIface = {
|
||||
name: 'org.gnome.ScreenSaver',
|
||||
methods: [{ name: 'GetActive',
|
||||
inSignature: '',
|
||||
outSignature: 'b' },
|
||||
{ name: 'Lock',
|
||||
inSignature: '' },
|
||||
{ name: 'SetActive',
|
||||
inSignature: 'b' }],
|
||||
signals: [{ name: 'ActiveChanged',
|
||||
inSignature: 'b' }]
|
||||
};
|
||||
|
||||
function ScreenSaverProxy() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
ScreenSaverProxy.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this,
|
||||
'org.gnome.ScreenSaver',
|
||||
'/org/gnome/ScreenSaver');
|
||||
|
||||
DBus.session.watch_name('org.gnome.ScreenSaver',
|
||||
false, // do not launch a name-owner if none exists
|
||||
Lang.bind(this, this._onSSAppeared),
|
||||
Lang.bind(this, this._onSSVanished));
|
||||
|
||||
this.screenSaverActive = false;
|
||||
this.connect('ActiveChanged',
|
||||
Lang.bind(this, this._onActiveChanged));
|
||||
},
|
||||
|
||||
_onSSAppeared: function(owner) {
|
||||
this.GetActiveRemote(Lang.bind(this, function(isActive) {
|
||||
this.screenSaverActive = isActive;
|
||||
}))
|
||||
},
|
||||
|
||||
_onSSVanished: function(oldOwner) {
|
||||
this.screenSaverActive = false;
|
||||
},
|
||||
|
||||
_onActiveChanged: function(object, isActive) {
|
||||
this.screenSaverActive = isActive;
|
||||
}
|
||||
};
|
||||
DBus.proxifyPrototype(ScreenSaverProxy.prototype, ScreenSaverIface);
|
@ -7,9 +7,6 @@ const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
/* http://daringfireball.net/2010/07/improved_regex_for_matching_urls */
|
||||
const _urlRegexp = new RegExp('\\b(([a-z][\\w-]+:(/{1,3}|[a-z0-9%])|www\\d{0,3}[.]|[a-z0-9.\\-]+[.][a-z]{2,4}/)([^\\s()<>]+|\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\))+(\\(([^\\s()<>]+|(\\([^\\s()<>]+\\)))*\\)|[^\\s`!()\\[\\]{};:\'\\".,<>?«»“”‘’]))', 'gi');
|
||||
|
||||
@ -48,7 +45,7 @@ function spawn(argv) {
|
||||
// occur when trying to parse or start the program.
|
||||
function spawnCommandLine(command_line) {
|
||||
try {
|
||||
let [success, argc, argv] = GLib.shell_parse_argv(command_line);
|
||||
let [success, argv] = GLib.shell_parse_argv(command_line);
|
||||
trySpawn(argv);
|
||||
} catch (err) {
|
||||
_handleSpawnError(command_line, err);
|
||||
@ -88,10 +85,10 @@ function trySpawn(argv)
|
||||
// Runs @command_line in the background. If launching @command_line
|
||||
// fails, this will throw an error.
|
||||
function trySpawnCommandLine(command_line) {
|
||||
let success, argc, argv;
|
||||
let success, argv;
|
||||
|
||||
try {
|
||||
[success, argc, argv] = GLib.shell_parse_argv(command_line);
|
||||
[success, argv] = GLib.shell_parse_argv(command_line);
|
||||
} catch (err) {
|
||||
// Replace "Error invoking GLib.shell_parse_argv: " with
|
||||
// something nicer
|
||||
@ -150,7 +147,7 @@ const _IGNORED_WORDS = [
|
||||
'Incorporated',
|
||||
'Ltd.',
|
||||
'Limited.',
|
||||
'Intel?',
|
||||
'Intel',
|
||||
'chipset',
|
||||
'adapter',
|
||||
'[hex]',
|
||||
@ -181,7 +178,7 @@ const _IGNORED_PHRASES = [
|
||||
];
|
||||
|
||||
function fixupPCIDescription(desc) {
|
||||
desc.replace(/[_,]/, ' ');
|
||||
desc = desc.replace(/[_,]/, ' ');
|
||||
|
||||
/* Attempt to shorten ID by ignoring certain phrases */
|
||||
for (let i = 0; i < _IGNORED_PHRASES.length; i++) {
|
||||
@ -197,7 +194,7 @@ function fixupPCIDescription(desc) {
|
||||
/* Attmept to shorten ID by ignoring certain individual words */
|
||||
let words = desc.split(' ');
|
||||
let out = [ ];
|
||||
for (let i = 0; i < words; i++) {
|
||||
for (let i = 0; i < words.length; i++) {
|
||||
let item = words[i];
|
||||
|
||||
// skip empty items (that come out from consecutive spaces)
|
||||
|
109
js/ui/altTab.js
@ -14,7 +14,8 @@ const Tweener = imports.ui.tweener;
|
||||
|
||||
const POPUP_APPICON_SIZE = 96;
|
||||
const POPUP_SCROLL_TIME = 0.10; // seconds
|
||||
const POPUP_FADE_TIME = 0.1; // seconds
|
||||
const POPUP_FADE_IN_TIME = 0.4; // seconds
|
||||
const POPUP_FADE_OUT_TIME = 0.1; // seconds
|
||||
|
||||
const APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
|
||||
|
||||
@ -74,7 +75,7 @@ AltTabPopup.prototype = {
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
|
||||
let rightPadding = this.actor.get_theme_node().get_padding(St.Side.RIGHT);
|
||||
@ -87,7 +88,7 @@ AltTabPopup.prototype = {
|
||||
let [childMinHeight, childNaturalHeight] = this._appSwitcher.actor.get_preferred_height(primary.width - hPadding);
|
||||
let [childMinWidth, childNaturalWidth] = this._appSwitcher.actor.get_preferred_width(childNaturalHeight);
|
||||
childBox.x1 = Math.max(primary.x + leftPadding, primary.x + Math.floor((primary.width - childNaturalWidth) / 2));
|
||||
childBox.x2 = Math.min(primary.x + primary.width - hPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||
this._appSwitcher.actor.allocate(childBox, flags);
|
||||
@ -97,8 +98,6 @@ AltTabPopup.prototype = {
|
||||
// those calculations
|
||||
if (this._thumbnails) {
|
||||
let icon = this._appIcons[this._currentApp].actor;
|
||||
// Force a stage relayout to make sure we get the correct position
|
||||
global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, 0, 0);
|
||||
let [posX, posY] = icon.get_transformed_position();
|
||||
let thumbnailCenter = posX + icon.width / 2;
|
||||
let [childMinWidth, childNaturalWidth] = this._thumbnails.actor.get_preferred_width(-1);
|
||||
@ -121,7 +120,7 @@ AltTabPopup.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
show : function(backward, switch_group) {
|
||||
show : function(backward, binding) {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let apps = tracker.get_running_apps ('');
|
||||
|
||||
@ -145,8 +144,14 @@ AltTabPopup.prototype = {
|
||||
|
||||
this._appIcons = this._appSwitcher.icons;
|
||||
|
||||
// Need to force an allocation so we can figure out whether we
|
||||
// need to scroll when selecting
|
||||
this.actor.opacity = 0;
|
||||
this.actor.show();
|
||||
this.actor.get_allocation_box();
|
||||
|
||||
// Make the initial selection
|
||||
if (switch_group) {
|
||||
if (binding == 'switch_group') {
|
||||
if (backward) {
|
||||
this._select(0, this._appIcons[0].cachedWindows.length - 1);
|
||||
} else {
|
||||
@ -155,30 +160,16 @@ AltTabPopup.prototype = {
|
||||
else
|
||||
this._select(0, 0);
|
||||
}
|
||||
} else if (binding == 'switch_group_backward') {
|
||||
this._select(0, this._appIcons[0].cachedWindows.length - 1);
|
||||
} else if (binding == 'switch_windows_backward') {
|
||||
this._select(this._appIcons.length - 1);
|
||||
} else if (this._appIcons.length == 1) {
|
||||
if (!backward && this._appIcons[0].cachedWindows.length > 1) {
|
||||
// For compatibility with the multi-app case below
|
||||
this._select(0, 1, true);
|
||||
} else
|
||||
this._select(0);
|
||||
this._select(0);
|
||||
} else if (backward) {
|
||||
this._select(this._appIcons.length - 1);
|
||||
} else {
|
||||
let firstWindows = this._appIcons[0].cachedWindows;
|
||||
if (firstWindows.length > 1) {
|
||||
let curAppNextWindow = firstWindows[1];
|
||||
let nextAppWindow = this._appIcons[1].cachedWindows[0];
|
||||
|
||||
// If the next window of the current app is more-recently-used
|
||||
// than the first window of the next app, then select it.
|
||||
if (curAppNextWindow.get_workspace() == global.screen.get_active_workspace() &&
|
||||
curAppNextWindow.get_user_time() > nextAppWindow.get_user_time())
|
||||
this._select(0, 1, true);
|
||||
else
|
||||
this._select(1);
|
||||
} else {
|
||||
this._select(1);
|
||||
}
|
||||
this._select(1);
|
||||
}
|
||||
|
||||
// There's a race condition; if the user released Alt before
|
||||
@ -192,12 +183,15 @@ AltTabPopup.prototype = {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.actor.opacity = 0;
|
||||
this.actor.show();
|
||||
// Using easeInOutExpo over 400ms gives us 150ms of "nearly
|
||||
// invisible" (less than 10% opacity), followed by a 100ms
|
||||
// tween in (to 90% opacity, with the last 10% coming over the
|
||||
// next 150ms). So if the user releases Alt quickly after we
|
||||
// start tweening, they'll never see the switcher.
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: POPUP_FADE_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
time: POPUP_FADE_IN_TIME,
|
||||
transition: 'easeInOutExpo'
|
||||
});
|
||||
|
||||
return true;
|
||||
@ -233,33 +227,25 @@ AltTabPopup.prototype = {
|
||||
|
||||
this._disableHover();
|
||||
|
||||
if (action == Meta.KeyBindingAction.SWITCH_GROUP)
|
||||
this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow());
|
||||
else if (keysym == Clutter.Escape)
|
||||
if (keysym == Clutter.Escape) {
|
||||
this.destroy();
|
||||
else if (this._thumbnailsFocused) {
|
||||
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
|
||||
if (backwards) {
|
||||
if (this._currentWindow == 0 || this._currentWindow == -1)
|
||||
this._select(this._previousApp());
|
||||
else
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
} else {
|
||||
if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
|
||||
this._select(this._nextApp());
|
||||
else
|
||||
this._select(this._currentApp, this._nextWindow());
|
||||
}
|
||||
else if (keysym == Clutter.Left)
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP) {
|
||||
this._select(this._currentApp, backwards ? this._previousWindow() : this._nextWindow());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD) {
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS) {
|
||||
this._select(backwards ? this._previousApp() : this._nextApp());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD) {
|
||||
this._select(this._previousApp());
|
||||
} else if (this._thumbnailsFocused) {
|
||||
if (keysym == Clutter.Left)
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
else if (keysym == Clutter.Right)
|
||||
this._select(this._currentApp, this._nextWindow());
|
||||
else if (keysym == Clutter.Up)
|
||||
this._select(this._currentApp, null, true);
|
||||
} else {
|
||||
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS)
|
||||
this._select(backwards ? this._previousApp() : this._nextApp());
|
||||
else if (keysym == Clutter.Left)
|
||||
if (keysym == Clutter.Left)
|
||||
this._select(this._previousApp());
|
||||
else if (keysym == Clutter.Right)
|
||||
this._select(this._nextApp());
|
||||
@ -388,7 +374,7 @@ AltTabPopup.prototype = {
|
||||
if (this.actor.visible) {
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 0,
|
||||
time: POPUP_FADE_TIME,
|
||||
time: POPUP_FADE_OUT_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
@ -601,7 +587,7 @@ SwitcherList.prototype = {
|
||||
this._rightArrow.opacity = this._rightGradient.opacity;
|
||||
},
|
||||
|
||||
addItem : function(item) {
|
||||
addItem : function(item, label) {
|
||||
let bbox = new St.Button({ style_class: 'item-box',
|
||||
reactive: true });
|
||||
|
||||
@ -612,6 +598,8 @@ SwitcherList.prototype = {
|
||||
bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
|
||||
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
|
||||
|
||||
bbox.label_actor = label;
|
||||
|
||||
this._items.push(bbox);
|
||||
},
|
||||
|
||||
@ -644,7 +632,7 @@ SwitcherList.prototype = {
|
||||
this._items[this._highlighted].add_style_pseudo_class('selected');
|
||||
}
|
||||
|
||||
let monitor = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
let itemSize = this._items[index].allocation.x2 - this._items[index].allocation.x1;
|
||||
let [posX, posY] = this._items[index].get_transformed_position();
|
||||
posX += this.actor.x;
|
||||
@ -672,7 +660,7 @@ SwitcherList.prototype = {
|
||||
|
||||
_scrollToRight : function() {
|
||||
this._scrollableLeft = true;
|
||||
let monitor = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
let padding = this.actor.get_theme_node().get_horizontal_padding();
|
||||
let parentPadding = this.actor.get_parent().get_theme_node().get_horizontal_padding();
|
||||
let x = this._items[this._highlighted].allocation.x2 - monitor.width + padding + parentPadding;
|
||||
@ -769,7 +757,7 @@ SwitcherList.prototype = {
|
||||
let children = this._list.get_children();
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let parentRightPadding = this.actor.get_parent().get_theme_node().get_padding(St.Side.RIGHT);
|
||||
if (this.actor.allocation.x2 == primary.x + primary.width - parentRightPadding) {
|
||||
if (this._squareItems)
|
||||
@ -899,7 +887,7 @@ AppSwitcher.prototype = {
|
||||
totalSpacing += this._separator.width + this._list.spacing;
|
||||
|
||||
// We just assume the whole screen here due to weirdness happing with the passed width
|
||||
let primary = global.get_primary_monitor();
|
||||
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;
|
||||
@ -997,7 +985,7 @@ AppSwitcher.prototype = {
|
||||
|
||||
_addIcon : function(appIcon) {
|
||||
this.icons.push(appIcon);
|
||||
this.addItem(appIcon.actor);
|
||||
this.addItem(appIcon.actor, appIcon.label);
|
||||
|
||||
let n = this._arrows.length;
|
||||
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
||||
@ -1067,9 +1055,12 @@ ThumbnailList.prototype = {
|
||||
this._labels.push(bin);
|
||||
bin.add_actor(name);
|
||||
box.add_actor(bin);
|
||||
|
||||
this.addItem(box, name);
|
||||
} else {
|
||||
this.addItem(box, null);
|
||||
}
|
||||
|
||||
this.addItem(box);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -6,10 +6,9 @@ const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
const DND = imports.ui.dnd;
|
||||
@ -22,6 +21,7 @@ const Tweener = imports.ui.tweener;
|
||||
const Workspace = imports.ui.workspace;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
const MAX_APPLICATION_WORK_MILLIS = 75;
|
||||
const MENU_POPUP_TIMEOUT = 600;
|
||||
const SCROLL_TIME = 0.1;
|
||||
|
||||
@ -34,6 +34,8 @@ AlphabeticalView.prototype = {
|
||||
this._grid = new IconGrid.IconGrid({ xAlign: St.Align.START });
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
|
||||
this._pendingAppLaterId = 0;
|
||||
this._apps = [];
|
||||
this._filterApp = null;
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
@ -42,7 +44,7 @@ AlphabeticalView.prototype = {
|
||||
this.actor = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
y_align: St.Align.START,
|
||||
vfade: true });
|
||||
style_class: 'vfade' });
|
||||
this.actor.add_actor(box);
|
||||
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this.actor.connect('notify::mapped', Lang.bind(this,
|
||||
@ -109,6 +111,30 @@ AlphabeticalView.prototype = {
|
||||
this._apps[i].actor.visible = filter(this._apps[i]._appInfo);
|
||||
},
|
||||
|
||||
// Create actors for the applications in an idle to avoid blocking
|
||||
// for too long; see bug 647778
|
||||
_addPendingApps: function() {
|
||||
let i;
|
||||
let startTimeMillis = new Date().getTime();
|
||||
for (i = 0; i < this._pendingAppIds.length; i++) {
|
||||
let id = this._pendingAppIds[i];
|
||||
this._addApp(this._pendingApps[id]);
|
||||
|
||||
let currentTimeMillis = new Date().getTime();
|
||||
if (currentTimeMillis - startTimeMillis > MAX_APPLICATION_WORK_MILLIS)
|
||||
break;
|
||||
}
|
||||
this._pendingAppIds.splice(0, i + 1);
|
||||
if (this._pendingAppIds.length > 0) {
|
||||
return true;
|
||||
} else {
|
||||
this._pendingAppLaterId = 0;
|
||||
this._pendingAppIds = null;
|
||||
this._pendingApps = null;
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
refresh: function(apps) {
|
||||
let ids = [];
|
||||
for (let i in apps)
|
||||
@ -119,9 +145,12 @@ AlphabeticalView.prototype = {
|
||||
|
||||
this._removeAll();
|
||||
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
this._addApp(apps[ids[i]]);
|
||||
}
|
||||
this._pendingAppIds = ids;
|
||||
this._pendingApps = apps;
|
||||
if (this._pendingAppLaterId)
|
||||
Meta.later_remove(this._pendingAppLaterId);
|
||||
this._pendingAppLaterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this, this._addPendingApps));
|
||||
}
|
||||
};
|
||||
|
||||
@ -143,10 +172,12 @@ ViewByCategories.prototype = {
|
||||
// (used only before the actor is mapped the first time)
|
||||
this._currentCategory = -2;
|
||||
this._filters = new St.BoxLayout({ vertical: true, reactive: true });
|
||||
this._filters.connect('scroll-event', Lang.bind(this, this._scrollFilter));
|
||||
|
||||
this._filtersBox = new St.ScrollView({ x_fill: false,
|
||||
y_fill: false,
|
||||
style_class: 'vfade' });
|
||||
this._filtersBox.add_actor(this._filters);
|
||||
this.actor.add(this._view.actor, { expand: true, x_fill: true, y_fill: true });
|
||||
this.actor.add(this._filters, { expand: false, y_fill: false, y_align: St.Align.START });
|
||||
this.actor.add(this._filtersBox, { expand: false, y_fill: false, y_align: St.Align.START });
|
||||
|
||||
// Always select the "All" filter when switching to the app view
|
||||
this.actor.connect('notify::mapped', Lang.bind(this,
|
||||
@ -164,14 +195,6 @@ ViewByCategories.prototype = {
|
||||
this.actor.add(this._focusDummy);
|
||||
},
|
||||
|
||||
_scrollFilter: function(actor, event) {
|
||||
let direction = event.get_scroll_direction();
|
||||
if (direction == Clutter.ScrollDirection.UP)
|
||||
this._selectCategory(Math.max(this._currentCategory - 1, -1))
|
||||
else if (direction == Clutter.ScrollDirection.DOWN)
|
||||
this._selectCategory(Math.min(this._currentCategory + 1, this._sections.length - 1));
|
||||
},
|
||||
|
||||
_selectCategory: function(num) {
|
||||
if (this._currentCategory == num) // nothing to do
|
||||
return;
|
||||
@ -224,7 +247,6 @@ ViewByCategories.prototype = {
|
||||
|
||||
let sections = this._appSystem.get_sections();
|
||||
this._apps = apps;
|
||||
this._view.refresh(apps);
|
||||
|
||||
/* Translators: Filter to display all applications */
|
||||
this._addFilter(_("All"), -1);
|
||||
@ -236,6 +258,7 @@ ViewByCategories.prototype = {
|
||||
this._addFilter(sections[i], i);
|
||||
|
||||
this._selectCategory(-1);
|
||||
this._view.refresh(apps);
|
||||
|
||||
if (this._focusDummy) {
|
||||
let focused = this._focusDummy.has_key_focus();
|
||||
@ -304,8 +327,16 @@ BaseAppSearchProvider.prototype = {
|
||||
params = Params.parse(params, { workspace: null,
|
||||
timestamp: null });
|
||||
|
||||
let workspace = params.workspace ? params.workspace.index() : -1;
|
||||
let event = Clutter.get_current_event();
|
||||
let modifiers = event ? Shell.get_event_state(event) : 0;
|
||||
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
|
||||
|
||||
let app = this._appSys.get_app(id);
|
||||
app.activate(params.workspace ? params.workspace.index() : -1);
|
||||
if (openNewWindow)
|
||||
app.open_new_window(workspace);
|
||||
else
|
||||
app.activate(workspace);
|
||||
},
|
||||
|
||||
dragActivateResult: function(id, params) {
|
||||
@ -313,7 +344,7 @@ BaseAppSearchProvider.prototype = {
|
||||
timestamp: null });
|
||||
|
||||
let app = this._appSys.get_app(id);
|
||||
app.open_new_window(params.workspace ? params.workspace.get_index() : -1);
|
||||
app.open_new_window(params.workspace ? params.workspace.index() : -1);
|
||||
}
|
||||
};
|
||||
|
||||
@ -403,6 +434,8 @@ AppWellIcon.prototype = {
|
||||
this.icon = new AppIcon(app, iconParams);
|
||||
this.actor.set_child(this.icon.actor);
|
||||
|
||||
this.actor.label_actor = this.icon.label;
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));
|
||||
|
@ -3,8 +3,6 @@
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
|
278
js/ui/automountManager.js
Normal file
@ -0,0 +1,278 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Lang = imports.lang;
|
||||
const DBus = imports.dbus;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||
const ScreenSaver = imports.misc.screenSaver;
|
||||
|
||||
// GSettings keys
|
||||
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
|
||||
const SETTING_ENABLE_AUTOMOUNT = 'automount';
|
||||
|
||||
const AUTORUN_EXPIRE_TIMEOUT_SECS = 10;
|
||||
|
||||
const ConsoleKitSessionIface = {
|
||||
name: 'org.freedesktop.ConsoleKit.Session',
|
||||
methods: [{ name: 'IsActive',
|
||||
inSignature: '',
|
||||
outSignature: 'b' }],
|
||||
signals: [{ name: 'ActiveChanged',
|
||||
inSignature: 'b' }]
|
||||
};
|
||||
|
||||
const ConsoleKitSessionProxy = DBus.makeProxyClass(ConsoleKitSessionIface);
|
||||
|
||||
const ConsoleKitManagerIface = {
|
||||
name: 'org.freedesktop.ConsoleKit.Manager',
|
||||
methods: [{ name: 'GetCurrentSession',
|
||||
inSignature: '',
|
||||
outSignature: 'o' }]
|
||||
};
|
||||
|
||||
function ConsoleKitManager() {
|
||||
this._init();
|
||||
};
|
||||
|
||||
ConsoleKitManager.prototype = {
|
||||
_init: function() {
|
||||
this.sessionActive = true;
|
||||
|
||||
DBus.system.proxifyObject(this,
|
||||
'org.freedesktop.ConsoleKit',
|
||||
'/org/freedesktop/ConsoleKit/Manager');
|
||||
|
||||
DBus.system.watch_name('org.freedesktop.ConsoleKit',
|
||||
false, // do not launch a name-owner if none exists
|
||||
Lang.bind(this, this._onManagerAppeared),
|
||||
Lang.bind(this, this._onManagerVanished));
|
||||
},
|
||||
|
||||
_onManagerAppeared: function(owner) {
|
||||
this.GetCurrentSessionRemote(Lang.bind(this, this._onCurrentSession));
|
||||
},
|
||||
|
||||
_onManagerVanished: function(oldOwner) {
|
||||
this.sessionActive = true;
|
||||
},
|
||||
|
||||
_onCurrentSession: function(session) {
|
||||
this._ckSession = new ConsoleKitSessionProxy(DBus.system, 'org.freedesktop.ConsoleKit', session);
|
||||
|
||||
this._ckSession.connect
|
||||
('ActiveChanged', Lang.bind(this, function(object, isActive) {
|
||||
this.sessionActive = isActive;
|
||||
}));
|
||||
this._ckSession.IsActiveRemote(Lang.bind(this, function(isActive) {
|
||||
this.sessionActive = isActive;
|
||||
}));
|
||||
}
|
||||
};
|
||||
DBus.proxifyPrototype(ConsoleKitManager.prototype, ConsoleKitManagerIface);
|
||||
|
||||
function AutomountManager() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AutomountManager.prototype = {
|
||||
_init: function() {
|
||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||
this._volumeQueue = [];
|
||||
|
||||
this.ckListener = new ConsoleKitManager();
|
||||
|
||||
this._ssProxy = new ScreenSaver.ScreenSaverProxy();
|
||||
this._ssProxy.connect('ActiveChanged',
|
||||
Lang.bind(this,
|
||||
this._screenSaverActiveChanged));
|
||||
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
|
||||
this._volumeMonitor.connect('volume-added',
|
||||
Lang.bind(this,
|
||||
this._onVolumeAdded));
|
||||
this._volumeMonitor.connect('volume-removed',
|
||||
Lang.bind(this,
|
||||
this._onVolumeRemoved));
|
||||
this._volumeMonitor.connect('drive-connected',
|
||||
Lang.bind(this,
|
||||
this._onDriveConnected));
|
||||
this._volumeMonitor.connect('drive-disconnected',
|
||||
Lang.bind(this,
|
||||
this._onDriveDisconnected));
|
||||
this._volumeMonitor.connect('drive-eject-button',
|
||||
Lang.bind(this,
|
||||
this._onDriveEjectButton));
|
||||
|
||||
Mainloop.idle_add(Lang.bind(this, this._startupMountAll));
|
||||
},
|
||||
|
||||
_screenSaverActiveChanged: function(object, isActive) {
|
||||
if (!isActive) {
|
||||
this._volumeQueue.forEach(Lang.bind(this, function(volume) {
|
||||
this._checkAndMountVolume(volume);
|
||||
}));
|
||||
}
|
||||
|
||||
// clear the queue anyway
|
||||
this._volumeQueue = [];
|
||||
},
|
||||
|
||||
_startupMountAll: function() {
|
||||
let volumes = this._volumeMonitor.get_volumes();
|
||||
volumes.forEach(Lang.bind(this, function(volume) {
|
||||
this._checkAndMountVolume(volume, { checkSession: false,
|
||||
useMountOp: false });
|
||||
}));
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onDriveConnected: function() {
|
||||
// if we're not in the current ConsoleKit session,
|
||||
// or screensaver is active, don't play sounds
|
||||
if (!this.ckListener.sessionActive)
|
||||
return;
|
||||
|
||||
if (this._ssProxy.screenSaverActive)
|
||||
return;
|
||||
|
||||
global.play_theme_sound(0, 'device-added-media');
|
||||
},
|
||||
|
||||
_onDriveDisconnected: function() {
|
||||
// if we're not in the current ConsoleKit session,
|
||||
// or screensaver is active, don't play sounds
|
||||
if (!this.ckListener.sessionActive)
|
||||
return;
|
||||
|
||||
if (this._ssProxy.screenSaverActive)
|
||||
return;
|
||||
|
||||
global.play_theme_sound(0, 'device-removed-media');
|
||||
},
|
||||
|
||||
_onDriveEjectButton: function(monitor, drive) {
|
||||
// TODO: this code path is not tested, as the GVfs volume monitor
|
||||
// doesn't emit this signal just yet.
|
||||
if (!this.ckListener.sessionActive)
|
||||
return;
|
||||
|
||||
// we force stop/eject in this case, so we don't have to pass a
|
||||
// mount operation object
|
||||
if (drive.can_stop()) {
|
||||
drive.stop
|
||||
(Gio.MountUnmountFlags.FORCE, null, null,
|
||||
Lang.bind(this, function(drive, res) {
|
||||
try {
|
||||
drive.stop_finish(res);
|
||||
} catch (e) {
|
||||
log("Unable to stop the drive after drive-eject-button " + e.toString());
|
||||
}
|
||||
}));
|
||||
} else if (drive.can_eject()) {
|
||||
drive.eject_with_operation
|
||||
(Gio.MountUnmountFlags.FORCE, null, null,
|
||||
Lang.bind(this, function(drive, res) {
|
||||
try {
|
||||
drive.eject_with_operation_finish(res);
|
||||
} catch (e) {
|
||||
log("Unable to eject the drive after drive-eject-button " + e.toString());
|
||||
}
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_onVolumeAdded: function(monitor, volume) {
|
||||
this._checkAndMountVolume(volume);
|
||||
},
|
||||
|
||||
_checkAndMountVolume: function(volume, params) {
|
||||
params = Params.parse(params, { checkSession: true,
|
||||
useMountOp: true });
|
||||
|
||||
if (params.checkSession) {
|
||||
// if we're not in the current ConsoleKit session,
|
||||
// don't attempt automount
|
||||
if (!this.ckListener.sessionActive)
|
||||
return;
|
||||
|
||||
if (this._ssProxy.screenSaverActive) {
|
||||
if (this._volumeQueue.indexOf(volume) == -1)
|
||||
this._volumeQueue.push(volume);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this._settings.get_boolean(SETTING_ENABLE_AUTOMOUNT) ||
|
||||
!volume.should_automount() ||
|
||||
!volume.can_mount()) {
|
||||
// allow the autorun to run anyway; this can happen if the
|
||||
// mount gets added programmatically later, even if
|
||||
// should_automount() or can_mount() are false, like for
|
||||
// blank optical media.
|
||||
this._allowAutorun(volume);
|
||||
this._allowAutorunExpire(volume);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.useMountOp) {
|
||||
let operation = new ShellMountOperation.ShellMountOperation(volume);
|
||||
this._mountVolume(volume, operation.mountOp);
|
||||
} else {
|
||||
this._mountVolume(volume, null);
|
||||
}
|
||||
},
|
||||
|
||||
_mountVolume: function(volume, operation) {
|
||||
this._allowAutorun(volume);
|
||||
volume.mount(0, operation, null,
|
||||
Lang.bind(this, this._onVolumeMounted));
|
||||
},
|
||||
|
||||
_onVolumeMounted: function(volume, res) {
|
||||
this._allowAutorunExpire(volume);
|
||||
|
||||
try {
|
||||
volume.mount_finish(res);
|
||||
} catch (e) {
|
||||
let string = e.toString();
|
||||
|
||||
// FIXME: needs proper error code handling instead of this
|
||||
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
|
||||
if (string.indexOf('No key available with this passphrase') != -1)
|
||||
this._reaskPassword(volume);
|
||||
else
|
||||
log('Unable to mount volume ' + volume.get_name() + ': ' + string);
|
||||
}
|
||||
},
|
||||
|
||||
_onVolumeRemoved: function(monitor, volume) {
|
||||
this._volumeQueue =
|
||||
this._volumeQueue.filter(function(element) {
|
||||
return (element != volume);
|
||||
});
|
||||
},
|
||||
|
||||
_reaskPassword: function(volume) {
|
||||
let operation = new ShellMountOperation.ShellMountOperation(volume, { reaskPassword: true });
|
||||
this._mountVolume(volume, operation.mountOp);
|
||||
},
|
||||
|
||||
_allowAutorun: function(volume) {
|
||||
volume.allowAutorun = true;
|
||||
},
|
||||
|
||||
_allowAutorunExpire: function(volume) {
|
||||
Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, function() {
|
||||
volume.allowAutorun = false;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
634
js/ui/autorunManager.js
Normal file
@ -0,0 +1,634 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Lang = imports.lang;
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||
|
||||
// GSettings keys
|
||||
const SETTINGS_SCHEMA = 'org.gnome.desktop.media-handling';
|
||||
const SETTING_DISABLE_AUTORUN = 'autorun-never';
|
||||
const SETTING_START_APP = 'autorun-x-content-start-app';
|
||||
const SETTING_IGNORE = 'autorun-x-content-ignore';
|
||||
const SETTING_OPEN_FOLDER = 'autorun-x-content-open-folder';
|
||||
|
||||
const AutorunSetting = {
|
||||
RUN: 0,
|
||||
IGNORE: 1,
|
||||
FILES: 2,
|
||||
ASK: 3
|
||||
};
|
||||
|
||||
const HOTPLUG_ICON_SIZE = 16;
|
||||
|
||||
// misc utils
|
||||
function ignoreAutorunForMount(mount) {
|
||||
let root = mount.get_root();
|
||||
let volume = mount.get_volume();
|
||||
|
||||
if ((root.is_native() && !isMountRootHidden(root)) ||
|
||||
(volume && volume.allowAutorun && volume.should_automount()))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function isMountRootHidden(root) {
|
||||
let path = root.get_path();
|
||||
|
||||
// skip any mounts in hidden directory hierarchies
|
||||
return (path.indexOf('/.') != -1);
|
||||
}
|
||||
|
||||
function startAppForMount(app, mount) {
|
||||
let files = [];
|
||||
let root = mount.get_root();
|
||||
let retval = false;
|
||||
|
||||
files.push(root);
|
||||
|
||||
try {
|
||||
retval = app.launch(files,
|
||||
global.create_app_launch_context())
|
||||
} catch (e) {
|
||||
log('Unable to launch the application ' + app.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/******************************************/
|
||||
|
||||
const HotplugSnifferIface = {
|
||||
name: 'org.gnome.Shell.HotplugSniffer',
|
||||
methods: [{ name: 'SniffURI',
|
||||
inSignature: 's',
|
||||
outSignature: 'as' }]
|
||||
};
|
||||
|
||||
const HotplugSniffer = function() {
|
||||
this._init();
|
||||
};
|
||||
|
||||
HotplugSniffer.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.proxifyObject(this,
|
||||
'org.gnome.Shell.HotplugSniffer',
|
||||
'/org/gnome/Shell/HotplugSniffer');
|
||||
},
|
||||
};
|
||||
DBus.proxifyPrototype(HotplugSniffer.prototype, HotplugSnifferIface);
|
||||
|
||||
function ContentTypeDiscoverer(callback) {
|
||||
this._init(callback);
|
||||
}
|
||||
|
||||
ContentTypeDiscoverer.prototype = {
|
||||
_init: function(callback) {
|
||||
this._callback = callback;
|
||||
},
|
||||
|
||||
guessContentTypes: function(mount) {
|
||||
// guess mount's content types using GIO
|
||||
mount.guess_content_type(false, null,
|
||||
Lang.bind(this,
|
||||
this._onContentTypeGuessed));
|
||||
},
|
||||
|
||||
_onContentTypeGuessed: function(mount, res) {
|
||||
let contentTypes = [];
|
||||
|
||||
try {
|
||||
contentTypes = mount.guess_content_type_finish(res);
|
||||
} catch (e) {
|
||||
log('Unable to guess content types on added mount ' + mount.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
|
||||
if (contentTypes.length) {
|
||||
this._emitCallback(mount, contentTypes);
|
||||
} else {
|
||||
let root = mount.get_root();
|
||||
|
||||
let hotplugSniffer = new HotplugSniffer();
|
||||
hotplugSniffer.SniffURIRemote
|
||||
(root.get_uri(), DBus.CALL_FLAG_START,
|
||||
Lang.bind(this, function(contentTypes) {
|
||||
this._emitCallback(mount, contentTypes);
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_emitCallback: function(mount, contentTypes) {
|
||||
if (!contentTypes)
|
||||
contentTypes = [];
|
||||
|
||||
// we're not interested in win32 software content types here
|
||||
contentTypes = contentTypes.filter(function(type) {
|
||||
return (type != 'x-content/win32-software');
|
||||
});
|
||||
|
||||
let apps = [];
|
||||
contentTypes.forEach(function(type) {
|
||||
let app = Gio.app_info_get_default_for_type(type, false);
|
||||
|
||||
if (app)
|
||||
apps.push(app);
|
||||
});
|
||||
|
||||
if (apps.length == 0)
|
||||
apps.push(Gio.app_info_get_default_for_type('inode/directory', false));
|
||||
|
||||
this._callback(mount, apps, contentTypes);
|
||||
}
|
||||
}
|
||||
|
||||
function AutorunManager() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AutorunManager.prototype = {
|
||||
_init: function() {
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
|
||||
this._volumeMonitor.connect('mount-added',
|
||||
Lang.bind(this,
|
||||
this._onMountAdded));
|
||||
this._volumeMonitor.connect('mount-removed',
|
||||
Lang.bind(this,
|
||||
this._onMountRemoved));
|
||||
|
||||
this._transDispatcher = new AutorunTransientDispatcher();
|
||||
this._createResidentSource();
|
||||
|
||||
let mounts = this._volumeMonitor.get_mounts();
|
||||
|
||||
mounts.forEach(Lang.bind(this, function (mount) {
|
||||
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
||||
function (mount, apps) {
|
||||
this._residentSource.addMount(mount, apps);
|
||||
}));
|
||||
|
||||
discoverer.guessContentTypes(mount);
|
||||
}));
|
||||
},
|
||||
|
||||
_createResidentSource: function() {
|
||||
this._residentSource = new AutorunResidentSource();
|
||||
this._residentSource.connect('destroy',
|
||||
Lang.bind(this,
|
||||
this._createResidentSource));
|
||||
},
|
||||
|
||||
_onMountAdded: function(monitor, mount) {
|
||||
// don't do anything if our session is not the currently
|
||||
// active one
|
||||
if (!Main.automountManager.ckListener.sessionActive)
|
||||
return;
|
||||
|
||||
let discoverer = new ContentTypeDiscoverer(Lang.bind (this,
|
||||
function (mount, apps, contentTypes) {
|
||||
this._transDispatcher.addMount(mount, apps, contentTypes);
|
||||
this._residentSource.addMount(mount, apps);
|
||||
}));
|
||||
|
||||
discoverer.guessContentTypes(mount);
|
||||
},
|
||||
|
||||
_onMountRemoved: function(monitor, mount) {
|
||||
this._transDispatcher.removeMount(mount);
|
||||
this._residentSource.removeMount(mount);
|
||||
},
|
||||
|
||||
ejectMount: function(mount) {
|
||||
let mountOp = new ShellMountOperation.ShellMountOperation(mount);
|
||||
|
||||
// first, see if we have a drive
|
||||
let drive = mount.get_drive();
|
||||
let volume = mount.get_volume();
|
||||
|
||||
if (drive &&
|
||||
drive.get_start_stop_type() == Gio.DriveStartStopType.SHUTDOWN &&
|
||||
drive.can_stop()) {
|
||||
drive.stop(0, mountOp.mountOp, null,
|
||||
Lang.bind(this, this._onStop));
|
||||
} else {
|
||||
if (mount.can_eject()) {
|
||||
mount.eject_with_operation(0, mountOp.mountOp, null,
|
||||
Lang.bind(this, this._onEject));
|
||||
} else if (volume && volume.can_eject()) {
|
||||
volume.eject_with_operation(0, mountOp.mountOp, null,
|
||||
Lang.bind(this, this._onEject));
|
||||
} else if (drive && drive.can_eject()) {
|
||||
drive.eject_with_operation(0, mountOp.mountOp, null,
|
||||
Lang.bind(this, this._onEject));
|
||||
} else if (mount.can_unmount()) {
|
||||
mount.unmount_with_operation(0, mountOp.mountOp, null,
|
||||
Lang.bind(this, this._onUnmount));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onUnmount: function(mount, res) {
|
||||
try {
|
||||
mount.unmount_with_operation_finish(res);
|
||||
} catch (e) {
|
||||
// FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
|
||||
// but we can't access the error code from JS.
|
||||
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
|
||||
log('Unable to eject the mount ' + mount.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
},
|
||||
|
||||
_onEject: function(source, res) {
|
||||
try {
|
||||
source.eject_with_operation_finish(res);
|
||||
} catch (e) {
|
||||
// FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
|
||||
// but we can't access the error code from JS.
|
||||
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
|
||||
log('Unable to eject the drive ' + source.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
},
|
||||
|
||||
_onStop: function(drive, res) {
|
||||
try {
|
||||
drive.stop_finish(res);
|
||||
} catch (e) {
|
||||
// FIXME: we need to ignore G_IO_ERROR_FAILED_HANDLED errors here
|
||||
// but we can't access the error code from JS.
|
||||
// See https://bugzilla.gnome.org/show_bug.cgi?id=591480
|
||||
log('Unable to stop the drive ' + drive.get_name()
|
||||
+ ': ' + e.toString());
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
function AutorunResidentSource() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AutorunResidentSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function() {
|
||||
MessageTray.Source.prototype._init.call(this, _('Removable Devices'));
|
||||
|
||||
this._mounts = [];
|
||||
|
||||
this._notification = new AutorunResidentNotification(this);
|
||||
this._setSummaryIcon(this.createNotificationIcon(HOTPLUG_ICON_SIZE));
|
||||
},
|
||||
|
||||
addMount: function(mount, apps) {
|
||||
if (ignoreAutorunForMount(mount))
|
||||
return;
|
||||
|
||||
let filtered = this._mounts.filter(function (element) {
|
||||
return (element.mount == mount);
|
||||
});
|
||||
|
||||
if (filtered.length != 0)
|
||||
return;
|
||||
|
||||
let element = { mount: mount, apps: apps };
|
||||
this._mounts.push(element);
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
removeMount: function(mount) {
|
||||
this._mounts =
|
||||
this._mounts.filter(function (element) {
|
||||
return (element.mount != mount);
|
||||
});
|
||||
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
if (this._mounts.length == 0) {
|
||||
this._notification.destroy();
|
||||
this.destroy();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this._notification.updateForMounts(this._mounts);
|
||||
|
||||
// add ourselves as a source, and push the notification
|
||||
if (!Main.messageTray.contains(this)) {
|
||||
Main.messageTray.add(this);
|
||||
this.pushNotification(this._notification);
|
||||
}
|
||||
},
|
||||
|
||||
createNotificationIcon: function(iconSize) {
|
||||
return new St.Icon ({ icon_name: 'drive-harddisk',
|
||||
icon_size: iconSize ? iconSize : this.ICON_SIZE });
|
||||
}
|
||||
}
|
||||
|
||||
function AutorunResidentNotification(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
AutorunResidentNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init: function(source) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
source.title, null,
|
||||
{ customContent: true });
|
||||
|
||||
// set the notification as resident
|
||||
this.setResident(true);
|
||||
|
||||
this._layout = new St.BoxLayout ({ style_class: 'hotplug-resident-box',
|
||||
vertical: true });
|
||||
|
||||
this.addActor(this._layout,
|
||||
{ x_expand: true,
|
||||
x_fill: true });
|
||||
},
|
||||
|
||||
updateForMounts: function(mounts) {
|
||||
// remove all the layout content
|
||||
this._layout.destroy_children();
|
||||
|
||||
for (let idx = 0; idx < mounts.length; idx++) {
|
||||
let element = mounts[idx];
|
||||
|
||||
let actor = this._itemForMount(element.mount, element.apps);
|
||||
this._layout.add(actor, { x_fill: true,
|
||||
expand: true });
|
||||
}
|
||||
},
|
||||
|
||||
_itemForMount: function(mount, apps) {
|
||||
let item = new St.BoxLayout();
|
||||
|
||||
// prepare the mount button content
|
||||
let mountLayout = new St.BoxLayout();
|
||||
|
||||
let mountIcon = new St.Icon({ gicon: mount.get_icon(),
|
||||
style_class: 'hotplug-resident-mount-icon' });
|
||||
mountLayout.add_actor(mountIcon);
|
||||
|
||||
let labelBin = new St.Bin({ y_align: St.Align.MIDDLE });
|
||||
let mountLabel =
|
||||
new St.Label({ text: mount.get_name(),
|
||||
style_class: 'hotplug-resident-mount-label',
|
||||
track_hover: true,
|
||||
reactive: true });
|
||||
labelBin.add_actor(mountLabel);
|
||||
mountLayout.add_actor(labelBin);
|
||||
|
||||
let mountButton = new St.Button({ child: mountLayout,
|
||||
x_align: St.Align.START,
|
||||
x_fill: true,
|
||||
style_class: 'hotplug-resident-mount',
|
||||
button_mask: St.ButtonMask.ONE });
|
||||
item.add(mountButton, { x_align: St.Align.START,
|
||||
expand: true });
|
||||
|
||||
let ejectIcon =
|
||||
new St.Icon({ icon_name: 'media-eject',
|
||||
style_class: 'hotplug-resident-eject-icon' });
|
||||
|
||||
let ejectButton =
|
||||
new St.Button({ style_class: 'hotplug-resident-eject-button',
|
||||
button_mask: St.ButtonMask.ONE,
|
||||
child: ejectIcon });
|
||||
item.add(ejectButton, { x_align: St.Align.END });
|
||||
|
||||
// now connect signals
|
||||
mountButton.connect('clicked', Lang.bind(this, function(actor, event) {
|
||||
startAppForMount(apps[0], mount);
|
||||
}));
|
||||
|
||||
ejectButton.connect('clicked', Lang.bind(this, function() {
|
||||
Main.autorunManager.ejectMount(mount);
|
||||
}));
|
||||
|
||||
return item;
|
||||
},
|
||||
}
|
||||
|
||||
function AutorunTransientDispatcher() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AutorunTransientDispatcher.prototype = {
|
||||
_init: function() {
|
||||
this._sources = [];
|
||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||
},
|
||||
|
||||
_getAutorunSettingForType: function(contentType) {
|
||||
let runApp = this._settings.get_strv(SETTING_START_APP);
|
||||
if (runApp.indexOf(contentType) != -1)
|
||||
return AutorunSetting.RUN;
|
||||
|
||||
let ignore = this._settings.get_strv(SETTING_IGNORE);
|
||||
if (ignore.indexOf(contentType) != -1)
|
||||
return AutorunSetting.IGNORE;
|
||||
|
||||
let openFiles = this._settings.get_strv(SETTING_OPEN_FOLDER);
|
||||
if (openFiles.indexOf(contentType) != -1)
|
||||
return AutorunSetting.FILES;
|
||||
|
||||
return AutorunSetting.ASK;
|
||||
},
|
||||
|
||||
_getSourceForMount: function(mount) {
|
||||
let filtered =
|
||||
this._sources.filter(function (source) {
|
||||
return (source.mount == mount);
|
||||
});
|
||||
|
||||
// we always make sure not to add two sources for the same
|
||||
// mount in addMount(), so it's safe to assume filtered.length
|
||||
// is always either 1 or 0.
|
||||
if (filtered.length == 1)
|
||||
return filtered[0];
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
_addSource: function(mount, apps) {
|
||||
// if we already have a source showing for this
|
||||
// mount, return
|
||||
if (this._getSourceForMount(mount))
|
||||
return;
|
||||
|
||||
// add a new source
|
||||
this._sources.push(new AutorunTransientSource(mount, apps));
|
||||
},
|
||||
|
||||
addMount: function(mount, apps, contentTypes) {
|
||||
// if autorun is disabled globally, return
|
||||
if (this._settings.get_boolean(SETTING_DISABLE_AUTORUN))
|
||||
return;
|
||||
|
||||
// if the mount doesn't want to be autorun, return
|
||||
if (ignoreAutorunForMount(mount))
|
||||
return;
|
||||
|
||||
let setting = this._getAutorunSettingForType(contentTypes[0]);
|
||||
|
||||
// check at the settings for the first content type
|
||||
// to see whether we should ask
|
||||
if (setting == AutorunSetting.IGNORE)
|
||||
return; // return right away
|
||||
|
||||
let success = false;
|
||||
let app = null;
|
||||
|
||||
if (setting == AutorunSetting.RUN) {
|
||||
app = Gio.app_info_get_default_for_type(type, false);
|
||||
} else if (setting == AutorunSetting.FILES) {
|
||||
app = Gio.app_info_get_default_for_type('inode/directory', false);
|
||||
}
|
||||
|
||||
if (app)
|
||||
success = startAppForMount(app, mount);
|
||||
|
||||
// we fallback here also in case the settings did not specify 'ask',
|
||||
// but we failed launching the default app or the default file manager
|
||||
if (!success)
|
||||
this._addSource(mount, apps);
|
||||
},
|
||||
|
||||
removeMount: function(mount) {
|
||||
let source = this._getSourceForMount(mount);
|
||||
|
||||
// if we aren't tracking this mount, don't do anything
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
// destroy the notification source
|
||||
source.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
function AutorunTransientSource(mount, apps) {
|
||||
this._init(mount, apps);
|
||||
}
|
||||
|
||||
AutorunTransientSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(mount, apps) {
|
||||
MessageTray.Source.prototype._init.call(this, mount.get_name());
|
||||
|
||||
this.mount = mount;
|
||||
this.apps = apps;
|
||||
|
||||
this._notification = new AutorunTransientNotification(this);
|
||||
this._setSummaryIcon(this.createNotificationIcon(this.ICON_SIZE));
|
||||
|
||||
// add ourselves as a source, and popup the notification
|
||||
Main.messageTray.add(this);
|
||||
this.notify(this._notification);
|
||||
},
|
||||
|
||||
createNotificationIcon: function(iconSize) {
|
||||
return new St.Icon({ gicon: this.mount.get_icon(),
|
||||
icon_size: iconSize ? iconSize : this.ICON_SIZE });
|
||||
}
|
||||
}
|
||||
|
||||
function AutorunTransientNotification(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
AutorunTransientNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init: function(source) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
source.title, null,
|
||||
{ customContent: true });
|
||||
|
||||
this._box = new St.BoxLayout({ style_class: 'hotplug-transient-box',
|
||||
vertical: true });
|
||||
this.addActor(this._box);
|
||||
|
||||
this._mount = source.mount;
|
||||
|
||||
source.apps.forEach(Lang.bind(this, function (app) {
|
||||
let actor = this._buttonForApp(app);
|
||||
|
||||
if (actor)
|
||||
this._box.add(actor, { x_fill: true,
|
||||
x_align: St.Align.START });
|
||||
}));
|
||||
|
||||
this._box.add(this._buttonForEject(), { x_fill: true,
|
||||
x_align: St.Align.START });
|
||||
|
||||
// set the notification to transient and urgent, so that it
|
||||
// expands out
|
||||
this.setTransient(true);
|
||||
this.setUrgency(MessageTray.Urgency.CRITICAL);
|
||||
},
|
||||
|
||||
_buttonForApp: function(app) {
|
||||
let box = new St.BoxLayout();
|
||||
let icon = new St.Icon({ gicon: app.get_icon(),
|
||||
style_class: 'hotplug-notification-item-icon' });
|
||||
box.add(icon);
|
||||
|
||||
let label = new St.Bin({ y_align: St.Align.MIDDLE,
|
||||
child: new St.Label
|
||||
({ text: _("Open with %s").format(app.get_display_name()) })
|
||||
});
|
||||
box.add(label);
|
||||
|
||||
let button = new St.Button({ child: box,
|
||||
x_fill: true,
|
||||
x_align: St.Align.START,
|
||||
button_mask: St.ButtonMask.ONE,
|
||||
style_class: 'hotplug-notification-item' });
|
||||
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
startAppForMount(app, this._mount);
|
||||
this.destroy();
|
||||
}));
|
||||
|
||||
return button;
|
||||
},
|
||||
|
||||
_buttonForEject: function() {
|
||||
let box = new St.BoxLayout();
|
||||
let icon = new St.Icon({ icon_name: 'media-eject',
|
||||
style_class: 'hotplug-notification-item-icon' });
|
||||
box.add(icon);
|
||||
|
||||
let label = new St.Bin({ y_align: St.Align.MIDDLE,
|
||||
child: new St.Label
|
||||
({ text: _("Eject") })
|
||||
});
|
||||
box.add(label);
|
||||
|
||||
let button = new St.Button({ child: box,
|
||||
x_fill: true,
|
||||
x_align: St.Align.START,
|
||||
button_mask: St.ButtonMask.ONE,
|
||||
style_class: 'hotplug-notification-item' });
|
||||
|
||||
button.connect('clicked', Lang.bind(this, function() {
|
||||
Main.autorunManager.ejectMount(this._mount);
|
||||
}));
|
||||
|
||||
return button;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const POPUP_ANIMATION_TIME = 0.15;
|
||||
@ -329,7 +330,7 @@ BoxPointer.prototype = {
|
||||
// We also want to keep it onscreen, and separated from the
|
||||
// edge by the same distance as the main part of the box is
|
||||
// separated from its sourceActor
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||
let arrowBase = themeNode.get_length('-arrow-base');
|
||||
|
@ -8,9 +8,6 @@ const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const C_ = Gettext.pgettext;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
|
@ -8,13 +8,13 @@ const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const ScreenSaver = imports.misc.screenSaver;
|
||||
|
||||
// This manages the shell "chrome"; the UI that's visible in the
|
||||
// normal mode (ie, outside the Overview), that surrounds the main
|
||||
// workspace content.
|
||||
|
||||
const defaultParams = {
|
||||
visibleInOverview: false,
|
||||
visibleInFullscreen: false,
|
||||
affectsStruts: true,
|
||||
affectsInputRegion: true
|
||||
@ -36,8 +36,12 @@ Chrome.prototype = {
|
||||
|
||||
this._trackedActors = [];
|
||||
|
||||
global.screen.connect('monitors-changed',
|
||||
Lang.bind(this, this._monitorsChanged));
|
||||
Main.connect('initialized', Lang.bind(this, this._finishInit));
|
||||
},
|
||||
|
||||
_finishInit: function() {
|
||||
Main.layoutManager.connect('monitors-changed',
|
||||
Lang.bind(this, this._relayout));
|
||||
global.screen.connect('restacked',
|
||||
Lang.bind(this, this._windowsRestacked));
|
||||
|
||||
@ -50,9 +54,15 @@ Chrome.prototype = {
|
||||
Main.overview.connect('hidden',
|
||||
Lang.bind(this, this._overviewHidden));
|
||||
|
||||
this._updateMonitors();
|
||||
this._updateFullscreen();
|
||||
this._queueUpdateRegions();
|
||||
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
|
||||
this._screenSaverProxy.connect('ActiveChanged', Lang.bind(this, this._onScreenSaverActiveChanged));
|
||||
this._screenSaverProxy.GetActiveRemote(Lang.bind(this,
|
||||
function(result, err) {
|
||||
if (!err)
|
||||
this._onScreenSaverActiveChanged(this._screenSaverProxy, result);
|
||||
}));
|
||||
|
||||
this._relayout();
|
||||
},
|
||||
|
||||
_allocated: function(actor, box, flags) {
|
||||
@ -73,11 +83,8 @@ Chrome.prototype = {
|
||||
// in its visibility will affect the input region, but NOT the
|
||||
// struts.
|
||||
//
|
||||
// If %visibleInOverview is %true in @params, @actor will remain
|
||||
// visible when the overview is brought up. Otherwise it will
|
||||
// automatically be hidden. Likewise, if %visibleInFullscreen is
|
||||
// %true, the actor will be visible even when a fullscreen window
|
||||
// should be covering it.
|
||||
// If %visibleInFullscreen is %true, the actor will be visible
|
||||
// even when a fullscreen window should be covering it.
|
||||
//
|
||||
// If %affectsStruts or %affectsInputRegion is %false, the actor
|
||||
// will not have the indicated effect.
|
||||
@ -96,7 +103,7 @@ Chrome.prototype = {
|
||||
//
|
||||
// @params can have any of the same values as in addActor(), though
|
||||
// some possibilities don't make sense (eg, trying to have a
|
||||
// %visibleInOverview child of a non-%visibleInOverview parent).
|
||||
// %visibleInFullscreen child of a non-%visibleInFullscreen parent).
|
||||
// By default, @actor has the same params as its chrome ancestor.
|
||||
trackActor: function(actor, params) {
|
||||
let ancestor = actor.get_parent();
|
||||
@ -189,10 +196,8 @@ Chrome.prototype = {
|
||||
_updateVisibility: function() {
|
||||
for (let i = 0; i < this._trackedActors.length; i++) {
|
||||
let actorData = this._trackedActors[i];
|
||||
if (this._inOverview && !actorData.visibleInOverview)
|
||||
this.actor.set_skip_paint(actorData.actor, true);
|
||||
else if (!this._inOverview && !actorData.visibleInFullscreen &&
|
||||
this._findMonitorForActor(actorData.actor).inFullscreen)
|
||||
if (!this._inOverview && !actorData.visibleInFullscreen &&
|
||||
this._findMonitorForActor(actorData.actor).inFullscreen)
|
||||
this.actor.set_skip_paint(actorData.actor, true);
|
||||
else
|
||||
this.actor.set_skip_paint(actorData.actor, false);
|
||||
@ -211,18 +216,18 @@ Chrome.prototype = {
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_updateMonitors: function() {
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
this._monitors = monitors;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let monitor = monitors[i];
|
||||
if (monitor.x == primary.x &&
|
||||
monitor.y == primary.y &&
|
||||
monitor.width == primary.width &&
|
||||
monitor.height == primary.height)
|
||||
this._primaryMonitor = monitor;
|
||||
}
|
||||
_relayout: function() {
|
||||
this._monitors = Main.layoutManager.monitors;
|
||||
this._primaryMonitor = Main.layoutManager.primaryMonitor;
|
||||
|
||||
this._updateFullscreen();
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_onScreenSaverActiveChanged: function(proxy, screenSaverActive) {
|
||||
this.actor.visible = !screenSaverActive;
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_findMonitorForRect: function(x, y, w, h) {
|
||||
@ -261,15 +266,6 @@ Chrome.prototype = {
|
||||
return this._primaryMonitor; // Not on any monitor, pretend its on the primary
|
||||
},
|
||||
|
||||
_monitorsChanged: function() {
|
||||
this._updateMonitors();
|
||||
|
||||
// Update everything that depends on monitor positions
|
||||
this._updateFullscreen();
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_queueUpdateRegions: function() {
|
||||
if (!this._updateRegionIdle)
|
||||
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
|
||||
@ -335,11 +331,6 @@ Chrome.prototype = {
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
}
|
||||
|
||||
// Figure out where the pointer is in case we lost track of
|
||||
// it during a grab. (In particular, if a trayicon popup menu
|
||||
// is dismissed, see if we need to close the message tray.)
|
||||
global.sync_pointer();
|
||||
},
|
||||
|
||||
_updateRegions: function() {
|
||||
|
@ -153,14 +153,14 @@ CtrlAltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
alloc.min_size = primary.width;
|
||||
alloc.natural_size = primary.width;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
alloc.min_size = primary.height;
|
||||
alloc.natural_size = primary.height;
|
||||
@ -168,7 +168,7 @@ CtrlAltTabPopup.prototype = {
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let leftPadding = this.actor.get_theme_node().get_padding(St.Side.LEFT);
|
||||
let vPadding = this.actor.get_theme_node().get_vertical_padding();
|
||||
@ -323,6 +323,6 @@ CtrlAltTabSwitcher.prototype = {
|
||||
let text = new St.Label({ text: item.name });
|
||||
box.add(text, { x_fill: false });
|
||||
|
||||
this.addItem(box);
|
||||
this.addItem(box, text);
|
||||
}
|
||||
};
|
||||
|
@ -6,8 +6,6 @@ const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
@ -326,7 +324,7 @@ Dash.prototype = {
|
||||
this._favRemoveTarget = null;
|
||||
}));
|
||||
}
|
||||
DND.removeMonitor(this._dragMonitor);
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
},
|
||||
|
||||
_onDragMotion: function(dragEvent) {
|
||||
@ -344,7 +342,10 @@ Dash.prototype = {
|
||||
|
||||
let srcIsFavorite = (id in favorites);
|
||||
|
||||
if (srcIsFavorite && this._favRemoveTarget == null) {
|
||||
if (srcIsFavorite &&
|
||||
dragEvent.source.actor &&
|
||||
this.actor.contains (dragEvent.source.actor) &&
|
||||
this._favRemoveTarget == null) {
|
||||
this._favRemoveTarget = new RemoveFavoriteIcon();
|
||||
this._favRemoveTarget.icon.setIconSize(this.iconSize);
|
||||
this._box.add(this._favRemoveTarget.actor);
|
||||
|
@ -8,8 +8,6 @@ const Cairo = imports.cairo;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Util = imports.misc.util;
|
||||
const Main = imports.ui.main;
|
||||
@ -200,6 +198,7 @@ DateMenuButton.prototype = {
|
||||
|
||||
_onPreferencesActivate: function() {
|
||||
this.menu.close();
|
||||
Main.overview.hide();
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-datetime-panel.desktop');
|
||||
app.activate(-1);
|
||||
},
|
||||
|
@ -61,7 +61,7 @@ function addDragMonitor(monitor) {
|
||||
dragMonitors.push(monitor);
|
||||
}
|
||||
|
||||
function removeMonitor(monitor) {
|
||||
function removeDragMonitor(monitor) {
|
||||
for (let i = 0; i < dragMonitors.length; i++)
|
||||
if (dragMonitors[i] == monitor) {
|
||||
dragMonitors.splice(i, 1);
|
||||
@ -284,13 +284,13 @@ _Draggable.prototype = {
|
||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||
|
||||
// Set the actor's scale such that it will keep the same
|
||||
// transformed size when it's reparented to the stage
|
||||
// transformed size when it's reparented to the uiGroup
|
||||
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
|
||||
this.actor.set_scale(scaledWidth / this.actor.width,
|
||||
scaledHeight / this.actor.height);
|
||||
}
|
||||
|
||||
this._dragActor.reparent(this.actor.get_stage());
|
||||
this._dragActor.reparent(Main.uiGroup);
|
||||
this._dragActor.raise_top();
|
||||
Shell.util_set_hidden_from_pick(this._dragActor, true);
|
||||
|
||||
@ -442,7 +442,7 @@ _Draggable.prototype = {
|
||||
return true;
|
||||
// If it accepted the drop without taking the actor,
|
||||
// handle it ourselves.
|
||||
if (this._dragActor.get_parent() == this._dragActor.get_stage()) {
|
||||
if (this._dragActor.get_parent() == Main.uiGroup) {
|
||||
if (this._restoreOnSuccess) {
|
||||
this._restoreDragActor(event.get_time());
|
||||
return true;
|
||||
|
@ -1,8 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DocInfo = imports.misc.docInfo;
|
||||
const Params = imports.misc.params;
|
||||
const Search = imports.ui.search;
|
||||
|
@ -22,9 +22,6 @@ const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdm = imports.gi.Gdm;
|
||||
const GLib = imports.gi.GLib;
|
||||
@ -408,10 +405,6 @@ EndSessionDialog.prototype = {
|
||||
},
|
||||
|
||||
_updateButtons: function() {
|
||||
if (this.state != ModalDialog.State.OPENING &&
|
||||
this.state != ModalDialog.State.OPENED)
|
||||
return;
|
||||
|
||||
let dialogContent = DialogContent[this._type];
|
||||
let buttons = [{ action: Lang.bind(this, this.cancel),
|
||||
label: _("Cancel"),
|
||||
@ -521,11 +514,12 @@ EndSessionDialog.prototype = {
|
||||
this._inhibitors.push(inhibitor);
|
||||
}
|
||||
|
||||
this._updateButtons();
|
||||
|
||||
if (!this.open(timestamp))
|
||||
throw new DBus.DBusError('org.gnome.Shell.ModalDialog.GrabError',
|
||||
"Cannot grab pointer and keyboard");
|
||||
|
||||
this._updateButtons();
|
||||
this._updateContent();
|
||||
|
||||
let signalId = this.connect('opened',
|
||||
|
@ -1,14 +1,22 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
imports.gi.versions.Clutter = '1.0';
|
||||
imports.gi.versions.Gio = '2.0';
|
||||
imports.gi.versions.Gdk = '3.0';
|
||||
imports.gi.versions.GdkPixbuf = '2.0';
|
||||
imports.gi.versions.Gtk = '3.0';
|
||||
|
||||
const Clutter = imports.gi.Clutter;;
|
||||
const Gettext = imports.gettext;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext_gtk30 = imports.gettext.domain('gtk30');
|
||||
|
||||
const Tweener = imports.ui.tweener;
|
||||
// We can't import shell JS modules yet, because they may have
|
||||
// variable initializations, etc, that depend on init() already having
|
||||
// been run.
|
||||
|
||||
const Format = imports.misc.format;
|
||||
|
||||
// "monkey patch" in some varargs ClutterContainer methods; we need
|
||||
// to do this per-container class since there is no representation
|
||||
@ -31,49 +39,42 @@ function _patchContainerClass(containerClass) {
|
||||
};
|
||||
}
|
||||
|
||||
// Replace @method with something that throws an error instead
|
||||
function _blockMethod(method, replacement, reason) {
|
||||
let match = method.match(/^(.+)\.([^.]+)$/);
|
||||
if (!match)
|
||||
throw new Error('Bad method name "' + method + '"');
|
||||
let proto = 'imports.gi.' + match[1] + '.prototype';
|
||||
let property = match[2];
|
||||
function init() {
|
||||
// Add some bindings to the global JS namespace; (gjs keeps the web
|
||||
// browser convention of having that namespace be called 'window'.)
|
||||
window.global = Shell.Global.get();
|
||||
|
||||
if (!global.set_property_mutable(proto, property, true))
|
||||
throw new Error('Bad method name "' + method + '"');
|
||||
window._ = Gettext.gettext;
|
||||
window.C_ = Gettext.pgettext;
|
||||
window.ngettext = Gettext.ngettext;
|
||||
|
||||
// eval() is evil in general, but we know it's safe here since
|
||||
// set_property_mutable() would have failed if proto was
|
||||
// malformed.
|
||||
let node = eval(proto);
|
||||
// Set the default direction for St widgets (this needs to be done before any use of St)
|
||||
if (Gtk.Widget.get_default_direction() == Gtk.TextDirection.RTL) {
|
||||
St.Widget.set_default_direction(St.TextDirection.RTL);
|
||||
}
|
||||
|
||||
let msg = 'Do not use "' + method + '".';
|
||||
if (replacement)
|
||||
msg += ' Use "' + replacement + '" instead.';
|
||||
if (reason)
|
||||
msg += ' (' + reason + ')';
|
||||
// Miscellaneous monkeypatching
|
||||
_patchContainerClass(St.BoxLayout);
|
||||
_patchContainerClass(St.Table);
|
||||
|
||||
node[property] = function() {
|
||||
throw new Error(msg);
|
||||
Clutter.Actor.prototype.toString = function() {
|
||||
return St.describe_actor(this);
|
||||
};
|
||||
|
||||
global.set_property_mutable(proto, property, false);
|
||||
}
|
||||
|
||||
function init() {
|
||||
Tweener.init();
|
||||
String.prototype.format = Format.format;
|
||||
let origToString = Object.prototype.toString;
|
||||
Object.prototype.toString = function() {
|
||||
let base = origToString.call(this);
|
||||
if ('actor' in this && this.actor instanceof Clutter.Actor)
|
||||
return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
|
||||
else
|
||||
return base;
|
||||
};
|
||||
|
||||
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
|
||||
Date.prototype.toLocaleFormat = function(format) {
|
||||
return Shell.util_format_date(format, this.getTime());
|
||||
};
|
||||
|
||||
// Set the default direction for St widgets (this needs to be done before any use of St)
|
||||
if (Gettext_gtk30.gettext('default:LTR') == 'default:RTL') {
|
||||
St.Widget.set_default_direction(St.TextDirection.RTL);
|
||||
}
|
||||
|
||||
let slowdownEnv = GLib.getenv('GNOME_SHELL_SLOWDOWN_FACTOR');
|
||||
if (slowdownEnv) {
|
||||
let factor = parseFloat(slowdownEnv);
|
||||
@ -81,24 +82,10 @@ function init() {
|
||||
St.set_slow_down_factor(factor);
|
||||
}
|
||||
|
||||
_patchContainerClass(St.BoxLayout);
|
||||
_patchContainerClass(St.Table);
|
||||
// OK, now things are initialized enough that we can import shell JS
|
||||
const Format = imports.misc.format;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
Clutter.Actor.prototype.toString = function() {
|
||||
return St.describe_actor(this);
|
||||
};
|
||||
|
||||
if (window.global === undefined) // test environment
|
||||
return;
|
||||
|
||||
_blockMethod('Clutter.Event.get_state', 'Shell.get_event_state',
|
||||
'gjs\'s handling of Clutter.ModifierType is broken. See bug 597292.');
|
||||
_blockMethod('Gdk.Window.get_device_position', 'global.get_pointer',
|
||||
'gjs\'s handling of Gdk.ModifierType is broken. See bug 597292.');
|
||||
|
||||
// Now close the back door to prevent extensions from trying to
|
||||
// abuse it. We can't actually delete it since
|
||||
// Shell.Global.prototype itself is read-only.
|
||||
global.set_property_mutable('imports.gi.Shell.Global.prototype', 'set_property_mutable', true);
|
||||
Shell.Global.prototype.set_property_mutable = undefined;
|
||||
Tweener.init();
|
||||
String.prototype.format = Format.format;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
|
||||
@ -22,8 +23,9 @@ const ExtensionType = {
|
||||
const extensionMeta = {};
|
||||
// Maps uuid -> importer object (extension directory tree)
|
||||
const extensions = {};
|
||||
// Array of uuids
|
||||
// Arrays of uuids
|
||||
var disabledExtensions;
|
||||
var enabledExtensions;
|
||||
// GFile for user extensions
|
||||
var userExtensionsDir = null;
|
||||
|
||||
@ -177,6 +179,7 @@ function init() {
|
||||
}
|
||||
|
||||
disabledExtensions = global.settings.get_strv('disabled-extensions', -1);
|
||||
enabledExtensions = global.settings.get_strv('enabled-extensions', -1);
|
||||
}
|
||||
|
||||
function _loadExtensionsIn(dir, type) {
|
||||
@ -194,7 +197,10 @@ function _loadExtensionsIn(dir, type) {
|
||||
if (fileType != Gio.FileType.DIRECTORY)
|
||||
continue;
|
||||
let name = info.get_name();
|
||||
let enabled = disabledExtensions.indexOf(name) < 0;
|
||||
// Enable all but disabled extensions if enabledExtensions is not set.
|
||||
// If it is set, enable one those, except they are disabled as well.
|
||||
let enabled = (enabledExtensions.length == 0 || enabledExtensions.indexOf(name) >= 0)
|
||||
&& disabledExtensions.indexOf(name) < 0;
|
||||
let child = dir.get_child(name);
|
||||
loadExtension(child, enabled, type);
|
||||
}
|
||||
|
@ -42,10 +42,10 @@ BaseIcon.prototype = {
|
||||
box.add_actor(this._iconBin);
|
||||
|
||||
if (params.showLabel) {
|
||||
this._name = new St.Label({ text: label });
|
||||
box.add_actor(this._name);
|
||||
this.label = new St.Label({ text: label });
|
||||
box.add_actor(this.label);
|
||||
} else {
|
||||
this._name = null;
|
||||
this.label = null;
|
||||
}
|
||||
|
||||
if (params.createIcon)
|
||||
@ -67,8 +67,8 @@ BaseIcon.prototype = {
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
if (this._name) {
|
||||
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(-1);
|
||||
if (this.label) {
|
||||
let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(-1);
|
||||
preferredHeight += this._spacing + labelNatHeight;
|
||||
|
||||
let labelHeight = availHeight >= preferredHeight ? labelNatHeight
|
||||
@ -79,7 +79,7 @@ BaseIcon.prototype = {
|
||||
childBox.x2 = availWidth;
|
||||
childBox.y1 = iconSize + this._spacing;
|
||||
childBox.y2 = childBox.y1 + labelHeight;
|
||||
this._name.allocate(childBox, flags);
|
||||
this.label.allocate(childBox, flags);
|
||||
}
|
||||
|
||||
childBox.x1 = Math.floor((availWidth - iconNatWidth) / 2);
|
||||
@ -98,8 +98,8 @@ BaseIcon.prototype = {
|
||||
alloc.min_size = iconMinHeight;
|
||||
alloc.natural_size = iconNatHeight;
|
||||
|
||||
if (this._name) {
|
||||
let [labelMinHeight, labelNatHeight] = this._name.get_preferred_height(forWidth);
|
||||
if (this.label) {
|
||||
let [labelMinHeight, labelNatHeight] = this.label.get_preferred_height(forWidth);
|
||||
alloc.min_size += this._spacing + labelMinHeight;
|
||||
alloc.natural_size += this._spacing + labelNatHeight;
|
||||
}
|
||||
|
609
js/ui/keyboard.js
Normal file
@ -0,0 +1,609 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Caribou = imports.gi.Caribou;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard';
|
||||
const SHOW_KEYBOARD = 'show-keyboard';
|
||||
const KEYBOARD_TYPE = 'keyboard-type';
|
||||
const ENABLE_DRAGGABLE = 'enable-drag';
|
||||
const ENABLE_FLOAT = 'enable-float';
|
||||
|
||||
// Key constants taken from Antler
|
||||
const PRETTY_KEYS = {
|
||||
'BackSpace': '\u232b',
|
||||
'space': ' ',
|
||||
'Return': '\u23ce',
|
||||
'Caribou_Prefs': '\u2328',
|
||||
'Caribou_ShiftUp': '\u2b06',
|
||||
'Caribou_ShiftDown': '\u2b07',
|
||||
'Caribou_Emoticons': '\u263a',
|
||||
'Caribou_Symbols': '123',
|
||||
'Caribou_Symbols_More': '{#*',
|
||||
'Caribou_Alpha': 'Abc',
|
||||
'Tab': 'Tab',
|
||||
'Escape': 'Esc',
|
||||
'Control_L': 'Ctrl',
|
||||
'Alt_L': 'Alt'
|
||||
};
|
||||
|
||||
const CaribouKeyboardIface = {
|
||||
name: 'org.gnome.Caribou.Keyboard',
|
||||
methods: [ { name: 'Show',
|
||||
inSignature: '',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'Hide',
|
||||
inSignature: '',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'SetCursorLocation',
|
||||
inSignature: 'iiii',
|
||||
outSignature: ''
|
||||
},
|
||||
{ name: 'SetEntryLocation',
|
||||
inSignature: 'iiii',
|
||||
outSignature: ''
|
||||
} ],
|
||||
properties: [ { name: 'Name',
|
||||
signature: 's',
|
||||
access: 'read' } ]
|
||||
};
|
||||
|
||||
function Key() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
Key.prototype = {
|
||||
_init : function(key, key_width, key_height) {
|
||||
this._key = key;
|
||||
|
||||
this._width = key_width;
|
||||
this._height = key_height;
|
||||
|
||||
this.actor = this._getKey();
|
||||
|
||||
this._extended_keys = this._key.get_extended_keys();
|
||||
this._extended_keyboard = {};
|
||||
|
||||
if (this._key.name == "Control_L" || this._key.name == "Alt_L")
|
||||
this._key.latch = true;
|
||||
|
||||
this._key.connect('key-pressed', Lang.bind(this, function ()
|
||||
{ this.actor.checked = true }));
|
||||
this._key.connect('key-released', Lang.bind(this, function ()
|
||||
{ this.actor.checked = false; }));
|
||||
|
||||
if (this._extended_keys.length > 0) {
|
||||
this._grabbed = false;
|
||||
this._eventCaptureId = 0;
|
||||
this._key.connect('notify::show-subkeys', Lang.bind(this, this._onShowSubkeysChanged));
|
||||
this._boxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
||||
{ x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START });
|
||||
// Adds style to existing keyboard style to avoid repetition
|
||||
this._boxPointer.actor.add_style_class_name('keyboard-subkeys');
|
||||
this._getExtendedKeys();
|
||||
this.actor._extended_keys = this._extended_keyboard;
|
||||
this._boxPointer.actor.hide();
|
||||
Main.chrome.addActor(this._boxPointer.actor, { visibleInFullscreen: true,
|
||||
affectsStruts: false });
|
||||
}
|
||||
},
|
||||
|
||||
_getKey: function () {
|
||||
let label = this._key.name;
|
||||
|
||||
if (label.length > 1) {
|
||||
let pretty = PRETTY_KEYS[label];
|
||||
if (pretty)
|
||||
label = pretty;
|
||||
else
|
||||
label = this._getUnichar(this._key);
|
||||
}
|
||||
|
||||
label = GLib.markup_escape_text(label, -1);
|
||||
let button = new St.Button ({ label: label, style_class: 'keyboard-key' });
|
||||
|
||||
button.width = this._width;
|
||||
button.key_width = this._key.width;
|
||||
button.height = this._height;
|
||||
button.draggable = false;
|
||||
button.connect('button-press-event', Lang.bind(this, function () { this._key.press(); }));
|
||||
button.connect('button-release-event', Lang.bind(this, function () { this._key.release(); }));
|
||||
|
||||
return button;
|
||||
},
|
||||
|
||||
_getUnichar: function(key) {
|
||||
let keyval = key.keyval;
|
||||
let unichar = Gdk.keyval_to_unicode(keyval);
|
||||
if (unichar) {
|
||||
return String.fromCharCode(unichar);
|
||||
} else {
|
||||
return key.name;
|
||||
}
|
||||
},
|
||||
|
||||
_getExtendedKeys: function () {
|
||||
this._extended_keyboard = new St.BoxLayout({ style_class: 'keyboard-layout',
|
||||
vertical: false });
|
||||
for (let i = 0; i < this._extended_keys.length; ++i) {
|
||||
let extended_key = this._extended_keys[i];
|
||||
let label = this._getUnichar(extended_key);
|
||||
let key = new St.Button({ label: label, style_class: 'keyboard-key' });
|
||||
key.extended_key = extended_key;
|
||||
key.width = this._width;
|
||||
key.height = this._height;
|
||||
key.draggable = false;
|
||||
key.connect('button-press-event', Lang.bind(this, function () { extended_key.press(); }));
|
||||
key.connect('button-release-event', Lang.bind(this, function () { extended_key.release(); }));
|
||||
this._extended_keyboard.add(key);
|
||||
}
|
||||
this._boxPointer.bin.add_actor(this._extended_keyboard);
|
||||
},
|
||||
|
||||
_onEventCapture: function (actor, event) {
|
||||
let source = event.get_source();
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS ||
|
||||
(event.type() == Clutter.EventType.BUTTON_RELEASE && source.draggable)) {
|
||||
if (this._extended_keyboard.contains(source)) {
|
||||
if (source.draggable) {
|
||||
source.extended_key.press();
|
||||
source.extended_key.release();
|
||||
}
|
||||
this._ungrab();
|
||||
return false;
|
||||
}
|
||||
this._boxPointer.actor.hide();
|
||||
this._ungrab();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_ungrab: function () {
|
||||
global.stage.disconnect(this._eventCaptureId);
|
||||
this._eventCaptureId = 0;
|
||||
this._grabbed = false;
|
||||
Main.popModal(this.actor);
|
||||
},
|
||||
|
||||
_onShowSubkeysChanged: function () {
|
||||
if (this._key.show_subkeys) {
|
||||
this.actor.fake_release();
|
||||
this._boxPointer.actor.raise_top();
|
||||
this._boxPointer.setPosition(this.actor, 5, 0.5);
|
||||
this._boxPointer.show(true);
|
||||
this.actor.set_hover(false);
|
||||
if (!this._grabbed) {
|
||||
Main.pushModal(this.actor);
|
||||
this._eventCaptureId = global.stage.connect('captured-event', Lang.bind(this, this._onEventCapture));
|
||||
this._grabbed = true;
|
||||
}
|
||||
this._key.release();
|
||||
} else {
|
||||
if (this._grabbed)
|
||||
this._ungrab();
|
||||
this._boxPointer.hide(true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function Keyboard() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
Keyboard.prototype = {
|
||||
_init: function () {
|
||||
DBus.session.exportObject('/org/gnome/Caribou/Keyboard', this);
|
||||
DBus.session.acquire_name('org.gnome.Caribou.Keyboard', 0, null, null);
|
||||
|
||||
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
|
||||
|
||||
this._keyboardSettings = new Gio.Settings({ schema: KEYBOARD_SCHEMA });
|
||||
this._keyboardSettings.connect('changed', Lang.bind(this, this._display));
|
||||
|
||||
this._setupKeyboard();
|
||||
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._redraw));
|
||||
|
||||
Main.layoutManager.bottomBox.add_actor(this.actor);
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this._display();
|
||||
},
|
||||
|
||||
_setupKeyboard: function() {
|
||||
if (this._keyboardNotifyId)
|
||||
this._keyboard.disconnect(this._keyboardNotifyId);
|
||||
let children = this.actor.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
children[i].destroy();
|
||||
|
||||
this._keyboard = new Caribou.KeyboardModel({ keyboard_type: this._keyboardSettings.get_string(KEYBOARD_TYPE) });
|
||||
this._groups = {};
|
||||
this._current_page = null;
|
||||
|
||||
// Initialize keyboard key measurements
|
||||
this._numOfHorizKeys = 0;
|
||||
this._numOfVertKeys = 0;
|
||||
|
||||
this._floatId = 0;
|
||||
|
||||
this._addKeys();
|
||||
|
||||
this._keyboardNotifyId = this._keyboard.connect('notify::active-group', Lang.bind(this, this._onGroupChanged));
|
||||
},
|
||||
|
||||
_display: function () {
|
||||
if (this._keyboard.keyboard_type != this._keyboardSettings.get_string(KEYBOARD_TYPE))
|
||||
this._setupKeyboard();
|
||||
|
||||
this._showKeyboard = this._keyboardSettings.get_boolean(SHOW_KEYBOARD);
|
||||
this._draggable = this._keyboardSettings.get_boolean(ENABLE_DRAGGABLE);
|
||||
this._floating = this._keyboardSettings.get_boolean(ENABLE_FLOAT);
|
||||
if (this._floating) {
|
||||
this._floatId = this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
|
||||
this._dragging = false;
|
||||
}
|
||||
else
|
||||
this.actor.disconnect(this._floatId);
|
||||
if (this._showKeyboard)
|
||||
this.show();
|
||||
else {
|
||||
this.hide();
|
||||
this.destroySource();
|
||||
}
|
||||
},
|
||||
|
||||
_startDragging: function (actor, event) {
|
||||
if (this._dragging) // don't allow two drags at the same time
|
||||
return;
|
||||
this._dragging = true;
|
||||
this._preDragStageMode = global.stage_input_mode;
|
||||
|
||||
Clutter.grab_pointer(this.actor);
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
|
||||
this._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
|
||||
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
|
||||
[this._dragStartX, this._dragStartY] = event.get_coords();
|
||||
[this._currentX, this._currentY] = this.actor.get_position();
|
||||
},
|
||||
|
||||
_endDragging: function () {
|
||||
if (this._dragging) {
|
||||
this.actor.disconnect(this._releaseId);
|
||||
this.actor.disconnect(this._motionId);
|
||||
|
||||
Clutter.ungrab_pointer();
|
||||
global.set_stage_input_mode(this._preDragStageMode);
|
||||
global.unset_cursor();
|
||||
this._dragging = false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
_motionEvent: function(actor, event) {
|
||||
let absX, absY;
|
||||
[absX, absY] = event.get_coords();
|
||||
global.set_cursor(Shell.Cursor.DND_IN_DRAG);
|
||||
this._moveHandle(absX, absY);
|
||||
return true;
|
||||
},
|
||||
|
||||
_moveHandle: function (stageX, stageY) {
|
||||
let x, y;
|
||||
x = stageX - this._dragStartX + this._currentX;
|
||||
y = stageY - this._dragStartY + this._currentY;
|
||||
this.actor.set_position(x,y);
|
||||
|
||||
},
|
||||
|
||||
_addKeys: function () {
|
||||
let groups = this._keyboard.get_groups();
|
||||
for (let i = 0; i < groups.length; ++i) {
|
||||
let gname = groups[i];
|
||||
let group = this._keyboard.get_group(gname);
|
||||
group.connect('notify::active-level', Lang.bind(this, this._onLevelChanged));
|
||||
let layers = {};
|
||||
let levels = group.get_levels();
|
||||
for (let j = 0; j < levels.length; ++j) {
|
||||
let lname = levels[j];
|
||||
let level = group.get_level(lname);
|
||||
let layout = new St.BoxLayout({ style_class: 'keyboard-layout',
|
||||
vertical: true });
|
||||
this._loadRows(level, layout);
|
||||
layers[lname] = layout;
|
||||
this.actor.add(layout, { x_fill: false });
|
||||
|
||||
layout.hide();
|
||||
}
|
||||
this._groups[gname] = layers;
|
||||
}
|
||||
|
||||
this._setActiveLayer();
|
||||
},
|
||||
|
||||
_getTrayIcon: function () {
|
||||
let trayButton = new St.Button ({ label: "tray", style_class: 'keyboard-key' });
|
||||
trayButton.key_width = 1;
|
||||
trayButton.connect('button-press-event', Lang.bind(this, function () {
|
||||
Main.layoutManager.updateForTray();
|
||||
}));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function () {
|
||||
trayButton.reactive = false;
|
||||
trayButton.add_style_pseudo_class('grayed');
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function () {
|
||||
trayButton.reactive = true;
|
||||
trayButton.remove_style_pseudo_class('grayed');
|
||||
}));
|
||||
|
||||
return trayButton;
|
||||
},
|
||||
|
||||
_addRows : function (keys, layout) {
|
||||
let keyboard_row = new St.BoxLayout();
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
let children = keys[i].get_children();
|
||||
let right_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
||||
let left_box = new St.BoxLayout({ style_class: 'keyboard-row' });
|
||||
for (let j = 0; j < children.length; ++j) {
|
||||
if (this._numOfHorizKeys == 0)
|
||||
this._numOfHorizKeys = children.length;
|
||||
let key = children[j];
|
||||
let button = new Key(key, 0, 0);
|
||||
|
||||
if (key.align == 'right')
|
||||
right_box.add(button.actor);
|
||||
else
|
||||
left_box.add(button.actor);
|
||||
if (key.name == "Caribou_Prefs") {
|
||||
key.connect('key-released', Lang.bind(this, this._onPrefsClick));
|
||||
|
||||
// Add new key for hiding message tray
|
||||
right_box.add(this._getTrayIcon());
|
||||
}
|
||||
}
|
||||
keyboard_row.add(left_box, { expand: true, x_fill: false, x_align: St.Align.START });
|
||||
keyboard_row.add(right_box, { expand: true, x_fill: false, x_align: St.Align.END });
|
||||
}
|
||||
layout.add(keyboard_row);
|
||||
},
|
||||
|
||||
_manageTray: function () {
|
||||
this.createSource();
|
||||
},
|
||||
|
||||
_onPrefsClick: function () {
|
||||
this.hide();
|
||||
this._manageTray();
|
||||
},
|
||||
|
||||
_loadRows : function (level, layout) {
|
||||
let rows = level.get_rows();
|
||||
for (let i = 0; i < rows.length; ++i) {
|
||||
let row = rows[i];
|
||||
if (this._numOfVertKeys == 0)
|
||||
this._numOfVertKeys = rows.length;
|
||||
this._addRows(row.get_columns(), layout);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
_redraw: function () {
|
||||
let monitor = Main.layoutManager.bottomMonitor;
|
||||
let maxHeight = monitor.height / 3;
|
||||
this.actor.width = monitor.width;
|
||||
|
||||
let layout = this._current_page;
|
||||
let verticalSpacing = layout.get_theme_node().get_length('spacing');
|
||||
let padding = layout.get_theme_node().get_length('padding');
|
||||
|
||||
let box = layout.get_children()[0].get_children()[0];
|
||||
let horizontalSpacing = box.get_theme_node().get_length('spacing');
|
||||
let allHorizontalSpacing = (this._numOfHorizKeys - 1) * horizontalSpacing;
|
||||
let keyWidth = Math.floor((this.actor.width - allHorizontalSpacing - 2 * padding) / this._numOfHorizKeys);
|
||||
|
||||
let allVerticalSpacing = (this._numOfVertKeys - 1) * verticalSpacing;
|
||||
let keyHeight = Math.floor((maxHeight - allVerticalSpacing - 2 * padding) / this._numOfVertKeys);
|
||||
|
||||
let keySize = Math.min(keyWidth, keyHeight);
|
||||
this.actor.height = keySize * this._numOfVertKeys + allVerticalSpacing + 2 * padding;
|
||||
|
||||
let rows = this._current_page.get_children();
|
||||
for (let i = 0; i < rows.length; ++i) {
|
||||
let keyboard_row = rows[i];
|
||||
let boxes = keyboard_row.get_children();
|
||||
for (let j = 0; j < boxes.length; ++j) {
|
||||
let keys = boxes[j].get_children();
|
||||
for (let k = 0; k < keys.length; ++k) {
|
||||
let child = keys[k];
|
||||
child.width = keySize * child.key_width;
|
||||
child.height = keySize;
|
||||
child.draggable = this._draggable;
|
||||
if (child._extended_keys) {
|
||||
let extended_keys = child._extended_keys.get_children();
|
||||
for (let n = 0; n < extended_keys.length; ++n) {
|
||||
let extended_key = extended_keys[n];
|
||||
extended_key.width = keySize;
|
||||
extended_key.height = keySize;
|
||||
extended_key.draggable = this._draggable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onLevelChanged: function () {
|
||||
this._setActiveLayer();
|
||||
this._redraw();
|
||||
},
|
||||
|
||||
_onGroupChanged: function () {
|
||||
this._setActiveLayer();
|
||||
this._redraw();
|
||||
},
|
||||
|
||||
_setActiveLayer: function () {
|
||||
let active_group_name = this._keyboard.active_group;
|
||||
let active_group = this._keyboard.get_group(active_group_name);
|
||||
let active_level = active_group.active_level;
|
||||
let layers = this._groups[active_group_name];
|
||||
|
||||
if (this._current_page != null) {
|
||||
this._current_page.hide();
|
||||
}
|
||||
|
||||
this._current_page = layers[active_level];
|
||||
this._current_page.show();
|
||||
},
|
||||
|
||||
createSource: function () {
|
||||
if (this._source == null) {
|
||||
this._source = new KeyboardSource(this);
|
||||
Main.messageTray.add(this._source);
|
||||
}
|
||||
},
|
||||
|
||||
destroySource: function () {
|
||||
if (this._source) {
|
||||
this._source.destroy();
|
||||
this._source = null;
|
||||
}
|
||||
},
|
||||
|
||||
show: function () {
|
||||
this._redraw();
|
||||
Main.layoutManager.showKeyboard();
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
Main.layoutManager.hideKeyboard();
|
||||
},
|
||||
|
||||
// Window placement method
|
||||
_updatePosition: function (x, y) {
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
x -= this.actor.width / 2;
|
||||
// Determines bottom/top centered
|
||||
if (y <= primary.height / 2)
|
||||
y += this.actor.height / 2;
|
||||
else
|
||||
y -= 3 * this.actor.height / 2;
|
||||
|
||||
// Accounting for monitor boundaries
|
||||
if (x < primary.x)
|
||||
x = primary.x;
|
||||
if (x + this.actor.width > primary.width)
|
||||
x = primary.width - this.actor.width;
|
||||
|
||||
this.actor.set_position(x, y);
|
||||
},
|
||||
|
||||
_moveTemporarily: function () {
|
||||
this._currentWindow = global.screen.get_display().focus_window;
|
||||
let rect = this._currentWindow.get_outer_rect();
|
||||
this._currentWindow.x = rect.x;
|
||||
this._currentWindow.y = rect.y;
|
||||
|
||||
let newX = this._currentWindow.x;
|
||||
let newY = 3 * this.actor.height / 2;
|
||||
this._currentWindow.move_frame(true, newX, newY);
|
||||
},
|
||||
|
||||
_setLocation: function (x, y) {
|
||||
if (this._floating)
|
||||
this._updatePosition(x, y);
|
||||
else {
|
||||
if (y >= 2 * this.actor.height)
|
||||
this._moveTemporarily();
|
||||
}
|
||||
},
|
||||
|
||||
// D-Bus methods
|
||||
Show: function() {
|
||||
this.destroySource();
|
||||
this.show();
|
||||
},
|
||||
|
||||
Hide: function() {
|
||||
if (this._currentWindow) {
|
||||
this._currentWindow.move_frame(true, this._currentWindow.x, this._currentWindow.y);
|
||||
this._currentWindow = null;
|
||||
}
|
||||
this.hide();
|
||||
this._manageTray();
|
||||
},
|
||||
|
||||
SetCursorLocation: function(x, y, w, h) {
|
||||
this._setLocation(x, y);
|
||||
},
|
||||
|
||||
SetEntryLocation: function(x, y, w, h) {
|
||||
this._setLocation(x, y);
|
||||
},
|
||||
|
||||
get Name() {
|
||||
return 'gnome-shell';
|
||||
}
|
||||
};
|
||||
DBus.conformExport(Keyboard.prototype, CaribouKeyboardIface);
|
||||
|
||||
function KeyboardSource() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
KeyboardSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(keyboard) {
|
||||
this._keyboard = keyboard;
|
||||
MessageTray.Source.prototype._init.call(this, _("Keyboard"));
|
||||
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
return new St.Icon({ icon_name: 'input-keyboard',
|
||||
icon_type: St.IconType.SYMBOLIC,
|
||||
icon_size: this.ICON_SIZE });
|
||||
},
|
||||
|
||||
handleSummaryClick: function() {
|
||||
let event = Clutter.get_current_event();
|
||||
if (event.type() != Clutter.EventType.BUTTON_RELEASE)
|
||||
return false;
|
||||
|
||||
if (event.get_button() != 1)
|
||||
return false;
|
||||
|
||||
this.open();
|
||||
return true;
|
||||
},
|
||||
|
||||
open: function() {
|
||||
this._keyboard.show();
|
||||
this._keyboard.destroySource();
|
||||
}
|
||||
};
|
422
js/ui/layout.js
Normal file
@ -0,0 +1,422 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Panel = imports.ui.panel;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const State = {
|
||||
HIDDEN: 0,
|
||||
SHOWING: 1,
|
||||
SHOWN: 2,
|
||||
HIDING: 3
|
||||
};
|
||||
|
||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||
|
||||
function LayoutManager() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
LayoutManager.prototype = {
|
||||
_init: function () {
|
||||
this._rtl = (St.Widget.get_default_direction() == St.TextDirection.RTL);
|
||||
this.monitors = [];
|
||||
this.primaryMonitor = null;
|
||||
this.primaryIndex = -1;
|
||||
this._hotCorners = [];
|
||||
this.bottomBox = new Clutter.Group();
|
||||
this.topBox = new Clutter.Group({ clip_to_allocation: true });
|
||||
this.bottomBox.add_actor(this.topBox);
|
||||
|
||||
global.screen.connect('monitors-changed', Lang.bind(this, this._monitorsChanged));
|
||||
this._updateMonitors();
|
||||
|
||||
Main.connect('layout-initialized', Lang.bind(this, this._initChrome));
|
||||
|
||||
Main.connect('main-ui-initialized', Lang.bind(this, this._finishInit));
|
||||
},
|
||||
|
||||
_initChrome: function() {
|
||||
Main.chrome.addActor(this.bottomBox, { affectsStruts: false,
|
||||
visibleInFullscreen: true });
|
||||
},
|
||||
|
||||
// _updateHotCorners needs access to Main.panel
|
||||
_finishInit: function() {
|
||||
this._updateHotCorners();
|
||||
|
||||
this.topBox.height = Main.messageTray.actor.height;
|
||||
this.topBox.y = - Main.messageTray.actor.height;
|
||||
|
||||
this._keyboardState = Main.keyboard.actor.visible ? State.SHOWN : State.HIDDEN;
|
||||
this._traySummoned = true;
|
||||
|
||||
Main.keyboard.actor.connect('allocation-changed', Lang.bind(this, this._reposition));
|
||||
},
|
||||
|
||||
_reposition: function () {
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function () { this._updateForKeyboard(); }));
|
||||
},
|
||||
|
||||
_updateForKeyboard: function () {
|
||||
if (Tweener.isTweening(this.bottomBox))
|
||||
return;
|
||||
|
||||
this.topBox.y = - Main.messageTray.actor.height;
|
||||
let bottom = this.bottomMonitor.y + this.bottomMonitor.height;
|
||||
if (this._keyboardState == State.SHOWN)
|
||||
this.bottomBox.y = bottom - Main.keyboard.actor.height;
|
||||
else {
|
||||
this.bottomBox.y = bottom;
|
||||
this._keyboardState = State.HIDDEN;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
updateForTray: function () {
|
||||
if (this._keyboardState == State.SHOWN) {
|
||||
if (this._traySummoned) {
|
||||
Main.messageTray.lock();
|
||||
this._traySummoned = false;
|
||||
}
|
||||
else {
|
||||
Main.messageTray.unlock();
|
||||
this._traySummoned = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Main.messageTray.unlock();
|
||||
this._traySummoned = false;
|
||||
}
|
||||
},
|
||||
|
||||
showKeyboard: function () {
|
||||
let bottom = this.bottomMonitor.y + this.bottomMonitor.height;
|
||||
// Keyboard height cannot be found directly since the first
|
||||
// call to this method may be when Keyboard.Keyboard() has
|
||||
// not returned; therefore the keyboard would be null
|
||||
Tweener.addTween(this.bottomBox,
|
||||
{ y: bottom - Main.keyboard.actor.height,
|
||||
time: 0.5,
|
||||
transition: 'easeOutQuad',
|
||||
});
|
||||
this._keyboardState = State.SHOWN;
|
||||
this.updateForTray();
|
||||
},
|
||||
|
||||
hideKeyboard: function () {
|
||||
let bottom = this.bottomMonitor.y + this.bottomMonitor.height;
|
||||
Tweener.addTween(this.bottomBox,
|
||||
{ y: bottom,
|
||||
time: 0.5,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
this._keyboardState = State.HIDDEN;
|
||||
this.updateForTray();
|
||||
},
|
||||
|
||||
// This is called by Main after everything else is constructed;
|
||||
// _updateHotCorners needs access to Main.panel, which didn't exist
|
||||
// yet when the LayoutManager was constructed.
|
||||
init: function() {
|
||||
global.screen.connect('monitors-changed', Lang.bind(this, this._monitorsChanged));
|
||||
this._updateHotCorners();
|
||||
},
|
||||
|
||||
_updateMonitors: function() {
|
||||
let screen = global.screen;
|
||||
|
||||
this.monitors = [];
|
||||
let nMonitors = screen.get_n_monitors();
|
||||
for (let i = 0; i < nMonitors; i++)
|
||||
this.monitors.push(screen.get_monitor_geometry(i));
|
||||
|
||||
if (nMonitors == 1) {
|
||||
this.primaryIndex = this.bottomIndex = 0;
|
||||
} else {
|
||||
// If there are monitors below the primary, then we need
|
||||
// to split primary from bottom.
|
||||
this.primaryIndex = this.bottomIndex = screen.get_primary_monitor();
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
let monitor = this.monitors[i];
|
||||
if (this._isAboveOrBelowPrimary(monitor)) {
|
||||
if (monitor.y > this.monitors[this.bottomIndex].y)
|
||||
this.bottomIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.primaryMonitor = this.monitors[this.primaryIndex];
|
||||
this.bottomMonitor = this.monitors[this.bottomIndex];
|
||||
|
||||
this.bottomBox.set_position(0, this.bottomMonitor.y + this.bottomMonitor.height);
|
||||
this.bottomBox.width = this.bottomMonitor.width;
|
||||
},
|
||||
|
||||
_updateHotCorners: function() {
|
||||
// destroy old hot corners
|
||||
for (let i = 0; i < this._hotCorners.length; i++)
|
||||
this._hotCorners[i].destroy();
|
||||
this._hotCorners = [];
|
||||
|
||||
// build new hot corners
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
if (i == this.primaryIndex)
|
||||
continue;
|
||||
|
||||
let monitor = this.monitors[i];
|
||||
let cornerX = this._rtl ? monitor.x + monitor.width : monitor.x;
|
||||
let cornerY = monitor.y;
|
||||
|
||||
let haveTopLeftCorner = true;
|
||||
|
||||
// Check if we have a top left (right for RTL) corner.
|
||||
// I.e. if there is no monitor directly above or to the left(right)
|
||||
let besideX = this._rtl ? monitor.x + 1 : cornerX - 1;
|
||||
let besideY = cornerY;
|
||||
let aboveX = cornerX;
|
||||
let aboveY = cornerY - 1;
|
||||
|
||||
for (let j = 0; j < this.monitors.length; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
let otherMonitor = this.monitors[j];
|
||||
if (besideX >= otherMonitor.x &&
|
||||
besideX < otherMonitor.x + otherMonitor.width &&
|
||||
besideY >= otherMonitor.y &&
|
||||
besideY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
if (aboveX >= otherMonitor.x &&
|
||||
aboveX < otherMonitor.x + otherMonitor.width &&
|
||||
aboveY >= otherMonitor.y &&
|
||||
aboveY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!haveTopLeftCorner)
|
||||
continue;
|
||||
|
||||
let corner = new HotCorner();
|
||||
this._hotCorners.push(corner);
|
||||
corner.actor.set_position(cornerX, cornerY);
|
||||
Main.chrome.addActor(corner.actor, { affectsStruts: false });
|
||||
}
|
||||
},
|
||||
|
||||
_monitorsChanged: function() {
|
||||
this._updateMonitors();
|
||||
this._updateHotCorners();
|
||||
|
||||
this.emit('monitors-changed');
|
||||
},
|
||||
|
||||
_isAboveOrBelowPrimary: function(monitor) {
|
||||
let primary = this.monitors[this.primaryIndex];
|
||||
let monitorLeft = monitor.x, monitorRight = monitor.x + monitor.width;
|
||||
let primaryLeft = primary.x, primaryRight = primary.x + primary.width;
|
||||
|
||||
if ((monitorLeft >= primaryLeft && monitorLeft <= primaryRight) ||
|
||||
(monitorRight >= primaryLeft && monitorRight <= primaryRight) ||
|
||||
(primaryLeft >= monitorLeft && primaryLeft <= monitorRight) ||
|
||||
(primaryRight >= monitorLeft && primaryRight <= monitorRight))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
get focusIndex() {
|
||||
let screen = global.screen;
|
||||
let display = screen.get_display();
|
||||
let focusWindow = display.focus_window;
|
||||
|
||||
if (focusWindow) {
|
||||
let wrect = focusWindow.get_outer_rect();
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
let monitor = this.monitors[i];
|
||||
|
||||
if (monitor.x <= wrect.x && monitor.y <= wrect.y &&
|
||||
monitor.x + monitor.width > wrect.x &&
|
||||
monitor.y + monitor.height > wrect.y)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return this.primaryIndex;
|
||||
},
|
||||
|
||||
get focusMonitor() {
|
||||
return this.monitors[this.focusIndex];
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(LayoutManager.prototype);
|
||||
|
||||
|
||||
// HotCorner:
|
||||
//
|
||||
// This class manages a "hot corner" that can toggle switching to
|
||||
// overview.
|
||||
function HotCorner() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
HotCorner.prototype = {
|
||||
_init : function() {
|
||||
// We use this flag to mark the case where the user has entered the
|
||||
// hot corner and has not left both the hot corner and a surrounding
|
||||
// guard area (the "environs"). This avoids triggering the hot corner
|
||||
// multiple times due to an accidental jitter.
|
||||
this._entered = false;
|
||||
|
||||
this.actor = new Clutter.Group({ name: 'hot-corner-environs',
|
||||
width: 3,
|
||||
height: 3,
|
||||
reactive: true });
|
||||
|
||||
this._corner = new Clutter.Rectangle({ name: 'hot-corner',
|
||||
width: 1,
|
||||
height: 1,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
this._corner._delegate = this;
|
||||
|
||||
this.actor.add_actor(this._corner);
|
||||
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
||||
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
||||
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||
} else {
|
||||
this._corner.set_position(0, 0);
|
||||
}
|
||||
|
||||
this._activationTime = 0;
|
||||
|
||||
this.actor.connect('leave-event',
|
||||
Lang.bind(this, this._onEnvironsLeft));
|
||||
|
||||
// Clicking on the hot corner environs should result in the
|
||||
// same behavior as clicking on the hot corner.
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this, this._onCornerClicked));
|
||||
|
||||
// In addition to being triggered by the mouse enter event,
|
||||
// the hot corner can be triggered by clicking on it. This is
|
||||
// useful if the user wants to undo the effect of triggering
|
||||
// the hot corner once in the hot corner.
|
||||
this._corner.connect('enter-event',
|
||||
Lang.bind(this, this._onCornerEntered));
|
||||
this._corner.connect('button-release-event',
|
||||
Lang.bind(this, this._onCornerClicked));
|
||||
this._corner.connect('leave-event',
|
||||
Lang.bind(this, this._onCornerLeft));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
|
||||
// We draw a ripple by using a source image and animating it scaling
|
||||
// outwards and fading away. We want the ripples to move linearly
|
||||
// or it looks unrealistic, but if the opacity of the ripple goes
|
||||
// linearly to zero it fades away too quickly, so we use Tweener's
|
||||
// 'onUpdate' to give a non-linear curve to the fade-away and make
|
||||
// it more visible in the middle section.
|
||||
|
||||
let [x, y] = this._corner.get_transformed_position();
|
||||
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
|
||||
opacity: 255 * Math.sqrt(startOpacity),
|
||||
scale_x: startScale,
|
||||
scale_y: startScale,
|
||||
x: x,
|
||||
y: y });
|
||||
ripple._opacity = startOpacity;
|
||||
if (ripple.get_direction() == St.TextDirection.RTL)
|
||||
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||
Tweener.addTween(ripple, { _opacity: finalOpacity,
|
||||
scale_x: finalScale,
|
||||
scale_y: finalScale,
|
||||
delay: delay,
|
||||
time: time,
|
||||
transition: 'linear',
|
||||
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
|
||||
onComplete: function() { ripple.destroy(); } });
|
||||
Main.uiGroup.add_actor(ripple);
|
||||
},
|
||||
|
||||
rippleAnimation: function() {
|
||||
// Show three concentric ripples expanding outwards; the exact
|
||||
// parameters were found by trial and error, so don't look
|
||||
// for them to make perfect sense mathematically
|
||||
|
||||
// delay time scale opacity => scale opacity
|
||||
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
|
||||
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
|
||||
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
|
||||
},
|
||||
|
||||
handleDragOver: function(source, actor, x, y, time) {
|
||||
if (source != Main.xdndHandler)
|
||||
return;
|
||||
|
||||
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||
this.rippleAnimation();
|
||||
Main.overview.showTemporarily();
|
||||
Main.overview.beginItemDrag(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_onCornerEntered : function() {
|
||||
if (!this._entered) {
|
||||
this._entered = true;
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._activationTime = Date.now() / 1000;
|
||||
|
||||
this.rippleAnimation();
|
||||
Main.overview.toggle();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCornerClicked : function() {
|
||||
if (this.shouldToggleOverviewOnClick())
|
||||
Main.overview.toggle();
|
||||
return true;
|
||||
},
|
||||
|
||||
_onCornerLeft : function(actor, event) {
|
||||
if (event.get_related() != this.actor)
|
||||
this._entered = false;
|
||||
// Consume event, otherwise this will confuse onEnvironsLeft
|
||||
return true;
|
||||
},
|
||||
|
||||
_onEnvironsLeft : function(actor, event) {
|
||||
if (event.get_related() != this._corner)
|
||||
this._entered = false;
|
||||
return false;
|
||||
},
|
||||
|
||||
// Checks if the Activities button is currently sensitive to
|
||||
// clicks. The first call to this function within the
|
||||
// HOT_CORNER_ACTIVATION_TIMEOUT time of the hot corner being
|
||||
// triggered will return false. This avoids opening and closing
|
||||
// the overview if the user both triggered the hot corner and
|
||||
// clicked the Activities button.
|
||||
shouldToggleOverviewOnClick: function() {
|
||||
if (Main.overview.animationInProgress)
|
||||
return false;
|
||||
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
@ -5,14 +5,13 @@ const Cogl = imports.gi.Cogl;
|
||||
const GConf = imports.gi.GConf;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const History = imports.misc.history;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
@ -100,12 +99,19 @@ Notebook.prototype = {
|
||||
selectIndex: function(index) {
|
||||
if (index == this._selectedIndex)
|
||||
return;
|
||||
this._unselect();
|
||||
if (index < 0) {
|
||||
this._unselect();
|
||||
this.emit('selection', null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Focus the new tab before unmapping the old one
|
||||
let tabData = this._tabs[index];
|
||||
if (!tabData.scrollView.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false))
|
||||
this.actor.grab_key_focus();
|
||||
|
||||
this._unselect();
|
||||
|
||||
tabData.labelBox.add_style_pseudo_class('selected');
|
||||
tabData.scrollView.show();
|
||||
this._selectedIndex = index;
|
||||
@ -430,7 +436,7 @@ Inspector.prototype = {
|
||||
if (!this._eventHandler)
|
||||
return;
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let [minWidth, minHeight, natWidth, natHeight] =
|
||||
this._eventHandler.get_preferred_size();
|
||||
@ -576,6 +582,53 @@ ErrorLog.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function Memory() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Memory.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ vertical: true });
|
||||
this._glibc_uordblks = new St.Label();
|
||||
this.actor.add(this._glibc_uordblks);
|
||||
|
||||
this._js_bytes = new St.Label();
|
||||
this.actor.add(this._js_bytes);
|
||||
|
||||
this._gjs_boxed = new St.Label();
|
||||
this.actor.add(this._gjs_boxed);
|
||||
|
||||
this._gjs_gobject = new St.Label();
|
||||
this.actor.add(this._gjs_gobject);
|
||||
|
||||
this._gjs_function = new St.Label();
|
||||
this.actor.add(this._gjs_function);
|
||||
|
||||
this._gjs_closure = new St.Label();
|
||||
this.actor.add(this._gjs_closure);
|
||||
|
||||
this._gcbutton = new St.Button({ label: 'Full GC',
|
||||
style_class: 'lg-obj-inspector-button' });
|
||||
this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); }));
|
||||
this.actor.add(this._gcbutton, { x_align: St.Align.START,
|
||||
x_fill: false });
|
||||
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, this._renderText));
|
||||
},
|
||||
|
||||
_renderText: function() {
|
||||
if (!this.actor.mapped)
|
||||
return;
|
||||
let memInfo = global.get_memory_info();
|
||||
this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks;
|
||||
this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes;
|
||||
this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed;
|
||||
this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject;
|
||||
this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function;
|
||||
this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure;
|
||||
}
|
||||
};
|
||||
|
||||
function Extensions() {
|
||||
this._init();
|
||||
}
|
||||
@ -707,6 +760,7 @@ LookingGlass.prototype = {
|
||||
let toolbar = new St.BoxLayout({ name: 'Toolbar' });
|
||||
this.actor.add_actor(toolbar);
|
||||
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: 24 });
|
||||
toolbar.add_actor(inspectIcon);
|
||||
inspectIcon.reactive = true;
|
||||
@ -744,12 +798,7 @@ LookingGlass.prototype = {
|
||||
let label = new St.Label({ text: 'js>>> ' });
|
||||
entryArea.add(label);
|
||||
|
||||
this._entry = new St.Entry();
|
||||
/* unmapping the edit box will un-focus it, undo that */
|
||||
notebook.connect('selection', Lang.bind(this, function (nb, child) {
|
||||
if (child == this._evalBox)
|
||||
global.stage.set_key_focus(this._entry);
|
||||
}));
|
||||
this._entry = new St.Entry({ can_focus: true });
|
||||
entryArea.add(this._entry, { expand: true });
|
||||
|
||||
this._windowList = new WindowList();
|
||||
@ -762,6 +811,9 @@ LookingGlass.prototype = {
|
||||
this._errorLog = new ErrorLog();
|
||||
notebook.appendPage('Errors', this._errorLog.actor);
|
||||
|
||||
this._memory = new Memory();
|
||||
notebook.appendPage('Memory', this._memory.actor);
|
||||
|
||||
this._extensions = new Extensions();
|
||||
notebook.appendPage('Extensions', this._extensions.actor);
|
||||
|
||||
@ -855,7 +907,7 @@ LookingGlass.prototype = {
|
||||
},
|
||||
|
||||
_resizeTo: function(actor) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let myWidth = primary.width * 0.7;
|
||||
let myHeight = primary.height * 0.7;
|
||||
let [srcX, srcY] = actor.get_transformed_position();
|
||||
@ -908,6 +960,7 @@ LookingGlass.prototype = {
|
||||
if (!Main.pushModal(this._entry))
|
||||
return;
|
||||
|
||||
this._notebook.selectIndex(0);
|
||||
this.actor.show();
|
||||
this.actor.lower(Main.chrome.actor);
|
||||
this._open = true;
|
||||
|
256
js/ui/main.js
@ -1,11 +1,5 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
imports.gi.versions.Clutter = '1.0';
|
||||
imports.gi.versions.Gio = '2.0';
|
||||
imports.gi.versions.Gdk = '3.0';
|
||||
imports.gi.versions.GdkPixbuf = '2.0';
|
||||
imports.gi.versions.Gtk = '3.0';
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
@ -16,21 +10,24 @@ const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AutomountManager = imports.ui.automountManager;
|
||||
const AutorunManager = imports.ui.autorunManager;
|
||||
const Chrome = imports.ui.chrome;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const EndSessionDialog = imports.ui.endSessionDialog;
|
||||
const PolkitAuthenticationAgent = imports.ui.polkitAuthenticationAgent;
|
||||
const Environment = imports.ui.environment;
|
||||
const ExtensionSystem = imports.ui.extensionSystem;
|
||||
const Keyboard = imports.ui.keyboard;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const Overview = imports.ui.overview;
|
||||
const Panel = imports.ui.panel;
|
||||
const PlaceDisplay = imports.ui.placeDisplay;
|
||||
const RunDialog = imports.ui.runDialog;
|
||||
const Layout = imports.ui.layout;
|
||||
const LookingGlass = imports.ui.lookingGlass;
|
||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||
const WindowAttentionHandler = imports.ui.windowAttentionHandler;
|
||||
@ -46,41 +43,41 @@ const Util = imports.misc.util;
|
||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
||||
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
||||
|
||||
let automountManager = null;
|
||||
let autorunManager = null;
|
||||
let chrome = null;
|
||||
let panel = null;
|
||||
let hotCorners = [];
|
||||
let placesManager = null;
|
||||
let overview = null;
|
||||
let runDialog = null;
|
||||
let lookingGlass = null;
|
||||
let wm = null;
|
||||
let messageTray = null;
|
||||
let notificationDaemon = null;
|
||||
let windowAttentionHandler = null;
|
||||
let telepathyClient = null;
|
||||
let ctrlAltTabManager = null;
|
||||
let recorder = null;
|
||||
let shellDBusService = null;
|
||||
let modalCount = 0;
|
||||
let modalActorFocusStack = [];
|
||||
let uiGroup = null;
|
||||
let magnifier = null;
|
||||
let xdndHandler = null;
|
||||
let statusIconDispatcher = null;
|
||||
let keyboard = null;
|
||||
let layoutManager = null;
|
||||
|
||||
let _runDialog = null;
|
||||
let lookingGlass = null;
|
||||
let _recorder = null;
|
||||
let _modalCount = 0;
|
||||
let _modalActorFocusStack = [];
|
||||
let _errorLogStack = [];
|
||||
let _startDate;
|
||||
let _defaultCssStylesheet = null;
|
||||
let _cssStylesheet = null;
|
||||
|
||||
let background = null;
|
||||
const Main = this;
|
||||
Signals.addSignalMethods(Main)
|
||||
|
||||
function start() {
|
||||
// Add a binding for 'global' in the global JS namespace; (gjs
|
||||
// keeps the web browser convention of having that namespace be
|
||||
// called 'window'.)
|
||||
window.global = Shell.Global.get();
|
||||
|
||||
// Now monkey patch utility functions into the global proxy;
|
||||
// Monkey patch utility functions into the global proxy;
|
||||
// This is easier and faster than indirecting down into global
|
||||
// if we want to call back up into JS.
|
||||
global.logError = _logError;
|
||||
@ -102,8 +99,6 @@ function start() {
|
||||
// not loading any events until the user presses the clock
|
||||
global.launch_calendar_server();
|
||||
|
||||
Environment.init();
|
||||
|
||||
// Ensure ShellWindowTracker and ShellAppUsage are initialized; this will
|
||||
// also initialize ShellAppSystem first. ShellAppSystem
|
||||
// needs to load all the .desktop files, and ShellWindowTracker
|
||||
@ -141,46 +136,62 @@ function start() {
|
||||
global.overlay_group.reparent(uiGroup);
|
||||
global.stage.add_actor(uiGroup);
|
||||
|
||||
placesManager = new PlaceDisplay.PlacesManager();
|
||||
xdndHandler = new XdndHandler.XdndHandler();
|
||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||
overview = new Overview.Overview();
|
||||
chrome = new Chrome.Chrome();
|
||||
magnifier = new Magnifier.Magnifier();
|
||||
statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
|
||||
panel = new Panel.Panel();
|
||||
wm = new WindowManager.WindowManager();
|
||||
messageTray = new MessageTray.MessageTray();
|
||||
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
||||
telepathyClient = new TelepathyClient.Client();
|
||||
// Initialize JS modules. We do this in several steps, so that
|
||||
// less-fundamental modules can depend on more-fundamental ones.
|
||||
|
||||
overview.init();
|
||||
statusIconDispatcher.start(messageTray.actor);
|
||||
// Overall layout management
|
||||
layoutManager = new Layout.LayoutManager();
|
||||
chrome = new Chrome.Chrome();
|
||||
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
|
||||
Main.emit('layout-initialized');
|
||||
|
||||
// Major UI elements; initialize overview first since both panel
|
||||
// and messageTray connect to its signals
|
||||
overview = new Overview.Overview();
|
||||
panel = new Panel.Panel();
|
||||
messageTray = new MessageTray.MessageTray();
|
||||
keyboard = new Keyboard.Keyboard();
|
||||
Main.emit('main-ui-initialized');
|
||||
|
||||
// Now the rest of the JS modules (arbitrarily in alphabetical
|
||||
// order).
|
||||
keyboard.init();
|
||||
magnifier = new Magnifier.Magnifier();
|
||||
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||
placesManager = new PlaceDisplay.PlacesManager();
|
||||
statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
|
||||
telepathyClient = new TelepathyClient.Client();
|
||||
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
|
||||
wm = new WindowManager.WindowManager();
|
||||
xdndHandler = new XdndHandler.XdndHandler();
|
||||
automountManager = new AutomountManager.AutomountManager();
|
||||
autorunManager = new AutorunManager.AutorunManager();
|
||||
|
||||
Main.emit('initialized');
|
||||
|
||||
_startDate = new Date();
|
||||
|
||||
let recorderSettings = new Gio.Settings({ schema: 'org.gnome.shell.recorder' });
|
||||
|
||||
global.screen.connect('toggle-recording', function() {
|
||||
if (recorder == null) {
|
||||
recorder = new Shell.Recorder({ stage: global.stage });
|
||||
if (_recorder == null) {
|
||||
_recorder = new Shell.Recorder({ stage: global.stage });
|
||||
}
|
||||
|
||||
if (recorder.is_recording()) {
|
||||
recorder.pause();
|
||||
if (_recorder.is_recording()) {
|
||||
_recorder.pause();
|
||||
} else {
|
||||
// read the parameters from GSettings always in case they have changed
|
||||
recorder.set_framerate(recorderSettings.get_int('framerate'));
|
||||
recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
|
||||
_recorder.set_framerate(recorderSettings.get_int('framerate'));
|
||||
_recorder.set_filename('shell-%d%u-%c.' + recorderSettings.get_string('file-extension'));
|
||||
let pipeline = recorderSettings.get_string('pipeline');
|
||||
|
||||
if (!pipeline.match(/^\s*$/))
|
||||
recorder.set_pipeline(pipeline);
|
||||
_recorder.set_pipeline(pipeline);
|
||||
else
|
||||
recorder.set_pipeline(null);
|
||||
_recorder.set_pipeline(null);
|
||||
|
||||
recorder.record();
|
||||
_recorder.record();
|
||||
}
|
||||
});
|
||||
|
||||
@ -193,14 +204,10 @@ function start() {
|
||||
// Attempt to become a PolicyKit authentication agent
|
||||
PolkitAuthenticationAgent.init()
|
||||
|
||||
global.screen.connect('monitors-changed', _relayout);
|
||||
|
||||
ExtensionSystem.init();
|
||||
ExtensionSystem.loadExtensions();
|
||||
|
||||
// Perform initial relayout here
|
||||
_relayout();
|
||||
|
||||
// Initialize the panel status area now that extensions are loaded
|
||||
panel.startStatusArea();
|
||||
panel.startupAnimation();
|
||||
|
||||
@ -223,6 +230,7 @@ function start() {
|
||||
|
||||
global.screen.connect('window-entered-monitor', _windowEnteredMonitor);
|
||||
global.screen.connect('window-left-monitor', _windowLeftMonitor);
|
||||
global.screen.connect('restacked', _windowsRestacked);
|
||||
|
||||
_nWorkspacesChanged();
|
||||
}
|
||||
@ -314,17 +322,24 @@ function _windowRemoved(workspace, window) {
|
||||
function _windowLeftMonitor(metaScreen, monitorIndex, metaWin) {
|
||||
// If the window left the primary monitor, that
|
||||
// might make that workspace empty
|
||||
if (monitorIndex == global.get_primary_monitor_index())
|
||||
if (monitorIndex == layoutManager.primaryIndex)
|
||||
_queueCheckWorkspaces();
|
||||
}
|
||||
|
||||
function _windowEnteredMonitor(metaScreen, monitorIndex, metaWin) {
|
||||
// If the window entered the primary monitor, that
|
||||
// might make that workspace non-empty
|
||||
if (monitorIndex == global.get_primary_monitor_index())
|
||||
if (monitorIndex == layoutManager.primaryIndex)
|
||||
_queueCheckWorkspaces();
|
||||
}
|
||||
|
||||
function _windowsRestacked() {
|
||||
// Figure out where the pointer is in case we lost track of
|
||||
// it during a grab. (In particular, if a trayicon popup menu
|
||||
// is dismissed, see if we need to close the message tray.)
|
||||
global.sync_pointer();
|
||||
}
|
||||
|
||||
function _queueCheckWorkspaces() {
|
||||
if (_checkWorkspacesId == 0)
|
||||
_checkWorkspacesId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, _checkWorkspaces);
|
||||
@ -408,12 +423,21 @@ function setThemeStylesheet(cssStylesheet)
|
||||
*/
|
||||
function loadTheme() {
|
||||
let themeContext = St.ThemeContext.get_for_stage (global.stage);
|
||||
let previousTheme = themeContext.get_theme();
|
||||
|
||||
let cssStylesheet = _defaultCssStylesheet;
|
||||
if (_cssStylesheet != null)
|
||||
cssStylesheet = _cssStylesheet;
|
||||
|
||||
let theme = new St.Theme ({ application_stylesheet: cssStylesheet });
|
||||
|
||||
if (previousTheme) {
|
||||
let customStylesheets = previousTheme.get_custom_stylesheets();
|
||||
|
||||
for (let i = 0; i < customStylesheets.length; i++)
|
||||
theme.load_stylesheet(customStylesheets[i]);
|
||||
}
|
||||
|
||||
themeContext.set_theme (theme);
|
||||
}
|
||||
|
||||
@ -479,80 +503,16 @@ function _getAndClearErrorStack() {
|
||||
return errors;
|
||||
}
|
||||
|
||||
function _relayout() {
|
||||
let monitors = global.get_monitors();
|
||||
// destroy old corners
|
||||
for (let i = 0; i < hotCorners.length; i++)
|
||||
hotCorners[i].destroy();
|
||||
hotCorners = [];
|
||||
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let monitor = monitors[i];
|
||||
let isPrimary = (monitor.x == primary.x &&
|
||||
monitor.y == primary.y &&
|
||||
monitor.width == primary.width &&
|
||||
monitor.height == primary.height);
|
||||
|
||||
let cornerX = monitor.x;
|
||||
let cornerY = monitor.y;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
cornerX += monitor.width;
|
||||
|
||||
|
||||
let haveTopLeftCorner = true;
|
||||
|
||||
/* Check if we have a top left (right for RTL) corner.
|
||||
* I.e. if there is no monitor directly above or to the left(right) */
|
||||
let besideX;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
besideX = monitor.x + 1;
|
||||
else
|
||||
besideX = cornerX - 1;
|
||||
let besideY = cornerY;
|
||||
let aboveX = cornerX;
|
||||
let aboveY = cornerY - 1;
|
||||
|
||||
for (let j = 0; j < monitors.length; j++) {
|
||||
if (i == j)
|
||||
continue;
|
||||
let otherMonitor = monitors[j];
|
||||
if (besideX >= otherMonitor.x &&
|
||||
besideX < otherMonitor.x + otherMonitor.width &&
|
||||
besideY >= otherMonitor.y &&
|
||||
besideY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
if (aboveX >= otherMonitor.x &&
|
||||
aboveX < otherMonitor.x + otherMonitor.width &&
|
||||
aboveY >= otherMonitor.y &&
|
||||
aboveY < otherMonitor.y + otherMonitor.height) {
|
||||
haveTopLeftCorner = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We only want hot corners where there is a natural top-left
|
||||
* corner, and on the primary monitor */
|
||||
if (!isPrimary && !haveTopLeftCorner)
|
||||
continue;
|
||||
|
||||
let corner = new Panel.HotCorner(isPrimary ? panel.button : null);
|
||||
hotCorners.push(corner);
|
||||
corner.actor.set_position(cornerX, cornerY);
|
||||
if (isPrimary)
|
||||
panel.setHotCorner(corner);
|
||||
function logStackTrace(msg) {
|
||||
try {
|
||||
throw new Error();
|
||||
} catch (e) {
|
||||
// e.stack must have at least two lines, with the first being
|
||||
// logStackTrace() (which we strip off), and the second being
|
||||
// our caller.
|
||||
let trace = e.stack.substr(e.stack.indexOf('\n') + 1);
|
||||
log(msg ? (msg + '\n' + trace) : trace);
|
||||
}
|
||||
|
||||
panel.relayout();
|
||||
overview.relayout();
|
||||
|
||||
// To avoid updating the position and size of the workspaces
|
||||
// in the overview, we just hide the overview. The positions
|
||||
// will be updated when it is next shown.
|
||||
overview.hide();
|
||||
}
|
||||
|
||||
function isWindowActorDisplayedOnWorkspace(win, workspaceIndex) {
|
||||
@ -572,7 +532,7 @@ function getWindowActorsForWorkspace(workspaceIndex) {
|
||||
// all key events will be delivered to the stage, so ::captured-event
|
||||
// on the stage can be used for global keybindings.)
|
||||
function _globalKeyPressHandler(actor, event) {
|
||||
if (modalCount == 0)
|
||||
if (_modalCount == 0)
|
||||
return false;
|
||||
if (event.type() != Clutter.EventType.KEY_PRESS)
|
||||
return false;
|
||||
@ -597,7 +557,7 @@ function _globalKeyPressHandler(actor, event) {
|
||||
|
||||
// Other bindings are only available when the overview is up and
|
||||
// no modal dialog is present.
|
||||
if (!overview.visible || modalCount > 1)
|
||||
if (!overview.visible || _modalCount > 1)
|
||||
return false;
|
||||
|
||||
// This isn't a Meta.KeyBindingAction yet
|
||||
@ -638,8 +598,8 @@ function _globalKeyPressHandler(actor, event) {
|
||||
}
|
||||
|
||||
function _findModal(actor) {
|
||||
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
||||
if (modalActorFocusStack[i].actor == actor)
|
||||
for (let i = 0; i < _modalActorFocusStack.length; i++) {
|
||||
if (_modalActorFocusStack[i].actor == actor)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
@ -669,7 +629,7 @@ function pushModal(actor, timestamp) {
|
||||
if (timestamp == undefined)
|
||||
timestamp = global.get_current_time();
|
||||
|
||||
if (modalCount == 0) {
|
||||
if (_modalCount == 0) {
|
||||
if (!global.begin_modal(timestamp)) {
|
||||
log('pushModal: invocation of begin_modal failed');
|
||||
return false;
|
||||
@ -678,11 +638,11 @@ function pushModal(actor, timestamp) {
|
||||
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
|
||||
modalCount += 1;
|
||||
_modalCount += 1;
|
||||
let actorDestroyId = actor.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack.splice(index, 1);
|
||||
_modalActorFocusStack.splice(index, 1);
|
||||
});
|
||||
let curFocus = global.stage.get_key_focus();
|
||||
let curFocusDestroyId;
|
||||
@ -690,10 +650,10 @@ function pushModal(actor, timestamp) {
|
||||
curFocusDestroyId = curFocus.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack[index].actor = null;
|
||||
_modalActorFocusStack[index].actor = null;
|
||||
});
|
||||
}
|
||||
modalActorFocusStack.push({ actor: actor,
|
||||
_modalActorFocusStack.push({ actor: actor,
|
||||
focus: curFocus,
|
||||
destroyId: actorDestroyId,
|
||||
focusDestroyId: curFocusDestroyId });
|
||||
@ -728,28 +688,28 @@ function popModal(actor, timestamp) {
|
||||
throw new Error('incorrect pop');
|
||||
}
|
||||
|
||||
modalCount -= 1;
|
||||
_modalCount -= 1;
|
||||
|
||||
let record = modalActorFocusStack[focusIndex];
|
||||
let record = _modalActorFocusStack[focusIndex];
|
||||
record.actor.disconnect(record.destroyId);
|
||||
|
||||
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||
if (focusIndex == _modalActorFocusStack.length - 1) {
|
||||
if (record.focus)
|
||||
record.focus.disconnect(record.focusDestroyId);
|
||||
global.stage.set_key_focus(record.focus);
|
||||
} else {
|
||||
let t = modalActorFocusStack[modalActorFocusStack.length - 1];
|
||||
let t = _modalActorFocusStack[_modalActorFocusStack.length - 1];
|
||||
if (t.focus)
|
||||
t.focus.disconnect(t.focusDestroyId);
|
||||
// Remove from the middle, shift the focus chain up
|
||||
for (let i = modalActorFocusStack.length - 1; i > focusIndex; i--) {
|
||||
modalActorFocusStack[i].focus = modalActorFocusStack[i - 1].focus;
|
||||
modalActorFocusStack[i].focusDestroyId = modalActorFocusStack[i - 1].focusDestroyId;
|
||||
for (let i = _modalActorFocusStack.length - 1; i > focusIndex; i--) {
|
||||
_modalActorFocusStack[i].focus = _modalActorFocusStack[i - 1].focus;
|
||||
_modalActorFocusStack[i].focusDestroyId = _modalActorFocusStack[i - 1].focusDestroyId;
|
||||
}
|
||||
}
|
||||
modalActorFocusStack.splice(focusIndex, 1);
|
||||
_modalActorFocusStack.splice(focusIndex, 1);
|
||||
|
||||
if (modalCount > 0)
|
||||
if (_modalCount > 0)
|
||||
return;
|
||||
|
||||
global.end_modal(timestamp);
|
||||
@ -765,10 +725,10 @@ function createLookingGlass() {
|
||||
}
|
||||
|
||||
function getRunDialog() {
|
||||
if (runDialog == null) {
|
||||
runDialog = new RunDialog.RunDialog();
|
||||
if (_runDialog == null) {
|
||||
_runDialog = new RunDialog.RunDialog();
|
||||
}
|
||||
return runDialog;
|
||||
return _runDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -20,9 +20,6 @@ const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const ANIMATION_TIME = 0.2;
|
||||
const NOTIFICATION_TIMEOUT = 4;
|
||||
const SUMMARY_TIMEOUT = 1;
|
||||
@ -411,6 +408,7 @@ Notification.prototype = {
|
||||
this._bannerBodyText = null;
|
||||
this._bannerBodyMarkup = false;
|
||||
this._titleFitsInBannerMode = true;
|
||||
this._titleDirection = St.TextDirection.NONE;
|
||||
this._spacing = 0;
|
||||
this._scrollPolicy = Gtk.PolicyType.AUTOMATIC;
|
||||
|
||||
@ -510,6 +508,19 @@ Notification.prototype = {
|
||||
title = title ? _fixMarkup(title.replace(/\n/g, ' '), params.titleMarkup) : '';
|
||||
this._titleLabel.clutter_text.set_markup('<b>' + title + '</b>');
|
||||
|
||||
if (Pango.find_base_dir(title, -1) == Pango.Direction.RTL)
|
||||
this._titleDirection = St.TextDirection.RTL;
|
||||
else
|
||||
this._titleDirection = St.TextDirection.LTR;
|
||||
|
||||
// Let the title's text direction control the overall direction
|
||||
// of the notification - in case where different scripts are used
|
||||
// in the notification, this is the right thing for the icon, and
|
||||
// arguably for action buttons as well. Labels other than the title
|
||||
// will be allocated at the available width, so that their alignment
|
||||
// is done correctly automatically.
|
||||
this._table.set_direction(this._titleDirection);
|
||||
|
||||
// Unless the notification has custom content, we save this._bannerBodyText
|
||||
// to add it to the content of the notification if the notification is
|
||||
// expandable due to other elements in its content area or due to the banner
|
||||
@ -546,7 +557,7 @@ Notification.prototype = {
|
||||
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
|
||||
vscrollbar_policy: this._scrollPolicy,
|
||||
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||
vfade: true });
|
||||
style_class: 'vfade' });
|
||||
this._table.add(this._scrollArea, { row: 1, col: 1 });
|
||||
this._contentArea = new St.BoxLayout({ name: 'notification-body',
|
||||
vertical: true });
|
||||
@ -711,23 +722,39 @@ Notification.prototype = {
|
||||
let availWidth = box.x2 - box.x1;
|
||||
|
||||
let titleBox = new Clutter.ActorBox();
|
||||
titleBox.x1 = titleBox.y1 = 0;
|
||||
titleBox.x2 = Math.min(titleNatW, availWidth);
|
||||
let titleBoxW = Math.min(titleNatW, availWidth);
|
||||
if (this._titleDirection == St.TextDirection.RTL) {
|
||||
titleBox.x1 = availWidth - titleBoxW;
|
||||
titleBox.x2 = availWidth;
|
||||
} else {
|
||||
titleBox.x1 = 0;
|
||||
titleBox.x2 = titleBoxW;
|
||||
}
|
||||
titleBox.y1 = 0;
|
||||
titleBox.y2 = titleNatH;
|
||||
this._titleLabel.allocate(titleBox, flags);
|
||||
this._titleFitsInBannerMode = (titleNatW <= availWidth);
|
||||
|
||||
let bannerFits = true;
|
||||
if (titleBox.x2 + this._spacing > availWidth) {
|
||||
if (titleBoxW + this._spacing > availWidth) {
|
||||
this._bannerLabel.opacity = 0;
|
||||
bannerFits = false;
|
||||
} else {
|
||||
let bannerBox = new Clutter.ActorBox();
|
||||
bannerBox.x1 = titleBox.x2 + this._spacing;
|
||||
|
||||
if (this._titleDirection == St.TextDirection.RTL) {
|
||||
bannerBox.x1 = 0;
|
||||
bannerBox.x2 = titleBox.x1 - this._spacing;
|
||||
|
||||
bannerFits = (bannerBox.x2 - bannerNatW >= 0);
|
||||
} else {
|
||||
bannerBox.x1 = titleBox.x2 + this._spacing;
|
||||
bannerBox.x2 = availWidth;
|
||||
|
||||
bannerFits = (bannerBox.x1 + bannerNatW <= availWidth);
|
||||
}
|
||||
bannerBox.y1 = 0;
|
||||
bannerBox.x2 = Math.min(bannerBox.x1 + bannerNatW, availWidth);
|
||||
bannerBox.y2 = titleNatH;
|
||||
bannerFits = (bannerBox.x1 + bannerNatW <= availWidth);
|
||||
this._bannerLabel.allocate(bannerBox, flags);
|
||||
|
||||
// Make _bannerLabel visible if the entire notification
|
||||
@ -802,6 +829,7 @@ Notification.prototype = {
|
||||
// Restore banner opacity in case the notification is shown in the
|
||||
// banner mode again on update.
|
||||
this._bannerLabel.opacity = 255;
|
||||
this.emit('collapsed');
|
||||
},
|
||||
|
||||
_onActionInvoked: function(actor, mouseButtonClicked, id) {
|
||||
@ -852,20 +880,96 @@ Source.prototype = {
|
||||
|
||||
_init: function(title) {
|
||||
this.title = title;
|
||||
|
||||
this.actor = new Shell.GenericContainer();
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
this._actorDestroyed = true;
|
||||
}));
|
||||
this._actorDestroyed = false;
|
||||
|
||||
this._counterLabel = new St.Label();
|
||||
this._counterBin = new St.Bin({ style_class: 'summary-source-counter',
|
||||
child: this._counterLabel });
|
||||
this._counterBin.hide();
|
||||
|
||||
this._iconBin = new St.Bin({ width: this.ICON_SIZE,
|
||||
height: this.ICON_SIZE,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
|
||||
this.actor.add_actor(this._iconBin);
|
||||
this.actor.add_actor(this._counterBin);
|
||||
|
||||
this.isTransient = false;
|
||||
this.isChat = false;
|
||||
|
||||
this.notifications = [];
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
let [min, nat] = this._iconBin.get_preferred_width(forHeight);
|
||||
alloc.min_size = min; alloc.nat_size = nat;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
let [min, nat] = this._iconBin.get_preferred_height(forWidth);
|
||||
alloc.min_size = min; alloc.nat_size = nat;
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
// the iconBin should fill our entire box
|
||||
this._iconBin.allocate(box, flags);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
let [minWidth, minHeight, naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
|
||||
let direction = this.actor.get_direction();
|
||||
|
||||
if (direction == St.TextDirection.LTR) {
|
||||
// allocate on the right in LTR
|
||||
childBox.x1 = box.x2 - naturalWidth;
|
||||
childBox.x2 = box.x2;
|
||||
} else {
|
||||
// allocate on the left in RTL
|
||||
childBox.x1 = 0;
|
||||
childBox.x2 = naturalWidth;
|
||||
}
|
||||
|
||||
childBox.y1 = box.y2 - naturalHeight;
|
||||
childBox.y2 = box.y2;
|
||||
|
||||
this._counterBin.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
_setCount: function(count, visible) {
|
||||
if (isNaN(parseInt(count)))
|
||||
throw new Error("Invalid notification count: " + count);
|
||||
|
||||
if (this._actorDestroyed)
|
||||
return;
|
||||
|
||||
this._counterBin.visible = visible;
|
||||
this._counterLabel.set_text(count.toString());
|
||||
},
|
||||
|
||||
_updateCount: function() {
|
||||
let count = this.notifications.length;
|
||||
this._setCount(count, count > 1);
|
||||
},
|
||||
|
||||
setTransient: function(isTransient) {
|
||||
this.isTransient = isTransient;
|
||||
},
|
||||
|
||||
setTitle: function(newTitle) {
|
||||
this.title = newTitle;
|
||||
this.emit('title-changed');
|
||||
},
|
||||
|
||||
// Called to create a new icon actor (of size this.ICON_SIZE).
|
||||
// Must be overridden by the subclass if you do not pass icons
|
||||
// explicitly to the Notification() constructor.
|
||||
@ -876,7 +980,7 @@ Source.prototype = {
|
||||
// Unlike createNotificationIcon, this always returns the same actor;
|
||||
// there is only one summary icon actor for a Source.
|
||||
getSummaryIcon: function() {
|
||||
return this._iconBin;
|
||||
return this.actor;
|
||||
},
|
||||
|
||||
pushNotification: function(notification) {
|
||||
@ -895,7 +999,11 @@ Source.prototype = {
|
||||
this.notifications.splice(index, 1);
|
||||
if (this.notifications.length == 0)
|
||||
this._lastNotificationRemoved();
|
||||
|
||||
this._updateCount();
|
||||
}));
|
||||
|
||||
this._updateCount();
|
||||
},
|
||||
|
||||
notify: function(notification) {
|
||||
@ -932,6 +1040,8 @@ Source.prototype = {
|
||||
for (let i = this.notifications.length - 1; i >= 0; i--)
|
||||
if (!this.notifications[i].resident)
|
||||
this.notifications[i].destroy();
|
||||
|
||||
this._updateCount();
|
||||
},
|
||||
|
||||
// Default implementation is to destroy this source, but subclasses can override
|
||||
@ -968,6 +1078,11 @@ SummaryItem.prototype = {
|
||||
this._sourceTitleBin.child = this._sourceTitle;
|
||||
this._sourceTitleBin.width = 0;
|
||||
|
||||
this.source.connect('title-changed',
|
||||
Lang.bind(this, function() {
|
||||
this._sourceTitle.text = source.title;
|
||||
}));
|
||||
|
||||
this._sourceBox.add(this._sourceIcon, { y_fill: false });
|
||||
this._sourceBox.add(this._sourceTitleBin, { expand: true, y_fill: false });
|
||||
this.actor.child = this._sourceBox;
|
||||
@ -975,7 +1090,7 @@ SummaryItem.prototype = {
|
||||
this.notificationStackView = new St.ScrollView({ name: source.isChat ? '' : 'summary-notification-stack-scrollview',
|
||||
vscrollbar_policy: source.isChat ? Gtk.PolicyType.NEVER : Gtk.PolicyType.AUTOMATIC,
|
||||
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||
vfade: true });
|
||||
style_class: 'vfade' });
|
||||
this.notificationStack = new St.BoxLayout({ name: 'summary-notification-stack',
|
||||
vertical: true });
|
||||
this.notificationStackView.add_actor(this.notificationStack);
|
||||
@ -1186,9 +1301,9 @@ MessageTray.prototype = {
|
||||
this._focusGrabber.connect('focus-grabbed', Lang.bind(this,
|
||||
function() {
|
||||
if (this._summaryBoxPointer.bin.child)
|
||||
this._lock();
|
||||
this.lock();
|
||||
}));
|
||||
this._focusGrabber.connect('focus-ungrabbed', Lang.bind(this, this._unlock));
|
||||
this._focusGrabber.connect('focus-ungrabbed', Lang.bind(this, this.unlock));
|
||||
this._focusGrabber.connect('button-pressed', Lang.bind(this,
|
||||
function(focusGrabber, source) {
|
||||
if (this._clickedSummaryItem && !this._clickedSummaryItem.actor.contains(source))
|
||||
@ -1198,7 +1313,7 @@ MessageTray.prototype = {
|
||||
this._focusGrabber.connect('escape-pressed', Lang.bind(this, this._escapeTray));
|
||||
|
||||
this._trayState = State.HIDDEN;
|
||||
this._locked = false;
|
||||
this._locked = 0;
|
||||
this._useLongerTrayLeftTimeout = false;
|
||||
this._trayLeftTimeoutId = 0;
|
||||
this._pointerInTray = false;
|
||||
@ -1214,21 +1329,21 @@ MessageTray.prototype = {
|
||||
this._notificationRemoved = false;
|
||||
this._reNotifyAfterHideNotification = null;
|
||||
|
||||
Main.chrome.addActor(this.actor, { affectsStruts: false,
|
||||
visibleInOverview: true });
|
||||
Main.layoutManager.topBox.add_actor(this.actor);
|
||||
Main.chrome.trackActor(this._notificationBin);
|
||||
Main.chrome.trackActor(this._summaryBin);
|
||||
Main.chrome.trackActor(this._summaryBoxPointer.actor);
|
||||
|
||||
global.screen.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._setSizePosition));
|
||||
|
||||
this._setSizePosition();
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this,
|
||||
function() {
|
||||
this._overviewVisible = true;
|
||||
if (this._locked) {
|
||||
if (this._locked > 0) {
|
||||
this._unsetClickedSummaryItem();
|
||||
this._unlock();
|
||||
this.unlock();
|
||||
} else {
|
||||
this._updateState();
|
||||
}
|
||||
@ -1236,9 +1351,9 @@ MessageTray.prototype = {
|
||||
Main.overview.connect('hiding', Lang.bind(this,
|
||||
function() {
|
||||
this._overviewVisible = false;
|
||||
if (this._locked) {
|
||||
if (this._locked > 0) {
|
||||
this._unsetClickedSummaryItem();
|
||||
this._unlock();
|
||||
this.unlock();
|
||||
} else {
|
||||
this._updateState();
|
||||
}
|
||||
@ -1255,20 +1370,20 @@ MessageTray.prototype = {
|
||||
},
|
||||
|
||||
_setSizePosition: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
this.actor.x = primary.x;
|
||||
this.actor.y = primary.y + primary.height - 1;
|
||||
this.actor.width = primary.width;
|
||||
let monitor = Main.layoutManager.bottomMonitor;
|
||||
this.actor.x = monitor.x;
|
||||
this.actor.y = -1;
|
||||
this.actor.width = monitor.width;
|
||||
this._notificationBin.x = 0;
|
||||
this._notificationBin.width = primary.width;
|
||||
this._notificationBin.width = monitor.width;
|
||||
this._summaryBin.x = 0;
|
||||
this._summaryBin.width = primary.width;
|
||||
this._summaryBin.width = monitor.width;
|
||||
|
||||
if (this._pointerBarrier)
|
||||
global.destroy_pointer_barrier(this._pointerBarrier);
|
||||
this._pointerBarrier =
|
||||
global.create_pointer_barrier(primary.x + primary.width, primary.y + primary.height - this.actor.height,
|
||||
primary.x + primary.width, primary.y + primary.height,
|
||||
global.create_pointer_barrier(monitor.x + monitor.width, monitor.y + monitor.height - this.actor.height,
|
||||
monitor.x + monitor.width, monitor.y + monitor.height,
|
||||
4 /* BarrierNegativeX */);
|
||||
|
||||
|
||||
@ -1409,15 +1524,16 @@ MessageTray.prototype = {
|
||||
this._notificationQueue.splice(index, 1);
|
||||
},
|
||||
|
||||
_lock: function() {
|
||||
this._locked = true;
|
||||
lock: function() {
|
||||
this._locked += 1;
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
_unlock: function() {
|
||||
if (!this._locked)
|
||||
return;
|
||||
this._locked = false;
|
||||
this._pointerInTray = this.actor.hover && !this._summaryBoxPointer.bin.hover;
|
||||
unlock: function() {
|
||||
if (this._locked > 0)
|
||||
this._locked -= 1;
|
||||
this._pointerInSummary = false;
|
||||
this._pointerInTray = false;
|
||||
this._updateState();
|
||||
},
|
||||
|
||||
@ -1578,6 +1694,8 @@ MessageTray.prototype = {
|
||||
this._clickedSummaryItemMouseButton != button) {
|
||||
this._clickedSummaryItem = summaryItem;
|
||||
this._clickedSummaryItemMouseButton = button;
|
||||
|
||||
summaryItem.source.emit('summary-item-clicked', button);
|
||||
} else {
|
||||
this._unsetClickedSummaryItem();
|
||||
}
|
||||
@ -1699,7 +1817,7 @@ MessageTray.prototype = {
|
||||
},
|
||||
|
||||
_escapeTray: function() {
|
||||
this._unlock();
|
||||
this.unlock();
|
||||
this._pointerInTray = false;
|
||||
this._pointerInSummary = false;
|
||||
this._updateNotificationTimeout(0);
|
||||
@ -1717,7 +1835,7 @@ MessageTray.prototype = {
|
||||
let notificationsPending = this._notificationQueue.length > 0 && (!this._busy || notificationUrgent);
|
||||
let notificationPinned = this._pointerInTray && !this._pointerInSummary && !this._notificationRemoved;
|
||||
let notificationExpanded = this._notificationBin.y < 0;
|
||||
let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && !this._locked) || this._notificationRemoved;
|
||||
let notificationExpired = (this._notificationTimeoutId == 0 && !(this._notification && this._notification.urgency == Urgency.CRITICAL) && !this._pointerInTray && (this._locked == 0)) || this._notificationRemoved;
|
||||
let canShowNotification = notificationsPending && this._summaryState == State.HIDDEN;
|
||||
|
||||
if (this._notificationState == State.HIDDEN) {
|
||||
@ -1733,17 +1851,17 @@ MessageTray.prototype = {
|
||||
}
|
||||
|
||||
// Summary
|
||||
let summarySummoned = this._pointerInSummary || this._overviewVisible;
|
||||
let summaryPinned = this._summaryTimeoutId != 0 || this._pointerInTray || summarySummoned || this._locked;
|
||||
let summarySummoned = this._pointerInSummary || this._overviewVisible || (this._locked > 0);
|
||||
let summaryPinned = this._summaryTimeoutId != 0 || this._pointerInTray || summarySummoned;
|
||||
let summaryHovered = this._pointerInTray || this._pointerInSummary;
|
||||
let summaryVisibleWithNoHover = (this._overviewVisible || this._locked) && !summaryHovered;
|
||||
let summaryVisibleWithNoHover = (this._overviewVisible || this._locked > 0) && !summaryHovered;
|
||||
let summaryNotificationIsForExpandedSummaryItem = (this._clickedSummaryItem == this._expandedSummaryItem);
|
||||
|
||||
let notificationsVisible = (this._notificationState == State.SHOWING ||
|
||||
this._notificationState == State.SHOWN);
|
||||
let notificationsDone = !notificationsVisible && !notificationsPending;
|
||||
|
||||
let summaryOptionalInOverview = this._overviewVisible && !this._locked && !summaryHovered;
|
||||
let summaryOptionalInOverview = this._overviewVisible && (this._locked == 0) && !summaryHovered;
|
||||
let mustHideSummary = (notificationsPending && (notificationUrgent || summaryOptionalInOverview))
|
||||
|| notificationsVisible;
|
||||
|
||||
@ -1827,18 +1945,16 @@ MessageTray.prototype = {
|
||||
},
|
||||
|
||||
_showTray: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
this._tween(this.actor, '_trayState', State.SHOWN,
|
||||
{ y: primary.y + primary.height - this.actor.height,
|
||||
{ y: 0,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
_hideTray: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
this._tween(this.actor, '_trayState', State.HIDDEN,
|
||||
{ y: primary.y + primary.height - 1,
|
||||
{ y: Main.layoutManager.topBox.height - 1,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
@ -1984,9 +2100,15 @@ MessageTray.prototype = {
|
||||
this._notification.expand(!autoExpanding);
|
||||
},
|
||||
|
||||
_onNotificationExpanded: function() {
|
||||
_onNotificationExpanded: function() {
|
||||
let expandedY = this.actor.height - this._notificationBin.height;
|
||||
if (this._notificationBin.y != expandedY)
|
||||
|
||||
// Don't animate the notification to its new position if it has shrunk:
|
||||
// there will be a very visible "gap" that breaks the illusion.
|
||||
|
||||
if (this._notificationBin.y < expandedY)
|
||||
this._notificationBin.y = expandedY;
|
||||
else if (this._notification.y != expandedY)
|
||||
this._tween(this._notificationBin, '_notificationState', State.SHOWN,
|
||||
{ y: expandedY,
|
||||
time: ANIMATION_TIME,
|
||||
@ -2001,7 +2123,6 @@ MessageTray.prototype = {
|
||||
},
|
||||
|
||||
_showSummary: function(timeout) {
|
||||
let primary = global.get_primary_monitor();
|
||||
this._summaryBin.opacity = 0;
|
||||
this._summaryBin.y = this.actor.height;
|
||||
this._tween(this._summaryBin, '_summaryState', State.SHOWN,
|
||||
|
@ -10,8 +10,6 @@ const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Params = imports.misc.params;
|
||||
|
||||
@ -50,10 +48,6 @@ ModalDialog.prototype = {
|
||||
coordinate: Clutter.BindCoordinate.POSITION | Clutter.BindCoordinate.SIZE });
|
||||
this._group.add_constraint(constraint);
|
||||
|
||||
global.focus_manager.add_group(this._group);
|
||||
this._initialKeyFocus = this._group;
|
||||
this._savedKeyFocus = null;
|
||||
|
||||
this._group.connect('destroy', Lang.bind(this, this._onGroupDestroy));
|
||||
|
||||
this._actionKeys = {};
|
||||
@ -94,6 +88,10 @@ ModalDialog.prototype = {
|
||||
{ expand: true,
|
||||
x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.END });
|
||||
|
||||
global.focus_manager.add_group(this._dialogLayout);
|
||||
this._initialKeyFocus = this._dialogLayout;
|
||||
this._savedKeyFocus = null;
|
||||
},
|
||||
|
||||
setButtons: function(buttons) {
|
||||
@ -151,7 +149,7 @@ ModalDialog.prototype = {
|
||||
},
|
||||
|
||||
_fadeOpen: function() {
|
||||
let monitor = global.get_focus_monitor();
|
||||
let monitor = Main.layoutManager.focusMonitor;
|
||||
|
||||
this._backgroundBin.set_position(monitor.x, monitor.y);
|
||||
this._backgroundBin.set_size(monitor.width, monitor.height);
|
||||
@ -195,6 +193,7 @@ ModalDialog.prototype = {
|
||||
|
||||
this.state = State.CLOSING;
|
||||
this.popModal(timestamp);
|
||||
this._savedKeyFocus = null;
|
||||
|
||||
Tweener.addTween(this._group,
|
||||
{ opacity: 0,
|
||||
|
@ -7,8 +7,6 @@ const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Mainloop = imports.mainloop;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const Main = imports.ui.main;
|
||||
@ -99,8 +97,10 @@ NotificationDaemon.prototype = {
|
||||
this._notifications = {};
|
||||
this._busProxy = new Bus();
|
||||
|
||||
Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||
Main.connect('initialized', Lang.bind(this, function() {
|
||||
Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||
}));
|
||||
|
||||
Shell.WindowTracker.get_default().connect('notify::focus-app',
|
||||
Lang.bind(this, this._onFocusAppChanged));
|
||||
@ -124,7 +124,7 @@ NotificationDaemon.prototype = {
|
||||
} else if (hints['image-data']) {
|
||||
let [width, height, rowStride, hasAlpha,
|
||||
bitsPerSample, nChannels, data] = hints['image-data'];
|
||||
return textureCache.load_from_raw(data, data.length, hasAlpha,
|
||||
return textureCache.load_from_raw(data, hasAlpha,
|
||||
width, height, rowStride, size);
|
||||
} else {
|
||||
let stockIcon;
|
||||
@ -150,7 +150,7 @@ NotificationDaemon.prototype = {
|
||||
//
|
||||
// Either a pid or ndata.notification is needed to retrieve or
|
||||
// create a source.
|
||||
_getSource: function(title, pid, ndata) {
|
||||
_getSource: function(title, pid, ndata, sender) {
|
||||
if (!pid && !(ndata && ndata.notification))
|
||||
return null;
|
||||
|
||||
@ -167,10 +167,13 @@ NotificationDaemon.prototype = {
|
||||
// with a transient one from the same sender, so we
|
||||
// always create a new source object for new transient notifications
|
||||
// and never add it to this._sources .
|
||||
if (!isForTransientNotification && this._sources[pid])
|
||||
return this._sources[pid];
|
||||
if (!isForTransientNotification && this._sources[pid]) {
|
||||
let source = this._sources[pid];
|
||||
source.setTitle(title);
|
||||
return source;
|
||||
}
|
||||
|
||||
let source = new Source(title, pid);
|
||||
let source = new Source(title, pid, sender);
|
||||
source.setTransient(isForTransientNotification);
|
||||
|
||||
if (!isForTransientNotification) {
|
||||
@ -189,9 +192,11 @@ NotificationDaemon.prototype = {
|
||||
actions, hints, timeout) {
|
||||
let id;
|
||||
|
||||
// Filter out chat and presence notifications from Empathy, since we
|
||||
// handle that information from telepathyClient.js
|
||||
// Filter out chat, presence, calls and invitation notifications from
|
||||
// Empathy, since we handle that information from telepathyClient.js
|
||||
if (appName == 'Empathy' && (hints['category'] == 'im.received' ||
|
||||
hints['category'] == 'x-empathy.im.room-invitation' ||
|
||||
hints['category'] == 'x-empathy.call.incoming' ||
|
||||
hints['category'] == 'presence.online' ||
|
||||
hints['category'] == 'presence.offline')) {
|
||||
// Ignore replacesId since we already sent back a
|
||||
@ -243,7 +248,7 @@ NotificationDaemon.prototype = {
|
||||
let sender = DBus.getCurrentMessageContext().sender;
|
||||
let pid = this._senderToPid[sender];
|
||||
|
||||
let source = this._getSource(appName, pid, ndata);
|
||||
let source = this._getSource(appName, pid, ndata, sender);
|
||||
|
||||
if (source) {
|
||||
this._notifyForSource(source, ndata);
|
||||
@ -264,7 +269,7 @@ NotificationDaemon.prototype = {
|
||||
if (!ndata)
|
||||
return;
|
||||
|
||||
source = this._getSource(appName, pid, ndata);
|
||||
source = this._getSource(appName, pid, ndata, sender);
|
||||
|
||||
// We only store sender-pid entries for persistent sources.
|
||||
// Removing the entries once the source is destroyed
|
||||
@ -413,7 +418,7 @@ NotificationDaemon.prototype = {
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon) {
|
||||
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null);
|
||||
let source = this._getSource(icon.title || icon.wm_class || _("Unknown"), icon.pid, null, null);
|
||||
source.setTrayIcon(icon);
|
||||
},
|
||||
|
||||
@ -426,18 +431,28 @@ NotificationDaemon.prototype = {
|
||||
|
||||
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
|
||||
|
||||
function Source(title, pid) {
|
||||
this._init(title, pid);
|
||||
function Source(title, pid, sender) {
|
||||
this._init(title, pid, sender);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(title, pid) {
|
||||
_init: function(title, pid, sender) {
|
||||
MessageTray.Source.prototype._init.call(this, title);
|
||||
|
||||
this._pid = pid;
|
||||
this._appStateChangedId = 0;
|
||||
if (sender)
|
||||
// TODO: dbus-glib implementation of watch_name() doesn’t return an id to be used for
|
||||
// unwatch_name() or implement unwatch_name(), however when we move to using GDBus implementation,
|
||||
// we should save the id here and call unwatch_name() with it in destroy().
|
||||
// Moving to GDBus is the work in progress: https://bugzilla.gnome.org/show_bug.cgi?id=648651
|
||||
// and https://bugzilla.gnome.org/show_bug.cgi?id=622921 .
|
||||
DBus.session.watch_name(sender,
|
||||
false,
|
||||
null,
|
||||
Lang.bind(this, this._onNameVanished));
|
||||
|
||||
this._setApp();
|
||||
if (this.app)
|
||||
this.title = this.app.get_name();
|
||||
@ -446,6 +461,14 @@ Source.prototype = {
|
||||
this._trayIcon = null;
|
||||
},
|
||||
|
||||
_onNameVanished: function() {
|
||||
// Destroy the notification source when its sender is removed from DBus.
|
||||
// Sender being removed from DBus would normally result in a tray icon being removed,
|
||||
// so allow the code path that handles the tray icon being removed to handle that case.
|
||||
if (!this.trayIcon)
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
processNotification: function(notification, icon) {
|
||||
if (!this.app)
|
||||
this._setApp();
|
||||
@ -498,10 +521,6 @@ Source.prototype = {
|
||||
if (!this.app)
|
||||
return;
|
||||
|
||||
// We only update the app if this.app is null, so we can't disconnect the old this._appStateChangedId
|
||||
// even if it were non-zero for some reason.
|
||||
this._appStateChangedId = this.app.connect('notify::state', Lang.bind(this, this._appStateChanged));
|
||||
|
||||
// Only override the icon if we were previously using
|
||||
// notification-based icons (ie, not a trayicon) or if it was unset before
|
||||
if (!this._trayIcon) {
|
||||
@ -526,19 +545,6 @@ Source.prototype = {
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
_appStateChanged: function() {
|
||||
// Destroy notification sources when their apps exit.
|
||||
// The app exiting would normally result in a tray icon being removed,
|
||||
// so the associated source would be destroyed through the code path
|
||||
// that handles the tray icon being removed. We should not destroy
|
||||
// the source associated with a tray icon when the application state
|
||||
// is Shell.AppState.STOPPED because running applications that have
|
||||
// no open windows would also have that state. This is often the case
|
||||
// for applications that use tray icons.
|
||||
if (!this._trayIcon && this.app.get_state() == Shell.AppState.STOPPED)
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
openApp: function() {
|
||||
if (this.app == null)
|
||||
return;
|
||||
@ -551,10 +557,6 @@ Source.prototype = {
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this.app && this._appStateChangedId) {
|
||||
this.app.disconnect(this._appStateChangedId);
|
||||
this._appStateChangedId = 0;
|
||||
}
|
||||
MessageTray.Source.prototype.destroy.call(this);
|
||||
}
|
||||
};
|
||||
|
@ -8,8 +8,6 @@ const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
@ -123,7 +121,7 @@ Overview.prototype = {
|
||||
let spacing = node.get_length('spacing');
|
||||
if (spacing != this._spacing) {
|
||||
this._spacing = spacing;
|
||||
this.relayout();
|
||||
this._relayout();
|
||||
}
|
||||
}));
|
||||
|
||||
@ -155,6 +153,18 @@ Overview.prototype = {
|
||||
|
||||
this._coverPane.hide();
|
||||
|
||||
this._windowSwitchTimeoutId = 0;
|
||||
this._windowSwitchTimestamp = 0;
|
||||
this._lastActiveWorkspaceIndex = -1;
|
||||
this._lastHoveredWindow = null;
|
||||
this._needsFakePointerEvent = false;
|
||||
|
||||
this.workspaces = null;
|
||||
|
||||
Main.connect('initialized', Lang.bind(this, this._finishInit));
|
||||
},
|
||||
|
||||
_finishInit: function() {
|
||||
// XDND
|
||||
this._dragMonitor = {
|
||||
dragMotion: Lang.bind(this, this._onDragMotion)
|
||||
@ -163,22 +173,11 @@ Overview.prototype = {
|
||||
Main.xdndHandler.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
Main.xdndHandler.connect('drag-end', Lang.bind(this, this._onDragEnd));
|
||||
|
||||
this._windowSwitchTimeoutId = 0;
|
||||
this._windowSwitchTimestamp = 0;
|
||||
this._lastActiveWorkspaceIndex = -1;
|
||||
this._lastHoveredWindow = null;
|
||||
this._needsFakePointerEvent = false;
|
||||
|
||||
this.workspaces = null;
|
||||
},
|
||||
|
||||
// The members we construct that are implemented in JS might
|
||||
// want to access the overview as Main.overview to connect
|
||||
// signal handlers and so forth. So we create them after
|
||||
// construction in this init() method.
|
||||
init: function() {
|
||||
this.shellInfo = new ShellInfo();
|
||||
|
||||
// The members we construct that are implemented in JS might
|
||||
// want to access the overview as Main.overview to connect
|
||||
// signal handlers and so forth. So we create them here.
|
||||
this.viewSelector = new ViewSelector.ViewSelector();
|
||||
this._group.add_actor(this.viewSelector.actor);
|
||||
|
||||
@ -204,6 +203,8 @@ Overview.prototype = {
|
||||
// the left of the overview
|
||||
Main.ctrlAltTabManager.addGroup(this.dash.actor, _("Dash"), 'user-bookmarks');
|
||||
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
||||
this._relayout();
|
||||
},
|
||||
|
||||
_onDragBegin: function() {
|
||||
@ -222,7 +223,7 @@ Overview.prototype = {
|
||||
}
|
||||
this._resetWindowSwitchTimeout();
|
||||
this._lastHoveredWindow = null;
|
||||
DND.removeMonitor(this._dragMonitor);
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
this.endItemDrag();
|
||||
},
|
||||
|
||||
@ -283,7 +284,8 @@ Overview.prototype = {
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (this._scrollDirection == SwipeScrollDirection.NONE)
|
||||
if (this._scrollDirection == SwipeScrollDirection.NONE
|
||||
|| event.get_button() != 1)
|
||||
return;
|
||||
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
@ -392,7 +394,7 @@ Overview.prototype = {
|
||||
[stageX, stageY] = event.get_coords();
|
||||
let dx = this._dragX - stageX;
|
||||
let dy = this._dragY - stageY;
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
this._dragX = stageX;
|
||||
this._dragY = stageY;
|
||||
@ -439,23 +441,25 @@ Overview.prototype = {
|
||||
return clone;
|
||||
},
|
||||
|
||||
relayout: function () {
|
||||
let primary = global.get_primary_monitor();
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
_relayout: function () {
|
||||
// To avoid updating the position and size of the workspaces
|
||||
// we just hide the overview. The positions will be updated
|
||||
// when it is next shown.
|
||||
this.hide();
|
||||
|
||||
let contentY = Main.panel.actor.height;
|
||||
let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
|
||||
this._group.set_position(primary.x, primary.y);
|
||||
this._group.set_size(primary.width, primary.height);
|
||||
|
||||
this._coverPane.set_position(0, contentY);
|
||||
this._coverPane.set_size(primary.width, contentHeight);
|
||||
this._coverPane.set_position(primary.x, primary.y);
|
||||
this._coverPane.set_size(primary.width, primary.height);
|
||||
|
||||
let dashWidth = Math.round(DASH_SPLIT_FRACTION * primary.width);
|
||||
let viewWidth = primary.width - dashWidth - this._spacing;
|
||||
let viewHeight = contentHeight - 2 * this._spacing;
|
||||
let viewY = contentY + this._spacing;
|
||||
let viewHeight = primary.height - 2 * this._spacing;
|
||||
let viewY = primary.y + this._spacing;
|
||||
let viewX = rtl ? 0 : dashWidth + this._spacing;
|
||||
|
||||
// Set the dash's x position - y is handled by a constraint
|
||||
|
492
js/ui/panel.js
@ -9,11 +9,10 @@ const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Config = imports.misc.config;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const Layout = imports.ui.layout;
|
||||
const Overview = imports.ui.overview;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
@ -26,8 +25,6 @@ const PANEL_ICON_SIZE = 24;
|
||||
|
||||
const STARTUP_ANIMATION_TIME = 0.2;
|
||||
|
||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||
|
||||
const BUTTON_DND_ACTIVATION_TIMEOUT = 250;
|
||||
|
||||
const ANIMATED_ICON_UPDATE_TIMEOUT = 100;
|
||||
@ -260,10 +257,14 @@ AppMenuButton.prototype = {
|
||||
this._iconBox = new Shell.Slicer({ name: 'appMenuIcon' });
|
||||
this._iconBox.connect('style-changed',
|
||||
Lang.bind(this, this._onIconBoxStyleChanged));
|
||||
this._iconBox.connect('notify::allocation',
|
||||
Lang.bind(this, this._updateIconBoxClip));
|
||||
this._container.add_actor(this._iconBox);
|
||||
this._label = new TextShadower();
|
||||
this._container.add_actor(this._label.actor);
|
||||
|
||||
this._iconBottomClip = 0;
|
||||
|
||||
this._quitMenu = new PopupMenu.PopupMenuItem('');
|
||||
this.menu.addMenuItem(this._quitMenu);
|
||||
this._quitMenu.connect('activate', Lang.bind(this, this._onQuit));
|
||||
@ -300,6 +301,7 @@ AppMenuButton.prototype = {
|
||||
|
||||
this._visible = true;
|
||||
this.actor.show();
|
||||
this.actor.reactive = true;
|
||||
|
||||
if (!this._targetIsCurrent)
|
||||
return;
|
||||
@ -316,6 +318,7 @@ AppMenuButton.prototype = {
|
||||
return;
|
||||
|
||||
this._visible = false;
|
||||
this.actor.reactive = false;
|
||||
if (!this._targetIsCurrent) {
|
||||
this.actor.hide();
|
||||
return;
|
||||
@ -334,11 +337,16 @@ AppMenuButton.prototype = {
|
||||
|
||||
_onIconBoxStyleChanged: function() {
|
||||
let node = this._iconBox.get_theme_node();
|
||||
let bottomClip = node.get_length('app-icon-bottom-clip');
|
||||
if (bottomClip > 0)
|
||||
this._iconBottomClip = node.get_length('app-icon-bottom-clip');
|
||||
this._updateIconBoxClip();
|
||||
},
|
||||
|
||||
_updateIconBoxClip: function() {
|
||||
let allocation = this._iconBox.allocation;
|
||||
if (this._iconBottomClip > 0)
|
||||
this._iconBox.set_clip(0, 0,
|
||||
this._iconBox.width,
|
||||
this._iconBox.height - bottomClip);
|
||||
allocation.x2 - allocation.x1,
|
||||
allocation.y2 - allocation.y1 - this._iconBottomClip);
|
||||
else
|
||||
this._iconBox.remove_clip();
|
||||
},
|
||||
@ -535,13 +543,163 @@ AppMenuButton.prototype = {
|
||||
|
||||
Signals.addSignalMethods(AppMenuButton.prototype);
|
||||
|
||||
// Activities button. Because everything else in the top bar is a
|
||||
// PanelMenu.Button, it simplifies some things to make this be one too.
|
||||
// We just hack it up to not actually have a menu attached to it.
|
||||
function ActivitiesButton() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
function PanelCorner(side) {
|
||||
this._init(side);
|
||||
ActivitiesButton.prototype = {
|
||||
__proto__: PanelMenu.Button.prototype,
|
||||
|
||||
_init: function() {
|
||||
PanelMenu.Button.prototype._init.call(this, 0.0);
|
||||
|
||||
let container = new Shell.GenericContainer();
|
||||
container.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
container.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
container.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor.child = container;
|
||||
this.actor.name = 'panelActivities';
|
||||
|
||||
/* Translators: If there is no suitable word for "Activities"
|
||||
in your language, you can use the word for "Overview". */
|
||||
this._label = new St.Label({ text: _("Activities") });
|
||||
container.add_actor(this._label);
|
||||
|
||||
this._hotCorner = new Layout.HotCorner();
|
||||
container.add_actor(this._hotCorner.actor);
|
||||
|
||||
// Hack up our menu...
|
||||
this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
|
||||
this.menu.close = Lang.bind(this, this._onMenuCloseRequest);
|
||||
this.menu.toggle = Lang.bind(this, this._onMenuToggleRequest);
|
||||
|
||||
this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
|
||||
this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
|
||||
this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
this.actor.add_style_pseudo_class('overview');
|
||||
this._escapeMenuGrab();
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||
this.actor.remove_style_pseudo_class('overview');
|
||||
this._escapeMenuGrab();
|
||||
}));
|
||||
|
||||
this._xdndTimeOut = 0;
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_width(forHeight);
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
[alloc.min_size, alloc.natural_size] = this._label.get_preferred_height(forWidth);
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
this._label.allocate(box, flags);
|
||||
|
||||
// The hot corner needs to be outside any padding/alignment
|
||||
// that has been imposed on us
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let hotBox = new Clutter.ActorBox();
|
||||
let ok, x, y;
|
||||
if (actor.get_direction() == St.TextDirection.LTR) {
|
||||
[ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
|
||||
} else {
|
||||
[ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
|
||||
// hotCorner.actor has northeast gravity, so we don't need
|
||||
// to adjust x for its width
|
||||
}
|
||||
|
||||
hotBox.x1 = Math.round(x);
|
||||
hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
|
||||
hotBox.y1 = Math.round(y);
|
||||
hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
|
||||
this._hotCorner.actor.allocate(hotBox, flags);
|
||||
},
|
||||
|
||||
handleDragOver: function(source, actor, x, y, time) {
|
||||
if (source != Main.xdndHandler)
|
||||
return;
|
||||
|
||||
if (this._xdndTimeOut != 0)
|
||||
Mainloop.source_remove(this._xdndTimeOut);
|
||||
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
|
||||
Lang.bind(this, this._xdndShowOverview, actor));
|
||||
},
|
||||
|
||||
_escapeMenuGrab: function() {
|
||||
if (this.menu.isOpen)
|
||||
this.menu.close();
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
if (!this._hotCorner.shouldToggleOverviewOnClick())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onMenuOpenRequest: function() {
|
||||
this.menu.isOpen = true;
|
||||
this.menu.emit('open-state-changed', true);
|
||||
},
|
||||
|
||||
_onMenuCloseRequest: function() {
|
||||
this.menu.isOpen = false;
|
||||
this.menu.emit('open-state-changed', false);
|
||||
},
|
||||
|
||||
_onMenuToggleRequest: function() {
|
||||
this.menu.isOpen = !this.menu.isOpen;
|
||||
this.menu.emit('open-state-changed', this.menu.isOpen);
|
||||
},
|
||||
|
||||
_onButtonRelease: function() {
|
||||
if (this.menu.isOpen) {
|
||||
this.menu.close();
|
||||
Main.overview.toggle();
|
||||
}
|
||||
},
|
||||
|
||||
_onKeyRelease: function(actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
|
||||
if (this.menu.isOpen)
|
||||
this.menu.close();
|
||||
Main.overview.toggle();
|
||||
}
|
||||
},
|
||||
|
||||
_xdndShowOverview: function(actor) {
|
||||
let [x, y, mask] = global.get_pointer();
|
||||
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||
|
||||
if (pickedActor == this.actor) {
|
||||
if (!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||
Main.overview.showTemporarily();
|
||||
Main.overview.beginItemDrag(actor);
|
||||
}
|
||||
}
|
||||
|
||||
Mainloop.source_remove(this._xdndTimeOut);
|
||||
this._xdndTimeOut = 0;
|
||||
}
|
||||
};
|
||||
|
||||
function PanelCorner(panel, side) {
|
||||
this._init(panel, side);
|
||||
}
|
||||
|
||||
PanelCorner.prototype = {
|
||||
_init: function(side) {
|
||||
_init: function(panel, side) {
|
||||
this._panel = panel;
|
||||
this._side = side;
|
||||
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
|
||||
this.actor.connect('repaint', Lang.bind(this, this._repaint));
|
||||
@ -617,185 +775,14 @@ PanelCorner.prototype = {
|
||||
this.actor.set_size(cornerRadius,
|
||||
innerBorderWidth + cornerRadius);
|
||||
if (this._side == St.Side.LEFT)
|
||||
this.actor.set_position(Main.panel.actor.x,
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
|
||||
this.actor.set_position(this._panel.actor.x,
|
||||
this._panel.actor.y + this._panel.actor.height - innerBorderWidth);
|
||||
else
|
||||
this.actor.set_position(Main.panel.actor.x + Main.panel.actor.width - cornerRadius,
|
||||
Main.panel.actor.y + Main.panel.actor.height - innerBorderWidth);
|
||||
this.actor.set_position(this._panel.actor.x + this._panel.actor.width - cornerRadius,
|
||||
this._panel.actor.y + this._panel.actor.height - innerBorderWidth);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* HotCorner:
|
||||
*
|
||||
* This class manages the "hot corner" that can toggle switching to
|
||||
* overview.
|
||||
*/
|
||||
function HotCorner(button) {
|
||||
this._init(button);
|
||||
}
|
||||
|
||||
HotCorner.prototype = {
|
||||
_init : function(button) {
|
||||
// This is the activities button associated with this hot corner,
|
||||
// if this is on the primary monitor (or null with the corner is
|
||||
// on a different monitor)
|
||||
this._button = button;
|
||||
|
||||
// We use this flag to mark the case where the user has entered the
|
||||
// hot corner and has not left both the hot corner and a surrounding
|
||||
// guard area (the "environs"). This avoids triggering the hot corner
|
||||
// multiple times due to an accidental jitter.
|
||||
this._entered = false;
|
||||
|
||||
this.actor = new Clutter.Group({ width: 3,
|
||||
height: 3,
|
||||
reactive: true });
|
||||
|
||||
this._corner = new Clutter.Rectangle({ width: 1,
|
||||
height: 1,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
|
||||
this.actor.add_actor(this._corner);
|
||||
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL) {
|
||||
this._corner.set_position(this.actor.width - this._corner.width, 0);
|
||||
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||
} else {
|
||||
this._corner.set_position(0, 0);
|
||||
}
|
||||
|
||||
this._activationTime = 0;
|
||||
|
||||
this.actor.connect('enter-event',
|
||||
Lang.bind(this, this._onEnvironsEntered));
|
||||
this.actor.connect('leave-event',
|
||||
Lang.bind(this, this._onEnvironsLeft));
|
||||
// Clicking on the hot corner environs should result in the same bahavior
|
||||
// as clicking on the hot corner.
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this, this._onCornerClicked));
|
||||
|
||||
// In addition to being triggered by the mouse enter event, the hot corner
|
||||
// can be triggered by clicking on it. This is useful if the user wants to
|
||||
// undo the effect of triggering the hot corner once in the hot corner.
|
||||
this._corner.connect('enter-event',
|
||||
Lang.bind(this, this._onCornerEntered));
|
||||
this._corner.connect('button-release-event',
|
||||
Lang.bind(this, this._onCornerClicked));
|
||||
this._corner.connect('leave-event',
|
||||
Lang.bind(this, this._onCornerLeft));
|
||||
|
||||
this._corner._delegate = this._corner;
|
||||
this._corner.handleDragOver = Lang.bind(this,
|
||||
function(source, actor, x, y, time) {
|
||||
if (source == Main.xdndHandler) {
|
||||
if(!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||
this.rippleAnimation();
|
||||
Main.overview.showTemporarily();
|
||||
Main.overview.beginItemDrag(actor);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Main.chrome.addActor(this.actor, { visibleInOverview: true, affectsStruts: false });
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
|
||||
// We draw a ripple by using a source image and animating it scaling
|
||||
// outwards and fading away. We want the ripples to move linearly
|
||||
// or it looks unrealistic, but if the opacity of the ripple goes
|
||||
// linearly to zero it fades away too quickly, so we use Tweener's
|
||||
// 'onUpdate' to give a non-linear curve to the fade-away and make
|
||||
// it more visible in the middle section.
|
||||
|
||||
let [x, y] = this._corner.get_transformed_position();
|
||||
let ripple = new St.BoxLayout({ style_class: 'ripple-box',
|
||||
opacity: 255 * Math.sqrt(startOpacity),
|
||||
scale_x: startScale,
|
||||
scale_y: startScale,
|
||||
x: x,
|
||||
y: y });
|
||||
ripple._opacity = startOpacity;
|
||||
if (ripple.get_direction() == St.TextDirection.RTL)
|
||||
ripple.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
|
||||
Tweener.addTween(ripple, { _opacity: finalOpacity,
|
||||
scale_x: finalScale,
|
||||
scale_y: finalScale,
|
||||
delay: delay,
|
||||
time: time,
|
||||
transition: 'linear',
|
||||
onUpdate: function() { ripple.opacity = 255 * Math.sqrt(ripple._opacity); },
|
||||
onComplete: function() { ripple.destroy(); } });
|
||||
Main.uiGroup.add_actor(ripple);
|
||||
},
|
||||
|
||||
rippleAnimation: function() {
|
||||
// Show three concentric ripples expanding outwards; the exact
|
||||
// parameters were found by trial and error, so don't look
|
||||
// for them to make perfect sense mathematically
|
||||
|
||||
// delay time scale opacity => scale opacity
|
||||
this._addRipple(0.0, 0.83, 0.25, 1.0, 1.5, 0.0);
|
||||
this._addRipple(0.05, 1.0, 0.0, 0.7, 1.25, 0.0);
|
||||
this._addRipple(0.35, 1.0, 0.0, 0.3, 1, 0.0);
|
||||
},
|
||||
|
||||
_onEnvironsEntered : function() {
|
||||
if (this._button)
|
||||
this._button.hover = true;
|
||||
},
|
||||
|
||||
_onCornerEntered : function() {
|
||||
if (!this._entered) {
|
||||
this._entered = true;
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._activationTime = Date.now() / 1000;
|
||||
|
||||
this.rippleAnimation();
|
||||
Main.overview.toggle();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCornerClicked : function() {
|
||||
if (!Main.overview.animationInProgress)
|
||||
this.maybeToggleOverviewOnClick();
|
||||
return false;
|
||||
},
|
||||
|
||||
_onCornerLeft : function(actor, event) {
|
||||
if (event.get_related() != this.actor)
|
||||
this._entered = false;
|
||||
// Consume event, otherwise this will confuse onEnvironsLeft
|
||||
return true;
|
||||
},
|
||||
|
||||
_onEnvironsLeft : function(actor, event) {
|
||||
if (this._button)
|
||||
this._button.hover = false;
|
||||
|
||||
if (event.get_related() != this._corner)
|
||||
this._entered = false;
|
||||
return false;
|
||||
},
|
||||
|
||||
// Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
|
||||
// of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
|
||||
// and clicked the Activities button.
|
||||
maybeToggleOverviewOnClick: function() {
|
||||
if (this._activationTime == 0 || Date.now() / 1000 - this._activationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
|
||||
Main.overview.toggle();
|
||||
this._activationTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function Panel() {
|
||||
this._init();
|
||||
@ -808,6 +795,8 @@ Panel.prototype = {
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._statusArea = {};
|
||||
|
||||
Main.overview.connect('shown', Lang.bind(this, function () {
|
||||
this.actor.add_style_class_name('in-overview');
|
||||
}));
|
||||
@ -823,8 +812,8 @@ Panel.prototype = {
|
||||
this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
|
||||
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
||||
|
||||
this._leftCorner = new PanelCorner(St.Side.LEFT);
|
||||
this._rightCorner = new PanelCorner(St.Side.RIGHT);
|
||||
this._leftCorner = new PanelCorner(this, St.Side.LEFT);
|
||||
this._rightCorner = new PanelCorner(this, St.Side.RIGHT);
|
||||
|
||||
/* This box container ensures that the centerBox is positioned in the *absolute*
|
||||
* center, but can be pushed aside if necessary. */
|
||||
@ -898,31 +887,16 @@ Panel.prototype = {
|
||||
}));
|
||||
|
||||
/* Button on the left side of the panel. */
|
||||
/* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
|
||||
let label = new St.Label({ text: _("Activities") });
|
||||
this.button = new St.Button({ name: 'panelActivities',
|
||||
style_class: 'panel-button',
|
||||
reactive: true,
|
||||
can_focus: true });
|
||||
this.button.set_child(label);
|
||||
this.button._delegate = this.button;
|
||||
this.button._xdndTimeOut = 0;
|
||||
this.button.handleDragOver = Lang.bind(this,
|
||||
function(source, actor, x, y, time) {
|
||||
if (source == Main.xdndHandler) {
|
||||
if (this.button._xdndTimeOut != 0)
|
||||
Mainloop.source_remove(this.button._xdndTimeOut);
|
||||
this.button._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
this._xdndShowOverview(actor);
|
||||
}));
|
||||
}
|
||||
});
|
||||
this._leftBox.add(this.button);
|
||||
this._activitiesButton = new ActivitiesButton();
|
||||
this._activities = this._activitiesButton.actor;
|
||||
this._leftBox.add(this._activities);
|
||||
|
||||
// Synchronize the buttons pseudo classes with its corner
|
||||
this.button.connect('style-changed', Lang.bind(this,
|
||||
// The activities button has a pretend menu, so as to integrate
|
||||
// more cleanly with the rest of the panel
|
||||
this._menus.addMenu(this._activitiesButton.menu);
|
||||
|
||||
// Synchronize the button's pseudo classes with its corner
|
||||
this._activities.connect('style-changed', Lang.bind(this,
|
||||
function(actor) {
|
||||
let rtl = actor.get_direction() == St.TextDirection.RTL;
|
||||
let corner = rtl ? this._rightCorner : this._leftCorner;
|
||||
@ -930,12 +904,10 @@ Panel.prototype = {
|
||||
corner.actor.set_style_pseudo_class(pseudoClass);
|
||||
}));
|
||||
|
||||
this._hotCorner = null;
|
||||
this._appMenu = new AppMenuButton();
|
||||
this._leftBox.add(this._appMenu.actor);
|
||||
|
||||
let appMenuButton = new AppMenuButton();
|
||||
this._leftBox.add(appMenuButton.actor);
|
||||
|
||||
this._menus.addMenu(appMenuButton.menu);
|
||||
this._menus.addMenu(this._appMenu.menu);
|
||||
|
||||
/* center */
|
||||
this._dateMenu = new DateMenu.DateMenuButton();
|
||||
@ -954,12 +926,12 @@ Panel.prototype = {
|
||||
this._rightBox.add(this._trayBox);
|
||||
this._rightBox.add(this._statusBox);
|
||||
|
||||
this._statusmenu = new StatusMenu.StatusMenuButton();
|
||||
this._statusmenu.actor.name = 'panelStatus';
|
||||
this._rightBox.add(this._statusmenu.actor);
|
||||
this._userMenu = new StatusMenu.StatusMenuButton();
|
||||
this._userMenu.actor.name = 'panelStatus';
|
||||
this._rightBox.add(this._userMenu.actor);
|
||||
|
||||
// Synchronize the buttons pseudo classes with its corner
|
||||
this._statusmenu.actor.connect('style-changed', Lang.bind(this,
|
||||
this._userMenu.actor.connect('style-changed', Lang.bind(this,
|
||||
function(actor) {
|
||||
let rtl = actor.get_direction() == St.TextDirection.RTL;
|
||||
let corner = rtl ? this._leftCorner : this._rightCorner;
|
||||
@ -967,68 +939,17 @@ Panel.prototype = {
|
||||
corner.actor.set_style_pseudo_class(pseudoClass);
|
||||
}));
|
||||
|
||||
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||
|
||||
// TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
|
||||
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
|
||||
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
|
||||
// to switch to.
|
||||
this.button.connect('clicked', Lang.bind(this, function(b) {
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._hotCorner.maybeToggleOverviewOnClick();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
// In addition to pressing the button, the Overview can be entered and exited by other means, such as
|
||||
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
|
||||
// and to be released when it is exited regardless of how it was triggered.
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
this.button.checked = true;
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||
this.button.checked = false;
|
||||
}));
|
||||
|
||||
Main.chrome.addActor(this.actor, { visibleInOverview: true });
|
||||
Main.chrome.addActor(this._leftCorner.actor, { visibleInOverview: true,
|
||||
affectsStruts: false,
|
||||
affectsInputRegion: false });
|
||||
Main.chrome.addActor(this._rightCorner.actor, { visibleInOverview: true,
|
||||
affectsStruts: false,
|
||||
affectsInputRegion: false });
|
||||
Main.chrome.addActor(this.actor);
|
||||
Main.chrome.addActor(this._leftCorner.actor, { affectsStruts: false,
|
||||
affectsInputRegion: false });
|
||||
Main.chrome.addActor(this._rightCorner.actor, { affectsStruts: false,
|
||||
affectsInputRegion: false });
|
||||
|
||||
Main.ctrlAltTabManager.addGroup(this.actor, _("Top Bar"), 'start-here',
|
||||
{ sortGroup: CtrlAltTab.SortGroup.TOP });
|
||||
},
|
||||
|
||||
_xdndShowOverview: function (actor) {
|
||||
let [x, y, mask] = global.get_pointer();
|
||||
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);
|
||||
|
||||
if (pickedActor != this.button) {
|
||||
Mainloop.source_remove(this.button._xdndTimeOut);
|
||||
this.button._xdndTimeOut = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Main.overview.visible && !Main.overview.animationInProgress) {
|
||||
Main.overview.showTemporarily();
|
||||
Main.overview.beginItemDrag(actor);
|
||||
}
|
||||
|
||||
Mainloop.source_remove(this.button._xdndTimeOut);
|
||||
this.button._xdndTimeOut = 0;
|
||||
},
|
||||
|
||||
|
||||
// While there can be multiple hotcorners (one per monitor), the hot corner
|
||||
// that is on top of the Activities button is special since it needs special
|
||||
// coordination with clicking on that button
|
||||
setHotCorner: function(corner) {
|
||||
this._hotCorner = corner;
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._relayout));
|
||||
this._relayout();
|
||||
},
|
||||
|
||||
startStatusArea: function() {
|
||||
@ -1042,11 +963,16 @@ Panel.prototype = {
|
||||
let indicator = new constructor();
|
||||
this._statusBox.add(indicator.actor);
|
||||
this._menus.addMenu(indicator.menu);
|
||||
|
||||
this._statusArea[role] = indicator;
|
||||
}
|
||||
|
||||
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||
|
||||
// PopupMenuManager depends on menus being added in order for
|
||||
// keyboard navigation
|
||||
this._menus.addMenu(this._statusmenu.menu);
|
||||
// keyboard navigation, so we couldn't add this before
|
||||
this._menus.addMenu(this._userMenu.menu);
|
||||
},
|
||||
|
||||
startupAnimation: function() {
|
||||
@ -1073,8 +999,8 @@ Panel.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
relayout: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
_relayout: function() {
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
this.actor.set_position(primary.x, primary.y);
|
||||
this.actor.set_size(primary.width, -1);
|
||||
|
@ -26,8 +26,7 @@ Button.prototype = {
|
||||
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP, 0);
|
||||
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
|
||||
Main.chrome.addActor(this.menu.actor, { visibleInOverview: true,
|
||||
affectsStruts: false });
|
||||
Main.chrome.addActor(this.menu.actor, { affectsStruts: false });
|
||||
this.menu.actor.hide();
|
||||
},
|
||||
|
||||
@ -36,7 +35,7 @@ Button.prototype = {
|
||||
// Setting the max-height won't do any good if the minimum height of the
|
||||
// menu is higher then the screen; it's useful if part of the menu is
|
||||
// scrollable so the minimum height is smaller than the natural height
|
||||
let monitor = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this.menu.actor.style = ('max-height: ' +
|
||||
Math.round(monitor.height - Main.panel.actor.height) +
|
||||
'px;');
|
||||
|
@ -7,8 +7,6 @@ const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
@ -270,10 +268,7 @@ PlacesManager.prototype = {
|
||||
if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
|
||||
return;
|
||||
|
||||
let [success, bookmarksContent, len] = GLib.file_get_contents(this._bookmarksPath);
|
||||
|
||||
if (!success)
|
||||
return;
|
||||
let bookmarksContent = Shell.get_file_contents_utf8_sync(this._bookmarksPath);
|
||||
|
||||
let bookmarks = bookmarksContent.split('\n');
|
||||
|
||||
|
@ -22,8 +22,6 @@
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const St = imports.gi.St;
|
||||
|
@ -13,9 +13,6 @@ const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const SLIDER_SCROLL_STEP = 0.05; /* Slider scrolling step in % */
|
||||
|
||||
function PopupBaseMenuItem(params) {
|
||||
@ -498,7 +495,7 @@ PopupSliderMenuItem.prototype = {
|
||||
this._slider = new St.DrawingArea({ style_class: 'popup-slider-menu-item', reactive: true });
|
||||
this.addActor(this._slider, { span: -1, expand: true });
|
||||
this._slider.connect('repaint', Lang.bind(this, this._sliderRepaint));
|
||||
this._slider.connect('button-press-event', Lang.bind(this, this._startDragging));
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
this._releaseId = this._motionId = 0;
|
||||
@ -707,11 +704,35 @@ PopupSwitchMenuItem.prototype = {
|
||||
this._switch = new Switch(active);
|
||||
|
||||
this.addActor(this.label);
|
||||
this.addActor(this._switch.actor, { align: St.Align.END });
|
||||
|
||||
this.connect('activate', Lang.bind(this,function(from) {
|
||||
this._statusBin = new St.Bin({ x_align: St.Align.END });
|
||||
this.addActor(this._statusBin, { align: St.Align.END });
|
||||
|
||||
this._statusLabel = new St.Label({ text: '',
|
||||
style_class: 'popup-inactive-menu-item'
|
||||
});
|
||||
this._statusBin.child = this._switch.actor;
|
||||
},
|
||||
|
||||
setStatus: function(text) {
|
||||
if (text != null) {
|
||||
this._statusLabel.text = text;
|
||||
this._statusBin.child = this._statusLabel;
|
||||
this.actor.reactive = false;
|
||||
this.actor.can_focus = false;
|
||||
} else {
|
||||
this._statusBin.child = this._switch.actor;
|
||||
this.actor.reactive = true;
|
||||
this.actor.can_focus = true;
|
||||
}
|
||||
},
|
||||
|
||||
activate: function(event) {
|
||||
if (this._switch.actor.mapped) {
|
||||
this.toggle();
|
||||
}));
|
||||
}
|
||||
|
||||
PopupBaseMenuItem.prototype.activate.call(this, event);
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
@ -766,6 +787,7 @@ PopupMenuBase.prototype = {
|
||||
this.box = new St.BoxLayout({ vertical: true });
|
||||
}
|
||||
this.box.connect_after('queue-relayout', Lang.bind(this, this._menuQueueRelayout));
|
||||
this.length = 0;
|
||||
|
||||
this.isOpen = false;
|
||||
|
||||
@ -855,6 +877,8 @@ PopupMenuBase.prototype = {
|
||||
menuItem.connect('destroy', Lang.bind(this, function() {
|
||||
menuItem.disconnect(menuItem._subMenuActivateId);
|
||||
menuItem.disconnect(menuItem._subMenuActiveChangeId);
|
||||
|
||||
this.length--;
|
||||
}));
|
||||
} else if (menuItem instanceof PopupSubMenuMenuItem) {
|
||||
if (before_item == null)
|
||||
@ -871,6 +895,8 @@ PopupMenuBase.prototype = {
|
||||
this._connectItemSignals(menuItem);
|
||||
else
|
||||
throw TypeError("Invalid argument to PopupMenuBase.addMenuItem()");
|
||||
|
||||
this.length++;
|
||||
},
|
||||
|
||||
getColumnWidths: function() {
|
||||
@ -920,6 +946,14 @@ PopupMenuBase.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
get firstMenuItem() {
|
||||
let items = this._getMenuItems();
|
||||
if (items.length)
|
||||
return items[0];
|
||||
else
|
||||
return null;
|
||||
},
|
||||
|
||||
removeAll: function() {
|
||||
let children = this._getMenuItems();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
|
@ -8,8 +8,6 @@ const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
@ -25,6 +23,10 @@ const HISTORY_KEY = 'command-history';
|
||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
const DISABLE_COMMAND_LINE_KEY = 'disable-command-line';
|
||||
|
||||
const TERMINAL_SCHEMA = 'org.gnome.desktop.default-applications.terminal';
|
||||
const EXEC_KEY = 'exec';
|
||||
const EXEC_ARG_KEY = 'exec-arg';
|
||||
|
||||
const DIALOG_GROW_TIME = 0.1;
|
||||
|
||||
function CommandCompleter() {
|
||||
@ -171,6 +173,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'run-dialog' });
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema: LOCKDOWN_SCHEMA });
|
||||
this._terminalSettings = new Gio.Settings({ schema: TERMINAL_SCHEMA });
|
||||
global.settings.connect('changed::development-tools', Lang.bind(this, function () {
|
||||
this._enableInternalCommands = global.settings.get_boolean('development-tools');
|
||||
}));
|
||||
@ -191,7 +194,7 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
}),
|
||||
|
||||
'debugexit': Lang.bind(this, function() {
|
||||
Meta.exit(Meta.ExitCode.ERROR);
|
||||
Meta.quit(Meta.ExitCode.ERROR);
|
||||
}),
|
||||
|
||||
// rt is short for "reload theme"
|
||||
@ -311,8 +314,11 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
f();
|
||||
} else if (input) {
|
||||
try {
|
||||
if (inTerminal)
|
||||
command = 'gnome-terminal -x ' + input;
|
||||
if (inTerminal) {
|
||||
let exec = this._terminalSettings.get_string(EXEC_KEY);
|
||||
let exec_arg = this._terminalSettings.get_string(EXEC_ARG_KEY);
|
||||
command = exec + ' ' + exec_arg + ' ' + input;
|
||||
}
|
||||
Util.trySpawnCommandLine(command);
|
||||
} catch (e) {
|
||||
// Mmmh, that failed - see if @input matches an existing file
|
||||
@ -327,33 +333,46 @@ __proto__: ModalDialog.ModalDialog.prototype,
|
||||
|
||||
if (GLib.file_test(path, GLib.FileTest.EXISTS)) {
|
||||
let file = Gio.file_new_for_path(path);
|
||||
Gio.app_info_launch_default_for_uri(file.get_uri(),
|
||||
global.create_app_launch_context());
|
||||
} else {
|
||||
this._commandError = true;
|
||||
|
||||
this._errorMessage.set_text(e.message);
|
||||
|
||||
if (!this._errorBox.visible) {
|
||||
let [errorBoxMinHeight, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
|
||||
|
||||
let parentActor = this._errorBox.get_parent();
|
||||
Tweener.addTween(parentActor,
|
||||
{ height: parentActor.height + errorBoxNaturalHeight,
|
||||
time: DIALOG_GROW_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
parentActor.set_height(-1);
|
||||
this._errorBox.show();
|
||||
})
|
||||
});
|
||||
try {
|
||||
Gio.app_info_launch_default_for_uri(file.get_uri(),
|
||||
global.create_app_launch_context());
|
||||
} catch (e) {
|
||||
// The exception from gjs contains an error string like:
|
||||
// Error invoking Gio.app_info_launch_default_for_uri: No application
|
||||
// is registered as handling this file
|
||||
// We are only interested in the part after the first colon.
|
||||
let message = e.message.replace(/[^:]*: *(.+)/, '$1');
|
||||
this._showError(message);
|
||||
}
|
||||
} else {
|
||||
this._showError(e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_showError : function(message) {
|
||||
this._commandError = true;
|
||||
|
||||
this._errorMessage.set_text(message);
|
||||
|
||||
if (!this._errorBox.visible) {
|
||||
let [errorBoxMinHeight, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
|
||||
|
||||
let parentActor = this._errorBox.get_parent();
|
||||
Tweener.addTween(parentActor,
|
||||
{ height: parentActor.height + errorBoxNaturalHeight,
|
||||
time: DIALOG_GROW_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
parentActor.set_height(-1);
|
||||
this._errorBox.show();
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
open: function() {
|
||||
this._history.lastItem();
|
||||
this._errorBox.hide();
|
||||
|
@ -3,10 +3,11 @@
|
||||
const DBus = imports.dbus;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
// This module provides functionality for driving the shell user interface
|
||||
// in an automated fashion. The primary current use case for this is
|
||||
// automated performance testing (see runPerfScript()), but it could
|
||||
@ -246,18 +247,14 @@ function _collect(scriptModule, outputFile) {
|
||||
Shell.write_string_to_stream(out, '"events":\n');
|
||||
Shell.PerfLog.get_default().dump_events(out);
|
||||
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let primary = Main.layoutManager.primaryIndex;
|
||||
Shell.write_string_to_stream(out, ',\n"monitors":\n[');
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let monitor = monitors[i];
|
||||
let is_primary = (monitor.x == primary.x &&
|
||||
monitor.y == primary.y &&
|
||||
monitor.width == primary.width &&
|
||||
monitor.height == primary.height);
|
||||
if (i != 0)
|
||||
Shell.write_string_to_stream(out, ', ');
|
||||
Shell.write_string_to_stream(out, '"%s%dx%d+%d+%d"'.format(is_primary ? "*" : "",
|
||||
Shell.write_string_to_stream(out, '"%s%dx%d+%d+%d"'.format(i == primary ? "*" : "",
|
||||
monitor.width, monitor.height,
|
||||
monitor.x, monitor.y));
|
||||
}
|
||||
|
@ -7,9 +7,6 @@ const Signals = imports.signals;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const FileUtils = imports.misc.fileUtils;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
@ -160,7 +157,7 @@ SearchProvider.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* getResultInfo:
|
||||
* getResultMeta:
|
||||
* @id: Result identifier string
|
||||
*
|
||||
* Return an object with 'id', 'name', (both strings) and 'createIcon'
|
||||
@ -276,7 +273,7 @@ OpenSearchSystem.prototype = {
|
||||
_addProvider: function(fileName) {
|
||||
let path = global.datadir + '/search_providers/' + fileName;
|
||||
let source = Shell.get_file_contents_utf8_sync(path);
|
||||
let [success, name, url, langs, icon_uri] = global.parse_search_provider(source);
|
||||
let [success, name, url, langs, icon_uri] = Shell.parse_search_provider(source);
|
||||
let provider ={ name: name,
|
||||
url: url,
|
||||
id: this._providers.length,
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
@ -30,6 +28,7 @@ SearchResult.prototype = {
|
||||
x_align: St.Align.START,
|
||||
y_fill: true });
|
||||
this.actor._delegate = this;
|
||||
this._dragActorSource = null;
|
||||
|
||||
let content = provider.createResultActor(metaInfo, terms);
|
||||
if (content == null) {
|
||||
@ -39,6 +38,11 @@ SearchResult.prototype = {
|
||||
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||
{ createIcon: this.metaInfo['createIcon'] });
|
||||
content.set_child(icon.actor);
|
||||
this._dragActorSource = icon.icon;
|
||||
this.actor.label_actor = icon.label;
|
||||
} else {
|
||||
if (content._delegate && content._delegate.getDragActorSource)
|
||||
this._dragActorSource = content._delegate.getDragActorSource();
|
||||
}
|
||||
this._content = content;
|
||||
this.actor.set_child(content);
|
||||
@ -77,6 +81,8 @@ SearchResult.prototype = {
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
if (this._dragActorSource)
|
||||
return this._dragActorSource;
|
||||
// not exactly right, but alignment problems are hard to notice
|
||||
return this._content;
|
||||
},
|
||||
@ -193,7 +199,7 @@ SearchResults.prototype = {
|
||||
|
||||
let scrollView = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
vfade: true });
|
||||
style_class: 'vfade' });
|
||||
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
scrollView.add_actor(this._content);
|
||||
|
||||
@ -259,6 +265,7 @@ SearchResults.prototype = {
|
||||
let title = new St.Label({ text: provider.name,
|
||||
style_class: 'dash-search-button-label' });
|
||||
|
||||
button.label_actor = title;
|
||||
bin.set_child(title);
|
||||
button.set_child(bin);
|
||||
provider.actor = button;
|
||||
@ -333,6 +340,13 @@ SearchResults.prototype = {
|
||||
let terms = this._searchSystem.getTerms();
|
||||
this._openSearchSystem.setSearchTerms(terms);
|
||||
|
||||
// To avoid CSS transitions causing flickering
|
||||
// of the selection when the first search result
|
||||
// stays the same, we hide the content while
|
||||
// filling in the results and setting the initial
|
||||
// selection.
|
||||
this._content.hide();
|
||||
|
||||
for (let i = 0; i < results.length; i++) {
|
||||
let [provider, providerResults] = results[i];
|
||||
let meta = this._metaForProvider(provider);
|
||||
@ -343,6 +357,8 @@ SearchResults.prototype = {
|
||||
if (this._selectedOpenSearchButton == -1)
|
||||
this.selectDown(false);
|
||||
|
||||
this._content.show();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
|
405
js/ui/shellMountOperation.js
Normal file
@ -0,0 +1,405 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const ModalDialog = imports.ui.modalDialog;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
const LIST_ITEM_ICON_SIZE = 48;
|
||||
|
||||
/* ------ Common Utils ------- */
|
||||
function _setLabelText(label, text) {
|
||||
if (text) {
|
||||
label.set_text(text);
|
||||
label.show();
|
||||
} else {
|
||||
label.set_text('');
|
||||
label.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function _setButtonsForChoices(dialog, choices) {
|
||||
let buttons = [];
|
||||
|
||||
for (let idx = 0; idx < choices.length; idx++) {
|
||||
let button = idx;
|
||||
buttons.unshift({ label: choices[idx],
|
||||
action: Lang.bind(dialog, function() {
|
||||
dialog.emit('response', button);
|
||||
})});
|
||||
}
|
||||
|
||||
dialog.setButtons(buttons);
|
||||
}
|
||||
|
||||
function _setLabelsForMessage(dialog, message) {
|
||||
let labels = message.split('\n');
|
||||
|
||||
_setLabelText(dialog.subjectLabel, labels[0]);
|
||||
if (labels.length > 1)
|
||||
_setLabelText(dialog.descriptionLabel, labels[1]);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------- */
|
||||
|
||||
function ListItem(app) {
|
||||
this._init(app);
|
||||
}
|
||||
|
||||
ListItem.prototype = {
|
||||
_init: function(app) {
|
||||
this._app = app;
|
||||
|
||||
let layout = new St.BoxLayout({ vertical: false});
|
||||
|
||||
this.actor = new St.Button({ style_class: 'show-processes-dialog-app-list-item',
|
||||
can_focus: true,
|
||||
child: layout,
|
||||
reactive: true,
|
||||
x_align: St.Align.START,
|
||||
x_fill: true });
|
||||
|
||||
this._icon = this._app.create_icon_texture(LIST_ITEM_ICON_SIZE);
|
||||
|
||||
let iconBin = new St.Bin({ style_class: 'show-processes-dialog-app-list-item-icon',
|
||||
child: this._icon });
|
||||
layout.add(iconBin);
|
||||
|
||||
this._nameLabel = new St.Label({ text: this._app.get_name(),
|
||||
style_class: 'show-processes-dialog-app-list-item-name' });
|
||||
let labelBin = new St.Bin({ y_align: St.Align.MIDDLE,
|
||||
child: this._nameLabel });
|
||||
layout.add(labelBin);
|
||||
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
},
|
||||
|
||||
_onClicked: function() {
|
||||
this.emit('activate');
|
||||
this._app.activate(-1);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ListItem.prototype);
|
||||
|
||||
function ShellMountOperation(source, params) {
|
||||
this._init(source, params);
|
||||
}
|
||||
|
||||
ShellMountOperation.prototype = {
|
||||
_init: function(source, params) {
|
||||
params = Params.parse(params, { reaskPassword: false });
|
||||
|
||||
this._reaskPassword = params.reaskPassword;
|
||||
|
||||
this._dialog = null;
|
||||
this._processesDialog = null;
|
||||
|
||||
this.mountOp = new Shell.MountOperation();
|
||||
|
||||
this.mountOp.connect('ask-question',
|
||||
Lang.bind(this, this._onAskQuestion));
|
||||
this.mountOp.connect('ask-password',
|
||||
Lang.bind(this, this._onAskPassword));
|
||||
this.mountOp.connect('show-processes-2',
|
||||
Lang.bind(this, this._onShowProcesses2));
|
||||
this.mountOp.connect('aborted',
|
||||
Lang.bind(this, this._onAborted));
|
||||
|
||||
this._icon = new St.Icon({ gicon: source.get_icon(),
|
||||
style_class: 'shell-mount-operation-icon' });
|
||||
},
|
||||
|
||||
_onAskQuestion: function(op, message, choices) {
|
||||
this._dialog = new ShellMountQuestionDialog(this._icon);
|
||||
|
||||
this._dialog.connect('response',
|
||||
Lang.bind(this, function(object, choice) {
|
||||
this.mountOp.set_choice(choice);
|
||||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||||
|
||||
this._dialog.close(global.get_current_time());
|
||||
this._dialog = null;
|
||||
}));
|
||||
|
||||
this._dialog.update(message, choices);
|
||||
this._dialog.open(global.get_current_time());
|
||||
},
|
||||
|
||||
_onAskPassword: function(op, message) {
|
||||
this._notificationShowing = true;
|
||||
this._source = new ShellMountPasswordSource(message, this._icon, this._reaskPassword);
|
||||
|
||||
this._source.connect('password-ready',
|
||||
Lang.bind(this, function(source, password) {
|
||||
this.mountOp.set_password(password);
|
||||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||||
|
||||
this._notificationShowing = false;
|
||||
this._source.destroy();
|
||||
}));
|
||||
|
||||
this._source.connect('destroy',
|
||||
Lang.bind(this, function() {
|
||||
if (!this._notificationShowing)
|
||||
return;
|
||||
|
||||
this._notificationShowing = false;
|
||||
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
|
||||
}));
|
||||
},
|
||||
|
||||
_onAborted: function(op) {
|
||||
if (!this._dialog)
|
||||
return;
|
||||
|
||||
this._dialog.close(global.get_current_time());
|
||||
this._dialog = null;
|
||||
},
|
||||
|
||||
_onShowProcesses2: function(op) {
|
||||
let processes = op.get_show_processes_pids();
|
||||
let choices = op.get_show_processes_choices();
|
||||
let message = op.get_show_processes_message();
|
||||
|
||||
if (!this._processesDialog) {
|
||||
this._processesDialog = new ShellProcessesDialog(this._icon);
|
||||
this._dialog = this._processesDialog;
|
||||
|
||||
this._processesDialog.connect('response',
|
||||
Lang.bind(this, function(object, choice) {
|
||||
if (choice == -1) {
|
||||
this.mountOp.reply(Gio.MountOperationResult.ABORTED);
|
||||
} else {
|
||||
this.mountOp.set_choice(choice);
|
||||
this.mountOp.reply(Gio.MountOperationResult.HANDLED);
|
||||
}
|
||||
|
||||
this._processesDialog.close(global.get_current_time());
|
||||
this._dialog = null;
|
||||
}));
|
||||
this._processesDialog.open(global.get_current_time());
|
||||
}
|
||||
|
||||
this._processesDialog.update(message, processes, choices);
|
||||
},
|
||||
}
|
||||
|
||||
function ShellMountQuestionDialog(icon) {
|
||||
this._init(icon);
|
||||
}
|
||||
|
||||
ShellMountQuestionDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
|
||||
_init: function(icon) {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'mount-question-dialog' });
|
||||
|
||||
let mainContentLayout = new St.BoxLayout();
|
||||
this.contentLayout.add(mainContentLayout, { x_fill: true,
|
||||
y_fill: false });
|
||||
|
||||
this._iconBin = new St.Bin({ child: icon });
|
||||
mainContentLayout.add(this._iconBin,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
let messageLayout = new St.BoxLayout({ vertical: true });
|
||||
mainContentLayout.add(messageLayout,
|
||||
{ y_align: St.Align.START });
|
||||
|
||||
this.subjectLabel = new St.Label({ style_class: 'mount-question-dialog-subject' });
|
||||
|
||||
messageLayout.add(this.subjectLabel,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this.descriptionLabel = new St.Label({ style_class: 'mount-question-dialog-description' });
|
||||
this.descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this.descriptionLabel.clutter_text.line_wrap = true;
|
||||
|
||||
messageLayout.add(this.descriptionLabel,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
},
|
||||
|
||||
update: function(message, choices) {
|
||||
_setLabelsForMessage(this, message);
|
||||
_setButtonsForChoices(this, choices);
|
||||
}
|
||||
}
|
||||
Signals.addSignalMethods(ShellMountQuestionDialog.prototype);
|
||||
|
||||
function ShellMountPasswordSource(message, icon, reaskPassword) {
|
||||
this._init(message, icon, reaskPassword);
|
||||
}
|
||||
|
||||
ShellMountPasswordSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(message, icon, reaskPassword) {
|
||||
let strings = message.split('\n');
|
||||
MessageTray.Source.prototype._init.call(this, strings[0]);
|
||||
|
||||
this._notification = new ShellMountPasswordNotification(this, strings, icon, reaskPassword);
|
||||
|
||||
// add ourselves as a source, and popup the notification
|
||||
Main.messageTray.add(this);
|
||||
this.notify(this._notification);
|
||||
},
|
||||
}
|
||||
Signals.addSignalMethods(ShellMountPasswordSource.prototype);
|
||||
|
||||
function ShellMountPasswordNotification(source, strings, icon, reaskPassword) {
|
||||
this._init(source, strings, icon, reaskPassword);
|
||||
}
|
||||
|
||||
ShellMountPasswordNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init: function(source, strings, icon, reaskPassword) {
|
||||
MessageTray.Notification.prototype._init.call(this, source,
|
||||
strings[0], null,
|
||||
{ customContent: true,
|
||||
icon: icon });
|
||||
|
||||
// set the notification to transient and urgent, so that it
|
||||
// expands out
|
||||
this.setTransient(true);
|
||||
this.setUrgency(MessageTray.Urgency.CRITICAL);
|
||||
|
||||
if (strings[1])
|
||||
this.addBody(strings[1]);
|
||||
|
||||
if (reaskPassword) {
|
||||
let label = new St.Label({ style_class: 'mount-password-reask',
|
||||
text: _("Wrong password, please try again") });
|
||||
|
||||
this.addActor(label);
|
||||
}
|
||||
|
||||
this._responseEntry = new St.Entry({ style_class: 'mount-password-entry',
|
||||
can_focus: true });
|
||||
this.setActionArea(this._responseEntry);
|
||||
|
||||
this._responseEntry.clutter_text.connect('activate',
|
||||
Lang.bind(this, this._onEntryActivated));
|
||||
this._responseEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||
|
||||
this._responseEntry.grab_key_focus();
|
||||
},
|
||||
|
||||
_onEntryActivated: function() {
|
||||
let text = this._responseEntry.get_text();
|
||||
if (text == '')
|
||||
return;
|
||||
|
||||
this.source.emit('password-ready', text);
|
||||
}
|
||||
}
|
||||
|
||||
function ShellProcessesDialog(icon) {
|
||||
this._init(icon);
|
||||
}
|
||||
|
||||
ShellProcessesDialog.prototype = {
|
||||
__proto__: ModalDialog.ModalDialog.prototype,
|
||||
|
||||
_init: function(icon) {
|
||||
ModalDialog.ModalDialog.prototype._init.call(this, { styleClass: 'show-processes-dialog' });
|
||||
|
||||
let mainContentLayout = new St.BoxLayout();
|
||||
this.contentLayout.add(mainContentLayout, { x_fill: true,
|
||||
y_fill: false });
|
||||
|
||||
this._iconBin = new St.Bin({ child: icon });
|
||||
mainContentLayout.add(this._iconBin,
|
||||
{ x_fill: true,
|
||||
y_fill: false,
|
||||
x_align: St.Align.END,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
let messageLayout = new St.BoxLayout({ vertical: true });
|
||||
mainContentLayout.add(messageLayout,
|
||||
{ y_align: St.Align.START });
|
||||
|
||||
this.subjectLabel = new St.Label({ style_class: 'show-processes-dialog-subject' });
|
||||
|
||||
messageLayout.add(this.subjectLabel,
|
||||
{ y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this.descriptionLabel = new St.Label({ style_class: 'show-processes-dialog-description' });
|
||||
this.descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this.descriptionLabel.clutter_text.line_wrap = true;
|
||||
|
||||
messageLayout.add(this.descriptionLabel,
|
||||
{ y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let scrollView = new St.ScrollView({ style_class: 'show-processes-dialog-app-list'});
|
||||
scrollView.set_policy(Gtk.PolicyType.NEVER,
|
||||
Gtk.PolicyType.AUTOMATIC);
|
||||
this.contentLayout.add(scrollView,
|
||||
{ x_fill: true,
|
||||
y_fill: true });
|
||||
scrollView.hide();
|
||||
|
||||
this._applicationList = new St.BoxLayout({ vertical: true });
|
||||
scrollView.add_actor(this._applicationList,
|
||||
{ x_fill: true,
|
||||
y_fill: true,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.MIDDLE });
|
||||
|
||||
this._applicationList.connect('actor-added',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 1)
|
||||
scrollView.show();
|
||||
}));
|
||||
|
||||
this._applicationList.connect('actor-removed',
|
||||
Lang.bind(this, function() {
|
||||
if (this._applicationList.get_children().length == 0)
|
||||
scrollView.hide();
|
||||
}));
|
||||
},
|
||||
|
||||
_setAppsForPids: function(pids) {
|
||||
// remove all the items
|
||||
this._applicationList.destroy_children();
|
||||
|
||||
pids.forEach(Lang.bind(this, function(pid) {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let app = tracker.get_app_from_pid(pid);
|
||||
|
||||
if (!app)
|
||||
return;
|
||||
|
||||
let item = new ListItem(app);
|
||||
this._applicationList.add(item.actor, { x_fill: true });
|
||||
|
||||
item.connect('activate',
|
||||
Lang.bind(this, function() {
|
||||
// use -1 to indicate Cancel
|
||||
this.emit('response', -1);
|
||||
}));
|
||||
}));
|
||||
},
|
||||
|
||||
update: function(message, processes, choices) {
|
||||
this._setAppsForPids(processes);
|
||||
_setLabelsForMessage(this, message);
|
||||
_setButtonsForChoices(this, choices);
|
||||
}
|
||||
}
|
||||
Signals.addSignalMethods(ShellProcessesDialog.prototype);
|
@ -10,13 +10,11 @@ const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
|
||||
const KEY_STICKY_KEYS_ENABLED = 'stickykeys-enable';
|
||||
const KEY_BOUNCE_KEYS_ENABLED = 'bouncekeys-enable';
|
||||
@ -42,6 +40,8 @@ const KEY_TEXT_SCALING_FACTOR = 'text-scaling-factor';
|
||||
|
||||
const HIGH_CONTRAST_THEME = 'HighContrast';
|
||||
|
||||
const KEYBOARD_SCHEMA = 'org.gnome.shell.keyboard'
|
||||
|
||||
function ATIndicator() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
@ -70,9 +70,9 @@ ATIndicator.prototype = {
|
||||
// 'screen-reader-enabled');
|
||||
// this.menu.addMenuItem(screenReader);
|
||||
|
||||
// let screenKeyboard = this._buildItem(_("Screen Keyboard"), APPLICATIONS_SCHEMA,
|
||||
// 'screen-keyboard-enabled');
|
||||
// this.menu.addMenuItem(screenKeyboard);
|
||||
let screenKeyboard = this._buildItem(_("Screen Keyboard"), KEYBOARD_SCHEMA,
|
||||
'show-keyboard');
|
||||
this.menu.addMenuItem(screenKeyboard);
|
||||
|
||||
let visualBell = this._buildItemGConf(_("Visual Alerts"), client, KEY_VISUAL_BELL);
|
||||
this.menu.addMenuItem(visualBell);
|
||||
@ -91,6 +91,7 @@ ATIndicator.prototype = {
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Universal Access Settings"), function() {
|
||||
Main.overview.hide();
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-universal-access-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
|
@ -16,9 +16,6 @@ const MessageTray = imports.ui.messageTray;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const ConnectionState = {
|
||||
DISCONNECTED: 0,
|
||||
CONNECTED: 1,
|
||||
@ -67,7 +64,7 @@ Indicator.prototype = {
|
||||
|
||||
this._fullMenuItems = [new PopupMenu.PopupSeparatorMenuItem(),
|
||||
new PopupMenu.PopupMenuItem(_("Send Files to Device...")),
|
||||
new PopupMenu.PopupMenuItem(_("Setup a New Device...")),
|
||||
new PopupMenu.PopupMenuItem(_("Set up a New Device...")),
|
||||
new PopupMenu.PopupSeparatorMenuItem()];
|
||||
this._hasDevices = false;
|
||||
this._deviceSep = this._fullMenuItems[0]; // hidden if no device exists
|
||||
@ -93,6 +90,7 @@ Indicator.prototype = {
|
||||
this._updateFullMenu();
|
||||
|
||||
this.menu.addAction(_("Bluetooth Settings"), function() {
|
||||
Main.overview.hide()
|
||||
let app = Shell.AppSystem.get_default().get_app('bluetooth-properties.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
@ -111,7 +109,11 @@ Indicator.prototype = {
|
||||
current_state != GnomeBluetoothApplet.KillswitchState.HARD_BLOCKED;
|
||||
|
||||
this._killswitch.setToggleState(on);
|
||||
this._killswitch.actor.reactive = can_toggle;
|
||||
if (can_toggle)
|
||||
this._killswitch.setStatus(null);
|
||||
else
|
||||
/* TRANSLATORS: this means that bluetooth was disabled by hardware rfkill */
|
||||
this._killswitch.setStatus(_("hardware disabled"));
|
||||
|
||||
if (has_adapter)
|
||||
this.actor.show();
|
||||
@ -127,13 +129,6 @@ Indicator.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_deviceCompare: function(d1, d2) {
|
||||
return d1.device_path == d2.device_path &&
|
||||
d1.bdaddr == d2.bdaddr &&
|
||||
d1.can_connect == d2.can_connect &&
|
||||
d1.capabilities == d2.capabilities;
|
||||
},
|
||||
|
||||
_updateDevices: function() {
|
||||
let devices = this._applet.get_devices();
|
||||
|
||||
@ -142,12 +137,8 @@ Indicator.prototype = {
|
||||
let item = this._deviceItems[i];
|
||||
let destroy = true;
|
||||
for (let j = 0; j < devices.length; j++) {
|
||||
// we need to deep compare because BluetoothSimpleDevice is a boxed type
|
||||
// (but we take advantage of that, because _skip will disappear the next
|
||||
// time get_devices() is called)
|
||||
if (this._deviceCompare(item._device, devices[j])) {
|
||||
item.label.text = devices[j].alias;
|
||||
devices[j]._skip = true;
|
||||
if (item._device.device_path == devices[j].device_path) {
|
||||
this._updateDeviceItem(item, devices[j]);
|
||||
destroy = false;
|
||||
break;
|
||||
}
|
||||
@ -162,7 +153,7 @@ Indicator.prototype = {
|
||||
this._hasDevices = newlist.length > 0;
|
||||
for (let i = 0; i < devices.length; i++) {
|
||||
let d = devices[i];
|
||||
if (d._skip)
|
||||
if (d._item)
|
||||
continue;
|
||||
let item = this._createDeviceItem(d);
|
||||
if (item) {
|
||||
@ -177,23 +168,62 @@ Indicator.prototype = {
|
||||
this._deviceSep.actor.hide();
|
||||
},
|
||||
|
||||
_updateDeviceItem: function(item, device) {
|
||||
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE) {
|
||||
item.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
let prevDevice = item._device;
|
||||
let prevCapabilities = prevDevice.capabilities;
|
||||
let prevCanConnect = prevDevice.can_connect;
|
||||
|
||||
// adopt the new device object
|
||||
item._device = device;
|
||||
device._item = item;
|
||||
|
||||
// update properties
|
||||
item.label.text = device.alias;
|
||||
|
||||
if (prevCapabilities != device.capabilities ||
|
||||
prevCanConnect != device.can_connect) {
|
||||
// need to rebuild the submenu
|
||||
item.menu.removeAll();
|
||||
this._buildDeviceSubMenu(item, device);
|
||||
}
|
||||
|
||||
// update connected property
|
||||
if (device.can_connect)
|
||||
item._connectedMenuitem.setToggleState(device.connected);
|
||||
},
|
||||
|
||||
_createDeviceItem: function(device) {
|
||||
if (!device.can_connect && device.capabilities == GnomeBluetoothApplet.Capabilities.NONE)
|
||||
return null;
|
||||
let item = new PopupMenu.PopupSubMenuMenuItem(device.alias);
|
||||
item._device = device;
|
||||
|
||||
// adopt the device object, and add a back link
|
||||
item._device = device;
|
||||
device._item = item;
|
||||
|
||||
this._buildDeviceSubMenu(item, device);
|
||||
|
||||
return item;
|
||||
},
|
||||
|
||||
_buildDeviceSubMenu: function(item, device) {
|
||||
if (device.can_connect) {
|
||||
item._connected = device.connected;
|
||||
let menuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
|
||||
|
||||
menuitem.connect('toggled', Lang.bind(this, function() {
|
||||
item._connectedMenuitem = new PopupMenu.PopupSwitchMenuItem(_("Connection"), device.connected);
|
||||
item._connectedMenuitem.connect('toggled', Lang.bind(this, function() {
|
||||
if (item._connected > ConnectionState.CONNECTED) {
|
||||
// operation already in progress, revert
|
||||
// (should not happen anyway)
|
||||
menuitem.setToggleState(menuitem.state);
|
||||
}
|
||||
if (item._connected) {
|
||||
item._connected = ConnectionState.DISCONNECTING;
|
||||
menuitem.setStatus(_("disconnecting..."));
|
||||
this._applet.disconnect_device(item._device.device_path, function(applet, success) {
|
||||
if (success) { // apply
|
||||
item._connected = ConnectionState.DISCONNECTED;
|
||||
@ -202,9 +232,11 @@ Indicator.prototype = {
|
||||
item._connected = ConnectionState.CONNECTED;
|
||||
menuitem.setToggleState(true);
|
||||
}
|
||||
menuitem.setStatus(null);
|
||||
});
|
||||
} else {
|
||||
item._connected = ConnectionState.CONNECTING;
|
||||
menuitem.setStatus(_("connecting..."));
|
||||
this._applet.connect_device(item._device.device_path, function(applet, success) {
|
||||
if (success) { // apply
|
||||
item._connected = ConnectionState.CONNECTED;
|
||||
@ -213,11 +245,12 @@ Indicator.prototype = {
|
||||
item._connected = ConnectionState.DISCONNECTED;
|
||||
menuitem.setToggleState(false);
|
||||
}
|
||||
menuitem.setStatus(null);
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
item.menu.addMenuItem(menuitem);
|
||||
item.menu.addMenuItem(item._connectedMenuitem);
|
||||
}
|
||||
|
||||
if (device.capabilities & GnomeBluetoothApplet.Capabilities.OBEX_PUSH) {
|
||||
@ -263,8 +296,6 @@ Indicator.prototype = {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return item;
|
||||
},
|
||||
|
||||
_updateFullMenu: function() {
|
||||
|
@ -9,13 +9,11 @@ const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
function LayoutMenuItem() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
@ -71,9 +69,11 @@ XKBIndicator.prototype = {
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Show Keyboard Layout..."), Lang.bind(this, function() {
|
||||
Main.overview.hide();
|
||||
Util.spawn(['gkbd-keyboard-display', '-g', String(this._config.get_current_group() + 1)]);
|
||||
}));
|
||||
this.menu.addAction(_("Localization Settings"), function() {
|
||||
Main.overview.hide();
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-region-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
|
@ -7,15 +7,13 @@ const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const BUS_NAME = 'org.gnome.PowerManager';
|
||||
const OBJECT_PATH = '/org/gnome/PowerManager';
|
||||
const BUS_NAME = 'org.gnome.SettingsDaemon';
|
||||
const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
|
||||
|
||||
const UPDeviceType = {
|
||||
UNKNOWN: 0,
|
||||
@ -43,7 +41,7 @@ const UPDeviceState = {
|
||||
};
|
||||
|
||||
const PowerManagerInterface = {
|
||||
name: 'org.gnome.PowerManager',
|
||||
name: 'org.gnome.SettingsDaemon.Power',
|
||||
methods: [
|
||||
{ name: 'GetDevices', inSignature: '', outSignature: 'a(susbut)' },
|
||||
{ name: 'GetPrimaryDevice', inSignature: '', outSignature: '(susbut)' },
|
||||
@ -83,6 +81,7 @@ Indicator.prototype = {
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this.menu.addAction(_("Power Settings"),function() {
|
||||
Main.overview.hide();
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-power-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
@ -94,7 +93,6 @@ Indicator.prototype = {
|
||||
_readPrimaryDevice: function() {
|
||||
this._proxy.GetPrimaryDeviceRemote(Lang.bind(this, function(device, error) {
|
||||
if (error) {
|
||||
this._checkError(error);
|
||||
this._hasPrimary = false;
|
||||
this._primaryDeviceId = null;
|
||||
this._batteryItem.actor.hide();
|
||||
@ -115,15 +113,15 @@ Indicator.prototype = {
|
||||
let timestring;
|
||||
if (time > 60) {
|
||||
if (minutes == 0) {
|
||||
timestring = Gettext.ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
|
||||
timestring = ngettext("%d hour remaining", "%d hours remaining", hours).format(hours);
|
||||
} else {
|
||||
/* TRANSLATORS: this is a time string, as in "%d hours %d minutes remaining" */
|
||||
let template = _("%d %s %d %s remaining");
|
||||
|
||||
timestring = template.format (hours, Gettext.ngettext("hour", "hours", hours), minutes, Gettext.ngettext("minute", "minutes", minutes));
|
||||
timestring = template.format (hours, ngettext("hour", "hours", hours), minutes, ngettext("minute", "minutes", minutes));
|
||||
}
|
||||
} else
|
||||
timestring = Gettext.ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
|
||||
timestring = ngettext("%d minute remaining", "%d minutes remaining", minutes).format(minutes);
|
||||
this._batteryItem.label.text = timestring;
|
||||
}
|
||||
this._primaryPercentage.text = Math.round(percentage) + '%';
|
||||
@ -146,7 +144,6 @@ Indicator.prototype = {
|
||||
this._deviceItems = [];
|
||||
|
||||
if (error) {
|
||||
this._checkError(error);
|
||||
this._deviceSep.actor.hide();
|
||||
return;
|
||||
}
|
||||
@ -177,21 +174,12 @@ Indicator.prototype = {
|
||||
this.setGIcon(gicon);
|
||||
this.actor.show();
|
||||
} else {
|
||||
this._checkError(error);
|
||||
this.menu.close();
|
||||
this.actor.hide();
|
||||
}
|
||||
}));
|
||||
this._readPrimaryDevice();
|
||||
this._readOtherDevices();
|
||||
},
|
||||
|
||||
_checkError: function(error) {
|
||||
if (!this._restarted && error && error.message.match(/org\.freedesktop\.DBus\.Error\.(UnknownMethod|InvalidArgs)/)) {
|
||||
Util.killall('gnome-power-manager');
|
||||
Util.spawn(['gnome-power-manager']);
|
||||
this._restarted = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -9,13 +9,11 @@ const Gvc = imports.gi.Gvc;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const VOLUME_ADJUSTMENT_STEP = 0.05; /* Volume adjustment step in % */
|
||||
|
||||
const VOLUME_NOTIFY_ID = 1;
|
||||
@ -64,6 +62,7 @@ Indicator.prototype = {
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Sound Settings"), function() {
|
||||
Main.overview.hide();
|
||||
let app = Shell.AppSystem.get_default().get_app('gnome-sound-panel.desktop');
|
||||
app.activate(-1);
|
||||
});
|
||||
|
@ -4,6 +4,7 @@ const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||
const Util = imports.misc.util;
|
||||
@ -38,10 +39,10 @@ StatusIconDispatcher.prototype = {
|
||||
// status icons
|
||||
// http://bugzilla.gnome.org/show_bug.cgi=id=621382
|
||||
Util.killall('indicator-application-service');
|
||||
},
|
||||
|
||||
start: function(themeWidget) {
|
||||
this._traymanager.manage_stage(global.stage, themeWidget);
|
||||
Main.connect('initialized', Lang.bind(this, function() {
|
||||
this._traymanager.manage_stage(global.stage, Main.messageTray.actor);
|
||||
}));
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon) {
|
||||
|
@ -9,30 +9,19 @@ const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
const UPowerGlib = imports.gi.UPowerGlib;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const ScreenSaver = imports.misc.screenSaver;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const BUS_NAME = 'org.gnome.ScreenSaver';
|
||||
const OBJECT_PATH = '/org/gnome/ScreenSaver';
|
||||
|
||||
const LOCKDOWN_SCHEMA = 'org.gnome.desktop.lockdown';
|
||||
const DISABLE_USER_SWITCH_KEY = 'disable-user-switching';
|
||||
const DISABLE_LOCK_SCREEN_KEY = 'disable-lock-screen';
|
||||
const DISABLE_LOG_OUT_KEY = 'disable-log-out';
|
||||
|
||||
const ScreenSaverInterface = {
|
||||
name: BUS_NAME,
|
||||
methods: [ { name: 'Lock', inSignature: '' } ]
|
||||
};
|
||||
|
||||
let ScreenSaverProxy = DBus.makeProxyClass(ScreenSaverInterface);
|
||||
|
||||
// Adapted from gdm/gui/user-switch-applet/applet.c
|
||||
//
|
||||
// Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
|
||||
@ -59,11 +48,12 @@ StatusMenuButton.prototype = {
|
||||
this._presence = new GnomeSession.Presence();
|
||||
this._presenceItems = {};
|
||||
this._session = new GnomeSession.SessionManager();
|
||||
this._haveShutdown = true;
|
||||
|
||||
this._account_mgr = Tp.AccountManager.dup()
|
||||
|
||||
this._upClient = new UPowerGlib.Client();
|
||||
this._screenSaverProxy = new ScreenSaverProxy(DBus.session, BUS_NAME, OBJECT_PATH);
|
||||
this._screenSaverProxy = new ScreenSaver.ScreenSaverProxy();
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._iconBox = new St.Bin();
|
||||
@ -91,12 +81,25 @@ StatusMenuButton.prototype = {
|
||||
Lang.bind(this, this._updateSwitchUser));
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
||||
Lang.bind(this, this._updateLogout));
|
||||
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
|
||||
Lang.bind(this, this._updateLockScreen));
|
||||
this._updateSwitchUser();
|
||||
this._updateLogout();
|
||||
this._updateLockScreen();
|
||||
|
||||
// Whether shutdown is available or not depends on both lockdown
|
||||
// settings (disable-log-out) and Polkit policy - the latter doesn't
|
||||
// notify, so we update the menu item each time the menu opens or
|
||||
// the lockdown setting changes, which should be close enough.
|
||||
this.menu.connect('open-state-changed', Lang.bind(this,
|
||||
function(menu, open) {
|
||||
if (open)
|
||||
this._updateHaveShutdown();
|
||||
}));
|
||||
this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
|
||||
Lang.bind(this, this._updateHaveShutdown));
|
||||
|
||||
this._upClient.connect('notify::can-suspend', Lang.bind(this, this._updateSuspendOrPowerOff));
|
||||
},
|
||||
|
||||
@ -113,13 +116,25 @@ StatusMenuButton.prototype = {
|
||||
},
|
||||
|
||||
_updateSessionSeparator: function() {
|
||||
let showSeparator = this._loginScreenItem.actor.visible ||
|
||||
this._logoutItem.actor.visible ||
|
||||
this._lockScreenItem.actor.visible;
|
||||
if (showSeparator)
|
||||
let sessionItemsVisible = this._loginScreenItem.actor.visible ||
|
||||
this._logoutItem.actor.visible ||
|
||||
this._lockScreenItem.actor.visible;
|
||||
|
||||
let showSessionSeparator = sessionItemsVisible &&
|
||||
this._suspendOrPowerOffItem.actor.visible;
|
||||
|
||||
let showSettingsSeparator = sessionItemsVisible ||
|
||||
this._suspendOrPowerOffItem.actor.visible;
|
||||
|
||||
if (showSessionSeparator)
|
||||
this._sessionSeparator.actor.show();
|
||||
else
|
||||
this._sessionSeparator.actor.hide();
|
||||
|
||||
if (showSettingsSeparator)
|
||||
this._settingsSeparator.actor.show();
|
||||
else
|
||||
this._settingsSeparator.actor.hide();
|
||||
},
|
||||
|
||||
_updateSwitchUser: function() {
|
||||
@ -149,16 +164,34 @@ StatusMenuButton.prototype = {
|
||||
this._updateSessionSeparator();
|
||||
},
|
||||
|
||||
_updateHaveShutdown: function() {
|
||||
this._session.CanShutdownRemote(Lang.bind(this,
|
||||
function(result, error) {
|
||||
if (!error) {
|
||||
this._haveShutdown = result;
|
||||
this._updateSuspendOrPowerOff();
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_updateSuspendOrPowerOff: function() {
|
||||
this._haveSuspend = this._upClient.get_can_suspend();
|
||||
|
||||
if (!this._suspendOrPowerOffItem)
|
||||
return;
|
||||
|
||||
if (!this._haveShutdown && !this._haveSuspend)
|
||||
this._suspendOrPowerOffItem.actor.hide();
|
||||
else
|
||||
this._suspendOrPowerOffItem.actor.show();
|
||||
this._updateSessionSeparator();
|
||||
|
||||
// If we can't suspend show Power Off... instead
|
||||
// and disable the alt key
|
||||
if (!this._haveSuspend) {
|
||||
this._suspendOrPowerOffItem.updateText(_("Power Off..."), null);
|
||||
} else if (!this._haveShutdown) {
|
||||
this._suspendOrPowerOffItem.updateText(_("Suspend"), null);
|
||||
} else {
|
||||
this._suspendOrPowerOffItem.updateText(_("Suspend"), _("Power Off..."));
|
||||
}
|
||||
@ -204,6 +237,7 @@ StatusMenuButton.prototype = {
|
||||
|
||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||
this.menu.addMenuItem(item);
|
||||
this._settingsSeparator = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Lock Screen"));
|
||||
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
|
||||
@ -257,8 +291,11 @@ StatusMenuButton.prototype = {
|
||||
|
||||
_onLoginScreenActivate: function() {
|
||||
Main.overview.hide();
|
||||
this._gdm.goto_login_session();
|
||||
this._onLockScreenActivate();
|
||||
// Ensure we only move to GDM after the screensaver has activated; in some
|
||||
// OS configurations, the X server may block event processing on VT switch
|
||||
this._screenSaverProxy.SetActiveRemote(true, Lang.bind(this, function() {
|
||||
this._gdm.goto_login_session();
|
||||
}));
|
||||
},
|
||||
|
||||
_onQuitSessionActivate: function() {
|
||||
@ -271,7 +308,8 @@ StatusMenuButton.prototype = {
|
||||
|
||||
if (this._haveSuspend &&
|
||||
this._suspendOrPowerOffItem.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
||||
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
|
||||
// Ensure we only suspend after the screensaver has activated
|
||||
this._screenSaverProxy.SetActiveRemote(true, Lang.bind(this, function() {
|
||||
this._upClient.suspend_sync(null);
|
||||
}));
|
||||
} else {
|
||||
|
@ -9,9 +9,6 @@ const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Tpl = imports.gi.TelepathyLogger;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
const C_ = Gettext.pgettext;
|
||||
|
||||
const History = imports.misc.history;
|
||||
const Main = imports.ui.main;
|
||||
@ -27,6 +24,9 @@ const SCROLLBACK_IDLE_LENGTH = 5;
|
||||
// See Source._displayPendingMessages
|
||||
const SCROLLBACK_HISTORY_LINES = 10;
|
||||
|
||||
// See Notification._onEntryChanged
|
||||
const COMPOSING_STOP_TIMEOUT = 5;
|
||||
|
||||
const NotificationDirection = {
|
||||
SENT: 'chat-sent',
|
||||
RECEIVED: 'chat-received'
|
||||
@ -72,27 +72,34 @@ function Client() {
|
||||
|
||||
Client.prototype = {
|
||||
_init : function() {
|
||||
// channel path -> Source
|
||||
this._sources = {};
|
||||
// channel path -> ChatSource
|
||||
this._chatSources = {};
|
||||
this._chatState = Tp.ChannelChatState.ACTIVE;
|
||||
|
||||
// Set up a SimpleObserver, which will call _observeChannels whenever a
|
||||
// channel matching its filters is detected.
|
||||
// The second argument, recover, means _observeChannels will be run
|
||||
// for any existing channel as well.
|
||||
let dbus = Tp.DBusDaemon.dup();
|
||||
this._observer = Tp.SimpleObserver.new(dbus, true, 'GnomeShell', true,
|
||||
Lang.bind(this, this._observeChannels));
|
||||
this._tpClient = new Shell.TpClient({ 'dbus_daemon': dbus,
|
||||
'name': 'GnomeShell',
|
||||
'uniquify-name': true })
|
||||
this._tpClient.set_observe_channels_func(
|
||||
Lang.bind(this, this._observeChannels));
|
||||
this._tpClient.set_approve_channels_func(
|
||||
Lang.bind(this, this._approveChannels));
|
||||
this._tpClient.set_handle_channels_func(
|
||||
Lang.bind(this, this._handleChannels));
|
||||
|
||||
// We only care about single-user text-based chats
|
||||
let props = {};
|
||||
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
|
||||
props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE] = Tp.HandleType.CONTACT;
|
||||
this._observer.add_observer_filter(props);
|
||||
// Allow other clients (such as Empathy) to pre-empt our channels if
|
||||
// needed
|
||||
this._tpClient.set_delegated_channels_callback(
|
||||
Lang.bind(this, this._delegatedChannelsCb));
|
||||
|
||||
try {
|
||||
this._observer.register();
|
||||
this._tpClient.register();
|
||||
} catch (e) {
|
||||
throw new Error('Couldn\'t register SimpleObserver. Error: \n' + e);
|
||||
throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
|
||||
}
|
||||
},
|
||||
|
||||
@ -105,7 +112,7 @@ Client.prototype = {
|
||||
this._finishObserveChannels(account, conn, channels, context);
|
||||
} else {
|
||||
Shell.get_self_contact_features(conn,
|
||||
contactFeatures.length, contactFeatures,
|
||||
contactFeatures,
|
||||
Lang.bind(this, function() {
|
||||
this._finishObserveChannels(account, conn, channels, context);
|
||||
}));
|
||||
@ -125,60 +132,216 @@ Client.prototype = {
|
||||
continue;
|
||||
|
||||
/* Request a TpContact */
|
||||
Shell.get_tp_contacts(conn, 1, [targetHandle],
|
||||
contactFeatures.length, contactFeatures,
|
||||
Shell.get_tp_contacts(conn, [targetHandle],
|
||||
contactFeatures,
|
||||
Lang.bind(this, function (connection, contacts, failed) {
|
||||
if (contacts.length < 1)
|
||||
return;
|
||||
|
||||
/* We got the TpContact */
|
||||
this._createSource(account, conn, channel, contacts[0]);
|
||||
this._createChatSource(account, conn, channel, contacts[0]);
|
||||
}), null);
|
||||
}
|
||||
|
||||
context.accept();
|
||||
},
|
||||
|
||||
_createSource: function(account, conn, channel, contact) {
|
||||
if (this._sources[channel.get_object_path()])
|
||||
_createChatSource: function(account, conn, channel, contact) {
|
||||
if (this._chatSources[channel.get_object_path()])
|
||||
return;
|
||||
|
||||
let source = new Source(account, conn, channel, contact);
|
||||
let source = new ChatSource(account, conn, channel, contact, this._tpClient);
|
||||
|
||||
this._sources[channel.get_object_path()] = source;
|
||||
this._chatSources[channel.get_object_path()] = source;
|
||||
source.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
delete this._sources[channel.get_object_path()];
|
||||
if (this._tpClient.is_handling_channel(channel)) {
|
||||
// The chat box has been destroyed so it can't
|
||||
// handle the channel any more.
|
||||
channel.close_async(function(src, result) {
|
||||
channel.close_finish(result);
|
||||
});
|
||||
}
|
||||
|
||||
delete this._chatSources[channel.get_object_path()];
|
||||
}));
|
||||
},
|
||||
|
||||
_handleChannels: function(handler, account, conn, channels,
|
||||
requests, user_action_time, context) {
|
||||
this._handlingChannels(account, conn, channels);
|
||||
context.accept();
|
||||
},
|
||||
|
||||
_handlingChannels: function(account, conn, channels) {
|
||||
let len = channels.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
let channel = channels[i];
|
||||
|
||||
// We can only handle text channel, so close any other channel
|
||||
if (!(channel instanceof Tp.TextChannel)) {
|
||||
channel.close_async(null);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this._tpClient.is_handling_channel(channel)) {
|
||||
// We are already handling the channel, display the source
|
||||
let source = this._chatSources[channel.get_object_path()];
|
||||
if (source)
|
||||
source.notify();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_displayRoomInvitation: function(conn, channel, dispatchOp, context) {
|
||||
// We can only approve the rooms if we have been invited to it
|
||||
let selfHandle = channel.group_get_self_handle();
|
||||
if (selfHandle == 0) {
|
||||
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
||||
return;
|
||||
}
|
||||
|
||||
let [invited, inviter, reason, msg] = channel.group_get_local_pending_info(selfHandle);
|
||||
if (!invited) {
|
||||
Shell.decline_dispatch_op(context, 'Not invited to the room');
|
||||
return;
|
||||
}
|
||||
|
||||
// Request a TpContact for the inviter
|
||||
Shell.get_tp_contacts(conn, [inviter],
|
||||
contactFeatures,
|
||||
Lang.bind(this, this._createRoomInviteSource, channel, context, dispatchOp));
|
||||
|
||||
context.delay();
|
||||
},
|
||||
|
||||
_createRoomInviteSource: function(connection, contacts, failed, channel, context, dispatchOp) {
|
||||
if (contacts.length < 1) {
|
||||
Shell.decline_dispatch_op(context, 'Failed to get inviter');
|
||||
return;
|
||||
}
|
||||
|
||||
// We got the TpContact
|
||||
|
||||
// FIXME: We don't have a 'chat room' icon (bgo #653737) use
|
||||
// system-users for now as Empathy does.
|
||||
let source = new ApproverSource(dispatchOp, _("Invitation"), 'system-users');
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notif = new RoomInviteNotification(source, dispatchOp, channel, contacts[0]);
|
||||
source.notify(notif);
|
||||
context.accept();
|
||||
},
|
||||
|
||||
_approveChannels: function(approver, account, conn, channels,
|
||||
dispatchOp, context) {
|
||||
let channel = channels[0];
|
||||
let chanType = channel.get_channel_type();
|
||||
|
||||
if (chanType == Tp.IFACE_CHANNEL_TYPE_TEXT)
|
||||
this._approveTextChannel(account, conn, channel, dispatchOp, context);
|
||||
else if (chanType == Tp.IFACE_CHANNEL_TYPE_STREAMED_MEDIA ||
|
||||
chanType == 'org.freedesktop.Telepathy.Channel.Type.Call.DRAFT')
|
||||
this._approveCall(account, conn, channel, dispatchOp, context);
|
||||
},
|
||||
|
||||
_approveTextChannel: function(account, conn, channel, dispatchOp, context) {
|
||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
||||
|
||||
if (targetHandleType == Tp.HandleType.CONTACT) {
|
||||
// Approve private text channels right away as we are going to handle it
|
||||
dispatchOp.claim_with_async(this._tpClient,
|
||||
Lang.bind(this, function(dispatchOp, result) {
|
||||
try {
|
||||
dispatchOp.claim_with_finish(result);
|
||||
this._handlingChannels(account, conn, [channel]);
|
||||
} catch (err) {
|
||||
throw new Error('Failed to Claim channel: ' + err);
|
||||
}}));
|
||||
|
||||
context.accept();
|
||||
} else {
|
||||
this._displayRoomInvitation(conn, channel, dispatchOp, context);
|
||||
}
|
||||
},
|
||||
|
||||
_approveCall: function(account, conn, channel, dispatchOp, context) {
|
||||
let [targetHandle, targetHandleType] = channel.get_handle();
|
||||
|
||||
Shell.get_tp_contacts(conn, [targetHandle],
|
||||
contactFeatures,
|
||||
Lang.bind(this, this._createAudioVideoSource, channel, context, dispatchOp));
|
||||
},
|
||||
|
||||
_createAudioVideoSource: function(connection, contacts, failed, channel, context, dispatchOp) {
|
||||
if (contacts.length < 1) {
|
||||
Shell.decline_dispatch_op(context, 'Failed to get inviter');
|
||||
return;
|
||||
}
|
||||
|
||||
let isVideo = false;
|
||||
|
||||
let props = channel.borrow_immutable_properties();
|
||||
|
||||
if (props['org.freedesktop.Telepathy.Channel.Type.Call.DRAFT.InitialVideo'] ||
|
||||
props[Tp.PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO])
|
||||
isVideo = true;
|
||||
|
||||
// We got the TpContact
|
||||
let source = new ApproverSource(dispatchOp, _("Call"), isVideo ? 'camera-web' : 'audio-input-microphone');
|
||||
Main.messageTray.add(source);
|
||||
|
||||
let notif = new AudioVideoNotification(source, dispatchOp, channel, contacts[0], isVideo);
|
||||
source.notify(notif);
|
||||
context.accept();
|
||||
},
|
||||
|
||||
_delegatedChannelsCb: function(client, channels) {
|
||||
// Nothing to do as we don't make a distinction between observed and
|
||||
// handled channels.
|
||||
}
|
||||
};
|
||||
|
||||
function Source(account, conn, channel, contact) {
|
||||
this._init(account, conn, channel, contact);
|
||||
function ChatSource(account, conn, channel, contact, client) {
|
||||
this._init(account, conn, channel, contact, client);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
ChatSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(account, conn, channel, contact) {
|
||||
_init: function(account, conn, channel, contact, client) {
|
||||
MessageTray.Source.prototype._init.call(this, contact.get_alias());
|
||||
|
||||
this.isChat = true;
|
||||
|
||||
this._account = account;
|
||||
this._contact = contact;
|
||||
this._client = client;
|
||||
|
||||
this._pendingMessages = [];
|
||||
|
||||
this._conn = conn;
|
||||
this._channel = channel;
|
||||
this._closedId = this._channel.connect('invalidated', Lang.bind(this, this._channelClosed));
|
||||
|
||||
this._notification = new Notification(this);
|
||||
this._notification = new ChatNotification(this);
|
||||
this._notification.setUrgency(MessageTray.Urgency.HIGH);
|
||||
|
||||
// We ack messages when the message box is collapsed if user has
|
||||
// interacted with it before and so read the messages:
|
||||
// - user clicked on it the tray
|
||||
// - user expanded the notification by hovering over the toaster notification
|
||||
this._shouldAck = false;
|
||||
|
||||
this.connect('summary-item-clicked', Lang.bind(this, this._summaryItemClicked));
|
||||
this._notification.connect('expanded', Lang.bind(this, this._notificationExpanded));
|
||||
this._notification.connect('collapsed', Lang.bind(this, this._notificationCollapsed));
|
||||
|
||||
this._presence = contact.get_presence_type();
|
||||
|
||||
this._sentId = this._channel.connect('message-sent', Lang.bind(this, this._messageSent));
|
||||
this._receivedId = this._channel.connect('message-received', Lang.bind(this, this._messageReceived));
|
||||
this._pendingId = this._channel.connect('pending-message-removed', Lang.bind(this, this._pendingRemoved));
|
||||
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
|
||||
@ -195,7 +358,7 @@ Source.prototype = {
|
||||
|
||||
_updateAlias: function() {
|
||||
let oldAlias = this.title;
|
||||
this.title = this._contact.get_alias();
|
||||
this.setTitle(this._contact.get_alias());
|
||||
this._notification.appendAliasChange(oldAlias, this.title);
|
||||
this.pushNotification(this._notification);
|
||||
},
|
||||
@ -224,13 +387,17 @@ Source.prototype = {
|
||||
},
|
||||
|
||||
open: function(notification) {
|
||||
let props = {};
|
||||
props[Tp.PROP_CHANNEL_CHANNEL_TYPE] = Tp.IFACE_CHANNEL_TYPE_TEXT;
|
||||
[props[Tp.PROP_CHANNEL_TARGET_HANDLE], props[Tp.PROP_CHANNEL_TARGET_HANDLE_TYPE]] = this._channel.get_handle();
|
||||
if (this._client.is_handling_channel(this._channel)) {
|
||||
// We are handling the channel, try to pass it to Empathy
|
||||
this._client.delegate_channels_async([this._channel], global.get_current_time(), "", null);
|
||||
}
|
||||
else {
|
||||
// We are not the handler, just ask to present the channel
|
||||
let dbus = Tp.DBusDaemon.dup();
|
||||
let cd = Tp.ChannelDispatcher.new(dbus);
|
||||
|
||||
let req = Tp.AccountChannelRequest.new(this._account, props, global.get_current_time());
|
||||
|
||||
req.ensure_channel_async('', null, null);
|
||||
cd.present_channel_async(this._channel, global.get_current_time(), null);
|
||||
}
|
||||
},
|
||||
|
||||
_getLogMessages: function() {
|
||||
@ -248,7 +415,20 @@ Source.prototype = {
|
||||
let logMessages = events.map(makeMessageFromTplEvent);
|
||||
|
||||
let pendingTpMessages = this._channel.get_pending_messages();
|
||||
let pendingMessages = pendingTpMessages.map(function (tpMessage) { return makeMessageFromTpMessage(tpMessage, NotificationDirection.RECEIVED); });
|
||||
let pendingMessages = [];
|
||||
|
||||
for (let i = 0; i < pendingTpMessages.length; i++) {
|
||||
let message = pendingTpMessages[i];
|
||||
|
||||
if (message.get_message_type() == Tp.ChannelTextMessageType.DELIVERY_REPORT)
|
||||
continue;
|
||||
|
||||
pendingMessages.push(makeMessageFromTpMessage(message, NotificationDirection.RECEIVED));
|
||||
|
||||
this._pendingMessages.push(message);
|
||||
}
|
||||
|
||||
this._updateCount();
|
||||
|
||||
let showTimestamp = false;
|
||||
|
||||
@ -284,6 +464,7 @@ Source.prototype = {
|
||||
_channelClosed: function() {
|
||||
this._channel.disconnect(this._closedId);
|
||||
this._channel.disconnect(this._receivedId);
|
||||
this._channel.disconnect(this._pendingId);
|
||||
this._channel.disconnect(this._sentId);
|
||||
|
||||
this._contact.disconnect(this._notifyAliasId);
|
||||
@ -293,7 +474,17 @@ Source.prototype = {
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
_updateCount: function() {
|
||||
this._setCount(this._pendingMessages.length, this._pendingMessages.length > 0);
|
||||
},
|
||||
|
||||
_messageReceived: function(channel, message) {
|
||||
if (message.get_message_type() == Tp.ChannelTextMessageType.DELIVERY_REPORT)
|
||||
return;
|
||||
|
||||
this._pendingMessages.push(message);
|
||||
this._updateCount();
|
||||
|
||||
message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
|
||||
this._notification.appendMessage(message);
|
||||
this.notify();
|
||||
@ -320,10 +511,25 @@ Source.prototype = {
|
||||
}
|
||||
|
||||
let msg = Tp.ClientMessage.new_text(type, text);
|
||||
this._channel.send_message_async(msg, 0, null);
|
||||
this._channel.send_message_async(msg, 0, Lang.bind(this, function (src, result) {
|
||||
this._channel.send_message_finish(result);
|
||||
}));
|
||||
},
|
||||
|
||||
_presenceChanged: function (contact, presence, type, status, message) {
|
||||
setChatState: function(state) {
|
||||
// We don't want to send COMPOSING every time a letter is typed into
|
||||
// the entry. We send the state only when it changes. Telepathy/Empathy
|
||||
// might change it behind our back if the user is using both
|
||||
// gnome-shell's entry and the Empathy conversation window. We could
|
||||
// keep track of it with the ChatStateChanged signal but it is good
|
||||
// enough right now.
|
||||
if (state != this._chatState) {
|
||||
this._chatState = state;
|
||||
this._channel.set_chat_state_async(state, null);
|
||||
}
|
||||
},
|
||||
|
||||
_presenceChanged: function (contact, presence, status, message) {
|
||||
let msg, shouldNotify, title;
|
||||
|
||||
if (this._presence == presence)
|
||||
@ -356,14 +562,53 @@ Source.prototype = {
|
||||
this._notification.appendPresence(msg, shouldNotify);
|
||||
if (shouldNotify)
|
||||
this.notify();
|
||||
},
|
||||
|
||||
_pendingRemoved: function(channel, message) {
|
||||
let idx = this._pendingMessages.indexOf(message);
|
||||
|
||||
if (idx >= 0) {
|
||||
this._pendingMessages.splice(idx, 1);
|
||||
this._updateCount();
|
||||
}
|
||||
else
|
||||
throw new Error('Message not in our pending list: ' + message);
|
||||
},
|
||||
|
||||
_ackMessages: function() {
|
||||
if (this._pendingMessages.length == 0)
|
||||
return;
|
||||
|
||||
// Don't clear our messages here, tp-glib will send a
|
||||
// 'pending-message-removed' for each one.
|
||||
this._channel.ack_messages_async(this._pendingMessages, Lang.bind(this, function(src, result) {
|
||||
this._channel.ack_messages_finish(result);}));
|
||||
},
|
||||
|
||||
_summaryItemClicked: function(source, button) {
|
||||
if (button != 1)
|
||||
return;
|
||||
|
||||
this._shouldAck = true;
|
||||
},
|
||||
|
||||
_notificationExpanded: function() {
|
||||
this._shouldAck = true;
|
||||
},
|
||||
|
||||
_notificationCollapsed: function() {
|
||||
if (this._shouldAck)
|
||||
this._ackMessages();
|
||||
|
||||
this._shouldAck = false;
|
||||
}
|
||||
};
|
||||
|
||||
function Notification(source) {
|
||||
function ChatNotification(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
Notification.prototype = {
|
||||
ChatNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init: function(source) {
|
||||
@ -373,6 +618,7 @@ Notification.prototype = {
|
||||
this._responseEntry = new St.Entry({ style_class: 'chat-response',
|
||||
can_focus: true });
|
||||
this._responseEntry.clutter_text.connect('activate', Lang.bind(this, this._onEntryActivated));
|
||||
this._responseEntry.clutter_text.connect('text-changed', Lang.bind(this, this._onEntryChanged));
|
||||
this.setActionArea(this._responseEntry);
|
||||
|
||||
this._oldMaxScrollAdjustment = 0;
|
||||
@ -389,6 +635,7 @@ Notification.prototype = {
|
||||
|
||||
this._history = [];
|
||||
this._timestampTimeoutId = 0;
|
||||
this._composingTimeoutId = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
@ -416,17 +663,43 @@ Notification.prototype = {
|
||||
styles.push('chat-action');
|
||||
}
|
||||
|
||||
this.update(this.source.title, messageBody, { customContent: true, bannerMarkup: true });
|
||||
if (message.direction == NotificationDirection.RECEIVED) {
|
||||
this.update(this.source.title, messageBody, { customContent: true,
|
||||
bannerMarkup: true });
|
||||
}
|
||||
|
||||
this._append(messageBody, styles, message.timestamp, noTimestamp);
|
||||
},
|
||||
|
||||
_filterMessages: function() {
|
||||
if (this._history.length < 1)
|
||||
return;
|
||||
|
||||
let lastMessageTime = this._history[0].time;
|
||||
let currentTime = (Date.now() / 1000);
|
||||
|
||||
// Keep the scrollback from growing too long. If the most
|
||||
// recent message (before the one we just added) is within
|
||||
// SCROLLBACK_RECENT_TIME, we will keep
|
||||
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
|
||||
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
|
||||
|
||||
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
|
||||
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
|
||||
|
||||
let filteredHistory = this._history.filter(function(item) { return item.realMessage });
|
||||
if (filteredHistory.length > maxLength) {
|
||||
let lastMessageToKeep = filteredHistory[maxLength];
|
||||
let expired = this._history.splice(this._history.indexOf(lastMessageToKeep));
|
||||
for (let i = 0; i < expired.length; i++)
|
||||
expired[i].actor.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
_append: function(text, styles, timestamp, noTimestamp) {
|
||||
let currentTime = (Date.now() / 1000);
|
||||
if (!timestamp)
|
||||
timestamp = currentTime;
|
||||
let lastMessageTime = -1;
|
||||
if (this._history.length > 0)
|
||||
lastMessageTime = this._history[0].time;
|
||||
|
||||
// Reset the old message timeout
|
||||
if (this._timestampTimeoutId)
|
||||
@ -449,23 +722,7 @@ Notification.prototype = {
|
||||
Lang.bind(this, this.appendTimestamp));
|
||||
}
|
||||
|
||||
if (this._history.length > 1) {
|
||||
// Keep the scrollback from growing too long. If the most
|
||||
// recent message (before the one we just added) is within
|
||||
// SCROLLBACK_RECENT_TIME, we will keep
|
||||
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
|
||||
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
|
||||
|
||||
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
|
||||
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
|
||||
let filteredHistory = this._history.filter(function(item) { return item.realMessage });
|
||||
if (filteredHistory.length > maxLength) {
|
||||
let lastMessageToKeep = filteredHistory[maxLength];
|
||||
let expired = this._history.splice(this._history.indexOf(lastMessageToKeep));
|
||||
for (let i = 0; i < expired.length; i++)
|
||||
expired[i].actor.destroy();
|
||||
}
|
||||
}
|
||||
this._filterMessages();
|
||||
},
|
||||
|
||||
_formatTimestamp: function(date) {
|
||||
@ -473,6 +730,8 @@ Notification.prototype = {
|
||||
|
||||
var daysAgo = (now.getTime() - date.getTime()) / (24 * 60 * 60 * 1000);
|
||||
|
||||
let format;
|
||||
|
||||
// Show a week day and time if date is in the last week
|
||||
if (daysAgo < 1 || (daysAgo < 7 && now.getDay() != date.getDay())) {
|
||||
/* Translators: this is a time format string followed by a date.
|
||||
@ -505,6 +764,9 @@ Notification.prototype = {
|
||||
this._history.unshift({ actor: timeLabel, time: lastMessageTime, realMessage: false });
|
||||
|
||||
this._timestampTimeoutId = 0;
|
||||
|
||||
this._filterMessages();
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
@ -516,21 +778,23 @@ Notification.prototype = {
|
||||
let label = this.addBody(text, true);
|
||||
label.add_style_class_name('chat-meta-message');
|
||||
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false});
|
||||
|
||||
this._filterMessages();
|
||||
},
|
||||
|
||||
appendAliasChange: function(oldAlias, newAlias) {
|
||||
// FIXME: uncomment this after 3.0 string freeze ends
|
||||
oldAlias = GLib.markup_escape_text(oldAlias, -1);
|
||||
newAlias = GLib.markup_escape_text(newAlias, -1);
|
||||
|
||||
// oldAlias = GLib.markup_escape_text(oldAlias, -1);
|
||||
// newAlias = GLib.markup_escape_text(newAlias, -1);
|
||||
/* Translators: this is the other person changing their old IM name to their new
|
||||
IM name. */
|
||||
let message = '<i>' + _("%s is now known as %s").format(oldAlias, newAlias) + '</i>';
|
||||
let label = this.addBody(message, true);
|
||||
label.add_style_class_name('chat-meta-message');
|
||||
this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false });
|
||||
this.update(newAlias, null, { customContent: true });
|
||||
|
||||
// /* Translators: this is the other person changing their old IM name to their new
|
||||
// IM name. */
|
||||
// let message = '<i>' + _("%s is now known as %s").format(oldAlias, newAlias) + '</i>';
|
||||
// let label = this.addBody(message, true);
|
||||
// label.add_style_class_name('chat-meta-message');
|
||||
// this._history.unshift({ actor: label, time: (Date.now() / 1000), realMessage: false });
|
||||
// this.update(newAlias, null, { customContent: true });
|
||||
this._filterMessages();
|
||||
},
|
||||
|
||||
_onEntryActivated: function() {
|
||||
@ -544,5 +808,166 @@ Notification.prototype = {
|
||||
// see Source._messageSent
|
||||
this._responseEntry.set_text('');
|
||||
this.source.respond(text);
|
||||
},
|
||||
|
||||
_composingStopTimeout: function() {
|
||||
this._composingTimeoutId = 0;
|
||||
|
||||
this.source.setChatState(Tp.ChannelChatState.PAUSED);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_onEntryChanged: function() {
|
||||
let text = this._responseEntry.get_text();
|
||||
|
||||
// If we're typing, we want to send COMPOSING.
|
||||
// If we empty the entry, we want to send ACTIVE.
|
||||
// If we've stopped typing for COMPOSING_STOP_TIMEOUT
|
||||
// seconds, we want to send PAUSED.
|
||||
|
||||
// Remove composing timeout.
|
||||
if (this._composingTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._composingTimeoutId);
|
||||
this._composingTimeoutId = 0;
|
||||
}
|
||||
|
||||
if (text != '') {
|
||||
this.source.setChatState(Tp.ChannelChatState.COMPOSING);
|
||||
|
||||
this._composingTimeoutId = Mainloop.timeout_add_seconds(
|
||||
COMPOSING_STOP_TIMEOUT,
|
||||
Lang.bind(this, this._composingStopTimeout));
|
||||
} else {
|
||||
this.source.setChatState(Tp.ChannelChatState.ACTIVE);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function ApproverSource(dispatchOp, text, icon) {
|
||||
this._init(dispatchOp, text, icon);
|
||||
}
|
||||
|
||||
ApproverSource.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(dispatchOp, text, icon) {
|
||||
MessageTray.Source.prototype._init.call(this, text);
|
||||
|
||||
this._icon = icon;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
|
||||
this._dispatchOp = dispatchOp;
|
||||
|
||||
// Destroy the source if the channel dispatch operation is invalidated
|
||||
// as we can't approve any more.
|
||||
this._invalidId = dispatchOp.connect('invalidated',
|
||||
Lang.bind(this, function(domain, code, msg) {
|
||||
this.destroy();
|
||||
}));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._invalidId != 0) {
|
||||
this._dispatchOp.disconnect(this._invalidId);
|
||||
this._invalidId = 0;
|
||||
}
|
||||
|
||||
MessageTray.Source.prototype.destroy.call(this);
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
return new St.Icon({ icon_name: this._icon,
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: this.ICON_SIZE });
|
||||
}
|
||||
}
|
||||
|
||||
function RoomInviteNotification(source, dispatchOp, channel, inviter) {
|
||||
this._init(source, dispatchOp, channel, inviter);
|
||||
}
|
||||
|
||||
RoomInviteNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init: function(source, dispatchOp, channel, inviter) {
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
/* translators: argument is a room name like
|
||||
* room@jabber.org for example. */
|
||||
_("Invitation to %s").format(channel.get_identifier()),
|
||||
null,
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
/* translators: first argument is the name of a contact and the second
|
||||
* one the name of a room. "Alice is inviting you to join room@jabber.org
|
||||
* for example. */
|
||||
this.addBody(_("%s is inviting you to join %s").format(inviter.get_alias(), channel.get_identifier()));
|
||||
|
||||
this.addButton('decline', _("Decline"));
|
||||
this.addButton('accept', _("Accept"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'decline':
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
|
||||
'', function(src, result) {
|
||||
src.leave_channels_finish(result)});
|
||||
break;
|
||||
case 'accept':
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(),
|
||||
function(src, result) {
|
||||
src.handle_with_time_finish(result)});
|
||||
break;
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
// Audio Video
|
||||
function AudioVideoNotification(source, dispatchOp, channel, contact, isVideo) {
|
||||
this._init(source, dispatchOp, channel, contact, isVideo);
|
||||
}
|
||||
|
||||
AudioVideoNotification.prototype = {
|
||||
__proto__: MessageTray.Notification.prototype,
|
||||
|
||||
_init: function(source, dispatchOp, channel, contact, isVideo) {
|
||||
let title = '';
|
||||
|
||||
if (isVideo)
|
||||
/* translators: argument is a contact name like Alice for example. */
|
||||
title = _("Video call from %s").format(contact.get_alias());
|
||||
else
|
||||
/* translators: argument is a contact name like Alice for example. */
|
||||
title = _("Call from %s").format(contact.get_alias());
|
||||
|
||||
MessageTray.Notification.prototype._init.call(this,
|
||||
source,
|
||||
title,
|
||||
null,
|
||||
{ customContent: true });
|
||||
this.setResident(true);
|
||||
|
||||
this.addButton('reject', _("Reject"));
|
||||
this.addButton('answer', _("Answer"));
|
||||
|
||||
this.connect('action-invoked', Lang.bind(this, function(self, action) {
|
||||
switch (action) {
|
||||
case 'reject':
|
||||
dispatchOp.leave_channels_async(Tp.ChannelGroupChangeReason.NONE,
|
||||
'', function(src, result) {
|
||||
src.leave_channels_finish(result)});
|
||||
break;
|
||||
case 'answer':
|
||||
dispatchOp.handle_with_time_async('', global.get_current_time(),
|
||||
function(src, result) {
|
||||
src.handle_with_time_finish(result)});
|
||||
break;
|
||||
}
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
@ -8,8 +8,6 @@ const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Search = imports.ui.search;
|
||||
@ -143,19 +141,21 @@ SearchTab.prototype = {
|
||||
'edit-find');
|
||||
|
||||
this._text.connect('text-changed', Lang.bind(this, this._onTextChanged));
|
||||
this._text.connect('activate', Lang.bind(this, function (se) {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._doSearch();
|
||||
this._text.connect('key-press-event', Lang.bind(this, function (o, e) {
|
||||
// We can't connect to 'activate' here because search providers
|
||||
// might want to do something with the modifiers in activateSelected.
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._doSearch();
|
||||
}
|
||||
this._searchResults.activateSelected();
|
||||
return true;
|
||||
}
|
||||
this._searchResults.activateSelected();
|
||||
return true;
|
||||
return false;
|
||||
}));
|
||||
|
||||
this._entry.connect('secondary-icon-clicked', Lang.bind(this,
|
||||
function() {
|
||||
this._reset();
|
||||
}));
|
||||
this._entry.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||
|
||||
global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
|
||||
@ -166,7 +166,14 @@ SearchTab.prototype = {
|
||||
hide: function() {
|
||||
BaseTab.prototype.hide.call(this);
|
||||
|
||||
this._reset();
|
||||
// Leave the entry focused when it doesn't have any text;
|
||||
// when replacing a selected search term, Clutter emits
|
||||
// two 'text-changed' signals, one for deleting the previous
|
||||
// text and one for the new one - the second one is handled
|
||||
// incorrectly when we remove focus
|
||||
// (https://bugzilla.gnome.org/show_bug.cgi?id=636341) */
|
||||
if (this._text.text != '')
|
||||
this._reset();
|
||||
},
|
||||
|
||||
_reset: function () {
|
||||
@ -226,7 +233,7 @@ SearchTab.prototype = {
|
||||
if (this._iconClickedId == 0) {
|
||||
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
|
||||
Lang.bind(this, function() {
|
||||
this.reset();
|
||||
this._reset();
|
||||
}));
|
||||
}
|
||||
this._activate();
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
@ -6,6 +6,7 @@ const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const AltTab = imports.ui.altTab;
|
||||
const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup;
|
||||
@ -22,8 +23,7 @@ function getDimShader() {
|
||||
if (dimShader === null)
|
||||
return null;
|
||||
if (!dimShader) {
|
||||
let [success, source, length] = GLib.file_get_contents(global.datadir +
|
||||
'/shaders/dim-window.glsl');
|
||||
let source = Shell.get_file_contents_utf8_sync(global.datadir + '/shaders/dim-window.glsl');
|
||||
try {
|
||||
let shader = new Clutter.Shader();
|
||||
shader.set_fragment_source(source, -1);
|
||||
@ -119,6 +119,8 @@ WindowManager.prototype = {
|
||||
this.setKeybindingHandler('switch_to_workspace_down', Lang.bind(this, this._showWorkspaceSwitcher));
|
||||
this.setKeybindingHandler('switch_windows', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_group', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_windows_backward', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_group_backward', Lang.bind(this, this._startAppSwitcher));
|
||||
this.setKeybindingHandler('switch_panels', Lang.bind(this, this._startA11ySwitcher));
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
@ -180,7 +182,7 @@ WindowManager.prototype = {
|
||||
*/
|
||||
this._minimizing.push(actor);
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
let xDest = primary.x;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
xDest += primary.width;
|
||||
@ -534,7 +536,7 @@ WindowManager.prototype = {
|
||||
|
||||
let tabPopup = new AltTab.AltTabPopup();
|
||||
|
||||
if (!tabPopup.show(backwards, binding == 'switch_group'))
|
||||
if (!tabPopup.show(backwards, binding))
|
||||
tabPopup.destroy();
|
||||
},
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GConf = imports.gi.GConf;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
@ -27,6 +28,8 @@ const CLOSE_BUTTON_FADE_TIME = 0.1;
|
||||
|
||||
const DRAGGING_WINDOW_OPACITY = 100;
|
||||
|
||||
const BUTTON_LAYOUT_KEY = '/desktop/gnome/shell/windows/button_layout';
|
||||
|
||||
// Define a layout scheme for small window counts. For larger
|
||||
// counts we fall back to an algorithm. We need more schemes here
|
||||
// unless we have a really good algorithm.
|
||||
@ -222,8 +225,12 @@ WindowClone.prototype = {
|
||||
let [width, height] = this.actor.get_transformed_size();
|
||||
|
||||
let monitorIndex = this.metaWindow.get_monitor();
|
||||
let availArea = global.get_monitors()[monitorIndex];
|
||||
if (monitorIndex == global.get_primary_monitor_index()) {
|
||||
let monitor = Main.layoutManager.monitors[monitorIndex];
|
||||
let availArea = new Meta.Rectangle({ x: monitor.x,
|
||||
y: monitor.y,
|
||||
width: monitor.width,
|
||||
height: monitor.height });
|
||||
if (monitorIndex == Main.layoutManager.primaryIndex) {
|
||||
availArea.y += Main.panel.actor.height;
|
||||
availArea.height -= Main.panel.actor.height;
|
||||
}
|
||||
@ -237,7 +244,7 @@ WindowClone.prototype = {
|
||||
this.emit('zoom-start');
|
||||
|
||||
if (!this._zoomLightbox)
|
||||
this._zoomLightbox = new Lightbox.Lightbox(global.stage,
|
||||
this._zoomLightbox = new Lightbox.Lightbox(Main.uiGroup,
|
||||
{ fadeTime: LIGHTBOX_FADE_TIME });
|
||||
this._zoomLightbox.show();
|
||||
|
||||
@ -248,7 +255,7 @@ WindowClone.prototype = {
|
||||
this._zoomGlobalOrig.setPosition.apply(this._zoomGlobalOrig, this.actor.get_transformed_position());
|
||||
this._zoomGlobalOrig.setScale(width / this.actor.width, height / this.actor.height);
|
||||
|
||||
this.actor.reparent(global.stage);
|
||||
this.actor.reparent(Main.uiGroup);
|
||||
this._zoomLightbox.highlight(this.actor);
|
||||
|
||||
[this.actor.x, this.actor.y] = this._zoomGlobalOrig.getPosition();
|
||||
@ -296,12 +303,30 @@ WindowClone.prototype = {
|
||||
},
|
||||
|
||||
_onDragBegin : function (draggable, time) {
|
||||
if (this._zooming)
|
||||
this._zoomEnd();
|
||||
|
||||
[this.dragOrigX, this.dragOrigY] = this.actor.get_position();
|
||||
this.dragOrigScale = this.actor.scale_x;
|
||||
this.inDrag = true;
|
||||
this.emit('drag-begin');
|
||||
},
|
||||
|
||||
_getWorkspaceActor : function() {
|
||||
let index = this.metaWindow.get_workspace().index();
|
||||
return Main.overview.workspaces.getWorkspaceByIndex(index);
|
||||
},
|
||||
|
||||
handleDragOver : function(source, actor, x, y, time) {
|
||||
let workspace = this._getWorkspaceActor();
|
||||
return workspace.handleDragOver(source, actor, x, y, time);
|
||||
},
|
||||
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
let workspace = this._getWorkspaceActor();
|
||||
workspace.acceptDrop(source, actor, x, y, time);
|
||||
},
|
||||
|
||||
_onDragCancelled : function (draggable, time) {
|
||||
this.emit('drag-cancelled');
|
||||
},
|
||||
@ -394,6 +419,8 @@ WindowOverlay.prototype = {
|
||||
|
||||
show: function() {
|
||||
this._hidden = false;
|
||||
if (this._windowClone.actor.has_pointer)
|
||||
this.closeButton.show();
|
||||
this.title.show();
|
||||
},
|
||||
|
||||
@ -430,9 +457,20 @@ WindowOverlay.prototype = {
|
||||
let button = this.closeButton;
|
||||
let title = this.title;
|
||||
|
||||
let gconf = GConf.Client.get_default();
|
||||
let layout = gconf.get_string(BUTTON_LAYOUT_KEY);
|
||||
let rtl = St.Widget.get_default_direction() == St.TextDirection.RTL;
|
||||
|
||||
let split = layout.split(":");
|
||||
let side;
|
||||
if (split[0].indexOf("close") > -1)
|
||||
side = rtl ? St.Side.RIGHT : St.Side.LEFT;
|
||||
else
|
||||
side = rtl ? St.Side.LEFT : St.Side.RIGHT;
|
||||
|
||||
let buttonX;
|
||||
let buttonY = cloneY - (button.height - button._overlap);
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
if (side == St.Side.LEFT)
|
||||
buttonX = cloneX - (button.width - button._overlap);
|
||||
else
|
||||
buttonX = cloneX + (cloneWidth - button._overlap);
|
||||
@ -559,7 +597,7 @@ Workspace.prototype = {
|
||||
this._height = 0;
|
||||
|
||||
this.monitorIndex = monitorIndex;
|
||||
this._monitor = global.get_monitors()[this.monitorIndex];
|
||||
this._monitor = Main.layoutManager.monitors[this.monitorIndex];
|
||||
this._windowOverlaysGroup = new Clutter.Group();
|
||||
// Without this the drop area will be overlapped.
|
||||
this._windowOverlaysGroup.set_size(0, 0);
|
||||
@ -614,6 +652,7 @@ Workspace.prototype = {
|
||||
function () {
|
||||
this._dropRect.set_position(x, y);
|
||||
this._dropRect.set_size(width, height);
|
||||
this.positionWindows(WindowPositionFlags.ANIMATE);
|
||||
return false;
|
||||
}));
|
||||
|
||||
@ -636,16 +675,6 @@ Workspace.prototype = {
|
||||
return this._windows.length == 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* setReactive:
|
||||
* @reactive: %true iff the workspace should be reactive
|
||||
*
|
||||
* Set the workspace (desktop) reactive
|
||||
**/
|
||||
setReactive: function(reactive) {
|
||||
this.actor.reactive = reactive;
|
||||
},
|
||||
|
||||
// Only use this for n <= 20 say
|
||||
_factorial: function(n) {
|
||||
let result = 1;
|
||||
@ -1113,7 +1142,9 @@ Workspace.prototype = {
|
||||
// the compositor finds out about them...
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function () {
|
||||
if (this.actor && metaWin.get_compositor_private())
|
||||
if (this.actor &&
|
||||
metaWin.get_compositor_private() &&
|
||||
metaWin.get_workspace() == this.metaWorkspace)
|
||||
this._doAddWindow(metaWin);
|
||||
return false;
|
||||
}));
|
||||
|
@ -56,7 +56,7 @@ WorkspaceSwitcherPopup.prototype = {
|
||||
|
||||
_getPreferredHeight : function (actor, forWidth, alloc) {
|
||||
let children = this._list.get_children();
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let availHeight = primary.height;
|
||||
availHeight -= Main.panel.actor.height;
|
||||
@ -82,7 +82,7 @@ WorkspaceSwitcherPopup.prototype = {
|
||||
},
|
||||
|
||||
_getPreferredWidth : function (actor, forHeight, alloc) {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
this._childWidth = Math.round(this._childHeight * primary.width / primary.height);
|
||||
|
||||
alloc.min_size = this._childWidth;
|
||||
@ -125,7 +125,7 @@ WorkspaceSwitcherPopup.prototype = {
|
||||
},
|
||||
|
||||
_position: function() {
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
this._container.x = primary.x + Math.floor((primary.width - this._container.width) / 2);
|
||||
this._container.y = primary.y + Main.panel.actor.height +
|
||||
Math.floor(((primary.height - Main.panel.actor.height) - this._container.height) / 2);
|
||||
|
@ -146,7 +146,7 @@ function WorkspaceThumbnail(metaWorkspace) {
|
||||
WorkspaceThumbnail.prototype = {
|
||||
_init : function(metaWorkspace) {
|
||||
this.metaWorkspace = metaWorkspace;
|
||||
this.monitorIndex = global.get_primary_monitor_index();
|
||||
this.monitorIndex = Main.layoutManager.primaryIndex;
|
||||
|
||||
this.actor = new St.Group({ reactive: true,
|
||||
clip_to_allocation: true,
|
||||
@ -170,7 +170,7 @@ WorkspaceThumbnail.prototype = {
|
||||
this._background = new Clutter.Clone({ source: global.background_actor });
|
||||
this._contents.add_actor(this._background);
|
||||
|
||||
let monitor = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
|
||||
|
||||
let windows = global.get_window_actors().filter(this._isMyWindow, this);
|
||||
@ -178,6 +178,11 @@ WorkspaceThumbnail.prototype = {
|
||||
// Create clones for windows that should be visible in the Overview
|
||||
this._windows = [];
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
windows[i].meta_window._minimizedChangedId =
|
||||
windows[i].meta_window.connect('notify::minimized',
|
||||
Lang.bind(this,
|
||||
this._updateMinimized));
|
||||
|
||||
if (this._isOverviewWindow(windows[i])) {
|
||||
this._addWindowClone(windows[i]);
|
||||
}
|
||||
@ -257,11 +262,18 @@ WorkspaceThumbnail.prototype = {
|
||||
return;
|
||||
|
||||
// Check if window still should be here
|
||||
if (win && this._isMyWindow(win))
|
||||
if (win && this._isMyWindow(win) && this._isOverviewWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._windows[index];
|
||||
this._windows.splice(index, 1);
|
||||
|
||||
if (win && this._isOverviewWindow(win)) {
|
||||
if (metaWin._minimizedChangedId) {
|
||||
metaWin.disconnect(metaWin._minimizedChangedId);
|
||||
delete metaWin._minimizedChangedId;
|
||||
}
|
||||
}
|
||||
clone.destroy();
|
||||
},
|
||||
|
||||
@ -276,7 +288,9 @@ WorkspaceThumbnail.prototype = {
|
||||
// the compositor finds out about them...
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function () {
|
||||
if (this.actor && metaWin.get_compositor_private())
|
||||
if (this.actor &&
|
||||
metaWin.get_compositor_private() &&
|
||||
metaWin.get_workspace() == this.metaWorkspace)
|
||||
this._doAddWindow(metaWin);
|
||||
return false;
|
||||
}));
|
||||
@ -288,6 +302,11 @@ WorkspaceThumbnail.prototype = {
|
||||
if (this._lookupIndex (metaWin) != -1)
|
||||
return;
|
||||
|
||||
if (!metaWin._minimizedChangedId)
|
||||
metaWin._minimizedChangedId = metaWin.connect('notify::minimized',
|
||||
Lang.bind(this,
|
||||
this._updateMinimized));
|
||||
|
||||
if (!this._isMyWindow(win) || !this._isOverviewWindow(win))
|
||||
return;
|
||||
|
||||
@ -314,6 +333,13 @@ WorkspaceThumbnail.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_updateMinimized: function(metaWin) {
|
||||
if (metaWin.minimized)
|
||||
this._doRemoveWindow(metaWin);
|
||||
else
|
||||
this._doAddWindow(metaWin);
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
@ -324,6 +350,14 @@ WorkspaceThumbnail.prototype = {
|
||||
global.screen.disconnect(this._windowEnteredMonitorId);
|
||||
global.screen.disconnect(this._windowLeftMonitorId);
|
||||
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let metaWin = this._windows[i].metaWindow;
|
||||
if (metaWin._minimizedChangedId) {
|
||||
metaWin.disconnect(metaWin._minimizedChangedId);
|
||||
delete metaWin._minimizedChangedId;
|
||||
}
|
||||
}
|
||||
|
||||
this._windows = [];
|
||||
this.actor = null;
|
||||
},
|
||||
@ -337,7 +371,8 @@ WorkspaceThumbnail.prototype = {
|
||||
// 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 tracker.is_window_interesting(win.get_meta_window()) &&
|
||||
win.get_meta_window().showing_on_its_workspace();
|
||||
},
|
||||
|
||||
// Create a clone of a (non-desktop) window and add it to the window list
|
||||
@ -493,7 +528,7 @@ ThumbnailsBox.prototype = {
|
||||
|
||||
// The "porthole" is the portion of the screen that we show in the workspaces
|
||||
let panelHeight = Main.panel.actor.height;
|
||||
let monitor = global.get_primary_monitor();
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
this._porthole = {
|
||||
x: monitor.x,
|
||||
y: monitor.y + panelHeight,
|
||||
|
@ -7,8 +7,6 @@ const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
@ -51,9 +49,12 @@ WorkspacesView.prototype = {
|
||||
this._height = 0;
|
||||
this._x = 0;
|
||||
this._y = 0;
|
||||
this._clipX = 0;
|
||||
this._clipY = 0;
|
||||
this._clipWidth = 0;
|
||||
this._clipHeight = 0;
|
||||
this._workspaceRatioSpacing = 0;
|
||||
this._spacing = 0;
|
||||
this._lostWorkspaces = [];
|
||||
this._animating = false; // tweening
|
||||
this._scrolling = false; // swipe-scrolling
|
||||
this._animatingScroll = false; // programatically updating the adjustment
|
||||
@ -69,10 +70,10 @@ WorkspacesView.prototype = {
|
||||
this._workspaces[activeWorkspaceIndex].actor.raise_top();
|
||||
|
||||
this._extraWorkspaces = [];
|
||||
let monitors = global.get_monitors();
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let m = 0;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
if (i == global.get_primary_monitor_index())
|
||||
if (i == Main.layoutManager.primaryIndex)
|
||||
continue;
|
||||
let ws = new Workspace.Workspace(null, i);
|
||||
this._extraWorkspaces[m++] = ws;
|
||||
@ -95,7 +96,8 @@ WorkspacesView.prototype = {
|
||||
this._overviewShownId =
|
||||
Main.overview.connect('shown',
|
||||
Lang.bind(this, function() {
|
||||
this.actor.set_clip(this._x, this._y, this._width, this._height);
|
||||
this.actor.set_clip(this._clipX, this._clipY,
|
||||
this._clipWidth, this._clipHeight);
|
||||
}));
|
||||
|
||||
this._scrollAdjustment = new St.Adjustment({ value: activeWorkspaceIndex,
|
||||
@ -139,6 +141,13 @@ WorkspacesView.prototype = {
|
||||
this._workspaces[i].setGeometry(x, y, width, height);
|
||||
},
|
||||
|
||||
setClipRect: function(x, y, width, height) {
|
||||
this._clipX = x;
|
||||
this._clipY = y;
|
||||
this._clipWidth = width;
|
||||
this._clipHeight = height;
|
||||
},
|
||||
|
||||
_lookupWorkspaceForMetaWindow: function (metaWindow) {
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
if (this._workspaces[i].containsMetaWindow(metaWindow))
|
||||
@ -152,6 +161,10 @@ WorkspacesView.prototype = {
|
||||
return this._workspaces[active];
|
||||
},
|
||||
|
||||
getWorkspaceByIndex: function(index) {
|
||||
return this._workspaces[index];
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||
@ -201,12 +214,10 @@ WorkspacesView.prototype = {
|
||||
|
||||
Tweener.removeTweens(workspace.actor);
|
||||
|
||||
let opacity = (this._inDrag && w != active) ? 200 : 255;
|
||||
let y = (w - active) * (this._height + this._spacing + this._workspaceRatioSpacing);
|
||||
|
||||
if (showAnimation) {
|
||||
let params = { y: y,
|
||||
opacity: opacity,
|
||||
time: WORKSPACE_SWITCH_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
};
|
||||
@ -224,32 +235,10 @@ WorkspacesView.prototype = {
|
||||
Tweener.addTween(workspace.actor, params);
|
||||
} else {
|
||||
workspace.actor.set_position(0, y);
|
||||
workspace.actor.opacity = opacity;
|
||||
if (w == 0)
|
||||
this._updateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
for (let l = 0; l < this._lostWorkspaces.length; l++) {
|
||||
let workspace = this._lostWorkspaces[l];
|
||||
|
||||
Tweener.removeTweens(workspace.actor);
|
||||
|
||||
workspace.actor.show();
|
||||
workspace.hideWindowsOverlays();
|
||||
|
||||
if (showAnimation) {
|
||||
Tweener.addTween(workspace.actor,
|
||||
{ y: workspace.x,
|
||||
time: WORKSPACE_SWITCH_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
this._cleanWorkspaces)
|
||||
});
|
||||
} else {
|
||||
this._cleanWorkspaces();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updateVisibility: function() {
|
||||
@ -270,17 +259,6 @@ WorkspacesView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_cleanWorkspaces: function() {
|
||||
if (this._lostWorkspaces.length == 0)
|
||||
return;
|
||||
|
||||
for (let l = 0; l < this._lostWorkspaces.length; l++)
|
||||
this._lostWorkspaces[l].destroy();
|
||||
this._lostWorkspaces = [];
|
||||
|
||||
this._updateWorkspaceActors(false);
|
||||
},
|
||||
|
||||
_updateScrollAdjustment: function(index, showAnimation) {
|
||||
if (this._scrolling)
|
||||
return;
|
||||
@ -303,12 +281,9 @@ WorkspacesView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces, lostWorkspaces) {
|
||||
updateWorkspaces: function(oldNumWorkspaces, newNumWorkspaces) {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
|
||||
for (let l = 0; l < lostWorkspaces.length; l++)
|
||||
lostWorkspaces[l].disconnectAll();
|
||||
|
||||
Tweener.addTween(this._scrollAdjustment,
|
||||
{ upper: newNumWorkspaces,
|
||||
time: WORKSPACE_SWITCH_TIME,
|
||||
@ -316,12 +291,13 @@ WorkspacesView.prototype = {
|
||||
});
|
||||
|
||||
if (newNumWorkspaces > oldNumWorkspaces) {
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++)
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
|
||||
this._workspaces[w].setGeometry(this._x, this._y,
|
||||
this._width, this._height);
|
||||
this.actor.add_actor(this._workspaces[w].actor);
|
||||
}
|
||||
|
||||
this._updateWorkspaceActors(false);
|
||||
} else {
|
||||
this._lostWorkspaces = lostWorkspaces;
|
||||
}
|
||||
|
||||
this._scrollToActive(true);
|
||||
@ -407,7 +383,7 @@ WorkspacesView.prototype = {
|
||||
this._extraWorkspaces[i].setReservedSlot(dragEvent.dragActor._delegate);
|
||||
}
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let topWorkspace, bottomWorkspace;
|
||||
@ -439,20 +415,14 @@ WorkspacesView.prototype = {
|
||||
if (topWorkspace) {
|
||||
if (topWorkspace.actor.contains(dragEvent.targetActor)) {
|
||||
hoverWorkspace = topWorkspace;
|
||||
topWorkspace.opacity = topWorkspace.actor.opacity = 255;
|
||||
result = topWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
||||
} else {
|
||||
topWorkspace.opacity = topWorkspace.actor.opacity = 200;
|
||||
}
|
||||
}
|
||||
|
||||
if (bottomWorkspace) {
|
||||
if (bottomWorkspace.actor.contains(dragEvent.targetActor)) {
|
||||
hoverWorkspace = bottomWorkspace;
|
||||
bottomWorkspace.opacity = bottomWorkspace.actor.opacity = 255;
|
||||
result = bottomWorkspace.handleDragOver(dragEvent.source, dragEvent.dragActor);
|
||||
} else {
|
||||
bottomWorkspace.opacity = bottomWorkspace.actor.opacity = 200;
|
||||
}
|
||||
}
|
||||
|
||||
@ -479,7 +449,7 @@ WorkspacesView.prototype = {
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
}
|
||||
DND.removeMonitor(this._dragMonitor);
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
this._inDrag = false;
|
||||
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
@ -580,8 +550,7 @@ WorkspacesDisplay.prototype = {
|
||||
controls.connect('scroll-event',
|
||||
Lang.bind(this, this._onScrollEvent));
|
||||
|
||||
this._monitorIndex = global.get_primary_monitor_index();
|
||||
this._monitor = global.get_monitors()[this._monitorIndex];
|
||||
this._monitorIndex = Main.layoutManager.primaryIndex;
|
||||
|
||||
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
|
||||
controls.add_actor(this._thumbnailsBox.actor);
|
||||
@ -597,7 +566,10 @@ WorkspacesDisplay.prototype = {
|
||||
|
||||
this._updateAlwaysZoom();
|
||||
|
||||
global.screen.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
||||
Main.layoutManager.connect('monitors-changed', Lang.bind(this, this._updateAlwaysZoom));
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._workspacesChanged));
|
||||
|
||||
Main.xdndHandler.connect('drag-begin', Lang.bind(this, function(){
|
||||
this._alwaysZoomOut = true;
|
||||
}));
|
||||
@ -607,7 +579,6 @@ WorkspacesDisplay.prototype = {
|
||||
this._updateAlwaysZoom();
|
||||
}));
|
||||
|
||||
this._nWorkspacesNotifyId = 0;
|
||||
this._switchWorkspaceNotifyId = 0;
|
||||
|
||||
this._itemDragBeginId = 0;
|
||||
@ -637,10 +608,6 @@ WorkspacesDisplay.prototype = {
|
||||
this.workspacesView = new WorkspacesView(this._workspaces);
|
||||
this._updateWorkspacesGeometry();
|
||||
|
||||
this._nWorkspacesNotifyId =
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._workspacesChanged));
|
||||
|
||||
this._restackedNotifyId =
|
||||
global.screen.connect('restacked',
|
||||
Lang.bind(this, this._onRestacked));
|
||||
@ -671,10 +638,6 @@ WorkspacesDisplay.prototype = {
|
||||
this._controls.hide();
|
||||
this._thumbnailsBox.hide();
|
||||
|
||||
if (this._nWorkspacesNotifyId > 0) {
|
||||
global.screen.disconnect(this._nWorkspacesNotifyId);
|
||||
this._nWorkspacesNotifyId = 0;
|
||||
}
|
||||
if (this._restackedNotifyId > 0){
|
||||
global.screen.disconnect(this._restackedNotifyId);
|
||||
this._restackedNotifyId = 0;
|
||||
@ -723,10 +686,15 @@ WorkspacesDisplay.prototype = {
|
||||
},
|
||||
|
||||
_updateAlwaysZoom: function() {
|
||||
this._alwaysZoomOut = false;
|
||||
// Always show the pager if workspaces are actually used,
|
||||
// e.g. there are windows on more than one
|
||||
this._alwaysZoomOut = global.screen.n_workspaces > 2;
|
||||
|
||||
let monitors = global.get_monitors();
|
||||
let primary = global.get_primary_monitor();
|
||||
if (this._alwaysZoomOut)
|
||||
return;
|
||||
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
|
||||
/* Look for any monitor to the right of the primary, if there is
|
||||
* one, we always keep zoom out, otherwise its hard to reach
|
||||
@ -794,6 +762,13 @@ WorkspacesDisplay.prototype = {
|
||||
|
||||
let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
|
||||
|
||||
let clipWidth = width - controlsVisible;
|
||||
let clipHeight = (fullHeight / fullWidth) * clipWidth;
|
||||
let clipX = rtl ? x + controlsVisible : x;
|
||||
let clipY = y + (fullHeight - clipHeight) / 2;
|
||||
|
||||
this.workspacesView.setClipRect(clipX, clipY, clipWidth, clipHeight);
|
||||
|
||||
if (this._zoomOut) {
|
||||
width -= controlsNatural;
|
||||
if (rtl)
|
||||
@ -832,6 +807,12 @@ WorkspacesDisplay.prototype = {
|
||||
if (oldNumWorkspaces == newNumWorkspaces)
|
||||
return;
|
||||
|
||||
this._updateAlwaysZoom();
|
||||
this._updateZoom();
|
||||
|
||||
if (this.workspacesView == null)
|
||||
return;
|
||||
|
||||
let lostWorkspaces = [];
|
||||
if (newNumWorkspaces > oldNumWorkspaces) {
|
||||
// Assume workspaces are only added at the end
|
||||
@ -857,24 +838,23 @@ WorkspacesDisplay.prototype = {
|
||||
lostWorkspaces = this._workspaces.splice(removedIndex,
|
||||
removedNum);
|
||||
|
||||
// Don't let the user try to select this workspace as it's
|
||||
// making its exit.
|
||||
for (let l = 0; l < lostWorkspaces.length; l++)
|
||||
lostWorkspaces[l].setReactive(false);
|
||||
for (let l = 0; l < lostWorkspaces.length; l++) {
|
||||
lostWorkspaces[l].disconnectAll();
|
||||
lostWorkspaces[l].destroy();
|
||||
}
|
||||
|
||||
this._thumbnailsBox.removeThumbmails(removedIndex, removedNum);
|
||||
}
|
||||
|
||||
this.workspacesView.updateWorkspaces(oldNumWorkspaces,
|
||||
newNumWorkspaces,
|
||||
lostWorkspaces);
|
||||
newNumWorkspaces);
|
||||
},
|
||||
|
||||
_updateZoom : function() {
|
||||
if (Main.overview.animationInProgress)
|
||||
return;
|
||||
|
||||
let shouldZoom = this._alwaysZoomOut || this._controls.hover || (this._inDrag && !this._cancelledDrag);
|
||||
let shouldZoom = this._alwaysZoomOut || this._controls.hover;
|
||||
if (shouldZoom != this._zoomOut) {
|
||||
this._zoomOut = shouldZoom;
|
||||
this._updateWorkspacesGeometry();
|
||||
@ -898,12 +878,22 @@ WorkspacesDisplay.prototype = {
|
||||
_dragBegin: function() {
|
||||
this._inDrag = true;
|
||||
this._cancelledDrag = false;
|
||||
this._updateZoom();
|
||||
this._dragMonitor = {
|
||||
dragMotion: Lang.bind(this, this._onDragMotion)
|
||||
};
|
||||
DND.addDragMonitor(this._dragMonitor);
|
||||
},
|
||||
|
||||
_dragCancelled: function() {
|
||||
this._cancelledDrag = true;
|
||||
this._updateZoom();
|
||||
DND.removeDragMonitor(this._dragMonitor);
|
||||
},
|
||||
|
||||
_onDragMotion: function(dragEvent) {
|
||||
let controlsHovered = this._controls.contains(dragEvent.targetActor);
|
||||
this._controls.set_hover(controlsHovered);
|
||||
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
},
|
||||
|
||||
_dragEnd: function() {
|
||||
|
@ -36,53 +36,48 @@ visually attractive and easy to use experience.
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
.B \-r, \-\-replace
|
||||
Replace the running metacity/gnome-panel
|
||||
.B \-\-replace
|
||||
Replace the running window manager
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-v, \-\-verbose
|
||||
Shows details about the results of running `gnome-shell'.
|
||||
.B \-\-sm-disable
|
||||
Disable connection to the session manager
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-g, \-\-debug
|
||||
Run under a debugger
|
||||
.B \-\-sm-client-id=ID
|
||||
Specify session management ID
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-\-debug\-command
|
||||
Command to use for debugging (defaults to 'gdb \-\-args')
|
||||
.B \-\-sm-save-file=FILE
|
||||
Initialize session from savefile
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-\-screen=SCREEN
|
||||
X screen to use
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-d, \-\-display=DISPLAY
|
||||
X display to use
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-\-sync
|
||||
.br
|
||||
Make X calls synchronously, useful when debugging down X errors
|
||||
Make X calls synchronous
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-\-xephyr
|
||||
Run a debugging instance inside Xephyr
|
||||
.B \-\-version
|
||||
Print version and exit
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-\-geometry
|
||||
Specify Xephyr screen geometry
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-w, \-\-wide
|
||||
Use widescreen (1280x800) with Xephyr
|
||||
.br
|
||||
|
||||
.TP
|
||||
.B \-\-create\-extension
|
||||
Create a new GNOME Shell extension
|
||||
|
||||
.TP
|
||||
.B \-\-eval\-file
|
||||
Evaluate the contents of the given JavaScript file
|
||||
.B \-\-help
|
||||
Display help and exit
|
||||
.br
|
||||
|
||||
.SH BUGS
|
||||
|
@ -1,14 +1,18 @@
|
||||
af
|
||||
an
|
||||
ar
|
||||
be
|
||||
bg
|
||||
bn
|
||||
bn_IN
|
||||
ca
|
||||
ca@valencia
|
||||
cs
|
||||
da
|
||||
de
|
||||
el
|
||||
en_GB
|
||||
eo
|
||||
es
|
||||
et
|
||||
eu
|
||||
@ -38,11 +42,13 @@ pt
|
||||
pt_BR
|
||||
ro
|
||||
ru
|
||||
sk
|
||||
sl
|
||||
sr
|
||||
sr@latin
|
||||
sv
|
||||
ta
|
||||
te
|
||||
th
|
||||
tr
|
||||
ug
|
||||
|
1426
po/ca@valencia.po
Normal file
94
po/ja.po
@ -11,9 +11,9 @@ 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: 2011-04-04 14:08+0000\n"
|
||||
"PO-Revision-Date: 2011-03-30 00:26+0900\n"
|
||||
"Last-Translator: Kiyotaka NISHIBORI <ml.nishibori.kiyotaka@gmail.com>\n"
|
||||
"POT-Creation-Date: 2011-04-22 21:34+0000\n"
|
||||
"PO-Revision-Date: 2011-04-19 23:13+0900\n"
|
||||
"Last-Translator: Jiro Matsuzawa <matsuzawa.jr@gmail.com>\n"
|
||||
"Language-Team: Japanese <gnome-translation@gnome.gr.jp>\n"
|
||||
"Language: ja\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -187,23 +187,23 @@ msgstr "'%s'の実行に失敗しました:"
|
||||
msgid "All"
|
||||
msgstr "すべて"
|
||||
|
||||
#: ../js/ui/appDisplay.js:328
|
||||
#: ../js/ui/appDisplay.js:329
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "アプリケーション"
|
||||
|
||||
#: ../js/ui/appDisplay.js:354
|
||||
#: ../js/ui/appDisplay.js:355
|
||||
msgid "SETTINGS"
|
||||
msgstr "設定"
|
||||
|
||||
#: ../js/ui/appDisplay.js:625
|
||||
#: ../js/ui/appDisplay.js:626
|
||||
msgid "New Window"
|
||||
msgstr "新しいウィンドウで開く"
|
||||
|
||||
#: ../js/ui/appDisplay.js:628
|
||||
#: ../js/ui/appDisplay.js:629
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "お気に入りから削除"
|
||||
|
||||
#: ../js/ui/appDisplay.js:629
|
||||
#: ../js/ui/appDisplay.js:630
|
||||
msgid "Add to Favorites"
|
||||
msgstr "お気に入りに追加"
|
||||
|
||||
@ -336,13 +336,13 @@ msgid "Nothing Scheduled"
|
||||
msgstr "予定がありません"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:490
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:492
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%B%e日 (%a)"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on different year
|
||||
#: ../js/ui/calendar.js:723 ../js/ui/telepathyClient.js:493
|
||||
#: ../js/ui/calendar.js:723 ../js/ui/telepathyClient.js:495
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%Y年%B%e日 (%a)"
|
||||
@ -363,7 +363,7 @@ msgstr "今週"
|
||||
msgid "Next week"
|
||||
msgstr "来週"
|
||||
|
||||
#: ../js/ui/dash.js:174 ../js/ui/messageTray.js:1007
|
||||
#: ../js/ui/dash.js:174 ../js/ui/messageTray.js:1037
|
||||
msgid "Remove"
|
||||
msgstr "削除"
|
||||
|
||||
@ -490,7 +490,7 @@ msgstr "%d 秒後にシステムを再起動します。"
|
||||
msgid "Restarting the system."
|
||||
msgstr "システムを再起動します。"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:417 ../js/ui/polkitAuthenticationAgent.js:172
|
||||
#: ../js/ui/endSessionDialog.js:413 ../js/ui/polkitAuthenticationAgent.js:172
|
||||
#: ../js/ui/status/bluetooth.js:466
|
||||
msgid "Cancel"
|
||||
msgstr "キャンセル"
|
||||
@ -525,11 +525,11 @@ msgstr "ソースの表示"
|
||||
msgid "Web Page"
|
||||
msgstr "ウェブページ"
|
||||
|
||||
#: ../js/ui/messageTray.js:1000
|
||||
#: ../js/ui/messageTray.js:1030
|
||||
msgid "Open"
|
||||
msgstr "開く"
|
||||
|
||||
#: ../js/ui/messageTray.js:2164
|
||||
#: ../js/ui/messageTray.js:2194
|
||||
msgid "System Information"
|
||||
msgstr "システム情報"
|
||||
|
||||
@ -829,139 +829,139 @@ msgstr "キーボードレイアウトの表示..."
|
||||
msgid "Localization Settings"
|
||||
msgstr "ローカライズ設定"
|
||||
|
||||
#: ../js/ui/status/network.js:105 ../js/ui/status/network.js:1466
|
||||
#: ../js/ui/status/network.js:109 ../js/ui/status/network.js:1498
|
||||
msgid "<unknown>"
|
||||
msgstr "< 不明 >"
|
||||
|
||||
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
|
||||
#: ../js/ui/status/network.js:318
|
||||
#: ../js/ui/status/network.js:326
|
||||
msgid "disabled"
|
||||
msgstr "利用不可"
|
||||
|
||||
#: ../js/ui/status/network.js:501
|
||||
#: ../js/ui/status/network.js:521
|
||||
msgid "connecting..."
|
||||
msgstr "接続中..."
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
#: ../js/ui/status/network.js:504
|
||||
#: ../js/ui/status/network.js:524
|
||||
msgid "authentication required"
|
||||
msgstr "認証要求"
|
||||
|
||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||
#. module, which is missing
|
||||
#: ../js/ui/status/network.js:514
|
||||
#: ../js/ui/status/network.js:534
|
||||
msgid "firmware missing"
|
||||
msgstr "ファームウェア無し"
|
||||
|
||||
#. Translators: this is for wired network devices that are physically disconnected
|
||||
#: ../js/ui/status/network.js:521
|
||||
#: ../js/ui/status/network.js:541
|
||||
msgid "cable unplugged"
|
||||
msgstr "ケーブル抜け"
|
||||
|
||||
#. Translators: this is for a network device that cannot be activated (for example it
|
||||
#. is disabled by rfkill, or it has no coverage
|
||||
#: ../js/ui/status/network.js:526
|
||||
#: ../js/ui/status/network.js:546
|
||||
msgid "unavailable"
|
||||
msgstr "利用不可"
|
||||
|
||||
#: ../js/ui/status/network.js:528
|
||||
#: ../js/ui/status/network.js:548
|
||||
msgid "connection failed"
|
||||
msgstr "接続失敗"
|
||||
|
||||
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
|
||||
#. and we cannot access its settings (including the name)
|
||||
#: ../js/ui/status/network.js:608 ../js/ui/status/network.js:1414
|
||||
#: ../js/ui/status/network.js:628 ../js/ui/status/network.js:1446
|
||||
msgid "Connected (private)"
|
||||
msgstr "接続 (制限付)"
|
||||
|
||||
#: ../js/ui/status/network.js:689
|
||||
#: ../js/ui/status/network.js:713
|
||||
msgid "Auto Ethernet"
|
||||
msgstr "自動イーサネット接続"
|
||||
|
||||
#: ../js/ui/status/network.js:764
|
||||
#: ../js/ui/status/network.js:788
|
||||
msgid "Auto broadband"
|
||||
msgstr "自動ブロードバンド接続"
|
||||
|
||||
#: ../js/ui/status/network.js:767
|
||||
#: ../js/ui/status/network.js:791
|
||||
msgid "Auto dial-up"
|
||||
msgstr "自動ダイヤルアップ"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:910 ../js/ui/status/network.js:1426
|
||||
#: ../js/ui/status/network.js:937 ../js/ui/status/network.js:1458
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "自動 %s"
|
||||
|
||||
#: ../js/ui/status/network.js:912
|
||||
#: ../js/ui/status/network.js:939
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "自動 Bluetooth 接続"
|
||||
|
||||
#: ../js/ui/status/network.js:1428
|
||||
#: ../js/ui/status/network.js:1460
|
||||
msgid "Auto wireless"
|
||||
msgstr "自動無線接続"
|
||||
|
||||
#: ../js/ui/status/network.js:1486
|
||||
#: ../js/ui/status/network.js:1518
|
||||
msgid "More..."
|
||||
msgstr "その他..."
|
||||
|
||||
#: ../js/ui/status/network.js:1509
|
||||
#: ../js/ui/status/network.js:1541
|
||||
msgid "Enable networking"
|
||||
msgstr "ネットワークを利用可能にする"
|
||||
|
||||
#: ../js/ui/status/network.js:1521
|
||||
#: ../js/ui/status/network.js:1553
|
||||
msgid "Wired"
|
||||
msgstr "有線接続"
|
||||
|
||||
#: ../js/ui/status/network.js:1532
|
||||
#: ../js/ui/status/network.js:1564
|
||||
msgid "Wireless"
|
||||
msgstr "無線接続"
|
||||
|
||||
#: ../js/ui/status/network.js:1542
|
||||
#: ../js/ui/status/network.js:1574
|
||||
msgid "Mobile broadband"
|
||||
msgstr "モバイルブロードバンド"
|
||||
|
||||
#: ../js/ui/status/network.js:1552
|
||||
#: ../js/ui/status/network.js:1584
|
||||
msgid "VPN Connections"
|
||||
msgstr "VPN 接続"
|
||||
|
||||
#: ../js/ui/status/network.js:1564
|
||||
#: ../js/ui/status/network.js:1596
|
||||
msgid "Network Settings"
|
||||
msgstr "ネットワーク設定"
|
||||
msgstr "ネットワークの設定"
|
||||
|
||||
#: ../js/ui/status/network.js:1854
|
||||
#: ../js/ui/status/network.js:1890
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "モバイルブロードバンド '%s' に接続しました"
|
||||
|
||||
#: ../js/ui/status/network.js:1858
|
||||
#: ../js/ui/status/network.js:1894
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "無線ネットワーク '%s' に接続しました"
|
||||
|
||||
#: ../js/ui/status/network.js:1862
|
||||
#: ../js/ui/status/network.js:1898
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "有線ネットワーク '%s' に接続しました"
|
||||
|
||||
#: ../js/ui/status/network.js:1866
|
||||
#: ../js/ui/status/network.js:1902
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "VPN ネットワーク '%s' に接続しました"
|
||||
|
||||
#: ../js/ui/status/network.js:1871
|
||||
#: ../js/ui/status/network.js:1907
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "'%s' に接続しました"
|
||||
|
||||
#: ../js/ui/status/network.js:1879
|
||||
#: ../js/ui/status/network.js:1915
|
||||
msgid "Connection established"
|
||||
msgstr "接続を確立しました"
|
||||
|
||||
#: ../js/ui/status/network.js:2005
|
||||
#: ../js/ui/status/network.js:2041
|
||||
msgid "Networking is disabled"
|
||||
msgstr "ネットワークを利用できません"
|
||||
|
||||
#: ../js/ui/status/network.js:2130
|
||||
#: ../js/ui/status/network.js:2166
|
||||
msgid "Network Manager"
|
||||
msgstr "ネットワークマネージャ"
|
||||
|
||||
@ -1082,7 +1082,7 @@ msgstr "%s は離席中です。"
|
||||
#. Translators: this is a time format string followed by a date.
|
||||
#. If applicable, replace %X with a strftime format valid for your
|
||||
#. locale, without seconds.
|
||||
#: ../js/ui/telepathyClient.js:482
|
||||
#: ../js/ui/telepathyClient.js:484
|
||||
#, no-c-format
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "%Aの%Xに送信"
|
||||
@ -1129,7 +1129,7 @@ msgstr[0] "入力数: %u"
|
||||
msgid "System Sounds"
|
||||
msgstr "システムのサウンド"
|
||||
|
||||
#: ../src/main.c:446
|
||||
#: ../src/main.c:445
|
||||
msgid "Print version"
|
||||
msgstr "バージョンを表示"
|
||||
|
||||
|
114
po/pl.po
@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-03-28 20:21+0200\n"
|
||||
"PO-Revision-Date: 2011-03-28 20:22+0200\n"
|
||||
"POT-Creation-Date: 2011-04-22 16:23+0200\n"
|
||||
"PO-Revision-Date: 2011-04-22 16:27+0200\n"
|
||||
"Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
|
||||
"Language-Team: Polish <gnomepl@aviary.pl>\n"
|
||||
"Language: pl\n"
|
||||
@ -196,23 +196,23 @@ msgstr "Wykonanie polecenia \"%s\" się nie powiodło:"
|
||||
msgid "All"
|
||||
msgstr "Wszystkie"
|
||||
|
||||
#: ../js/ui/appDisplay.js:328
|
||||
#: ../js/ui/appDisplay.js:329
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Programy"
|
||||
|
||||
#: ../js/ui/appDisplay.js:354
|
||||
#: ../js/ui/appDisplay.js:355
|
||||
msgid "SETTINGS"
|
||||
msgstr "Ustawienia"
|
||||
|
||||
#: ../js/ui/appDisplay.js:625
|
||||
#: ../js/ui/appDisplay.js:626
|
||||
msgid "New Window"
|
||||
msgstr "Nowe okno"
|
||||
|
||||
#: ../js/ui/appDisplay.js:628
|
||||
#: ../js/ui/appDisplay.js:629
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "Usuń z ulubionych"
|
||||
|
||||
#: ../js/ui/appDisplay.js:629
|
||||
#: ../js/ui/appDisplay.js:630
|
||||
msgid "Add to Favorites"
|
||||
msgstr "Dodaj do ulubionych"
|
||||
|
||||
@ -345,13 +345,13 @@ msgid "Nothing Scheduled"
|
||||
msgstr "Nic nie zaplanowano"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on current year
|
||||
#: ../js/ui/calendar.js:720
|
||||
#: ../js/ui/calendar.js:720 ../js/ui/telepathyClient.js:492
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d"
|
||||
msgstr "%A, %e %B"
|
||||
|
||||
#. Translators: Shown on calendar heading when selected day occurs on different year
|
||||
#: ../js/ui/calendar.js:723
|
||||
#: ../js/ui/calendar.js:723 ../js/ui/telepathyClient.js:495
|
||||
msgctxt "calendar heading"
|
||||
msgid "%A, %B %d, %Y"
|
||||
msgstr "%A, %e %B %Y"
|
||||
@ -372,7 +372,7 @@ msgstr "Ten tydzień"
|
||||
msgid "Next week"
|
||||
msgstr "Następny tydzień"
|
||||
|
||||
#: ../js/ui/dash.js:174 ../js/ui/messageTray.js:1000
|
||||
#: ../js/ui/dash.js:174 ../js/ui/messageTray.js:1037
|
||||
msgid "Remove"
|
||||
msgstr "Usuń"
|
||||
|
||||
@ -408,7 +408,7 @@ msgstr "%a, %R"
|
||||
#. for AM/PM.
|
||||
#: ../js/ui/dateMenu.js:177
|
||||
msgid "%a %b %e, %l:%M:%S %p"
|
||||
msgstr "%a %e %b, %H:%M:%S %p"
|
||||
msgstr "%a %e %b, %l:%M:%S %p"
|
||||
|
||||
#: ../js/ui/dateMenu.js:178
|
||||
msgid "%a %b %e, %l:%M %p"
|
||||
@ -499,7 +499,7 @@ msgstr "System zostanie automatycznie uruchomiony ponownie za %d sekund."
|
||||
msgid "Restarting the system."
|
||||
msgstr "Ponowne uruchamianie systemu."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:415 ../js/ui/polkitAuthenticationAgent.js:172
|
||||
#: ../js/ui/endSessionDialog.js:413 ../js/ui/polkitAuthenticationAgent.js:172
|
||||
#: ../js/ui/status/bluetooth.js:466
|
||||
msgid "Cancel"
|
||||
msgstr "Anuluj"
|
||||
@ -534,11 +534,11 @@ msgstr "Wyświetl źródło"
|
||||
msgid "Web Page"
|
||||
msgstr "Strona WWW"
|
||||
|
||||
#: ../js/ui/messageTray.js:993
|
||||
#: ../js/ui/messageTray.js:1030
|
||||
msgid "Open"
|
||||
msgstr "Otwórz"
|
||||
|
||||
#: ../js/ui/messageTray.js:2151
|
||||
#: ../js/ui/messageTray.js:2194
|
||||
msgid "System Information"
|
||||
msgstr "Informacje systemowe"
|
||||
|
||||
@ -561,18 +561,18 @@ msgid "Dash"
|
||||
msgstr "Ulubione"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#: ../js/ui/panel.js:515
|
||||
#: ../js/ui/panel.js:524
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
msgstr "Zakończ program %s"
|
||||
|
||||
#. Button on the left side of the panel.
|
||||
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
|
||||
#: ../js/ui/panel.js:878
|
||||
#: ../js/ui/panel.js:902
|
||||
msgid "Activities"
|
||||
msgstr "Podgląd"
|
||||
|
||||
#: ../js/ui/panel.js:979
|
||||
#: ../js/ui/panel.js:1003
|
||||
msgid "Top Bar"
|
||||
msgstr "Górny pasek"
|
||||
|
||||
@ -630,11 +630,11 @@ msgstr "toggle-switch-intl"
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Proszę wprowadzić polecenie:"
|
||||
|
||||
#: ../js/ui/searchDisplay.js:310
|
||||
#: ../js/ui/searchDisplay.js:311
|
||||
msgid "Searching..."
|
||||
msgstr "Wyszukiwanie..."
|
||||
|
||||
#: ../js/ui/searchDisplay.js:324
|
||||
#: ../js/ui/searchDisplay.js:325
|
||||
msgid "No matching results."
|
||||
msgstr "Brak wyników."
|
||||
|
||||
@ -838,139 +838,139 @@ msgstr "Wyświetl układ klawiatury..."
|
||||
msgid "Localization Settings"
|
||||
msgstr "Ustawienia lokalizacji"
|
||||
|
||||
#: ../js/ui/status/network.js:104 ../js/ui/status/network.js:1454
|
||||
#: ../js/ui/status/network.js:109 ../js/ui/status/network.js:1498
|
||||
msgid "<unknown>"
|
||||
msgstr "<nieznane>"
|
||||
|
||||
#. Translators: this indicates that wireless or wwan is disabled by hardware killswitch
|
||||
#: ../js/ui/status/network.js:311
|
||||
#: ../js/ui/status/network.js:326
|
||||
msgid "disabled"
|
||||
msgstr "wyłączone"
|
||||
|
||||
#: ../js/ui/status/network.js:494
|
||||
#: ../js/ui/status/network.js:521
|
||||
msgid "connecting..."
|
||||
msgstr "łączenie..."
|
||||
|
||||
#. Translators: this is for network connections that require some kind of key or password
|
||||
#: ../js/ui/status/network.js:497
|
||||
#: ../js/ui/status/network.js:524
|
||||
msgid "authentication required"
|
||||
msgstr "wymagane jest uwierzytelnienie"
|
||||
|
||||
#. Translators: this is for devices that require some kind of firmware or kernel
|
||||
#. module, which is missing
|
||||
#: ../js/ui/status/network.js:507
|
||||
#: ../js/ui/status/network.js:534
|
||||
msgid "firmware missing"
|
||||
msgstr "brak oprogramowania wbudowanego"
|
||||
|
||||
#. Translators: this is for wired network devices that are physically disconnected
|
||||
#: ../js/ui/status/network.js:514
|
||||
#: ../js/ui/status/network.js:541
|
||||
msgid "cable unplugged"
|
||||
msgstr "kabel jest niepodłączony"
|
||||
|
||||
#. Translators: this is for a network device that cannot be activated (for example it
|
||||
#. is disabled by rfkill, or it has no coverage
|
||||
#: ../js/ui/status/network.js:519
|
||||
#: ../js/ui/status/network.js:546
|
||||
msgid "unavailable"
|
||||
msgstr "niedostępne"
|
||||
|
||||
#: ../js/ui/status/network.js:521
|
||||
#: ../js/ui/status/network.js:548
|
||||
msgid "connection failed"
|
||||
msgstr "połączenie się nie powiodło"
|
||||
|
||||
#. TRANSLATORS: this is the indication that a connection for another logged in user is active,
|
||||
#. and we cannot access its settings (including the name)
|
||||
#: ../js/ui/status/network.js:602 ../js/ui/status/network.js:1402
|
||||
#: ../js/ui/status/network.js:628 ../js/ui/status/network.js:1446
|
||||
msgid "Connected (private)"
|
||||
msgstr "Połączono (prywatne)"
|
||||
|
||||
#: ../js/ui/status/network.js:683
|
||||
#: ../js/ui/status/network.js:713
|
||||
msgid "Auto Ethernet"
|
||||
msgstr "Automatyczne Ethernet"
|
||||
|
||||
#: ../js/ui/status/network.js:758
|
||||
#: ../js/ui/status/network.js:788
|
||||
msgid "Auto broadband"
|
||||
msgstr "Automatyczne komórkowe"
|
||||
|
||||
#: ../js/ui/status/network.js:761
|
||||
#: ../js/ui/status/network.js:791
|
||||
msgid "Auto dial-up"
|
||||
msgstr "Automatyczne wdzwaniane"
|
||||
|
||||
#. TRANSLATORS: this the automatic wireless connection name (including the network name)
|
||||
#: ../js/ui/status/network.js:904 ../js/ui/status/network.js:1414
|
||||
#: ../js/ui/status/network.js:937 ../js/ui/status/network.js:1458
|
||||
#, c-format
|
||||
msgid "Auto %s"
|
||||
msgstr "Automatyczne %s"
|
||||
|
||||
#: ../js/ui/status/network.js:906
|
||||
#: ../js/ui/status/network.js:939
|
||||
msgid "Auto bluetooth"
|
||||
msgstr "Automatyczne Bluetooth"
|
||||
|
||||
#: ../js/ui/status/network.js:1416
|
||||
#: ../js/ui/status/network.js:1460
|
||||
msgid "Auto wireless"
|
||||
msgstr "Automatyczne bezprzewodowe"
|
||||
|
||||
#: ../js/ui/status/network.js:1474
|
||||
#: ../js/ui/status/network.js:1518
|
||||
msgid "More..."
|
||||
msgstr "Więcej..."
|
||||
|
||||
#: ../js/ui/status/network.js:1497
|
||||
#: ../js/ui/status/network.js:1541
|
||||
msgid "Enable networking"
|
||||
msgstr "Włącz sieć"
|
||||
|
||||
#: ../js/ui/status/network.js:1509
|
||||
#: ../js/ui/status/network.js:1553
|
||||
msgid "Wired"
|
||||
msgstr "Przewodowe"
|
||||
|
||||
#: ../js/ui/status/network.js:1520
|
||||
#: ../js/ui/status/network.js:1564
|
||||
msgid "Wireless"
|
||||
msgstr "Bezprzewodowe"
|
||||
|
||||
#: ../js/ui/status/network.js:1530
|
||||
#: ../js/ui/status/network.js:1574
|
||||
msgid "Mobile broadband"
|
||||
msgstr "Komórkowe"
|
||||
|
||||
#: ../js/ui/status/network.js:1540
|
||||
#: ../js/ui/status/network.js:1584
|
||||
msgid "VPN Connections"
|
||||
msgstr "Połączenia VPN"
|
||||
|
||||
#: ../js/ui/status/network.js:1549
|
||||
#: ../js/ui/status/network.js:1596
|
||||
msgid "Network Settings"
|
||||
msgstr "Ustawienia sieci"
|
||||
|
||||
#: ../js/ui/status/network.js:1844
|
||||
#: ../js/ui/status/network.js:1890
|
||||
#, c-format
|
||||
msgid "You're now connected to mobile broadband connection '%s'"
|
||||
msgstr "Połączono z siecią komórkową \"%s\""
|
||||
|
||||
#: ../js/ui/status/network.js:1848
|
||||
#: ../js/ui/status/network.js:1894
|
||||
#, c-format
|
||||
msgid "You're now connected to wireless network '%s'"
|
||||
msgstr "Połączono z siecią bezprzewodową \"%s\""
|
||||
|
||||
#: ../js/ui/status/network.js:1852
|
||||
#: ../js/ui/status/network.js:1898
|
||||
#, c-format
|
||||
msgid "You're now connected to wired network '%s'"
|
||||
msgstr "Połączono z siecią przewodową \"%s\""
|
||||
|
||||
#: ../js/ui/status/network.js:1856
|
||||
#: ../js/ui/status/network.js:1902
|
||||
#, c-format
|
||||
msgid "You're now connected to VPN network '%s'"
|
||||
msgstr "Połączono z siecią VPN \"%s\""
|
||||
|
||||
#: ../js/ui/status/network.js:1861
|
||||
#: ../js/ui/status/network.js:1907
|
||||
#, c-format
|
||||
msgid "You're now connected to '%s'"
|
||||
msgstr "Połączono z siecią \"%s\""
|
||||
|
||||
#: ../js/ui/status/network.js:1869
|
||||
#: ../js/ui/status/network.js:1915
|
||||
msgid "Connection established"
|
||||
msgstr "Nawiązano połączenie"
|
||||
|
||||
#: ../js/ui/status/network.js:1991
|
||||
#: ../js/ui/status/network.js:2041
|
||||
msgid "Networking is disabled"
|
||||
msgstr "Sieć jest wyłączona"
|
||||
|
||||
#: ../js/ui/status/network.js:2116
|
||||
#: ../js/ui/status/network.js:2166
|
||||
msgid "Network Manager"
|
||||
msgstr "Menedżer sieci"
|
||||
|
||||
@ -1076,22 +1076,22 @@ msgstr "Głośność"
|
||||
msgid "Microphone"
|
||||
msgstr "Mikrofon"
|
||||
|
||||
#: ../js/ui/telepathyClient.js:331
|
||||
#: ../js/ui/telepathyClient.js:335
|
||||
#, c-format
|
||||
msgid "%s is online."
|
||||
msgstr "Użytkownik %s jest online."
|
||||
msgstr "Użytkownik %s jest w trybie online."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:336
|
||||
#: ../js/ui/telepathyClient.js:340
|
||||
#, c-format
|
||||
msgid "%s is offline."
|
||||
msgstr "Użytkownik %s jest offline."
|
||||
msgstr "Użytkownik %s jest w trybie offline."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:339
|
||||
#: ../js/ui/telepathyClient.js:343
|
||||
#, c-format
|
||||
msgid "%s is away."
|
||||
msgstr "Użytkownik %s jest nieobecny."
|
||||
|
||||
#: ../js/ui/telepathyClient.js:342
|
||||
#: ../js/ui/telepathyClient.js:346
|
||||
#, c-format
|
||||
msgid "%s is busy."
|
||||
msgstr "Użytkownik %s jest zajęty."
|
||||
@ -1099,7 +1099,7 @@ msgstr "Użytkownik %s jest zajęty."
|
||||
#. Translators: this is a time format string followed by a date.
|
||||
#. If applicable, replace %X with a strftime format valid for your
|
||||
#. locale, without seconds.
|
||||
#: ../js/ui/telepathyClient.js:473
|
||||
#: ../js/ui/telepathyClient.js:484
|
||||
#, no-c-format
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "Wysłano o %H:%M w dniu %e %b"
|
||||
@ -1150,7 +1150,7 @@ msgstr[2] "%u wejść"
|
||||
msgid "System Sounds"
|
||||
msgstr "Dźwięki systemowe"
|
||||
|
||||
#: ../src/main.c:446
|
||||
#: ../src/main.c:445
|
||||
msgid "Print version"
|
||||
msgstr "Wyświetla wersję"
|
||||
|
||||
|