Compare commits
305 Commits
Author | SHA1 | Date | |
---|---|---|---|
59724c5dd5 | |||
3bb500fed4 | |||
dcd3945bb7 | |||
f414f616c4 | |||
e21e90c5e6 | |||
1e7b2ef51f | |||
c291de7479 | |||
aee1a18270 | |||
6c67f26e7d | |||
deb651acbf | |||
d2011f6d7f | |||
416adec904 | |||
a72dca3610 | |||
5e5035a0f7 | |||
ffdb85e003 | |||
6a969b934f | |||
8d3ff56846 | |||
d8d046f2b3 | |||
0bec76b6ee | |||
aa3aea7520 | |||
49fcc93a4b | |||
eaec459ee9 | |||
72c6f0025d | |||
aa3caff714 | |||
522ccaba3f | |||
3d00864599 | |||
bd3dfb8f6a | |||
1b3c89f32b | |||
a4475465f1 | |||
84f14cb61c | |||
d0de411a59 | |||
2b9645b268 | |||
4f08bebbf0 | |||
4e8c476153 | |||
1d374ac8bd | |||
83f0f4ea36 | |||
18f569280c | |||
fc0c98805f | |||
6722b69b8a | |||
f9d909f985 | |||
dd42cfa853 | |||
4ed4bb330e | |||
f02b007337 | |||
0035de4ab7 | |||
28552d4b38 | |||
42066a7c46 | |||
45847470d1 | |||
72b0a3d78f | |||
fc3ad390b7 | |||
926de53c0c | |||
e6cd112379 | |||
2cefc8be27 | |||
991179835e | |||
0ca2fee54f | |||
778ef365d9 | |||
45937ed85d | |||
65a9c09c9c | |||
67b14d5fe5 | |||
f976e46c46 | |||
7026209eae | |||
1e82d6edc2 | |||
50ac1dd197 | |||
9d933356e1 | |||
c2a5c00111 | |||
edb561a6ff | |||
14c2460fe4 | |||
598362448a | |||
845273d4c0 | |||
3aebfdc319 | |||
f423c371c8 | |||
6fe1ad62ba | |||
63efe1db11 | |||
002ae0e7f1 | |||
4f5e5e1999 | |||
f4feb409ff | |||
05a035e6fd | |||
7c2a3cc233 | |||
7f660fd4d7 | |||
c0730b610e | |||
b0cfcc4842 | |||
1afc9fefcc | |||
90bea5785e | |||
61dacf3d91 | |||
3ae45bddad | |||
9ad4070d58 | |||
1981b21ea8 | |||
9896135c97 | |||
0d340099da | |||
cacc780111 | |||
a9a6da08a1 | |||
ccb6b93b65 | |||
5623f3b4b5 | |||
a227d595f5 | |||
012955e341 | |||
a41cd7d3cc | |||
11d947f1e5 | |||
2bb717b0b7 | |||
770f8c6538 | |||
e76e0042a8 | |||
91e266113c | |||
ed2956a2ea | |||
aa6f352cb0 | |||
5a42a91ee0 | |||
4d682c7861 | |||
20fec42496 | |||
437df2f0bd | |||
445aa54622 | |||
7fa9ca0a9c | |||
0fe7ae1810 | |||
9c251d85cf | |||
959b5fe5cf | |||
75a8bf626a | |||
eb514f335c | |||
ad77b4ddfc | |||
534bf2b000 | |||
3821fd04a4 | |||
b55b9cc7a9 | |||
ac6462c7c6 | |||
aa7b0a285b | |||
0a63de8c8d | |||
0992bd41ed | |||
ed52a5a58b | |||
79bf770783 | |||
c7e3b68dcd | |||
1b9318c82f | |||
6a142c4260 | |||
c49f2e1384 | |||
9208473e59 | |||
08ece4c186 | |||
99c29366ee | |||
7a11964dfb | |||
c4922f6624 | |||
4f2070a7c6 | |||
03177dc474 | |||
b9b4886a6f | |||
33e35f269f | |||
b886656f61 | |||
8589bfb62e | |||
6a36a68f32 | |||
a0a701757e | |||
effe6fab3a | |||
8e560f98d1 | |||
58aabfcf5b | |||
19e3f794f8 | |||
2b1077aaa1 | |||
547cdf86cc | |||
7653175c6f | |||
a4c1b55111 | |||
93205eefb9 | |||
ec3f8d4b85 | |||
0258c7a518 | |||
ebfdb8ec3c | |||
6823bad2d8 | |||
491100c7ee | |||
762e770c84 | |||
c214e3b07a | |||
b656b1c22f | |||
d211680534 | |||
d44c3d0cd3 | |||
6cb1692841 | |||
593acb954d | |||
d209bc69b6 | |||
4d64bbcf7d | |||
5bd4329b11 | |||
02870e5363 | |||
2a59478b37 | |||
04030f22a6 | |||
2cc4558018 | |||
215eb5c65f | |||
5faef316b8 | |||
6751ca4c18 | |||
84e0a20701 | |||
e04e507659 | |||
6a48dee037 | |||
ea3fd0cf65 | |||
9c614057be | |||
8096e71c53 | |||
73977795a6 | |||
3b3445146d | |||
650dea017b | |||
70099872ab | |||
dc5618558f | |||
62481f4b7c | |||
d3418f6381 | |||
57dd862e35 | |||
db76fb8ff9 | |||
9e5704b498 | |||
3deaeb4a90 | |||
afb7f08e6b | |||
38c70e73b9 | |||
e60bf44c2e | |||
746a8692ac | |||
a00762ddd9 | |||
3981b27d8f | |||
62786c09a8 | |||
67c216a6fe | |||
e933302ae4 | |||
75d5e84a4b | |||
f160dda187 | |||
9c474a635a | |||
d445bd17eb | |||
584f8c8381 | |||
032a688a72 | |||
285a7467d0 | |||
3289105ac4 | |||
51861b1e6b | |||
d85f97c744 | |||
98847f2279 | |||
1d58ea25ab | |||
9de05994db | |||
c9f3afc38f | |||
3526bc0f0a | |||
079809af1d | |||
26719b02e4 | |||
3a45ddcaad | |||
f839100bc2 | |||
c93767768c | |||
0011755b41 | |||
ec932b2306 | |||
1c0c38574d | |||
78b81650f5 | |||
62bfde45aa | |||
5b624a34b8 | |||
9c008ab998 | |||
6edcd82103 | |||
d5aa276c41 | |||
d54efe0838 | |||
d0fe1211f2 | |||
3e20843d9c | |||
7c9d90b0aa | |||
b6e6e097b7 | |||
3842981c35 | |||
926177785d | |||
7d80647170 | |||
c2a21bb885 | |||
eaff1e9290 | |||
93c5e6d97e | |||
20fc9735fa | |||
d450b74e10 | |||
e8fa2b6417 | |||
c459ef6888 | |||
d1a3a000af | |||
5ce8980db3 | |||
8c32cff6fc | |||
bc99db9fd3 | |||
a5eae8e3d8 | |||
82a764ee93 | |||
ce2c90a534 | |||
28cc0da151 | |||
f1957dccb7 | |||
0af4dc0b4c | |||
687e1ebf69 | |||
805b686576 | |||
101daf6791 | |||
5d12ab415c | |||
0810ab62db | |||
6f00d81abf | |||
4184edc7f8 | |||
05f9f991d8 | |||
3df7ef6ce6 | |||
d836194e31 | |||
8ed3e2117f | |||
62fcda5d91 | |||
0a780376f3 | |||
efb9f167bd | |||
eb69f3aa76 | |||
c15a885418 | |||
fe60db64e0 | |||
b90cc5ff26 | |||
e9f95ca605 | |||
017c2468ee | |||
8c6a2874ff | |||
557130d2f2 | |||
84cbbafaae | |||
72a663f554 | |||
7c762ef9df | |||
3182aba744 | |||
e6339fbb45 | |||
a6d8c25494 | |||
cd4eda8bef | |||
a0bd4a02e4 | |||
42b54aaa21 | |||
bbfa616f27 | |||
7e31015ba2 | |||
aa2fc3c858 | |||
d4f0b5bdf3 | |||
eda27d5194 | |||
589e6c29f3 | |||
4b46533ce8 | |||
6687b9b739 | |||
91c4408d23 | |||
83adb2a864 | |||
5918faddf7 | |||
916c02a2f5 | |||
a84fb99c0a | |||
69d5cef3b2 | |||
38d05a8285 | |||
f8899cf274 | |||
dbbf4097a5 | |||
acb1497f4f | |||
e545ec59b9 | |||
da26a9daf8 | |||
a2f263dcbb | |||
ce5cd3bf30 | |||
9a05aea76f |
1
.gitignore
vendored
1
.gitignore
vendored
@ -24,6 +24,7 @@ data/gnome-shell-wayland.desktop.in
|
||||
data/gnome-shell-extension-prefs.desktop
|
||||
data/gnome-shell-extension-prefs.desktop.in
|
||||
data/gschemas.compiled
|
||||
data/perf-background.xml
|
||||
data/org.gnome.shell.gschema.xml
|
||||
data/org.gnome.shell.gschema.valid
|
||||
data/org.gnome.shell.evolution.calendar.gschema.xml
|
||||
|
155
NEWS
155
NEWS
@ -1,3 +1,158 @@
|
||||
3.14.2
|
||||
======
|
||||
* Do not hard-depend on latest NetworkManager [Florian; #738485]
|
||||
* Fix check for isToday in calendar [Darcy; #738725]
|
||||
* Fix workspace changes from app picker [Yuki; #737534]
|
||||
* Misc. bug fixes [Yuki; #739497]
|
||||
|
||||
Contributors:
|
||||
Darcy, Florian Müllner, Yuki
|
||||
|
||||
3.14.1.5
|
||||
========
|
||||
* Fix handing of SystemBackground [Owen; #738652]
|
||||
* Summarize queued up notifications [Devyani; #702460]
|
||||
* Plug an animation object leak [Rui; #739252]
|
||||
* Improve handling of multi-day events [Andreas; #727302]
|
||||
|
||||
Contributors:
|
||||
Andreas Brauchli, Devyani Kota, Rui Matos, Owen W. Taylor
|
||||
|
||||
3.14.1
|
||||
======
|
||||
* Fix pulse animation for scrolled app folders [Florian; #736885]
|
||||
* Fix updating background on file changes [Owen; #710756]
|
||||
* Obtain keyboard variant from IBus [Jinkyu; #735066]
|
||||
* Implement Ctrl-u / Ctrl-k keybindings in entries [Florian; #737346]
|
||||
* Pass VPN hints to auth dialog [Dan; #737592]
|
||||
* Only allow one screenshot request at a time [Adel; #737456]
|
||||
* Respect disable-save-to-disc lockdown setting [Florian; #737846]
|
||||
* Respect scaling-factor for profile pictures [Darcy; #735419]
|
||||
* Focus login screen after lifting the lock screen shield [Ray; #708105]
|
||||
* Speed up pulse animation for few items [Carlos S.; #737017]
|
||||
* Fix gap between workspace switcher and screen edge [Florian; #728899]
|
||||
* Disable unredirection during recordings [Adel; #738226]
|
||||
* Ensure there's always at least one input source [Rui; #738303]
|
||||
* Restrict width of dash icons' context menus [Adel; #738054]
|
||||
* Misc. bug fixes [Jasper, Florian, Carlos G., Owen; #736999, #737382, #737001,
|
||||
#738314, #738256, #738147]
|
||||
|
||||
Contributors:
|
||||
Darcy Beurle, Cosimo Cecchi, Adel Gadllah, Carlos Garnacho, Rui Matos,
|
||||
Florian Müllner, Carlos Soriano, Jasper St. Pierre, Ray Strode, Patrick Ward,
|
||||
Dan Williams, Owen W. Taylor, Jinkyu Yi
|
||||
|
||||
Translations:
|
||||
Мирослав Николић po/sr, sr@latin.po, Fran Diéguez [gl], Marek Černocký [cs],
|
||||
Saibal Ray [bn_IN], Rajesh Ranjan [hi], Friedel Wolff [af],
|
||||
Zhou Fang [zh_CN], Krishnababu Krothapalli [te], Kjartan Maraas [nb],
|
||||
Rūdolfs Mazurs [lv], Sweta Kothari [gu], Christian Kirbach [de],
|
||||
Cheng-Chia Tseng [zh_TW], Pedro Albuquerque [pt], Daniel Mustieles [es],
|
||||
Luca Ferretti [it], Baurzhan Muftakhidinov [kk], Arash Mousavi [fa],
|
||||
Milo Casagrande [it]
|
||||
|
||||
3.14.0
|
||||
======
|
||||
* Fix exposure of the accessible tree [Alejandro; #736821]
|
||||
* Hide empty app folders in app picker [Florian; #736910]
|
||||
|
||||
Contributors:
|
||||
Florian Müllner, Alejandro Piñeiro
|
||||
|
||||
Translations:
|
||||
Yuri Myasoedov [ru], Pawan Chitrakar [ne], Manoj Kumar Giri [or],
|
||||
Daniel Mustieles [es], GNOME Translation Robot [de], Rajesh Ranjan [hi],
|
||||
Shankar Prasad [kn], Kenneth Nielsen [da], Daniel Korostil [uk],
|
||||
Changwoo Ryu [ko], A S Alam [pa], Tom Tryfonidis [el], Petr Kovar [cs]
|
||||
|
||||
3.13.92
|
||||
=======
|
||||
* Fix submenu arrow animations [Hashem; #728927]
|
||||
* Always initialize clutter accessibility [Alejandro; #735908]
|
||||
* Adapt to mutter background changes [Owen; #735638]
|
||||
* Improve handling of outOfDate extensions in prefs [Florian; #736185]
|
||||
* Port offline updates to PackageKit's DBus interface [Kalev; #736337]
|
||||
* location: Translate accuracy levels for geoclue [Zeeshan; #736479]
|
||||
* Implement input source switching [Rui; #736435]
|
||||
* Fix crash when dragging window from workspace switcher [Carlos G.; #735972]
|
||||
* Clean out list of default favorites [Elad; #735682]
|
||||
* Add settings link to location submenu [Florian; #736542]
|
||||
* Fix keynav of message tray menu button [Florian; #707799]
|
||||
* Misc. bug fixes [Carlos G., Florian, Rui; #736110, #736329, #736343,
|
||||
#735927, #735976]
|
||||
|
||||
Contributors:
|
||||
Elad Alfassa, Zeeshan Ali (Khattak), Michael Catanzaro, Adel Gadllah,
|
||||
Carlos Garnacho, Kalev Lember, Rui Matos, Florian Müllner, Hashem Nasarat,
|
||||
Alejandro Piñeiro, Carlos Soriano, Jasper St. Pierre, Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Piotr Drąg [pl], Changwoo Ryu [ko], Yuri Myasoedov [ru], Zhou Fang [ja],
|
||||
Peter Mráz [sk], Ville-Pekka Vainio [fi], Sweta Kothari [gu],
|
||||
Marek Černocký [cs], A S Alam [pa], Christian Kirbach [de],
|
||||
Alexandre Franke [fr], Aurimas Černius [lt], Khaled Hosny [ar],
|
||||
Enrico Nicoletto [pt_BR], Andika Triwidada [id], Shantha kumar [ta],
|
||||
Matej Urbančič [sl], Pawan Chitrakar [ne], Yosef Or Boczko [he],
|
||||
Balázs Úr [hu], Dušan Kazik [sk], Gil Forcada [ca],
|
||||
Carles Ferrando [ca@valencia], Nilamdyuti Goswami [as], Ivaylo Valkov [bg],
|
||||
Sandeep Sheshrao Shedmake [mr], Umarzuki Bin Mochlis Moktar [ms],
|
||||
Muhammet Kara [tr], Jiro Matsuzawa [ja], Kris Thomsen [da],
|
||||
Mattias Eriksson [sv]
|
||||
|
||||
3.13.91
|
||||
=======
|
||||
* Fix keynav into session menu on login screen [Florian; #735614]
|
||||
* Add gesture to summon message tray [Carlos G.; #735625]
|
||||
* Accept scrolls/swipes either way on the screen shield [Jasper; #734874]
|
||||
* Animate opening the app picker and improve app folder animations
|
||||
[Carlos S.; #734726]
|
||||
* Animate app icons on launching a new window [Carlos S., Florian; #734726]
|
||||
* Show the on-screen keyboard when touch input is being used [David; #702015]
|
||||
* Misc. bug fixes [Bastien, Owen, Florian, Carlos G.; #735190, #735385,
|
||||
#735608, #735681]
|
||||
|
||||
Contributors:
|
||||
Carlos Garnacho, David King, Kalev Lember, Florian Müllner, Bastien Nocera,
|
||||
Carlos Soriano, Jasper St. Pierre, Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Fran Diéguez [gl], Sweta Kothari [gu], Manoj Kumar Giri [or],
|
||||
Alain Lojewski [fr], Praveen Illa [te], Arash Mousavi [fa],
|
||||
Andika Triwidada [id]
|
||||
|
||||
3.13.90
|
||||
=======
|
||||
* Make use of GLSL optional [Adel; #733623]
|
||||
* Update on-screen-keyboard position on monitor changes [Cosimo; #733790]
|
||||
* Improve window manager animations [Giovanni; #732857]
|
||||
* Handle touch events [Carlos G.; #733633]
|
||||
* Try to not show "New Window" action for single-window apps
|
||||
[Giovanni; #722554]
|
||||
* Fix overview exceeding screen size with many apps installed
|
||||
[Carlos S.; #723496]
|
||||
* Add Software to default favorites [Mathieu; #734406]
|
||||
* Improve app picker <-> desktop transition [Carlos S.; #732901]
|
||||
* Remove <shift>-magic for switcher popups [Christophe; #732296]
|
||||
* Add a special background to use for performance testing [Owen; #734610]
|
||||
* Add support for default disabled search providers [Giovanni; #734110]
|
||||
* Fix portals that don't redirect properly [Giovanni; #733848]
|
||||
* Fix history trimming in chat notifications [Giovanni; #733899]
|
||||
* Try to use default calendar application [Florian; #722333]
|
||||
* Only show location menu when geolocation is in use [Zeeshan; #731122]
|
||||
* Misc. bug fixes and cleanups [Giovanni, Carlos G., Zeeshan, Carlos S.,
|
||||
Cosimo; #711682, #733840, #734483, #734680, #733813, #735062]
|
||||
|
||||
Contributors:
|
||||
Zeeshan Ali (Khattak), Mathieu Bridon, Giovanni Campagna, Cosimo Cecchi,
|
||||
Piotr Drąg, Christophe Fergeau, Adel Gadllah, Carlos Garnacho,
|
||||
Florian Müllner, Carlos Soriano, Jasper St. Pierre, Olav Vitters,
|
||||
Owen W. Taylor
|
||||
|
||||
Translations:
|
||||
Aurimas Černius [lt], MarMav [el], Inaki Larranaga Murgoitio [eu],
|
||||
Reinout van Schouwen [nl], ngoswami [as], Fabio Tomat [fur],
|
||||
Chao-Hsiung Liao [zh_HK, zh_TW]
|
||||
|
||||
3.13.4
|
||||
======
|
||||
* Handle portal login requests [Giovanni; #704416]
|
||||
|
@ -1,5 +1,5 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell],[3.13.4],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
AC_INIT([gnome-shell],[3.14.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell],[gnome-shell])
|
||||
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
AC_CONFIG_SRCDIR([src/shell-global.c])
|
||||
@ -76,8 +76,8 @@ AC_MSG_RESULT($enable_systemd)
|
||||
CLUTTER_MIN_VERSION=1.15.90
|
||||
GOBJECT_INTROSPECTION_MIN_VERSION=0.10.1
|
||||
GJS_MIN_VERSION=1.39.0
|
||||
MUTTER_MIN_VERSION=3.13.4
|
||||
GTK_MIN_VERSION=3.7.9
|
||||
MUTTER_MIN_VERSION=3.14.2
|
||||
GTK_MIN_VERSION=3.13.2
|
||||
GIO_MIN_VERSION=2.37.0
|
||||
LIBECAL_MIN_VERSION=3.5.3
|
||||
LIBEDATASERVER_MIN_VERSION=3.5.3
|
||||
|
@ -74,6 +74,13 @@ dist_theme_DATA = \
|
||||
theme/ws-switch-arrow-up.png \
|
||||
theme/ws-switch-arrow-down.png
|
||||
|
||||
backgrounddir = $(pkgdatadir)
|
||||
background_DATA = perf-background.xml
|
||||
|
||||
perf-background.xml: perf-background.xml.in
|
||||
$(AM_V_GEN) sed -e "s|@datadir[@]|$(datadir)|" \
|
||||
$< > $@ || rm $@
|
||||
|
||||
keysdir = @GNOME_KEYBINDINGS_KEYSDIR@
|
||||
keys_in_files = 50-gnome-shell-system.xml.in
|
||||
keys_DATA = $(keys_in_files:.xml.in=.xml)
|
||||
@ -106,6 +113,7 @@ EXTRA_DIST = \
|
||||
$(menu_DATA) \
|
||||
$(convert_DATA) \
|
||||
$(keys_in_files) \
|
||||
perf-background.xml.in \
|
||||
org.gnome.Shell.PortalHelper.desktop.in \
|
||||
org.gnome.Shell.PortalHelper.service.in \
|
||||
org.gnome.shell.gschema.xml.in.in
|
||||
@ -117,6 +125,7 @@ CLEANFILES += \
|
||||
$(desktop_DATA) \
|
||||
$(keys_DATA) \
|
||||
$(gsettings_SCHEMAS) \
|
||||
perf-background.xml \
|
||||
gschemas.compiled \
|
||||
org.gnome.shell.gschema.valid \
|
||||
org.gnome.shell.gschema.xml.in
|
||||
|
@ -31,7 +31,7 @@
|
||||
</_description>
|
||||
</key>
|
||||
<key name="favorite-apps" type="as">
|
||||
<default>[ 'epiphany.desktop', 'evolution.desktop', 'empathy.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'libreoffice-writer.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Documents.desktop' ]</default>
|
||||
<default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
|
||||
<_summary>List of desktop file IDs for favorite applications</_summary>
|
||||
<_description>
|
||||
The applications corresponding to these identifiers
|
||||
@ -74,7 +74,6 @@
|
||||
<child name="calendar" schema="org.gnome.shell.calendar"/>
|
||||
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
|
||||
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
|
||||
<child name="location" schema="org.gnome.shell.location"/>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.calendar" path="/org/gnome/shell/calendar/"
|
||||
@ -144,32 +143,6 @@
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<enum id="org.gnome.shell.geoclue.AccuracyLevel">
|
||||
<value value="0" nick="off"/>
|
||||
<value value="1" nick="country"/>
|
||||
<value value="4" nick="city"/>
|
||||
<value value="5" nick="neighborhood"/>
|
||||
<value value="6" nick="street"/>
|
||||
<value value="8" nick="exact"/>
|
||||
</enum>
|
||||
<schema id="org.gnome.shell.location"
|
||||
path="/org/gnome/shell/location/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
<key name="max-accuracy-level" enum="org.gnome.shell.geoclue.AccuracyLevel">
|
||||
<default>'exact'</default>
|
||||
<_summary>The maximum accuracy level of location.</_summary>
|
||||
<_description>
|
||||
Configures the maximum level of location accuracy applications are
|
||||
allowed to see. Valid options are 'off' (disable location tracking),
|
||||
'country', 'city', 'neighborhood', 'street', and 'exact' (typically
|
||||
requires GPS receiver). Please keep in mind that this only controls
|
||||
what GeoClue will allow applications to see and they can find user's
|
||||
location on their own using network resources (albeit with street-level
|
||||
accuracy at best).
|
||||
</_description>
|
||||
</key>
|
||||
</schema>
|
||||
|
||||
<schema id="org.gnome.shell.app-switcher"
|
||||
path="/org/gnome/shell/app-switcher/"
|
||||
gettext-domain="@GETTEXT_PACKAGE@">
|
||||
|
31
data/perf-background.xml.in
Normal file
31
data/perf-background.xml.in
Normal file
@ -0,0 +1,31 @@
|
||||
<!-- With an animated background, performance will differ depending on whether
|
||||
one layer or two layers are being blended together. This messes up our
|
||||
benchmarks. We could just benchmark a single image, but since blended
|
||||
images are present for much of the day with the GNOME default background,
|
||||
we want to make sure that also performs well; for that reason we ship
|
||||
an "animated" background that animates super-slowly to use during
|
||||
performance tests; it will be in the blended state until 2030. -->
|
||||
<background>
|
||||
<starttime>
|
||||
<year>1990</year>
|
||||
<month>1</month>
|
||||
<day>1</day>
|
||||
<hour>0</hour>
|
||||
<minute>00</minute>
|
||||
<second>00</second>
|
||||
</starttime>
|
||||
|
||||
<!-- One transition that takes 40 years -->
|
||||
<transition type="overlay">
|
||||
<duration>1261440000.0</duration>
|
||||
<from>@datadir@/backgrounds/gnome/adwaita-morning.jpg</from>
|
||||
<to>@datadir@/backgrounds/gnome/adwaita-day.jpg</to>
|
||||
</transition>
|
||||
|
||||
<!-- A single slide doesn't work, so another slide for 1 minute after 40 years -->
|
||||
<static>
|
||||
<duration>60</duration>
|
||||
<file>/usr/share/backgrounds/gnome/Sandstone.jpg</file>
|
||||
</static>
|
||||
|
||||
</background>
|
@ -232,6 +232,10 @@ StScrollBar StButton#vhandle:active {
|
||||
border-width: 0px;
|
||||
}
|
||||
|
||||
.app-well-menu {
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
/* The remaining popup-menu sizing is all done in ems, so that if you
|
||||
* override .popup-menu.font-size, everything else will scale with it.
|
||||
*/
|
||||
@ -478,7 +482,7 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
/* Common radii */
|
||||
|
||||
#searchEntry,
|
||||
.search-entry,
|
||||
.modal-dialog-button,
|
||||
.notification-button,
|
||||
.hotplug-notification-item,
|
||||
@ -500,7 +504,7 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
/* Entries */
|
||||
|
||||
#searchEntry,
|
||||
.search-entry,
|
||||
.login-dialog StEntry,
|
||||
.notification StEntry,
|
||||
.modal-dialog StEntry {
|
||||
@ -512,7 +516,7 @@ StScrollBar StButton#vhandle:active {
|
||||
padding: 4px 12px;
|
||||
}
|
||||
|
||||
#searchEntry,
|
||||
.search-entry,
|
||||
.login-dialog StEntry,
|
||||
.run-dialog-entry,
|
||||
.notification StEntry {
|
||||
@ -524,8 +528,8 @@ StScrollBar StButton#vhandle:active {
|
||||
box-shadow: inset 0px 2px 4px rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
#searchEntry:focus,
|
||||
#searchEntry:hover,
|
||||
.search-entry:focus,
|
||||
.search-entry:hover,
|
||||
.login-dialog StEntry:focus,
|
||||
.notification StEntry:focus,
|
||||
.modal-dialog StEntry {
|
||||
@ -542,18 +546,18 @@ StScrollBar StButton#vhandle:active {
|
||||
border: 2px solid #3465a4;
|
||||
}
|
||||
|
||||
#searchEntry {
|
||||
.search-entry {
|
||||
border-color: rgba(245,245,245,0.3);
|
||||
color: rgb(192, 192, 192);
|
||||
caret-color: rgb(192, 192, 192);
|
||||
}
|
||||
|
||||
#searchEntry:hover {
|
||||
.search-entry:hover {
|
||||
color: rgb(128, 128, 128);
|
||||
caret-color: rgb(128, 128, 128);
|
||||
}
|
||||
|
||||
#searchEntry:focus {
|
||||
.search-entry:focus {
|
||||
color: rgb(64, 64, 64);
|
||||
caret-color: rgb(64, 64, 64);
|
||||
font-weight: bold;
|
||||
@ -917,7 +921,7 @@ StScrollBar StButton#vhandle:active {
|
||||
|
||||
/* Search Box */
|
||||
|
||||
#searchEntry {
|
||||
.search-entry {
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
@ -926,8 +930,8 @@ StScrollBar StButton#vhandle:active {
|
||||
color: #c0c0c0;
|
||||
}
|
||||
|
||||
#searchEntry:hover .search-entry-icon,
|
||||
#searchEntry:focus .search-entry-icon {
|
||||
.search-entry:hover .search-entry-icon,
|
||||
.search-entry:focus .search-entry-icon {
|
||||
color: #8d8f8a;
|
||||
}
|
||||
|
||||
@ -1159,6 +1163,7 @@ StScrollBar StButton#vhandle:active {
|
||||
.show-apps:checked > .overview-icon,
|
||||
.show-apps:active > .overview-icon,
|
||||
.search-provider-icon:active,
|
||||
.grid-search-result:active .overview-icon,
|
||||
.list-search-result:active {
|
||||
background-gradient-start: rgba(255, 255, 255, .05);
|
||||
background-gradient-end: rgba(255, 255, 255, .15);
|
||||
@ -1489,6 +1494,10 @@ StScrollBar StButton#vhandle:active {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.events-day-time-ellipses {
|
||||
color: rgba(153, 153, 153, 1.0);
|
||||
}
|
||||
|
||||
.events-day-time:rtl {
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -27,7 +27,9 @@ its dependencies to build from tarballs.</description>
|
||||
<download-page rdf:resource="http://download.gnome.org/sources/gnome-shell/" />
|
||||
<bug-database rdf:resource="https://bugzilla.gnome.org/browse.cgi?product=gnome-shell" />
|
||||
|
||||
<category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />
|
||||
<category rdf:resource="http://api.gnome.org/doap-extensions#core" />
|
||||
<programming-language>JavaScript</programming-language>
|
||||
<programming-language>C</programming-language>
|
||||
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
|
@ -59,14 +59,10 @@ const Application = new Lang.Class({
|
||||
|
||||
_extensionAvailable: function(uuid) {
|
||||
let extension = ExtensionUtils.extensions[uuid];
|
||||
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
|
||||
|
||||
if (!extension)
|
||||
return false;
|
||||
|
||||
if (checkVersion && ExtensionUtils.isOutOfDate(extension))
|
||||
return false;
|
||||
|
||||
if (!extension.dir.get_child('prefs.js').query_exists(null))
|
||||
return false;
|
||||
|
||||
@ -285,6 +281,10 @@ const ExtensionRow = new Lang.Class({
|
||||
function() {
|
||||
this._switch.state = this._isEnabled();
|
||||
}));
|
||||
this._settings.connect('changed::disable-extension-version-validation',
|
||||
Lang.bind(this, function() {
|
||||
this._switch.sensitive = this._canEnable();
|
||||
}));
|
||||
|
||||
this._buildUI();
|
||||
},
|
||||
@ -323,6 +323,7 @@ const ExtensionRow = new Lang.Class({
|
||||
this.prefsButton = button;
|
||||
|
||||
this._switch = new Gtk.Switch({ valign: Gtk.Align.CENTER,
|
||||
sensitive: this._canEnable(),
|
||||
state: this._isEnabled() });
|
||||
this._switch.connect('notify::active', Lang.bind(this,
|
||||
function() {
|
||||
@ -335,6 +336,13 @@ const ExtensionRow = new Lang.Class({
|
||||
hbox.add(this._switch);
|
||||
},
|
||||
|
||||
_canEnable: function() {
|
||||
let extension = ExtensionUtils.extensions[this.uuid];
|
||||
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
|
||||
|
||||
return !(checkVersion && ExtensionUtils.isOutOfDate(extension));
|
||||
},
|
||||
|
||||
_isEnabled: function() {
|
||||
let extensions = this._settings.get_strv('enabled-extensions');
|
||||
return extensions.indexOf(this.uuid) != -1;
|
||||
|
@ -134,8 +134,7 @@ const AuthPrompt = new Lang.Class({
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._userVerifier.clear();
|
||||
this._userVerifier.disconnectAll();
|
||||
this._userVerifier.destroy();
|
||||
this._userVerifier = null;
|
||||
},
|
||||
|
||||
@ -419,11 +418,13 @@ const AuthPrompt = new Lang.Class({
|
||||
},
|
||||
|
||||
setUser: function(user) {
|
||||
let oldChild = this._userWell.get_child();
|
||||
if (oldChild)
|
||||
oldChild.destroy();
|
||||
|
||||
if (user) {
|
||||
let userWidget = new UserWidget.UserWidget(user);
|
||||
this._userWell.set_child(userWidget.actor);
|
||||
} else {
|
||||
this._userWell.set_child(null);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -64,6 +64,8 @@ const UserListItem = new Lang.Class({
|
||||
reactive: true,
|
||||
x_align: St.Align.START,
|
||||
x_fill: true });
|
||||
this.actor.connect('destroy',
|
||||
Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._userWidget = new UserWidget.UserWidget(this.user);
|
||||
layout.add(this._userWidget.actor);
|
||||
@ -87,6 +89,10 @@ const UserListItem = new Lang.Class({
|
||||
this.actor.remove_style_pseudo_class('logged-in');
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
this._user.disconnect(this._userChangedId);
|
||||
},
|
||||
|
||||
_onClicked: function() {
|
||||
this.emit('activate');
|
||||
},
|
||||
@ -373,13 +379,12 @@ const LoginDialog = new Lang.Class({
|
||||
if (GLib.getenv('GDM_GREETER_TEST') != '1') {
|
||||
this._greeter = gdmClient.get_greeter_sync(null);
|
||||
|
||||
this._greeter.connect('default-session-name-changed',
|
||||
Lang.bind(this, this._onDefaultSessionChanged));
|
||||
|
||||
this._greeter.connect('session-opened',
|
||||
Lang.bind(this, this._onSessionOpened));
|
||||
this._greeter.connect('timed-login-requested',
|
||||
Lang.bind(this, this._onTimedLoginRequested));
|
||||
this._defaultSessionChangedId = this._greeter.connect('default-session-name-changed',
|
||||
Lang.bind(this, this._onDefaultSessionChanged));
|
||||
this._sessionOpenedId = this._greeter.connect('session-opened',
|
||||
Lang.bind(this, this._onSessionOpened));
|
||||
this._timedLoginRequestedId = this._greeter.connect('timed-login-requested',
|
||||
Lang.bind(this, this._onTimedLoginRequested));
|
||||
}
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA });
|
||||
@ -394,8 +399,8 @@ const LoginDialog = new Lang.Class({
|
||||
Lang.bind(this, this._updateLogo));
|
||||
|
||||
this._textureCache = St.TextureCache.get_default();
|
||||
this._textureCache.connect('texture-file-changed',
|
||||
Lang.bind(this, this._updateLogoTexture));
|
||||
this._updateLogoTextureId = this._textureCache.connect('texture-file-changed',
|
||||
Lang.bind(this, this._updateLogoTexture));
|
||||
|
||||
this._userSelectionBox = new St.BoxLayout({ style_class: 'login-dialog-user-selection-box',
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
@ -476,8 +481,8 @@ const LoginDialog = new Lang.Class({
|
||||
// If the user list is enabled, it should take key focus; make sure the
|
||||
// screen shield is initialized first to prevent it from stealing the
|
||||
// focus later
|
||||
Main.layoutManager.connect('startup-complete',
|
||||
Lang.bind(this, this._updateDisableUserList));
|
||||
this._startupCompleteId = Main.layoutManager.connect('startup-complete',
|
||||
Lang.bind(this, this._updateDisableUserList));
|
||||
},
|
||||
|
||||
_ensureUserListLoaded: function() {
|
||||
@ -665,10 +670,12 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_gotGreeterSessionProxy: function(proxy) {
|
||||
proxy.connect('g-properties-changed', Lang.bind(this, function() {
|
||||
if (proxy.Active)
|
||||
this._loginScreenSessionActivated();
|
||||
}));
|
||||
this._greeterSessionProxy = proxy;
|
||||
this._greeterSessionProxyChangedId =
|
||||
proxy.connect('g-properties-changed', Lang.bind(this, function() {
|
||||
if (proxy.Active)
|
||||
this._loginScreenSessionActivated();
|
||||
}));
|
||||
},
|
||||
|
||||
_startSession: function(serviceName) {
|
||||
@ -890,6 +897,30 @@ const LoginDialog = new Lang.Class({
|
||||
this._userManager.disconnect(this._userManagerLoadedId);
|
||||
this._userManagerLoadedId = 0;
|
||||
}
|
||||
if (this._userAddedId) {
|
||||
this._userManager.disconnect(this._userAddedId);
|
||||
this._userAddedId = 0;
|
||||
}
|
||||
if (this._userRemovedId) {
|
||||
this._userManager.disconnect(this._userRemovedId);
|
||||
this._userRemovedId = 0;
|
||||
}
|
||||
this._textureCache.disconnect(this._updateLogoTextureId);
|
||||
Main.layoutManager.disconnect(this._startupCompleteId);
|
||||
if (this._settings) {
|
||||
this._settings.run_dispose();
|
||||
this._settings = null;
|
||||
}
|
||||
if (this._greeter) {
|
||||
this._greeter.disconnect(this._defaultSessionChangedId);
|
||||
this._greeter.disconnect(this._sessionOpenedId);
|
||||
this._greeter.disconnect(this._timedLoginRequestedId);
|
||||
this._greeter = null;
|
||||
}
|
||||
if (this._greeterSessionProxy) {
|
||||
this._greeterSessionProxy.disconnect(this._greeterSessionProxyChangedId);
|
||||
this._greeterSessionProxy = null;
|
||||
}
|
||||
},
|
||||
|
||||
_loadUserList: function() {
|
||||
@ -904,15 +935,15 @@ const LoginDialog = new Lang.Class({
|
||||
this._userList.addUser(users[i]);
|
||||
}
|
||||
|
||||
this._userManager.connect('user-added',
|
||||
Lang.bind(this, function(userManager, user) {
|
||||
this._userList.addUser(user);
|
||||
}));
|
||||
this._userAddedId = this._userManager.connect('user-added',
|
||||
Lang.bind(this, function(userManager, user) {
|
||||
this._userList.addUser(user);
|
||||
}));
|
||||
|
||||
this._userManager.connect('user-removed',
|
||||
Lang.bind(this, function(userManager, user) {
|
||||
this._userList.removeUser(user);
|
||||
}));
|
||||
this._userRemovedId = this._userManager.connect('user-removed',
|
||||
Lang.bind(this, function(userManager, user) {
|
||||
this._userList.removeUser(user);
|
||||
}));
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
@ -926,6 +957,8 @@ const LoginDialog = new Lang.Class({
|
||||
this.actor.show();
|
||||
this.actor.opacity = 0;
|
||||
|
||||
Main.pushModal(this.actor, { keybindingMode: Shell.KeyBindingMode.LOGIN_SCREEN });
|
||||
|
||||
Tweener.addTween(this.actor,
|
||||
{ opacity: 255,
|
||||
time: 1,
|
||||
@ -935,7 +968,8 @@ const LoginDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
close: function() {
|
||||
Main.ctrlAltTabManager.removeGroup(this.dialogLayout);
|
||||
Main.popModal(this.actor);
|
||||
Main.ctrlAltTabManager.removeGroup(this.actor);
|
||||
},
|
||||
|
||||
cancel: function() {
|
||||
|
@ -142,10 +142,10 @@ const ShellUserVerifier = new Lang.Class({
|
||||
// after a user has been picked.
|
||||
this._checkForSmartcard();
|
||||
|
||||
this._smartcardManager.connect('smartcard-inserted',
|
||||
Lang.bind(this, this._checkForSmartcard));
|
||||
this._smartcardManager.connect('smartcard-removed',
|
||||
Lang.bind(this, this._checkForSmartcard));
|
||||
this._smartcardInsertedId = this._smartcardManager.connect('smartcard-inserted',
|
||||
Lang.bind(this, this._checkForSmartcard));
|
||||
this._smartcardRemovedId = this._smartcardManager.connect('smartcard-removed',
|
||||
Lang.bind(this, this._checkForSmartcard));
|
||||
|
||||
this._messageQueue = [];
|
||||
this._messageQueueTimeoutId = 0;
|
||||
@ -159,8 +159,8 @@ const ShellUserVerifier = new Lang.Class({
|
||||
if (this._oVirtCredentialsManager.hasToken())
|
||||
this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken());
|
||||
|
||||
this._oVirtCredentialsManager.connect('user-authenticated',
|
||||
Lang.bind(this, this._oVirtUserAuthenticated));
|
||||
this._oVirtUserAuthenticatedId = this._oVirtCredentialsManager.connect('user-authenticated',
|
||||
Lang.bind(this, this._oVirtUserAuthenticated));
|
||||
},
|
||||
|
||||
begin: function(userName, hold) {
|
||||
@ -191,20 +191,37 @@ const ShellUserVerifier = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_clearUserVerifier: function() {
|
||||
if (this._userVerifier) {
|
||||
this._userVerifier.run_dispose();
|
||||
this._userVerifier = null;
|
||||
}
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
if (this._cancellable) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable = null;
|
||||
}
|
||||
|
||||
if (this._userVerifier) {
|
||||
this._userVerifier.run_dispose();
|
||||
this._userVerifier = null;
|
||||
}
|
||||
|
||||
this._clearUserVerifier();
|
||||
this._clearMessageQueue();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.clear();
|
||||
|
||||
this._settings.run_dispose();
|
||||
this._settings = null;
|
||||
|
||||
this._smartcardManager.disconnect(this._smartcardInsertedId);
|
||||
this._smartcardManager.disconnect(this._smartcardRemovedId);
|
||||
this._smartcardManager = null;
|
||||
|
||||
this._oVirtCredentialsManager.disconnect(this._oVirtUserAuthenticatedId);
|
||||
this._oVirtCredentialsManager = null;
|
||||
},
|
||||
|
||||
answerQuery: function(serviceName, answer) {
|
||||
if (!this.hasPendingMessages) {
|
||||
this._userVerifier.call_answer_query(serviceName, answer, this._cancellable, null);
|
||||
@ -283,9 +300,10 @@ const ShellUserVerifier = new Lang.Class({
|
||||
|
||||
this._fprintManager.GetDefaultDeviceRemote(Gio.DBusCallFlags.NONE, this._cancellable, Lang.bind(this,
|
||||
function(device, error) {
|
||||
if (!error && device)
|
||||
if (!error && device) {
|
||||
this._haveFingerprintReader = true;
|
||||
this._updateDefaultService();
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
@ -326,6 +344,7 @@ const ShellUserVerifier = new Lang.Class({
|
||||
|
||||
_reauthenticationChannelOpened: function(client, result) {
|
||||
try {
|
||||
this._clearUserVerifier();
|
||||
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||
return;
|
||||
@ -349,6 +368,7 @@ const ShellUserVerifier = new Lang.Class({
|
||||
|
||||
_userVerifierGot: function(client, result) {
|
||||
try {
|
||||
this._clearUserVerifier();
|
||||
this._userVerifier = client.get_user_verifier_finish(result);
|
||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||
return;
|
||||
|
@ -16,7 +16,9 @@
|
||||
<file>misc/fileUtils.js</file>
|
||||
<file>misc/gnomeSession.js</file>
|
||||
<file>misc/history.js</file>
|
||||
<file>misc/ibusManager.js</file>
|
||||
<file>misc/jsParse.js</file>
|
||||
<file>misc/keyboardManager.js</file>
|
||||
<file>misc/loginManager.js</file>
|
||||
<file>misc/modemManager.js</file>
|
||||
<file>misc/objectManager.js</file>
|
||||
@ -42,6 +44,7 @@
|
||||
<file>ui/dash.js</file>
|
||||
<file>ui/dateMenu.js</file>
|
||||
<file>ui/dnd.js</file>
|
||||
<file>ui/edgeDragAction.js</file>
|
||||
<file>ui/endSessionDialog.js</file>
|
||||
<file>ui/environment.js</file>
|
||||
<file>ui/extensionDownloader.js</file>
|
||||
|
180
js/misc/ibusManager.js
Normal file
180
js/misc/ibusManager.js
Normal file
@ -0,0 +1,180 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
|
||||
try {
|
||||
var IBus = imports.gi.IBus;
|
||||
if (!('new_async' in IBus.Bus))
|
||||
throw "IBus version is too old";
|
||||
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
||||
} catch (e) {
|
||||
var IBus = null;
|
||||
log(e);
|
||||
}
|
||||
|
||||
let _ibusManager = null;
|
||||
|
||||
function getIBusManager() {
|
||||
if (_ibusManager == null)
|
||||
_ibusManager = new IBusManager();
|
||||
return _ibusManager;
|
||||
}
|
||||
|
||||
const IBusManager = new Lang.Class({
|
||||
Name: 'IBusManager',
|
||||
|
||||
// This is the longest we'll keep the keyboard frozen until an input
|
||||
// source is active.
|
||||
_MAX_INPUT_SOURCE_ACTIVATION_TIME: 4000, // ms
|
||||
|
||||
_init: function() {
|
||||
if (!IBus)
|
||||
return;
|
||||
|
||||
IBus.init();
|
||||
|
||||
this._candidatePopup = new IBusCandidatePopup.CandidatePopup();
|
||||
|
||||
this._panelService = null;
|
||||
this._engines = {};
|
||||
this._ready = false;
|
||||
this._registerPropertiesId = 0;
|
||||
this._currentEngineName = null;
|
||||
|
||||
this._ibus = IBus.Bus.new_async();
|
||||
this._ibus.connect('connected', Lang.bind(this, this._onConnected));
|
||||
this._ibus.connect('disconnected', Lang.bind(this, this._clear));
|
||||
// Need to set this to get 'global-engine-changed' emitions
|
||||
this._ibus.set_watch_ibus_signal(true);
|
||||
this._ibus.connect('global-engine-changed', Lang.bind(this, this._engineChanged));
|
||||
|
||||
this._spawn();
|
||||
},
|
||||
|
||||
_spawn: function() {
|
||||
try {
|
||||
Gio.Subprocess.new(['ibus-daemon', '--xim', '--panel', 'disable'],
|
||||
Gio.SubprocessFlags.NONE);
|
||||
} catch(e) {
|
||||
log('Failed to launch ibus-daemon: ' + e.message);
|
||||
}
|
||||
},
|
||||
|
||||
_clear: function() {
|
||||
if (this._panelService)
|
||||
this._panelService.destroy();
|
||||
|
||||
this._panelService = null;
|
||||
this._candidatePopup.setPanelService(null);
|
||||
this._engines = {};
|
||||
this._ready = false;
|
||||
this._registerPropertiesId = 0;
|
||||
this._currentEngineName = null;
|
||||
|
||||
this.emit('ready', false);
|
||||
|
||||
this._spawn();
|
||||
},
|
||||
|
||||
_onConnected: function() {
|
||||
this._ibus.list_engines_async(-1, null, Lang.bind(this, this._initEngines));
|
||||
this._ibus.request_name_async(IBus.SERVICE_PANEL,
|
||||
IBus.BusNameFlag.REPLACE_EXISTING,
|
||||
-1, null,
|
||||
Lang.bind(this, this._initPanelService));
|
||||
},
|
||||
|
||||
_initEngines: function(ibus, result) {
|
||||
let enginesList = this._ibus.list_engines_async_finish(result);
|
||||
if (enginesList) {
|
||||
for (let i = 0; i < enginesList.length; ++i) {
|
||||
let name = enginesList[i].get_name();
|
||||
this._engines[name] = enginesList[i];
|
||||
}
|
||||
this._updateReadiness();
|
||||
} else {
|
||||
this._clear();
|
||||
}
|
||||
},
|
||||
|
||||
_initPanelService: function(ibus, result) {
|
||||
let success = this._ibus.request_name_async_finish(result);
|
||||
if (success) {
|
||||
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
|
||||
object_path: IBus.PATH_PANEL });
|
||||
this._candidatePopup.setPanelService(this._panelService);
|
||||
this._panelService.connect('update-property', Lang.bind(this, this._updateProperty));
|
||||
// If an engine is already active we need to get its properties
|
||||
this._ibus.get_global_engine_async(-1, null, Lang.bind(this, function(i, result) {
|
||||
let engine;
|
||||
try {
|
||||
engine = this._ibus.get_global_engine_async_finish(result);
|
||||
if (!engine)
|
||||
return;
|
||||
} catch(e) {
|
||||
return;
|
||||
}
|
||||
this._engineChanged(this._ibus, engine.get_name());
|
||||
}));
|
||||
this._updateReadiness();
|
||||
} else {
|
||||
this._clear();
|
||||
}
|
||||
},
|
||||
|
||||
_updateReadiness: function() {
|
||||
this._ready = (Object.keys(this._engines).length > 0 &&
|
||||
this._panelService != null);
|
||||
this.emit('ready', this._ready);
|
||||
},
|
||||
|
||||
_engineChanged: function(bus, engineName) {
|
||||
if (!this._ready)
|
||||
return;
|
||||
|
||||
this._currentEngineName = engineName;
|
||||
|
||||
if (this._registerPropertiesId != 0)
|
||||
return;
|
||||
|
||||
this._registerPropertiesId =
|
||||
this._panelService.connect('register-properties', Lang.bind(this, function(p, props) {
|
||||
if (!props.get(0))
|
||||
return;
|
||||
|
||||
this._panelService.disconnect(this._registerPropertiesId);
|
||||
this._registerPropertiesId = 0;
|
||||
|
||||
this.emit('properties-registered', this._currentEngineName, props);
|
||||
}));
|
||||
},
|
||||
|
||||
_updateProperty: function(panel, prop) {
|
||||
this.emit('property-updated', this._currentEngineName, prop);
|
||||
},
|
||||
|
||||
activateProperty: function(key, state) {
|
||||
this._panelService.property_activate(key, state);
|
||||
},
|
||||
|
||||
getEngineDesc: function(id) {
|
||||
if (!IBus || !this._ready)
|
||||
return null;
|
||||
|
||||
return this._engines[id];
|
||||
},
|
||||
|
||||
setEngine: function(id, callback) {
|
||||
if (!IBus || !this._ready || id == this._currentEngineName) {
|
||||
if (callback)
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
|
||||
null, callback);
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(IBusManager.prototype);
|
153
js/misc/keyboardManager.js
Normal file
153
js/misc/keyboardManager.js
Normal file
@ -0,0 +1,153 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||
const Lang = imports.lang;
|
||||
const Meta = imports.gi.Meta;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const DEFAULT_LOCALE = 'en_US';
|
||||
const DEFAULT_LAYOUT = 'us';
|
||||
const DEFAULT_VARIANT = '';
|
||||
|
||||
let _xkbInfo = null;
|
||||
|
||||
function getXkbInfo() {
|
||||
if (_xkbInfo == null)
|
||||
_xkbInfo = new GnomeDesktop.XkbInfo();
|
||||
return _xkbInfo;
|
||||
}
|
||||
|
||||
let _keyboardManager = null;
|
||||
|
||||
function getKeyboardManager() {
|
||||
if (_keyboardManager == null)
|
||||
_keyboardManager = new KeyboardManager();
|
||||
return _keyboardManager;
|
||||
}
|
||||
|
||||
function releaseKeyboard() {
|
||||
if (Main.modalCount > 0)
|
||||
global.display.unfreeze_keyboard(global.get_current_time());
|
||||
else
|
||||
global.display.ungrab_keyboard(global.get_current_time());
|
||||
}
|
||||
|
||||
function holdKeyboard() {
|
||||
global.freeze_keyboard(global.get_current_time());
|
||||
}
|
||||
|
||||
const KeyboardManager = new Lang.Class({
|
||||
Name: 'KeyboardManager',
|
||||
|
||||
// The XKB protocol doesn't allow for more that 4 layouts in a
|
||||
// keymap. Wayland doesn't impose this limit and libxkbcommon can
|
||||
// handle up to 32 layouts but since we need to support X clients
|
||||
// even as a Wayland compositor, we can't bump this.
|
||||
MAX_LAYOUTS_PER_GROUP: 4,
|
||||
|
||||
_init: function() {
|
||||
this._xkbInfo = getXkbInfo();
|
||||
this._current = null;
|
||||
this._localeLayoutInfo = this._getLocaleLayout();
|
||||
this._layoutInfos = {};
|
||||
},
|
||||
|
||||
_applyLayoutGroup: function(group) {
|
||||
let options = this._buildOptionsString();
|
||||
let [layouts, variants] = this._buildGroupStrings(group);
|
||||
Meta.get_backend().set_keymap(layouts, variants, options);
|
||||
},
|
||||
|
||||
_applyLayoutGroupIndex: function(idx) {
|
||||
Meta.get_backend().lock_layout_group(idx);
|
||||
},
|
||||
|
||||
apply: function(id) {
|
||||
let info = this._layoutInfos[id];
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (this._current && this._current.group == info.group) {
|
||||
if (this._current.groupIndex != info.groupIndex)
|
||||
this._applyLayoutGroupIndex(info.groupIndex);
|
||||
} else {
|
||||
this._applyLayoutGroup(info.group);
|
||||
this._applyLayoutGroupIndex(info.groupIndex);
|
||||
}
|
||||
|
||||
this._current = info;
|
||||
},
|
||||
|
||||
reapply: function() {
|
||||
if (!this._current)
|
||||
return;
|
||||
|
||||
this._applyLayoutGroup(this._current.group);
|
||||
this._applyLayoutGroupIndex(this._current.groupIndex);
|
||||
},
|
||||
|
||||
setUserLayouts: function(ids) {
|
||||
this._current = null;
|
||||
this._layoutInfos = {};
|
||||
|
||||
for (let i = 0; i < ids.length; ++i) {
|
||||
let [found, , , _layout, _variant] = this._xkbInfo.get_layout_info(ids[i]);
|
||||
if (found)
|
||||
this._layoutInfos[ids[i]] = { id: ids[i], layout: _layout, variant: _variant };
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
let group = [];
|
||||
for (let id in this._layoutInfos) {
|
||||
// We need to leave one slot on each group free so that we
|
||||
// can add a layout containing the symbols for the
|
||||
// language used in UI strings to ensure that toolkits can
|
||||
// handle mnemonics like Alt+Ф even if the user is
|
||||
// actually typing in a different layout.
|
||||
let groupIndex = i % (this.MAX_LAYOUTS_PER_GROUP - 1);
|
||||
if (groupIndex == 0)
|
||||
group = [];
|
||||
|
||||
let info = this._layoutInfos[id];
|
||||
group[groupIndex] = info;
|
||||
info.group = group;
|
||||
info.groupIndex = groupIndex;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
},
|
||||
|
||||
_getLocaleLayout: function() {
|
||||
let locale = GLib.get_language_names()[0];
|
||||
if (locale.indexOf('_') == -1)
|
||||
locale = DEFAULT_LOCALE;
|
||||
|
||||
let [found, , id] = GnomeDesktop.get_input_source_from_locale(locale);
|
||||
if (!found)
|
||||
[, , id] = GnomeDesktop.get_input_source_from_locale(DEFAULT_LOCALE);
|
||||
|
||||
let [found, , , _layout, _variant] = this._xkbInfo.get_layout_info(id);
|
||||
if (found)
|
||||
return { layout: _layout, variant: _variant };
|
||||
else
|
||||
return { layout: DEFAULT_LAYOUT, variant: DEFAULT_VARIANT };
|
||||
},
|
||||
|
||||
_buildGroupStrings: function(_group) {
|
||||
let group = _group.concat(this._localeLayoutInfo);
|
||||
let layouts = group.map(function(g) { return g.layout; }).join(',');
|
||||
let variants = group.map(function(g) { return g.variant; }).join(',');
|
||||
return [layouts, variants];
|
||||
},
|
||||
|
||||
setKeyboardOptions: function(options) {
|
||||
this._xkbOptions = options;
|
||||
},
|
||||
|
||||
_buildOptionsString: function() {
|
||||
let options = this._xkbOptions.join(',');
|
||||
return options;
|
||||
}
|
||||
});
|
@ -188,7 +188,7 @@ function run() {
|
||||
////////////////////////////////////////
|
||||
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let app = appSys.lookup_app('gedit.desktop');
|
||||
let app = appSys.lookup_app('org.gnome.gedit.desktop');
|
||||
|
||||
Scripting.scriptEvent('geditLaunch');
|
||||
app.activate();
|
||||
@ -270,7 +270,7 @@ function script_redrawTestDone(time) {
|
||||
function script_collectTimings(time) {
|
||||
for (let timing in redrawTimes) {
|
||||
let times = redrawTimes[timing];
|
||||
times.sort();
|
||||
times.sort(function(a, b) { return a - b });
|
||||
|
||||
let len = times.length;
|
||||
let median;
|
||||
|
@ -49,13 +49,14 @@ const PortalWindow = new Lang.Class({
|
||||
_init: function(application, url, timestamp, doneCallback) {
|
||||
this.parent({ application: application });
|
||||
|
||||
if (url) {
|
||||
this._uri = new Soup.URI(uri);
|
||||
} else {
|
||||
if (!url) {
|
||||
url = 'http://www.gnome.org';
|
||||
this._uri = null;
|
||||
this._everSeenRedirect = false;
|
||||
this._originalUrlWasGnome = true;
|
||||
} else {
|
||||
this._originalUrlWasGnome = false;
|
||||
}
|
||||
this._uri = new Soup.URI(url);
|
||||
this._everSeenRedirect = false;
|
||||
this._originalUrl = url;
|
||||
this._doneCallback = doneCallback;
|
||||
this._lastRecheck = 0;
|
||||
@ -110,37 +111,7 @@ const PortalWindow = new Lang.Class({
|
||||
let request = decision.get_request();
|
||||
let uri = new Soup.URI(request.get_uri());
|
||||
|
||||
if (this._uri != null) {
|
||||
if (!uri.host_equal(uri, this._uri)) {
|
||||
// We *may* have finished here, but we don't know for
|
||||
// sure. Tell gnome-shell to run another connectivity check
|
||||
// (but ratelimit the checks, we don't want to spam
|
||||
// gnome.org for portals that have 10 or more internal
|
||||
// redirects - and unfortunately they exist)
|
||||
// If we hit the rate limit, we also queue a recheck
|
||||
// when the window is closed, just in case we miss the
|
||||
// final check and don't realize we're connected
|
||||
// This should not be a problem in the cancelled logic,
|
||||
// because if the user doesn't want to start the login,
|
||||
// we should not see any redirect at all, outside this._uri
|
||||
|
||||
let now = GLib.get_monotonic_time();
|
||||
let shouldRecheck = (now - this._lastRecheck) >
|
||||
CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT;
|
||||
|
||||
if (shouldRecheck) {
|
||||
this._lastRecheck = now;
|
||||
this._recheckAtExit = false;
|
||||
this._doneCallback(PortalHelperResult.RECHECK);
|
||||
} else {
|
||||
this._recheckAtExit = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the URI, in case of chained redirects, so we still
|
||||
// think we're doing the login until gnome-shell kills us
|
||||
this._uri = uri;
|
||||
} else {
|
||||
if (!uri.host_equal(this._uri) && this._originalUrlWasGnome) {
|
||||
if (uri.get_host() == 'www.gnome.org' && this._everSeenRedirect) {
|
||||
// Yay, we got to gnome!
|
||||
decision.ignore();
|
||||
@ -151,6 +122,34 @@ const PortalWindow = new Lang.Class({
|
||||
}
|
||||
}
|
||||
|
||||
// We *may* have finished here, but we don't know for
|
||||
// sure. Tell gnome-shell to run another connectivity check
|
||||
// (but ratelimit the checks, we don't want to spam
|
||||
// nmcheck.gnome.org for portals that have 10 or more internal
|
||||
// redirects - and unfortunately they exist)
|
||||
// If we hit the rate limit, we also queue a recheck
|
||||
// when the window is closed, just in case we miss the
|
||||
// final check and don't realize we're connected
|
||||
// This should not be a problem in the cancelled logic,
|
||||
// because if the user doesn't want to start the login,
|
||||
// we should not see any redirect at all, outside this._uri
|
||||
|
||||
let now = GLib.get_monotonic_time();
|
||||
let shouldRecheck = (now - this._lastRecheck) >
|
||||
CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT;
|
||||
|
||||
if (shouldRecheck) {
|
||||
this._lastRecheck = now;
|
||||
this._recheckAtExit = false;
|
||||
this._doneCallback(PortalHelperResult.RECHECK);
|
||||
} else {
|
||||
this._recheckAtExit = true;
|
||||
}
|
||||
|
||||
// Update the URI, in case of chained redirects, so we still
|
||||
// think we're doing the login until gnome-shell kills us
|
||||
this._uri = uri;
|
||||
|
||||
decision.use();
|
||||
return true;
|
||||
},
|
||||
|
@ -58,6 +58,14 @@ const AppSwitcherPopup = new Lang.Class({
|
||||
this._currentWindow = -1;
|
||||
|
||||
this.thumbnailsVisible = false;
|
||||
|
||||
let apps = Shell.AppSystem.get_default().get_running ();
|
||||
|
||||
if (apps.length == 0)
|
||||
return;
|
||||
|
||||
this._switcherList = new AppSwitcher(apps, this);
|
||||
this._items = this._switcherList.icons;
|
||||
},
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
@ -99,20 +107,6 @@ const AppSwitcherPopup = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_createSwitcher: function() {
|
||||
let apps = Shell.AppSystem.get_default().get_running ();
|
||||
|
||||
if (apps.length == 0)
|
||||
return false;
|
||||
|
||||
this._switcherList = new AppSwitcher(apps, this);
|
||||
this._items = this._switcherList.icons;
|
||||
if (this._items.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_initialSelection: function(backward, binding) {
|
||||
if (binding == 'switch-group') {
|
||||
if (backward) {
|
||||
@ -151,13 +145,13 @@ const AppSwitcherPopup = new Lang.Class({
|
||||
this._items[this._selectedIndex].cachedWindows.length);
|
||||
},
|
||||
|
||||
_keyPressHandler: function(keysym, backwards, action) {
|
||||
_keyPressHandler: function(keysym, action) {
|
||||
if (action == Meta.KeyBindingAction.SWITCH_GROUP) {
|
||||
this._select(this._selectedIndex, backwards ? this._previousWindow() : this._nextWindow());
|
||||
this._select(this._selectedIndex, this._nextWindow());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_GROUP_BACKWARD) {
|
||||
this._select(this._selectedIndex, this._previousWindow());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_APPLICATIONS) {
|
||||
this._select(backwards ? this._previous() : this._next());
|
||||
this._select(this._next());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD) {
|
||||
this._select(this._previous());
|
||||
} else if (this._thumbnailsFocused) {
|
||||
@ -365,9 +359,18 @@ const WindowSwitcherPopup = new Lang.Class({
|
||||
Name: 'WindowSwitcherPopup',
|
||||
Extends: SwitcherPopup.SwitcherPopup,
|
||||
|
||||
_init: function(items) {
|
||||
this.parent(items);
|
||||
_init: function() {
|
||||
this.parent();
|
||||
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.window-switcher' });
|
||||
|
||||
let windows = this._getWindowList();
|
||||
|
||||
if (windows.length == 0)
|
||||
return;
|
||||
|
||||
let mode = this._settings.get_enum('app-icon-mode');
|
||||
this._switcherList = new WindowList(windows, mode);
|
||||
this._items = this._switcherList.icons;
|
||||
},
|
||||
|
||||
_getWindowList: function() {
|
||||
@ -375,34 +378,9 @@ const WindowSwitcherPopup = new Lang.Class({
|
||||
return global.display.get_tab_list(Meta.TabList.NORMAL, workspace);
|
||||
},
|
||||
|
||||
_createSwitcher: function() {
|
||||
let windows = this._getWindowList();
|
||||
|
||||
if (windows.length == 0)
|
||||
return false;
|
||||
|
||||
let mode = this._settings.get_enum('app-icon-mode');
|
||||
this._switcherList = new WindowList(windows, mode);
|
||||
this._items = this._switcherList.icons;
|
||||
|
||||
if (this._items.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_initialSelection: function(backward, binding) {
|
||||
if (binding == 'switch-windows-backward' || backward)
|
||||
this._select(this._items.length - 1);
|
||||
else if (this._items.length == 1)
|
||||
this._select(0);
|
||||
else
|
||||
this._select(1);
|
||||
},
|
||||
|
||||
_keyPressHandler: function(keysym, backwards, action) {
|
||||
_keyPressHandler: function(keysym, action) {
|
||||
if (action == Meta.KeyBindingAction.SWITCH_WINDOWS) {
|
||||
this._select(backwards ? this._previous() : this._next());
|
||||
this._select(this._next());
|
||||
} else if (action == Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD) {
|
||||
this._select(this._previous());
|
||||
} else {
|
||||
|
@ -34,7 +34,9 @@ const MIN_COLUMNS = 4;
|
||||
const MIN_ROWS = 4;
|
||||
|
||||
const INACTIVE_GRID_OPACITY = 77;
|
||||
const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.40;
|
||||
// This time needs to be less than IconGrid.EXTRA_SPACE_ANIMATION_TIME
|
||||
// to not clash with other animations
|
||||
const INACTIVE_GRID_OPACITY_ANIMATION_TIME = 0.24;
|
||||
const FOLDER_SUBICON_FRACTION = .4;
|
||||
|
||||
const MIN_FREQUENT_APPS_COUNT = 3;
|
||||
@ -43,6 +45,16 @@ const INDICATORS_BASE_TIME = 0.25;
|
||||
const INDICATORS_ANIMATION_DELAY = 0.125;
|
||||
const INDICATORS_ANIMATION_MAX_TIME = 0.75;
|
||||
|
||||
// Follow iconGrid animations approach and divide by 2 to animate out to
|
||||
// not annoy the user when the user wants to quit appDisplay.
|
||||
// Also, make sure we don't exceed iconGrid animation total time or
|
||||
// views switch time.
|
||||
const INDICATORS_BASE_TIME_OUT = 0.125;
|
||||
const INDICATORS_ANIMATION_DELAY_OUT = 0.0625;
|
||||
const INDICATORS_ANIMATION_MAX_TIME_OUT =
|
||||
Math.min (VIEWS_SWITCH_TIME,
|
||||
IconGrid.ANIMATION_TIME_OUT + IconGrid.ANIMATION_MAX_DELAY_OUT_FOR_ITEM);
|
||||
|
||||
const PAGE_SWITCH_TIME = 0.3;
|
||||
|
||||
const VIEWS_SWITCH_TIME = 0.4;
|
||||
@ -177,26 +189,98 @@ const BaseAppView = new Lang.Class({
|
||||
this.selectApp(id);
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_doSpringAnimation: function(animationDirection) {
|
||||
this._grid.actor.opacity = 255;
|
||||
this._grid.animateSpring(animationDirection,
|
||||
Main.overview.getShowAppsButton());
|
||||
},
|
||||
|
||||
animate: function(animationDirection, onComplete) {
|
||||
if (animationDirection == IconGrid.AnimationDirection.IN) {
|
||||
let toAnimate = this._grid.actor.connect('notify::allocation', Lang.bind(this,
|
||||
function() {
|
||||
this._grid.actor.disconnect(toAnimate);
|
||||
// We need to hide the grid temporary to not flash it
|
||||
// for a frame
|
||||
this._grid.actor.opacity = 0;
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this, function() {
|
||||
this._doSpringAnimation(animationDirection)
|
||||
}));
|
||||
}));
|
||||
} else {
|
||||
this._doSpringAnimation(animationDirection);
|
||||
}
|
||||
|
||||
if (onComplete) {
|
||||
let animationDoneId = this._grid.connect('animation-done', Lang.bind(this,
|
||||
function () {
|
||||
this._grid.disconnect(animationDoneId);
|
||||
onComplete();
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
animateSwitch: function(animationDirection) {
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.removeTweens(this._grid.actor);
|
||||
|
||||
let params = { time: VIEWS_SWITCH_TIME,
|
||||
transition: 'easeOutQuad' };
|
||||
if (animationDirection == IconGrid.AnimationDirection.IN) {
|
||||
this.actor.show();
|
||||
params.opacity = 255;
|
||||
params.delay = VIEWS_SWITCH_ANIMATION_DELAY;
|
||||
} else {
|
||||
params.opacity = 0;
|
||||
params.delay = 0;
|
||||
params.onComplete = Lang.bind(this, function() { this.actor.hide() });
|
||||
}
|
||||
|
||||
Tweener.addTween(this._grid.actor, params);
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(BaseAppView.prototype);
|
||||
|
||||
const PageIndicatorsActor = new Lang.Class({
|
||||
Name:'PageIndicatorsActor',
|
||||
Extends: St.BoxLayout,
|
||||
|
||||
_init: function() {
|
||||
this.parent({ style_class: 'page-indicators',
|
||||
vertical: true,
|
||||
x_expand: true, y_expand: true,
|
||||
x_align: Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
reactive: true,
|
||||
clip_to_allocation: true });
|
||||
},
|
||||
|
||||
vfunc_get_preferred_height: function(forWidth) {
|
||||
// We want to request the natural height of all our children as our
|
||||
// natural height, so we chain up to St.BoxLayout, but we only request 0
|
||||
// as minimum height, since it's not that important if some indicators
|
||||
// are not shown
|
||||
let [, natHeight] = this.parent(forWidth);
|
||||
return [0, natHeight];
|
||||
}
|
||||
});
|
||||
|
||||
const PageIndicators = new Lang.Class({
|
||||
Name:'PageIndicators',
|
||||
|
||||
_init: function() {
|
||||
this.actor = new St.BoxLayout({ style_class: 'page-indicators',
|
||||
vertical: true,
|
||||
x_expand: true, y_expand: true,
|
||||
x_align: Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
reactive: true });
|
||||
this.actor = new PageIndicatorsActor();
|
||||
this._nPages = 0;
|
||||
this._currentPage = undefined;
|
||||
|
||||
this.actor.connect('notify::mapped',
|
||||
Lang.bind(this, this._animateIndicators));
|
||||
Lang.bind(this, function() {
|
||||
this.animateIndicators(IconGrid.AnimationDirection.IN);
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
setNPages: function(nPages) {
|
||||
@ -237,7 +321,7 @@ const PageIndicators = new Lang.Class({
|
||||
children[i].set_checked(i == this._currentPage);
|
||||
},
|
||||
|
||||
_animateIndicators: function() {
|
||||
animateIndicators: function(animationDirection) {
|
||||
if (!this.actor.mapped)
|
||||
return;
|
||||
|
||||
@ -245,24 +329,32 @@ const PageIndicators = new Lang.Class({
|
||||
if (children.length == 0)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < this._nPages; i++)
|
||||
Tweener.removeTweens(children[i]);
|
||||
|
||||
let offset;
|
||||
if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
|
||||
offset = -children[0].width;
|
||||
else
|
||||
offset = children[0].width;
|
||||
|
||||
let delay = INDICATORS_ANIMATION_DELAY;
|
||||
let totalAnimationTime = INDICATORS_BASE_TIME + INDICATORS_ANIMATION_DELAY * this._nPages;
|
||||
if (totalAnimationTime > INDICATORS_ANIMATION_MAX_TIME)
|
||||
delay -= (totalAnimationTime - INDICATORS_ANIMATION_MAX_TIME) / this._nPages;
|
||||
let isAnimationIn = animationDirection == IconGrid.AnimationDirection.IN;
|
||||
let delay = isAnimationIn ? INDICATORS_ANIMATION_DELAY :
|
||||
INDICATORS_ANIMATION_DELAY_OUT;
|
||||
let baseTime = isAnimationIn ? INDICATORS_BASE_TIME : INDICATORS_BASE_TIME_OUT;
|
||||
let totalAnimationTime = baseTime + delay * this._nPages;
|
||||
let maxTime = isAnimationIn ? INDICATORS_ANIMATION_MAX_TIME :
|
||||
INDICATORS_ANIMATION_MAX_TIME_OUT;
|
||||
if (totalAnimationTime > maxTime)
|
||||
delay -= (totalAnimationTime - maxTime) / this._nPages;
|
||||
|
||||
for (let i = 0; i < this._nPages; i++) {
|
||||
children[i].translation_x = offset;
|
||||
children[i].translation_x = isAnimationIn ? offset : 0;
|
||||
Tweener.addTween(children[i],
|
||||
{ translation_x: 0,
|
||||
time: INDICATORS_BASE_TIME + delay * i,
|
||||
{ translation_x: isAnimationIn ? 0 : offset,
|
||||
time: baseTime + delay * i,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: VIEWS_SWITCH_ANIMATION_DELAY
|
||||
delay: isAnimationIn ? VIEWS_SWITCH_ANIMATION_DELAY : 0
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -305,7 +397,7 @@ const AllView = new Lang.Class({
|
||||
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
|
||||
this._currentPage = 0;
|
||||
this._grid.currentPage = 0;
|
||||
this._stack.add_actor(this._grid.actor);
|
||||
this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true });
|
||||
this._stack.add_actor(this._eventBlocker);
|
||||
@ -437,14 +529,52 @@ const AllView = new Lang.Class({
|
||||
this._refilterApps();
|
||||
},
|
||||
|
||||
// Overriden from BaseAppView
|
||||
animate: function (animationDirection, onComplete) {
|
||||
if (animationDirection == IconGrid.AnimationDirection.OUT &&
|
||||
this._displayingPopup && this._currentPopup) {
|
||||
this._currentPopup.popdown();
|
||||
let spaceClosedId = this._grid.connect('space-closed', Lang.bind(this,
|
||||
function() {
|
||||
this._grid.disconnect(spaceClosedId);
|
||||
// Given that we can't call this.parent() inside the
|
||||
// signal handler, call again animate which will
|
||||
// call the parent given that popup is already
|
||||
// closed.
|
||||
this.animate(animationDirection, onComplete);
|
||||
}));
|
||||
} else {
|
||||
this.parent(animationDirection, onComplete);
|
||||
if (animationDirection == IconGrid.AnimationDirection.OUT)
|
||||
this._pageIndicators.animateIndicators(animationDirection);
|
||||
}
|
||||
},
|
||||
|
||||
animateSwitch: function(animationDirection) {
|
||||
this.parent(animationDirection);
|
||||
|
||||
if (this._currentPopup && this._displayingPopup &&
|
||||
animationDirection == IconGrid.AnimationDirection.OUT)
|
||||
Tweener.addTween(this._currentPopup.actor,
|
||||
{ time: VIEWS_SWITCH_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
opacity: 0,
|
||||
onComplete: function() {
|
||||
this.opacity = 255;
|
||||
} });
|
||||
|
||||
if (animationDirection == IconGrid.AnimationDirection.OUT)
|
||||
this._pageIndicators.animateIndicators(animationDirection);
|
||||
},
|
||||
|
||||
getCurrentPageY: function() {
|
||||
return this._grid.getPageY(this._currentPage);
|
||||
return this._grid.getPageY(this._grid.currentPage);
|
||||
},
|
||||
|
||||
goToPage: function(pageNumber) {
|
||||
pageNumber = clamp(pageNumber, 0, this._grid.nPages() - 1);
|
||||
|
||||
if (this._currentPage == pageNumber && this._displayingPopup && this._currentPopup)
|
||||
if (this._grid.currentPage == pageNumber && this._displayingPopup && this._currentPopup)
|
||||
return;
|
||||
if (this._displayingPopup && this._currentPopup)
|
||||
this._currentPopup.popdown();
|
||||
@ -464,7 +594,7 @@ const AllView = new Lang.Class({
|
||||
let time;
|
||||
// Only take the velocity into account on page changes, otherwise
|
||||
// return smoothly to the current page using the default velocity
|
||||
if (this._currentPage != pageNumber) {
|
||||
if (this._grid.currentPage != pageNumber) {
|
||||
let minVelocity = totalHeight / (PAGE_SWITCH_TIME * 1000);
|
||||
velocity = Math.max(minVelocity, velocity);
|
||||
time = (diffToPage / velocity) / 1000;
|
||||
@ -475,9 +605,9 @@ const AllView = new Lang.Class({
|
||||
// longer than PAGE_SWITCH_TIME
|
||||
time = Math.min(time, PAGE_SWITCH_TIME);
|
||||
|
||||
this._currentPage = pageNumber;
|
||||
this._grid.currentPage = pageNumber;
|
||||
Tweener.addTween(this._adjustment,
|
||||
{ value: this._grid.getPageY(this._currentPage),
|
||||
{ value: this._grid.getPageY(this._grid.currentPage),
|
||||
time: time,
|
||||
transition: 'easeOutQuad' });
|
||||
this._pageIndicators.setCurrentPage(pageNumber);
|
||||
@ -506,9 +636,9 @@ const AllView = new Lang.Class({
|
||||
|
||||
let direction = event.get_scroll_direction();
|
||||
if (direction == Clutter.ScrollDirection.UP)
|
||||
this.goToPage(this._currentPage - 1);
|
||||
this.goToPage(this._grid.currentPage - 1);
|
||||
else if (direction == Clutter.ScrollDirection.DOWN)
|
||||
this.goToPage(this._currentPage + 1);
|
||||
this.goToPage(this._grid.currentPage + 1);
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
},
|
||||
@ -548,10 +678,10 @@ const AllView = new Lang.Class({
|
||||
return Clutter.EVENT_STOP;
|
||||
|
||||
if (event.get_key_symbol() == Clutter.Page_Up) {
|
||||
this.goToPage(this._currentPage - 1);
|
||||
this.goToPage(this._grid.currentPage - 1);
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (event.get_key_symbol() == Clutter.Page_Down) {
|
||||
this.goToPage(this._currentPage + 1);
|
||||
this.goToPage(this._grid.currentPage + 1);
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
@ -612,6 +742,7 @@ const AllView = new Lang.Class({
|
||||
|
||||
if (this._availWidth != availWidth || this._availHeight != availHeight || oldNPages != this._grid.nPages()) {
|
||||
this._adjustment.value = 0;
|
||||
this._grid.currentPage = 0;
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
|
||||
function() {
|
||||
this._pageIndicators.setNPages(this._grid.nPages());
|
||||
@ -773,6 +904,19 @@ const AppDisplay = new Lang.Class({
|
||||
let layout = new ControlsBoxLayout({ homogeneous: true });
|
||||
this._controls = new St.Widget({ style_class: 'app-view-controls',
|
||||
layout_manager: layout });
|
||||
this._controls.connect('notify::mapped', Lang.bind(this,
|
||||
function() {
|
||||
// controls are faded either with their parent or
|
||||
// explicitly in animate(); we can't know how they'll be
|
||||
// shown next, so make sure to restore their opacity
|
||||
// when they are hidden
|
||||
if (this._controls.mapped)
|
||||
return;
|
||||
|
||||
Tweener.removeTweens(this._controls);
|
||||
this._controls.opacity = 255;
|
||||
}));
|
||||
|
||||
layout.hookup_style(this._controls);
|
||||
this.actor.add_actor(new St.Bin({ child: this._controls }));
|
||||
|
||||
@ -796,23 +940,39 @@ const AppDisplay = new Lang.Class({
|
||||
this._updateFrequentVisibility();
|
||||
},
|
||||
|
||||
animate: function(animationDirection, onComplete) {
|
||||
let currentView = this._views[global.settings.get_uint('app-picker-view')].view;
|
||||
|
||||
// Animate controls opacity using iconGrid animation time, since
|
||||
// it will be the time the AllView or FrequentView takes to show
|
||||
// it entirely.
|
||||
let finalOpacity;
|
||||
if (animationDirection == IconGrid.AnimationDirection.IN) {
|
||||
this._controls.opacity = 0;
|
||||
finalOpacity = 255;
|
||||
} else {
|
||||
finalOpacity = 0
|
||||
}
|
||||
|
||||
Tweener.addTween(this._controls,
|
||||
{ time: IconGrid.ANIMATION_TIME_IN,
|
||||
transition: 'easeInOutQuad',
|
||||
opacity: finalOpacity,
|
||||
});
|
||||
|
||||
currentView.animate(animationDirection, onComplete);
|
||||
},
|
||||
|
||||
_showView: function(activeIndex) {
|
||||
for (let i = 0; i < this._views.length; i++) {
|
||||
let actor = this._views[i].view.actor;
|
||||
|
||||
let params = { time: VIEWS_SWITCH_TIME,
|
||||
opacity: (i == activeIndex) ? 255 : 0,
|
||||
delay: (i == activeIndex) ? VIEWS_SWITCH_ANIMATION_DELAY : 0 };
|
||||
if (i == activeIndex)
|
||||
actor.visible = true;
|
||||
else
|
||||
params.onComplete = function() { actor.hide(); };
|
||||
Tweener.addTween(actor, params);
|
||||
|
||||
if (i == activeIndex)
|
||||
this._views[i].control.add_style_pseudo_class('checked');
|
||||
else
|
||||
this._views[i].control.remove_style_pseudo_class('checked');
|
||||
|
||||
let animationDirection = i == activeIndex ? IconGrid.AnimationDirection.IN :
|
||||
IconGrid.AnimationDirection.OUT;
|
||||
this._views[i].view.animateSwitch(animationDirection);
|
||||
}
|
||||
},
|
||||
|
||||
@ -894,26 +1054,6 @@ const AppSearchProvider = new Lang.Class({
|
||||
this.getInitialResultSet(terms, callback, cancellable);
|
||||
},
|
||||
|
||||
activateResult: function(result) {
|
||||
let app = this._appSys.lookup_app(result);
|
||||
let event = Clutter.get_current_event();
|
||||
let modifiers = event ? event.get_state() : 0;
|
||||
let openNewWindow = modifiers & Clutter.ModifierType.CONTROL_MASK;
|
||||
|
||||
if (openNewWindow)
|
||||
app.open_new_window(-1);
|
||||
else
|
||||
app.activate();
|
||||
},
|
||||
|
||||
dragActivateResult: function(id, params) {
|
||||
params = Params.parse(params, { workspace: -1,
|
||||
timestamp: 0 });
|
||||
|
||||
let app = this._appSys.lookup_app(id);
|
||||
app.open_new_window(workspace);
|
||||
},
|
||||
|
||||
createResultObject: function (resultMeta) {
|
||||
let app = this._appSys.lookup_app(resultMeta['id']);
|
||||
return new AppIcon(app);
|
||||
@ -945,8 +1085,13 @@ const FolderView = new Lang.Class({
|
||||
Util.ensureActorVisibleInScrollView(this.actor, actor);
|
||||
},
|
||||
|
||||
// Overriden from BaseAppView
|
||||
animate: function(animationDirection) {
|
||||
this._grid.animatePulse(animationDirection);
|
||||
},
|
||||
|
||||
createFolderIcon: function(size) {
|
||||
let layout = new Clutter.TableLayout();
|
||||
let layout = new Clutter.GridLayout();
|
||||
let icon = new St.Widget({ layout_manager: layout,
|
||||
style_class: 'app-folder-icon' });
|
||||
layout.hookup_style(icon);
|
||||
@ -962,7 +1107,7 @@ const FolderView = new Lang.Class({
|
||||
} else {
|
||||
bin = new St.Bin({ width: subSize, height: subSize });
|
||||
}
|
||||
layout.pack(bin, rtl ? (i + 1) % 2 : i % 2, Math.floor(i / 2));
|
||||
layout.attach(bin, rtl ? (i + 1) % 2 : i % 2, Math.floor(i / 2), 1, 1);
|
||||
}
|
||||
|
||||
return icon;
|
||||
@ -1122,6 +1267,7 @@ const FolderIcon = new Lang.Class({
|
||||
addAppId(appInfo.get_id());
|
||||
});
|
||||
|
||||
this.actor.visible = this.view.getAllItems().length > 0;
|
||||
this.view.loadGrid();
|
||||
this.emit('apps-changed');
|
||||
},
|
||||
@ -1320,8 +1466,17 @@ const AppFolderPopup = new Lang.Class({
|
||||
this.actor.show();
|
||||
|
||||
this._boxPointer.setArrowActor(this._source.actor);
|
||||
// We need to hide the icons of the view until the boxpointer animation
|
||||
// is completed so we can animate the icons after as we like without
|
||||
// showing them while boxpointer is animating.
|
||||
this._view.actor.opacity = 0;
|
||||
this._boxPointer.show(BoxPointer.PopupAnimation.FADE |
|
||||
BoxPointer.PopupAnimation.SLIDE);
|
||||
BoxPointer.PopupAnimation.SLIDE,
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
this._view.actor.opacity = 255;
|
||||
this._view.animate(IconGrid.AnimationDirection.IN);
|
||||
}));
|
||||
|
||||
this.emit('open-state-changed', true);
|
||||
},
|
||||
@ -1382,7 +1537,9 @@ const AppIcon = new Lang.Class({
|
||||
|
||||
this.actor.label_actor = this.icon.label;
|
||||
|
||||
this.actor.connect('leave-event', Lang.bind(this, this._onLeaveEvent));
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent));
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
this.actor.connect('popup-menu', Lang.bind(this, this._onKeyboardPopupMenu));
|
||||
|
||||
@ -1407,10 +1564,11 @@ const AppIcon = new Lang.Class({
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._menuTimeoutId = 0;
|
||||
this._stateChangedId = this.app.connect('notify::state',
|
||||
Lang.bind(this,
|
||||
this._onStateChanged));
|
||||
this._onStateChanged();
|
||||
this._stateChangedId = this.app.connect('notify::state', Lang.bind(this,
|
||||
function () {
|
||||
this._updateRunningStyle();
|
||||
}));
|
||||
this._updateRunningStyle();
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
@ -1431,24 +1589,33 @@ const AppIcon = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_onStateChanged: function() {
|
||||
_updateRunningStyle: function() {
|
||||
if (this.app.state != Shell.AppState.STOPPED)
|
||||
this.actor.add_style_class_name('running');
|
||||
else
|
||||
this.actor.remove_style_class_name('running');
|
||||
},
|
||||
|
||||
_setPopupTimeout: function() {
|
||||
this._removeMenuTimeout();
|
||||
this._menuTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT,
|
||||
Lang.bind(this, function() {
|
||||
this._menuTimeoutId = 0;
|
||||
this.popupMenu();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
GLib.Source.set_name_by_id(this._menuTimeoutId, '[gnome-shell] this.popupMenu');
|
||||
},
|
||||
|
||||
_onLeaveEvent: function(actor, event) {
|
||||
this.actor.fake_release();
|
||||
this._removeMenuTimeout();
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
let button = event.get_button();
|
||||
if (button == 1) {
|
||||
this._removeMenuTimeout();
|
||||
this._menuTimeoutId = Mainloop.timeout_add(MENU_POPUP_TIMEOUT,
|
||||
Lang.bind(this, function() {
|
||||
this._menuTimeoutId = 0;
|
||||
this.popupMenu();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}));
|
||||
GLib.Source.set_name_by_id(this._menuTimeoutId, '[gnome-shell] this.popupMenu');
|
||||
this._setPopupTimeout();
|
||||
} else if (button == 3) {
|
||||
this.popupMenu();
|
||||
return Clutter.EVENT_STOP;
|
||||
@ -1456,16 +1623,16 @@ const AppIcon = new Lang.Class({
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onTouchEvent: function (actor, event) {
|
||||
if (event.type() == Clutter.EventType.TOUCH_BEGIN)
|
||||
this._setPopupTimeout();
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onClicked: function(actor, button) {
|
||||
this._removeMenuTimeout();
|
||||
|
||||
if (button == 1) {
|
||||
this._onActivate(Clutter.get_current_event());
|
||||
} else if (button == 2) {
|
||||
this.app.open_new_window(-1);
|
||||
Main.overview.hide();
|
||||
}
|
||||
return false;
|
||||
this.activate(button);
|
||||
},
|
||||
|
||||
_onKeyboardPopupMenu: function() {
|
||||
@ -1519,19 +1686,29 @@ const AppIcon = new Lang.Class({
|
||||
this.emit('menu-state-changed', false);
|
||||
},
|
||||
|
||||
_onActivate: function (event) {
|
||||
let modifiers = event.get_state();
|
||||
activate: function (button) {
|
||||
let event = Clutter.get_current_event();
|
||||
let modifiers = event ? event.get_state() : 0;
|
||||
let openNewWindow = this.app.can_open_new_window () &&
|
||||
modifiers & Clutter.ModifierType.CONTROL_MASK &&
|
||||
this.app.state == Shell.AppState.RUNNING ||
|
||||
button && button == 2;
|
||||
|
||||
if (modifiers & Clutter.ModifierType.CONTROL_MASK
|
||||
&& this.app.state == Shell.AppState.RUNNING) {
|
||||
if (this.app.state == Shell.AppState.STOPPED || openNewWindow)
|
||||
this.animateLaunch();
|
||||
|
||||
if (openNewWindow)
|
||||
this.app.open_new_window(-1);
|
||||
} else {
|
||||
else
|
||||
this.app.activate();
|
||||
}
|
||||
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
animateLaunch: function() {
|
||||
this.icon.animateZoomOut();
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch : function(params) {
|
||||
params = Params.parse(params, { workspace: -1,
|
||||
timestamp: 0 });
|
||||
@ -1610,12 +1787,17 @@ const AppIconMenu = new Lang.Class({
|
||||
if (!this._source.app.is_window_backed()) {
|
||||
this._appendSeparator();
|
||||
|
||||
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
|
||||
this._newWindowMenuItem.connect('activate', Lang.bind(this, function() {
|
||||
this._source.app.open_new_window(-1);
|
||||
this.emit('activate-window', null);
|
||||
}));
|
||||
this._appendSeparator();
|
||||
if (this._source.app.can_open_new_window()) {
|
||||
this._newWindowMenuItem = this._appendMenuItem(_("New Window"));
|
||||
this._newWindowMenuItem.connect('activate', Lang.bind(this, function() {
|
||||
if (this._source.app.state == Shell.AppState.STOPPED)
|
||||
this._source.animateLaunch();
|
||||
|
||||
this._source.app.open_new_window(-1);
|
||||
this.emit('activate-window', null);
|
||||
}));
|
||||
this._appendSeparator();
|
||||
}
|
||||
|
||||
let appInfo = this._source.app.get_app_info();
|
||||
let actions = appInfo.list_actions();
|
||||
|
@ -14,7 +14,13 @@ const RENAMED_DESKTOP_IDS = {
|
||||
'gcalctool.desktop': 'gnome-calculator.desktop',
|
||||
'gedit.desktop': 'org.gnome.gedit.desktop',
|
||||
'glchess.desktop': 'gnome-chess.desktop',
|
||||
'glines.desktop': 'five-or-more.desktop',
|
||||
'gnect.desktop': 'four-in-a-row.desktop',
|
||||
'gnibbles.desktop': 'gnome-nibbles.desktop',
|
||||
'gnobots2.desktop': 'gnome-robots.desktop',
|
||||
'gnome-boxes.desktop': 'org.gnome.Boxes.desktop',
|
||||
'gnome-clocks.desktop': 'org.gnome.clocks.desktop',
|
||||
'gnome-contacts.desktop': 'org.gnome.Contacts.desktop',
|
||||
'gnome-documents.desktop': 'org.gnome.Documents.desktop',
|
||||
'gnome-font-viewer.desktop': 'org.gnome.font-viewer.desktop',
|
||||
'gnome-photos.desktop': 'org.gnome.Photos.desktop',
|
||||
@ -22,8 +28,12 @@ const RENAMED_DESKTOP_IDS = {
|
||||
'gnome-software.desktop': 'org.gnome.Software.desktop',
|
||||
'gnome-weather.desktop': 'org.gnome.Weather.Application.desktop',
|
||||
'gnomine.desktop': 'gnome-mines.desktop',
|
||||
'gnotravex.desktop': 'gnome-tetravex.desktop',
|
||||
'gnotski.desktop': 'gnome-klotski.desktop',
|
||||
'gtali.desktop': 'tali.desktop',
|
||||
'nautilus.desktop': 'org.gnome.Nautilus.desktop',
|
||||
'polari.desktop': 'org.gnome.Polari.desktop',
|
||||
'totem.desktop': 'org.gnome.Totem.desktop',
|
||||
};
|
||||
|
||||
const AppFavorites = new Lang.Class({
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -33,8 +33,7 @@ function addBackgroundMenu(actor, layoutManager) {
|
||||
actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
|
||||
actor._backgroundManager.addMenu(actor._backgroundMenu);
|
||||
|
||||
function openMenu() {
|
||||
let [x, y] = global.get_pointer();
|
||||
function openMenu(x, y) {
|
||||
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
|
||||
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
|
||||
}
|
||||
@ -42,16 +41,21 @@ function addBackgroundMenu(actor, layoutManager) {
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('long-press', function(action, actor, state) {
|
||||
if (state == Clutter.LongPressState.QUERY)
|
||||
return action.get_button() == 1 && !actor._backgroundMenu.isOpen;
|
||||
return ((action.get_button() == 0 ||
|
||||
action.get_button() == 1) &&
|
||||
!actor._backgroundMenu.isOpen);
|
||||
if (state == Clutter.LongPressState.ACTIVATE) {
|
||||
openMenu();
|
||||
let [x, y] = action.get_coords();
|
||||
openMenu(x, y);
|
||||
actor._backgroundManager.ignoreRelease();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
clickAction.connect('clicked', function(action) {
|
||||
if (action.get_button() == 3)
|
||||
openMenu();
|
||||
if (action.get_button() == 3) {
|
||||
let [x, y] = action.get_coords();
|
||||
openMenu(x, y);
|
||||
}
|
||||
});
|
||||
actor.add_action(clickAction);
|
||||
|
||||
|
@ -13,6 +13,7 @@ const Shell = imports.gi.Shell;
|
||||
|
||||
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
const SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||
const ELLIPSIS_CHAR = '\u2026';
|
||||
|
||||
// alias to prevent xgettext from picking up strings translated in GTK+
|
||||
const gtk30_ = Gettext_gtk30.gettext;
|
||||
@ -58,19 +59,21 @@ function _getEndOfDay(date) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function _formatEventTime(event, clockFormat) {
|
||||
function _formatEventTime(event, clockFormat, periodBegin, periodEnd) {
|
||||
let ret;
|
||||
if (event.allDay) {
|
||||
let allDay = (event.allDay || (event.date <= periodBegin && event.end >= periodEnd));
|
||||
if (allDay) {
|
||||
/* Translators: Shown in calendar event list for all day events
|
||||
* Keep it short, best if you can use less then 10 characters
|
||||
*/
|
||||
ret = C_("event list time", "All Day");
|
||||
} else {
|
||||
let date = event.date >= periodBegin ? event.date : event.end;
|
||||
switch (clockFormat) {
|
||||
case '24h':
|
||||
/* Translators: Shown in calendar event list, if 24h format,
|
||||
\u2236 is a ratio character, similar to : */
|
||||
ret = event.date.toLocaleFormat(C_("event list time", "%H\u2236%M"));
|
||||
ret = date.toLocaleFormat(C_("event list time", "%H\u2236%M"));
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -79,7 +82,7 @@ function _formatEventTime(event, clockFormat) {
|
||||
/* Translators: Shown in calendar event list, if 12h format,
|
||||
\u2236 is a ratio character, similar to : and \u2009 is
|
||||
a thin space */
|
||||
ret = event.date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p"));
|
||||
ret = date.toLocaleFormat(C_("event list time", "%l\u2236%M\u2009%p"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -361,6 +364,12 @@ const DBusEventSource = new Lang.Class({
|
||||
result.push(event);
|
||||
}
|
||||
}
|
||||
result.sort(function(event1, event2) {
|
||||
// sort events by end time on ending day
|
||||
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
|
||||
let d2 = event2.date < begin && event2.end <= end ? event2.end : event2.date;
|
||||
return d1.getTime() - d2.getTime();
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
@ -409,7 +418,7 @@ const Calendar = new Lang.Class({
|
||||
this._shouldDateGrabFocus = false;
|
||||
|
||||
this.actor = new St.Widget({ style_class: 'calendar',
|
||||
layout_manager: new Clutter.TableLayout(),
|
||||
layout_manager: new Clutter.GridLayout(),
|
||||
reactive: true });
|
||||
|
||||
this.actor.connect('scroll-event',
|
||||
@ -447,8 +456,7 @@ const Calendar = new Lang.Class({
|
||||
|
||||
// Top line of the calendar '<| September 2009 |>'
|
||||
this._topBox = new St.BoxLayout();
|
||||
layout.pack(this._topBox, 0, 0);
|
||||
layout.set_span(this._topBox, offsetCols + 7, 1);
|
||||
layout.attach(this._topBox, 0, 0, offsetCols + 7, 1);
|
||||
|
||||
this._backButton = new St.Button({ style_class: 'calendar-change-month-back',
|
||||
accessible_name: _("Previous month"),
|
||||
@ -485,7 +493,7 @@ const Calendar = new Lang.Class({
|
||||
col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
|
||||
else
|
||||
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
|
||||
layout.pack(label, col, 1);
|
||||
layout.attach(label, col, 1, 1, 1);
|
||||
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||
}
|
||||
|
||||
@ -657,14 +665,14 @@ const Calendar = new Lang.Class({
|
||||
col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
|
||||
else
|
||||
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
|
||||
layout.pack(button, col, row);
|
||||
layout.attach(button, col, row, 1, 1);
|
||||
|
||||
this._buttons.push(button);
|
||||
|
||||
if (this._useWeekdate && iter.getDay() == 4) {
|
||||
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
|
||||
style_class: 'calendar-day-base calendar-week-number'});
|
||||
layout.pack(label, rtl ? 7 : 0, row);
|
||||
layout.attach(label, rtl ? 7 : 0, row, 1, 1);
|
||||
}
|
||||
|
||||
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||
@ -707,7 +715,7 @@ const EventsList = new Lang.Class({
|
||||
Name: 'EventsList',
|
||||
|
||||
_init: function() {
|
||||
let layout = new Clutter.TableLayout();
|
||||
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
|
||||
this.actor = new St.Widget({ style_class: 'events-table',
|
||||
layout_manager: layout });
|
||||
layout.hookup_style(this.actor);
|
||||
@ -722,68 +730,82 @@ const EventsList = new Lang.Class({
|
||||
this._eventSource.connect('changed', Lang.bind(this, this._update));
|
||||
},
|
||||
|
||||
_addEvent: function(event, index, includeDayName) {
|
||||
_addEvent: function(event, index, includeDayName, periodBegin, periodEnd) {
|
||||
let dayString;
|
||||
if (includeDayName)
|
||||
dayString = _getEventDayAbbreviation(event.date.getDay());
|
||||
else
|
||||
if (includeDayName) {
|
||||
if (event.date >= periodBegin)
|
||||
dayString = _getEventDayAbbreviation(event.date.getDay());
|
||||
else /* show event end day if it began earlier */
|
||||
dayString = _getEventDayAbbreviation(event.end.getDay());
|
||||
} else {
|
||||
dayString = '';
|
||||
}
|
||||
|
||||
let dayLabel = new St.Label({ style_class: 'events-day-dayname',
|
||||
text: dayString });
|
||||
text: dayString,
|
||||
x_align: Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.START });
|
||||
dayLabel.clutter_text.line_wrap = false;
|
||||
dayLabel.clutter_text.ellipsize = false;
|
||||
|
||||
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
|
||||
|
||||
let layout = this.actor.layout_manager;
|
||||
layout.pack(dayLabel, rtl ? 2 : 0, index);
|
||||
layout.child_set(dayLabel, { x_expand: false,
|
||||
x_align: Clutter.TableAlignment.END,
|
||||
y_align: Clutter.TableAlignment.START });
|
||||
|
||||
layout.attach(dayLabel, rtl ? 2 : 0, index, 1, 1);
|
||||
let clockFormat = this._desktopSettings.get_string(CLOCK_FORMAT_KEY);
|
||||
let timeString = _formatEventTime(event, clockFormat);
|
||||
let timeString = _formatEventTime(event, clockFormat, periodBegin, periodEnd);
|
||||
let timeLabel = new St.Label({ style_class: 'events-day-time',
|
||||
text: timeString });
|
||||
text: timeString,
|
||||
y_align: Clutter.ActorAlign.START });
|
||||
timeLabel.clutter_text.line_wrap = false;
|
||||
timeLabel.clutter_text.ellipsize = false;
|
||||
|
||||
layout.pack(timeLabel, 1, index);
|
||||
layout.child_set(timeLabel, { x_expand: false,
|
||||
y_align: Clutter.TableAlignment.START });
|
||||
let preEllipsisLabel = new St.Label({ style_class: 'events-day-time-ellipses',
|
||||
text: ELLIPSIS_CHAR,
|
||||
y_align: Clutter.ActorAlign.START });
|
||||
let postEllipsisLabel = new St.Label({ style_class: 'events-day-time-ellipses',
|
||||
text: ELLIPSIS_CHAR,
|
||||
y_align: Clutter.ActorAlign.START });
|
||||
if (event.allDay || event.date >= periodBegin)
|
||||
preEllipsisLabel.opacity = 0;
|
||||
if (event.allDay || event.end <= periodEnd)
|
||||
postEllipsisLabel.opacity = 0;
|
||||
|
||||
let timeLabelBoxLayout = new St.BoxLayout();
|
||||
timeLabelBoxLayout.add(preEllipsisLabel);
|
||||
timeLabelBoxLayout.add(timeLabel);
|
||||
timeLabelBoxLayout.add(postEllipsisLabel);
|
||||
layout.attach(timeLabelBoxLayout, 1, index, 1, 1);
|
||||
|
||||
let titleLabel = new St.Label({ style_class: 'events-day-task',
|
||||
text: event.summary });
|
||||
text: event.summary,
|
||||
x_expand: true });
|
||||
titleLabel.clutter_text.line_wrap = true;
|
||||
titleLabel.clutter_text.ellipsize = false;
|
||||
|
||||
layout.pack(titleLabel, rtl ? 0 : 2, index);
|
||||
layout.child_set(titleLabel, { x_expand: true });
|
||||
layout.attach(titleLabel, rtl ? 0 : 2, index, 1, 1);
|
||||
},
|
||||
|
||||
_addPeriod: function(header, index, begin, end, includeDayName, showNothingScheduled) {
|
||||
let events = this._eventSource.getEvents(begin, end);
|
||||
_addPeriod: function(header, index, periodBegin, periodEnd, includeDayName, showNothingScheduled) {
|
||||
let events = this._eventSource.getEvents(periodBegin, periodEnd);
|
||||
|
||||
if (events.length == 0 && !showNothingScheduled)
|
||||
return index;
|
||||
|
||||
let label = new St.Label({ style_class: 'events-day-header', text: header });
|
||||
let layout = this.actor.layout_manager;
|
||||
layout.pack(label, 0, index);
|
||||
layout.child_set(label, { column_span: 3, x_expand: false });
|
||||
layout.attach(label, 0, index, 3, 1);
|
||||
index++;
|
||||
|
||||
for (let n = 0; n < events.length; n++) {
|
||||
this._addEvent(events[n], index, includeDayName);
|
||||
this._addEvent(events[n], index, includeDayName, periodBegin, periodEnd);
|
||||
index++;
|
||||
}
|
||||
|
||||
if (events.length == 0 && showNothingScheduled) {
|
||||
let now = new Date();
|
||||
/* Translators: Text to show if there are no events */
|
||||
let nothingEvent = new CalendarEvent(now, now, _("Nothing Scheduled"), true);
|
||||
this._addEvent(nothingEvent, index, false);
|
||||
let nothingEvent = new CalendarEvent(periodBegin, periodBegin, _("Nothing Scheduled"), true);
|
||||
this._addEvent(nothingEvent, index, false, periodBegin, periodEnd);
|
||||
index++;
|
||||
}
|
||||
|
||||
|
@ -80,44 +80,58 @@ const KeyringDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_buildControlTable: function() {
|
||||
let layout = new Clutter.TableLayout();
|
||||
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
|
||||
let table = new St.Widget({ style_class: 'keyring-dialog-control-table',
|
||||
layout_manager: layout });
|
||||
layout.hookup_style(table);
|
||||
let rtl = table.get_text_direction() == Clutter.TextDirection.RTL;
|
||||
let row = 0;
|
||||
|
||||
if (this.prompt.password_visible) {
|
||||
let label = new St.Label({ style_class: 'prompt-dialog-password-label' });
|
||||
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
label.set_text(_("Password:"));
|
||||
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
layout.pack(label, 0, row);
|
||||
layout.child_set(label, { x_expand: false, y_fill: false,
|
||||
x_align: Clutter.TableAlignment.START });
|
||||
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||
text: '',
|
||||
can_focus: true });
|
||||
can_focus: true,
|
||||
x_expand: true });
|
||||
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
|
||||
this._passwordEntry.clutter_text.connect('activate', Lang.bind(this, this._onPasswordActivate));
|
||||
layout.pack(this._passwordEntry, 1, row);
|
||||
|
||||
if (rtl) {
|
||||
layout.attach(this._passwordEntry, 0, row, 1, 1);
|
||||
layout.attach(label, 1, row, 1, 1);
|
||||
} else {
|
||||
layout.attach(label, 0, row, 1, 1);
|
||||
layout.attach(this._passwordEntry, 1, row, 1, 1);
|
||||
}
|
||||
row++;
|
||||
} else {
|
||||
this._passwordEntry = null;
|
||||
}
|
||||
|
||||
if (this.prompt.confirm_visible) {
|
||||
var label = new St.Label(({ style_class: 'prompt-dialog-password-label' }));
|
||||
var label = new St.Label(({ style_class: 'prompt-dialog-password-label',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
y_align: Clutter.ActorAlign.CENTER }));
|
||||
label.set_text(_("Type again:"));
|
||||
layout.pack(label, 0, row);
|
||||
layout.child_set(label, { x_expand: false, y_fill: false,
|
||||
x_align: Clutter.TableAlignment.START });
|
||||
this._confirmEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||
text: '',
|
||||
can_focus: true });
|
||||
can_focus: true,
|
||||
x_expand: true });
|
||||
this._confirmEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
|
||||
ShellEntry.addContextMenu(this._confirmEntry, { isPassword: true });
|
||||
this._confirmEntry.clutter_text.connect('activate', Lang.bind(this, this._onConfirmActivate));
|
||||
layout.pack(this._confirmEntry, 1, row);
|
||||
if (rtl) {
|
||||
layout.attach(this._confirmEntry, 0, row, 1, 1);
|
||||
layout.attach(label, 1, row, 1, 1);
|
||||
} else {
|
||||
layout.attach(label, 0, row, 1, 1);
|
||||
layout.attach(this._confirmEntry, 1, row, 1, 1);
|
||||
}
|
||||
row++;
|
||||
} else {
|
||||
this._confirmEntry = null;
|
||||
@ -130,15 +144,15 @@ const KeyringDialog = new Lang.Class({
|
||||
let choice = new CheckBox.CheckBox();
|
||||
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
|
||||
layout.pack(choice.actor, 1, row);
|
||||
layout.attach(choice.actor, rtl ? 0 : 1, row, 1, 1);
|
||||
row++;
|
||||
}
|
||||
|
||||
let warning = new St.Label({ style_class: 'prompt-dialog-error-label' });
|
||||
let warning = new St.Label({ style_class: 'prompt-dialog-error-label',
|
||||
x_align: Clutter.ActorAlign.START });
|
||||
warning.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
warning.clutter_text.line_wrap = true;
|
||||
layout.pack(warning, 1, row);
|
||||
layout.child_set(warning, { x_fill: false, x_align: Clutter.TableAlignment.START });
|
||||
layout.attach(warning, rtl ? 0 : 1, row, 1, 1);
|
||||
this.prompt.bind_property('warning-visible', warning, 'visible', GObject.BindingFlags.SYNC_CREATE);
|
||||
this.prompt.bind_property('warning', warning, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
|
@ -72,7 +72,7 @@ const NetworkSecretDialog = new Lang.Class({
|
||||
expand: true });
|
||||
}
|
||||
|
||||
let layout = new Clutter.TableLayout();
|
||||
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
|
||||
let secretTable = new St.Widget({ style_class: 'network-dialog-secret-table',
|
||||
layout_manager: layout });
|
||||
layout.hookup_style(secretTable);
|
||||
@ -83,14 +83,17 @@ const NetworkSecretDialog = new Lang.Class({
|
||||
for (let i = 0; i < this._content.secrets.length; i++) {
|
||||
let secret = this._content.secrets[i];
|
||||
let label = new St.Label({ style_class: 'prompt-dialog-password-label',
|
||||
text: secret.label });
|
||||
text: secret.label,
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
label.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
|
||||
let reactive = secret.key != null;
|
||||
|
||||
secret.entry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
|
||||
text: secret.value, can_focus: reactive,
|
||||
reactive: reactive });
|
||||
reactive: reactive,
|
||||
x_expand: true });
|
||||
ShellEntry.addContextMenu(secret.entry,
|
||||
{ isPassword: secret.password });
|
||||
|
||||
@ -118,14 +121,12 @@ const NetworkSecretDialog = new Lang.Class({
|
||||
secret.valid = true;
|
||||
|
||||
if (rtl) {
|
||||
layout.pack(secret.entry, 0, pos);
|
||||
layout.pack(label, 1, pos);
|
||||
layout.attach(secret.entry, 0, pos, 1, 1);
|
||||
layout.attach(label, 1, pos, 1, 1);
|
||||
} else {
|
||||
layout.pack(label, 0, pos);
|
||||
layout.pack(secret.entry, 1, pos);
|
||||
layout.attach(label, 0, pos, 1, 1);
|
||||
layout.attach(secret.entry, 1, pos, 1, 1);
|
||||
}
|
||||
layout.child_set(label, { x_expand: false, y_fill: false,
|
||||
x_align: Clutter.TableAlignment.START });
|
||||
pos++;
|
||||
|
||||
if (secret.password)
|
||||
@ -379,6 +380,12 @@ const VPNRequestHandler = new Lang.Class({
|
||||
argv.push('-i');
|
||||
if (flags & NMClient.SecretAgentGetSecretsFlags.REQUEST_NEW)
|
||||
argv.push('-r');
|
||||
if (authHelper.supportsHints) {
|
||||
for (let i = 0; i < hints.length; i++) {
|
||||
argv.push('-t');
|
||||
argv.push(hints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this._newStylePlugin = authHelper.externalUIMode;
|
||||
|
||||
@ -597,7 +604,15 @@ const NetworkAgent = new Lang.Class({
|
||||
Name: 'NetworkAgent',
|
||||
|
||||
_init: function() {
|
||||
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent' });
|
||||
try {
|
||||
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent',
|
||||
capabilities: NMClient.SecretAgentCapabilities.VPN_HINTS
|
||||
});
|
||||
} catch(e) {
|
||||
// Support older versions without NetworkAgent:capabilities
|
||||
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent'
|
||||
});
|
||||
}
|
||||
|
||||
this._dialogs = { };
|
||||
this._vpnRequests = { };
|
||||
@ -697,16 +712,23 @@ const NetworkAgent = new Lang.Class({
|
||||
let service = keyfile.get_string('VPN Connection', 'service');
|
||||
let binary = keyfile.get_string('GNOME', 'auth-dialog');
|
||||
let externalUIMode = false;
|
||||
let hints = false;
|
||||
|
||||
try {
|
||||
externalUIMode = keyfile.get_boolean('GNOME', 'supports-external-ui-mode');
|
||||
} catch(e) { } // ignore errors if key does not exist
|
||||
|
||||
try {
|
||||
hints = keyfile.get_boolean('GNOME', 'supports-hints');
|
||||
} catch(e) { } // ignore errors if key does not exist
|
||||
|
||||
let path = binary;
|
||||
if (!GLib.path_is_absolute(path)) {
|
||||
path = GLib.build_filenamev([Config.LIBEXECDIR, path]);
|
||||
}
|
||||
|
||||
if (GLib.file_test(path, GLib.FileTest.IS_EXECUTABLE))
|
||||
this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode };
|
||||
this._vpnBinaries[service] = { fileName: path, externalUIMode: externalUIMode, supportsHints: hints };
|
||||
else
|
||||
throw new Error('VPN plugin at %s is not executable'.format(path));
|
||||
} catch(e) {
|
||||
|
@ -863,13 +863,6 @@ const ChatNotification = new Lang.Class({
|
||||
for (let i = 0; i < expired.length; i++)
|
||||
expired[i].actor.destroy();
|
||||
}
|
||||
|
||||
let groups = this._contentArea.get_children();
|
||||
for (let i = 0; i < groups.length; i++) {
|
||||
let group = groups[i];
|
||||
if (group.get_n_children() == 0)
|
||||
group.destroy();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -911,16 +904,19 @@ const ChatNotification = new Lang.Class({
|
||||
this._lastGroup = group;
|
||||
let emptyLine = new St.Label({ style_class: 'chat-empty-line' });
|
||||
this.addActor(emptyLine);
|
||||
this._history.unshift({ actor: emptyLine, time: timestamp,
|
||||
realMessage: false });
|
||||
}
|
||||
|
||||
this._lastMessageBox = new St.BoxLayout({ vertical: false });
|
||||
this._lastMessageBox.add(body, props.childProps);
|
||||
this.addActor(this._lastMessageBox);
|
||||
let lineBox = new St.BoxLayout({ vertical: false });
|
||||
lineBox.add(body, props.childProps);
|
||||
this.addActor(lineBox);
|
||||
this._lastMessageBox = lineBox;
|
||||
|
||||
this.updated();
|
||||
|
||||
let timestamp = props.timestamp;
|
||||
this._history.unshift({ actor: body, time: timestamp,
|
||||
this._history.unshift({ actor: lineBox, time: timestamp,
|
||||
realMessage: group != 'meta' });
|
||||
|
||||
if (!props.noTimestamp) {
|
||||
|
@ -140,27 +140,17 @@ const CtrlAltTabPopup = new Lang.Class({
|
||||
Name: 'CtrlAltTabPopup',
|
||||
Extends: SwitcherPopup.SwitcherPopup,
|
||||
|
||||
_createSwitcher: function() {
|
||||
_init: function(items) {
|
||||
this.parent(items);
|
||||
|
||||
this._switcherList = new CtrlAltTabSwitcher(this._items);
|
||||
return true;
|
||||
},
|
||||
|
||||
_initialSelection: function(backward, binding) {
|
||||
if (binding == 'switch-panels') {
|
||||
if (backward)
|
||||
this._selectedIndex = this._items.length - 1;
|
||||
} else if (binding == 'switch-panels-backward') {
|
||||
if (!backward)
|
||||
this._selectedIndex = this._items.length - 1;
|
||||
}
|
||||
this._select(this._selectedIndex);
|
||||
},
|
||||
|
||||
_keyPressHandler: function(keysym, backwards, action) {
|
||||
_keyPressHandler: function(keysym, action) {
|
||||
if (action == Meta.KeyBindingAction.SWITCH_PANELS)
|
||||
this._select(backwards ? this._previous() : this._next());
|
||||
this._select(this._next());
|
||||
else if (action == Meta.KeyBindingAction.SWITCH_PANELS_BACKWARD)
|
||||
this._select(backwards ? this._next() : this._previous());
|
||||
this._select(this._previous());
|
||||
else if (keysym == Clutter.Left)
|
||||
this._select(this._previous());
|
||||
else if (keysym == Clutter.Right)
|
||||
|
@ -3,6 +3,7 @@
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GnomeDesktop = imports.gi.GnomeDesktop;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Cairo = imports.cairo;
|
||||
@ -124,14 +125,19 @@ const DateMenuButton = new Lang.Class({
|
||||
if (isOpen) {
|
||||
let now = new Date();
|
||||
this._calendar.setDate(now);
|
||||
|
||||
/* Translators: This is the date format to use when the calendar popup is
|
||||
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
|
||||
*/
|
||||
let dateFormat = _("%A %B %e, %Y");
|
||||
this._date.set_label(now.toLocaleFormat(dateFormat));
|
||||
}
|
||||
}));
|
||||
|
||||
// Done with hbox for calendar and event list
|
||||
|
||||
this._clock = new GnomeDesktop.WallClock();
|
||||
this._clock.connect('notify::clock', Lang.bind(this, this._updateClockAndDate));
|
||||
this._updateClockAndDate();
|
||||
this._clock.bind_property('clock', this._clockDisplay, 'text', GObject.BindingFlags.SYNC_CREATE);
|
||||
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
this._sessionUpdated();
|
||||
@ -141,7 +147,7 @@ const DateMenuButton = new Lang.Class({
|
||||
let now = new Date();
|
||||
return now.getYear() == date.getYear() &&
|
||||
now.getMonth() == date.getMonth() &&
|
||||
now.getDay() == date.getDay();
|
||||
now.getDate() == date.getDate();
|
||||
},
|
||||
|
||||
_appInstalledChanged: function() {
|
||||
@ -196,25 +202,18 @@ const DateMenuButton = new Lang.Class({
|
||||
this._dateAndTimeSeparator.actor.visible = Main.sessionMode.allowSettings;
|
||||
},
|
||||
|
||||
_updateClockAndDate: function() {
|
||||
this._clockDisplay.set_text(this._clock.clock);
|
||||
/* Translators: This is the date format to use when the calendar popup is
|
||||
* shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
|
||||
*/
|
||||
let dateFormat = _("%A %B %e, %Y");
|
||||
let displayDate = new Date();
|
||||
this._date.set_label(displayDate.toLocaleFormat(dateFormat));
|
||||
},
|
||||
|
||||
_getCalendarApp: function() {
|
||||
if (this._calendarApp !== undefined)
|
||||
return this._calendarApp;
|
||||
|
||||
let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
|
||||
if (apps && (apps.length > 0))
|
||||
this._calendarApp = apps[0];
|
||||
else
|
||||
if (apps && (apps.length > 0)) {
|
||||
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
|
||||
let defaultInRecommended = apps.some(function(a) { return a.equal(app); });
|
||||
this._calendarApp = defaultInRecommended ? app : apps[0];
|
||||
} else {
|
||||
this._calendarApp = null;
|
||||
}
|
||||
return this._calendarApp;
|
||||
},
|
||||
|
||||
|
78
js/ui/edgeDragAction.js
Normal file
78
js/ui/edgeDragAction.js
Normal file
@ -0,0 +1,78 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const EDGE_THRESHOLD = 20;
|
||||
const DRAG_DISTANCE = 80;
|
||||
|
||||
const EdgeDragAction = new Lang.Class({
|
||||
Name: 'EdgeDragAction',
|
||||
Extends: Clutter.GestureAction,
|
||||
|
||||
_init : function(side) {
|
||||
this.parent();
|
||||
this._side = side;
|
||||
this.set_n_touch_points(1);
|
||||
|
||||
global.display.connect('grab-op-begin', Lang.bind(this, function() {
|
||||
this.cancel();
|
||||
}));
|
||||
},
|
||||
|
||||
_getMonitorRect : function (x, y) {
|
||||
let rect = new Meta.Rectangle({ x: x - 1, y: y - 1, width: 1, height: 1 });
|
||||
let monitorIndex = global.screen.get_monitor_index_for_rect(rect);
|
||||
|
||||
return global.screen.get_monitor_geometry(monitorIndex);
|
||||
},
|
||||
|
||||
vfunc_gesture_prepare : function(action, actor) {
|
||||
if (this.get_n_current_points() == 0)
|
||||
return false;
|
||||
|
||||
let [x, y] = this.get_press_coords(0);
|
||||
let monitorRect = this._getMonitorRect(x, y);
|
||||
|
||||
return ((this._side == St.Side.LEFT && x < monitorRect.x + EDGE_THRESHOLD) ||
|
||||
(this._side == St.Side.RIGHT && x > monitorRect.x + monitorRect.width - EDGE_THRESHOLD) ||
|
||||
(this._side == St.Side.TOP && y < monitorRect.y + EDGE_THRESHOLD) ||
|
||||
(this._side == St.Side.BOTTOM && y > monitorRect.y + monitorRect.height - EDGE_THRESHOLD));
|
||||
},
|
||||
|
||||
vfunc_gesture_progress : function (action, actor) {
|
||||
let [startX, startY] = this.get_press_coords(0);
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let offsetX = Math.abs (x - startX);
|
||||
let offsetY = Math.abs (y - startY);
|
||||
|
||||
if (offsetX < EDGE_THRESHOLD && offsetY < EDGE_THRESHOLD)
|
||||
return true;
|
||||
|
||||
if ((offsetX > offsetY &&
|
||||
(this._side == St.Side.TOP || this._side == St.Side.BOTTOM)) ||
|
||||
(offsetY > offsetX &&
|
||||
(this._side == St.Side.LEFT || this._side == St.Side.RIGHT))) {
|
||||
this.cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
vfunc_gesture_end : function (action, actor) {
|
||||
let [startX, startY] = this.get_press_coords(0);
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let monitorRect = this._getMonitorRect(startX, startY);
|
||||
|
||||
if ((this._side == St.Side.TOP && y > monitorRect.y + DRAG_DISTANCE) ||
|
||||
(this._side == St.Side.BOTTOM && y < monitorRect.y + monitorRect.height - DRAG_DISTANCE) ||
|
||||
(this._side == St.Side.LEFT && x > monitorRect.x + DRAG_DISTANCE) ||
|
||||
(this._side == St.Side.RIGHT && x < monitorRect.x + monitorRect.width - DRAG_DISTANCE))
|
||||
this.emit('activated');
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(EdgeDragAction.prototype);
|
@ -38,8 +38,6 @@ const UserWidget = imports.ui.userWidget;
|
||||
|
||||
let _endSessionDialog = null;
|
||||
|
||||
const TRIGGER_OFFLINE_UPDATE = '/usr/libexec/pk-trigger-offline-update';
|
||||
|
||||
const _ITEM_ICON_SIZE = 48;
|
||||
const _DIALOG_ICON_SIZE = 48;
|
||||
|
||||
@ -134,11 +132,18 @@ const restartInstallDialogContent = {
|
||||
showOtherSessions: true,
|
||||
};
|
||||
|
||||
const DialogType = {
|
||||
LOGOUT: 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */,
|
||||
SHUTDOWN: 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */,
|
||||
RESTART: 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */,
|
||||
UPDATE_RESTART: 3
|
||||
};
|
||||
|
||||
const DialogContent = {
|
||||
0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */: logoutDialogContent,
|
||||
1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */: shutdownDialogContent,
|
||||
2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */: restartDialogContent,
|
||||
3: restartInstallDialogContent
|
||||
0 /* DialogType.LOGOUT */: logoutDialogContent,
|
||||
1 /* DialogType.SHUTDOWN */: shutdownDialogContent,
|
||||
2 /* DialogType.RESTART */: restartDialogContent,
|
||||
3 /* DialogType.UPDATE_RESTART */: restartInstallDialogContent
|
||||
};
|
||||
|
||||
const MAX_USERS_IN_SESSION_DIALOG = 5;
|
||||
@ -155,6 +160,19 @@ const LogindSessionIface = '<node> \
|
||||
|
||||
const LogindSession = Gio.DBusProxy.makeProxyWrapper(LogindSessionIface);
|
||||
|
||||
const PkOfflineIface = '<node> \
|
||||
<interface name="org.freedesktop.PackageKit.Offline"> \
|
||||
<property name="UpdatePrepared" type="b" access="read"/> \
|
||||
<property name="TriggerAction" type="s" access="read"/> \
|
||||
<method name="Trigger"> \
|
||||
<arg type="s" name="action" direction="in"/> \
|
||||
</method> \
|
||||
<method name="Cancel"/> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const PkOfflineProxy = Gio.DBusProxy.makeProxyWrapper(PkOfflineIface);
|
||||
|
||||
const UPowerIface = '<node> \
|
||||
<interface name="org.freedesktop.UPower"> \
|
||||
<property name="OnBattery" type="b" access="read"/> \
|
||||
@ -245,9 +263,14 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._loginManager = LoginManager.getLoginManager();
|
||||
this._userManager = AccountsService.UserManager.get_default();
|
||||
this._user = this._userManager.get_user(GLib.get_user_name());
|
||||
this._updatesFile = Gio.File.new_for_path('/system-update');
|
||||
this._preparedUpdateFile = Gio.File.new_for_path('/var/lib/PackageKit/prepared-update');
|
||||
|
||||
this._pkOfflineProxy = new PkOfflineProxy(Gio.DBus.system,
|
||||
'org.freedesktop.PackageKit',
|
||||
'/org/freedesktop/PackageKit',
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error)
|
||||
log(error.message);
|
||||
}));
|
||||
this._powerProxy = new UPowerProxy(Gio.DBus.system,
|
||||
'org.freedesktop.UPower',
|
||||
'/org/freedesktop/UPower',
|
||||
@ -499,31 +522,29 @@ const EndSessionDialog = new Lang.Class({
|
||||
},
|
||||
|
||||
_triggerOfflineUpdateReboot: function(callback) {
|
||||
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, 'reboot'], callback);
|
||||
this._pkOfflineProxy.TriggerRemote('reboot',
|
||||
function (result, error) {
|
||||
if (error)
|
||||
log(error.message);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
_triggerOfflineUpdateShutdown: function(callback) {
|
||||
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, 'power-off'], callback);
|
||||
this._pkOfflineProxy.TriggerRemote('power-off',
|
||||
function (result, error) {
|
||||
if (error)
|
||||
log(error.message);
|
||||
|
||||
callback();
|
||||
});
|
||||
},
|
||||
|
||||
_triggerOfflineUpdateCancel: function(callback) {
|
||||
this._pkexecSpawn([TRIGGER_OFFLINE_UPDATE, '--cancel'], callback);
|
||||
},
|
||||
|
||||
_pkexecSpawn: function(argv, callback) {
|
||||
let ret, pid;
|
||||
try {
|
||||
[ret, pid] = GLib.spawn_async(null, ['pkexec'].concat(argv), null,
|
||||
GLib.SpawnFlags.DO_NOT_REAP_CHILD | GLib.SpawnFlags.SEARCH_PATH,
|
||||
null);
|
||||
} catch (e) {
|
||||
log('Error spawning "pkexec %s": %s'.format(argv.join(' '), e.toString()));
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, function(pid, status) {
|
||||
GLib.spawn_close_pid(pid);
|
||||
this._pkOfflineProxy.CancelRemote(function (result, error) {
|
||||
if (error)
|
||||
log(error.message);
|
||||
|
||||
callback();
|
||||
});
|
||||
@ -677,8 +698,9 @@ const EndSessionDialog = new Lang.Class({
|
||||
this._totalSecondsToStayOpen = totalSecondsToStayOpen;
|
||||
this._type = type;
|
||||
|
||||
if (this._type == 2 && this._updatesFile.query_exists(null))
|
||||
this._type = 3;
|
||||
if (this._type == DialogType.RESTART &&
|
||||
this._pkOfflineProxy.TriggerAction == 'reboot')
|
||||
this._type = DialogType.UPDATE_RESTART;
|
||||
|
||||
this._applications = [];
|
||||
this._applicationList.destroy_all_children();
|
||||
@ -705,19 +727,19 @@ const EndSessionDialog = new Lang.Class({
|
||||
if (dialogContent.showOtherSessions)
|
||||
this._loadSessions();
|
||||
|
||||
let preparedUpdate = this._preparedUpdateFile.query_exists(null);
|
||||
let updateAlreadyTriggered = this._updatesFile.query_exists(null);
|
||||
let updateAlreadyTriggered = this._pkOfflineProxy.TriggerAction == 'power-off' || this._pkOfflineProxy.TriggerAction == 'reboot';
|
||||
let updatePrepared = this._pkOfflineProxy.UpdatePrepared;
|
||||
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
|
||||
|
||||
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText);
|
||||
this._checkBox.actor.visible = (dialogContent.checkBoxText && preparedUpdate && updatesAllowed);
|
||||
this._checkBox.actor.checked = (preparedUpdate && updateAlreadyTriggered);
|
||||
this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
|
||||
this._checkBox.actor.checked = (updatePrepared && updateAlreadyTriggered);
|
||||
|
||||
// We show the warning either together with the checkbox, or when
|
||||
// updates have already been triggered, but the user doesn't have
|
||||
// enough permissions to cancel them.
|
||||
this._batteryWarning.visible = (dialogContent.showBatteryWarning &&
|
||||
(this._checkBox.actor.visible || preparedUpdate && updateAlreadyTriggered && !updatesAllowed));
|
||||
(this._checkBox.actor.visible || updatePrepared && updateAlreadyTriggered && !updatesAllowed));
|
||||
|
||||
this._updateButtons();
|
||||
|
||||
|
@ -271,10 +271,17 @@ function onEnabledExtensionsChanged() {
|
||||
}
|
||||
|
||||
function _onVersionValidationChanged() {
|
||||
// we want to reload all extensions, but only enable
|
||||
// extensions when allowed by the sessionMode, so
|
||||
// temporarily disable them all
|
||||
enabledExtensions = [];
|
||||
for (let uuid in ExtensionUtils.extensions)
|
||||
reloadExtension(ExtensionUtils.extensions[uuid]);
|
||||
enabledExtensions = getEnabledExtensions();
|
||||
|
||||
if (Main.sessionMode.allowExtensions) {
|
||||
enabledExtensions.forEach(function(uuid) {
|
||||
if (ExtensionUtils.extensions[uuid])
|
||||
reloadExtension(ExtensionUtils.extensions[uuid]);
|
||||
enableExtension(uuid);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ const GrabHelper = new Lang.Class({
|
||||
this._grabStack = [];
|
||||
|
||||
this._actors = [];
|
||||
this._ignoreRelease = false;
|
||||
this._ignoreUntilRelease = false;
|
||||
|
||||
this._modalCount = 0;
|
||||
},
|
||||
@ -215,7 +215,7 @@ const GrabHelper = new Lang.Class({
|
||||
|
||||
_popGrabHelper(this);
|
||||
|
||||
this._ignoreRelease = false;
|
||||
this._ignoreUntilRelease = false;
|
||||
|
||||
Main.popModal(this._owner);
|
||||
global.sync_pointer();
|
||||
@ -228,7 +228,7 @@ const GrabHelper = new Lang.Class({
|
||||
// like the ComboBoxMenu that go away on press, but need to eat
|
||||
// the next release event.
|
||||
ignoreRelease: function() {
|
||||
this._ignoreRelease = true;
|
||||
this._ignoreUntilRelease = true;
|
||||
},
|
||||
|
||||
// ungrab:
|
||||
@ -283,12 +283,22 @@ const GrabHelper = new Lang.Class({
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
let motion = type == Clutter.EventType.MOTION;
|
||||
let press = type == Clutter.EventType.BUTTON_PRESS;
|
||||
let release = type == Clutter.EventType.BUTTON_RELEASE;
|
||||
let button = press || release;
|
||||
|
||||
if (release && this._ignoreRelease) {
|
||||
this._ignoreRelease = false;
|
||||
let touchUpdate = type == Clutter.EventType.TOUCH_UPDATE;
|
||||
let touchBegin = type == Clutter.EventType.TOUCH_BEGIN;
|
||||
let touchEnd = type == Clutter.EventType.TOUCH_END;
|
||||
let touch = touchUpdate || touchBegin || touchEnd;
|
||||
|
||||
if (touch && !global.display.is_pointer_emulating_sequence (event.get_event_sequence()))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (this._ignoreUntilRelease && (motion || release || touch)) {
|
||||
if (release || touchEnd)
|
||||
this._ignoreUntilRelease = false;
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
@ -298,11 +308,12 @@ const GrabHelper = new Lang.Class({
|
||||
if (Main.keyboard.shouldTakeEvent(event))
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
if (button) {
|
||||
// If we have a press event, ignore the next event,
|
||||
// which should be a release event.
|
||||
if (press)
|
||||
this._ignoreRelease = true;
|
||||
if (button || touchBegin) {
|
||||
// If we have a press event, ignore the next
|
||||
// motion/release events.
|
||||
if (press || touchBegin)
|
||||
this._ignoreUntilRelease = true;
|
||||
|
||||
let i = this._actorInGrabStack(event.get_source()) + 1;
|
||||
this.ungrab({ actor: this._grabStack[i].actor, isUser: true });
|
||||
return Clutter.EVENT_STOP;
|
||||
|
@ -10,12 +10,30 @@ const St = imports.gi.St;
|
||||
const Lang = imports.lang;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const ICON_SIZE = 96;
|
||||
const MIN_ICON_SIZE = 16;
|
||||
|
||||
const EXTRA_SPACE_ANIMATION_TIME = 0.25;
|
||||
|
||||
const ANIMATION_TIME_IN = 0.350;
|
||||
const ANIMATION_TIME_OUT = 1/2 * ANIMATION_TIME_IN;
|
||||
const ANIMATION_MAX_DELAY_FOR_ITEM = 2/3 * ANIMATION_TIME_IN;
|
||||
const ANIMATION_BASE_DELAY_FOR_ITEM = 1/4 * ANIMATION_MAX_DELAY_FOR_ITEM;
|
||||
const ANIMATION_MAX_DELAY_OUT_FOR_ITEM = 2/3 * ANIMATION_TIME_OUT;
|
||||
const ANIMATION_FADE_IN_TIME_FOR_ITEM = 1/4 * ANIMATION_TIME_IN;
|
||||
|
||||
const ANIMATION_BOUNCE_ICON_SCALE = 1.1;
|
||||
|
||||
const AnimationDirection = {
|
||||
IN: 0,
|
||||
OUT: 1
|
||||
};
|
||||
|
||||
const APPICON_ANIMATION_OUT_SCALE = 3;
|
||||
const APPICON_ANIMATION_OUT_TIME = 0.25;
|
||||
|
||||
const BaseIcon = new Lang.Class({
|
||||
Name: 'BaseIcon',
|
||||
|
||||
@ -173,9 +191,55 @@ const BaseIcon = new Lang.Class({
|
||||
|
||||
_onIconThemeChanged: function() {
|
||||
this._createIconTexture(this.iconSize);
|
||||
},
|
||||
|
||||
animateZoomOut: function() {
|
||||
// Animate only the child instead of the entire actor, so the
|
||||
// styles like hover and running are not applied while
|
||||
// animating.
|
||||
zoomOutActor(this.actor.child);
|
||||
}
|
||||
});
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(Math.min(value, max), min);
|
||||
};
|
||||
|
||||
function zoomOutActor(actor) {
|
||||
let actorClone = new Clutter.Clone({ source: actor,
|
||||
reactive: false });
|
||||
let [width, height] = actor.get_transformed_size();
|
||||
let [x, y] = actor.get_transformed_position();
|
||||
actorClone.set_size(width, height);
|
||||
actorClone.set_position(x, y);
|
||||
actorClone.opacity = 255;
|
||||
actorClone.set_pivot_point(0.5, 0.5);
|
||||
|
||||
Main.uiGroup.add_actor(actorClone);
|
||||
|
||||
// Avoid monitor edges to not zoom outside the current monitor
|
||||
let monitor = Main.layoutManager.findMonitorForActor(actor);
|
||||
let scaledWidth = width * APPICON_ANIMATION_OUT_SCALE;
|
||||
let scaledHeight = height * APPICON_ANIMATION_OUT_SCALE;
|
||||
let scaledX = x - (scaledWidth - width) / 2;
|
||||
let scaledY = y - (scaledHeight - height) / 2;
|
||||
let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth);
|
||||
let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight);
|
||||
|
||||
Tweener.addTween(actorClone,
|
||||
{ time: APPICON_ANIMATION_OUT_TIME,
|
||||
scale_x: APPICON_ANIMATION_OUT_SCALE,
|
||||
scale_y: APPICON_ANIMATION_OUT_SCALE,
|
||||
translation_x: containedX - scaledX,
|
||||
translation_y: containedY - scaledY,
|
||||
opacity: 0,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() {
|
||||
actorClone.destroy();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const IconGrid = new Lang.Class({
|
||||
Name: 'IconGrid',
|
||||
|
||||
@ -338,15 +402,202 @@ const IconGrid = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_calculateChildBox: function(child, x, y, box) {
|
||||
let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight] =
|
||||
child.get_preferred_size();
|
||||
/**
|
||||
* Intended to be override by subclasses if they need a different
|
||||
* set of items to be animated.
|
||||
*/
|
||||
_getChildrenToAnimate: function() {
|
||||
return this._getVisibleChildren();
|
||||
},
|
||||
|
||||
_animationDone: function() {
|
||||
this._animating = false;
|
||||
this.emit('animation-done');
|
||||
},
|
||||
|
||||
animatePulse: function(animationDirection) {
|
||||
if (animationDirection != AnimationDirection.IN)
|
||||
throw new Error("Pulse animation only implements 'in' animation direction");
|
||||
|
||||
if (this._animating)
|
||||
return;
|
||||
|
||||
this._animating = true;
|
||||
|
||||
let actors = this._getChildrenToAnimate();
|
||||
if (actors.length == 0) {
|
||||
this._animationDone();
|
||||
return;
|
||||
}
|
||||
|
||||
// For few items the animation can be slow, so use a smaller
|
||||
// delay when there are less than 4 items
|
||||
// (ANIMATION_BASE_DELAY_FOR_ITEM = 1/4 *
|
||||
// ANIMATION_MAX_DELAY_FOR_ITEM)
|
||||
let maxDelay = Math.min(ANIMATION_BASE_DELAY_FOR_ITEM * actors.length,
|
||||
ANIMATION_MAX_DELAY_FOR_ITEM);
|
||||
|
||||
for (let index = 0; index < actors.length; index++) {
|
||||
let actor = actors[index];
|
||||
actor.reactive = false;
|
||||
actor.set_scale(0, 0);
|
||||
actor.set_pivot_point(0.5, 0.5);
|
||||
|
||||
let delay = index / actors.length * maxDelay;
|
||||
let bounceUpTime = ANIMATION_TIME_IN / 4;
|
||||
let isLastItem = index == actors.length - 1;
|
||||
Tweener.addTween(actor,
|
||||
{ time: bounceUpTime,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
scale_x: ANIMATION_BOUNCE_ICON_SCALE,
|
||||
scale_y: ANIMATION_BOUNCE_ICON_SCALE,
|
||||
onComplete: Lang.bind(this, function() {
|
||||
Tweener.addTween(actor,
|
||||
{ time: ANIMATION_TIME_IN - bounceUpTime,
|
||||
transition: 'easeInOutQuad',
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
onComplete: Lang.bind(this, function() {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
actor.reactive = true;
|
||||
})
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
animateSpring: function(animationDirection, sourceActor) {
|
||||
if (this._animating)
|
||||
return;
|
||||
|
||||
this._animating = true;
|
||||
|
||||
let actors = this._getChildrenToAnimate();
|
||||
if (actors.length == 0) {
|
||||
this._animationDone();
|
||||
return;
|
||||
}
|
||||
|
||||
let [sourceX, sourceY] = sourceActor.get_transformed_position();
|
||||
let [sourceWidth, sourceHeight] = sourceActor.get_size();
|
||||
// Get the center
|
||||
let [sourceCenterX, sourceCenterY] = [sourceX + sourceWidth / 2, sourceY + sourceHeight / 2];
|
||||
// Design decision, 1/2 of the source actor size.
|
||||
let [sourceScaledWidth, sourceScaledHeight] = [sourceWidth / 2, sourceHeight / 2];
|
||||
|
||||
actors.forEach(function(actor) {
|
||||
let [actorX, actorY] = actor._transformedPosition = actor.get_transformed_position();
|
||||
let [x, y] = [actorX - sourceX, actorY - sourceY];
|
||||
actor._distance = Math.sqrt(x * x + y * y);
|
||||
});
|
||||
let maxDist = actors.reduce(function(prev, cur) {
|
||||
return Math.max(prev, cur._distance);
|
||||
}, 0);
|
||||
let minDist = actors.reduce(function(prev, cur) {
|
||||
return Math.min(prev, cur._distance);
|
||||
}, Infinity);
|
||||
let normalization = maxDist - minDist;
|
||||
|
||||
for (let index = 0; index < actors.length; index++) {
|
||||
let actor = actors[index];
|
||||
actor.opacity = 0;
|
||||
actor.reactive = false;
|
||||
|
||||
let actorClone = new Clutter.Clone({ source: actor });
|
||||
Main.uiGroup.add_actor(actorClone);
|
||||
|
||||
let [width, height,,] = this._getAllocatedChildSizeAndSpacing(actor);
|
||||
actorClone.set_size(width, height);
|
||||
let scaleX = sourceScaledWidth / width;
|
||||
let scaleY = sourceScaledHeight / height;
|
||||
let [adjustedSourcePositionX, adjustedSourcePositionY] = [sourceCenterX - sourceScaledWidth / 2, sourceCenterY - sourceScaledHeight / 2];
|
||||
|
||||
let movementParams, fadeParams;
|
||||
if (animationDirection == AnimationDirection.IN) {
|
||||
let isLastItem = actor._distance == minDist;
|
||||
|
||||
actorClone.opacity = 0;
|
||||
actorClone.set_scale(scaleX, scaleY);
|
||||
|
||||
actorClone.set_position(adjustedSourcePositionX, adjustedSourcePositionY);
|
||||
|
||||
let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM;
|
||||
let [finalX, finalY] = actor._transformedPosition;
|
||||
movementParams = { time: ANIMATION_TIME_IN,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
x: finalX,
|
||||
y: finalY,
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
onComplete: Lang.bind(this, function() {
|
||||
if (isLastItem)
|
||||
this._animationDone();
|
||||
|
||||
actor.opacity = 255;
|
||||
actor.reactive = true;
|
||||
actorClone.destroy();
|
||||
})};
|
||||
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
opacity: 255 };
|
||||
} else {
|
||||
let isLastItem = actor._distance == maxDist;
|
||||
|
||||
let [startX, startY] = actor._transformedPosition;
|
||||
actorClone.set_position(startX, startY);
|
||||
|
||||
let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM;
|
||||
movementParams = { time: ANIMATION_TIME_OUT,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: delay,
|
||||
x: adjustedSourcePositionX,
|
||||
y: adjustedSourcePositionY,
|
||||
scale_x: scaleX,
|
||||
scale_y: scaleY,
|
||||
onComplete: Lang.bind(this, function() {
|
||||
if (isLastItem) {
|
||||
this._animationDone();
|
||||
this._restoreItemsOpacity();
|
||||
}
|
||||
actor.reactive = true;
|
||||
actorClone.destroy();
|
||||
})};
|
||||
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
transition: 'easeInOutQuad',
|
||||
delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM,
|
||||
opacity: 0 };
|
||||
}
|
||||
|
||||
|
||||
Tweener.addTween(actorClone, movementParams);
|
||||
Tweener.addTween(actorClone, fadeParams);
|
||||
}
|
||||
},
|
||||
|
||||
_restoreItemsOpacity: function() {
|
||||
for (let index = 0; index < this._items.length; index++) {
|
||||
this._items[index].actor.opacity = 255;
|
||||
}
|
||||
},
|
||||
|
||||
_getAllocatedChildSizeAndSpacing: function(child) {
|
||||
let [,, natWidth, natHeight] = child.get_preferred_size();
|
||||
let width = Math.min(this._getHItemSize(), natWidth);
|
||||
let xSpacing = Math.max(0, width - natWidth) / 2;
|
||||
let height = Math.min(this._getVItemSize(), natHeight);
|
||||
let ySpacing = Math.max(0, height - natHeight) / 2;
|
||||
return [width, height, xSpacing, ySpacing];
|
||||
},
|
||||
|
||||
_calculateChildBox: function(child, x, y, box) {
|
||||
/* Center the item in its allocation horizontally */
|
||||
let width = Math.min(this._getHItemSize(), childNaturalWidth);
|
||||
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
|
||||
let height = Math.min(this._getVItemSize(), childNaturalHeight);
|
||||
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
|
||||
let [width, height, childXSpacing, childYSpacing] =
|
||||
this._getAllocatedChildSizeAndSpacing(child);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
|
||||
@ -524,12 +775,13 @@ const IconGrid = new Lang.Class({
|
||||
|
||||
this._updateSpacingForSize(availWidth, availHeight);
|
||||
}
|
||||
let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() { this._updateChildrenScale(scale); }));
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
|
||||
Lang.bind(this, this._updateIconSizes));
|
||||
},
|
||||
|
||||
// Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up
|
||||
_updateChildrenScale: function(scale) {
|
||||
_updateIconSizes: function() {
|
||||
let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
|
||||
let newIconSize = Math.floor(ICON_SIZE * scale);
|
||||
for (let i in this._items) {
|
||||
this._items[i].icon.setIconSize(newIconSize);
|
||||
@ -545,6 +797,7 @@ const PaginatedIconGrid = new Lang.Class({
|
||||
_init: function(params) {
|
||||
this.parent(params);
|
||||
this._nPages = 0;
|
||||
this.currentPage = 0;
|
||||
this._rowsPerPage = 0;
|
||||
this._spaceBetweenPages = 0;
|
||||
this._childrenPerPage = 0;
|
||||
@ -608,6 +861,15 @@ const PaginatedIconGrid = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
// Overriden from IconGrid
|
||||
_getChildrenToAnimate: function() {
|
||||
let children = this._getVisibleChildren();
|
||||
let firstIndex = this._childrenPerPage * this.currentPage;
|
||||
let lastIndex = firstIndex + this._childrenPerPage;
|
||||
|
||||
return children.slice(firstIndex, lastIndex);
|
||||
},
|
||||
|
||||
_computePages: function (availWidthPerPage, availHeightPerPage) {
|
||||
let [nColumns, usedWidth] = this._computeLayout(availWidthPerPage);
|
||||
let nRows;
|
||||
|
@ -23,6 +23,12 @@ const KEYBOARD_TYPE = 'keyboard-type';
|
||||
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
|
||||
const SHOW_KEYBOARD = 'screen-keyboard-enabled';
|
||||
|
||||
const CURSOR_BUS_NAME = 'org.gnome.SettingsDaemon.Cursor';
|
||||
const CURSOR_OBJECT_PATH = '/org/gnome/SettingsDaemon/Cursor';
|
||||
|
||||
const CARIBOU_BUS_NAME = 'org.gnome.Caribou.Daemon';
|
||||
const CARIBOU_OBJECT_PATH = '/org/gnome/Caribou/Daemon';
|
||||
|
||||
const CaribouKeyboardIface = '<node> \
|
||||
<interface name="org.gnome.Caribou.Keyboard"> \
|
||||
<method name="Show"> \
|
||||
@ -47,13 +53,29 @@ const CaribouKeyboardIface = '<node> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const CaribouDaemonIface = '<node> \
|
||||
<interface name="org.gnome.Caribou.Daemon"> \
|
||||
<method name="Run" /> \
|
||||
<method name="Quit" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const CursorManagerIface = '<node> \
|
||||
<interface name="org.gnome.SettingsDaemon.Cursor"> \
|
||||
<property name="ShowOSK" type="b" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
|
||||
const CaribouDaemonProxy = Gio.DBusProxy.makeProxyWrapper(CaribouDaemonIface);
|
||||
const CursorManagerProxy = Gio.DBusProxy.makeProxyWrapper(CursorManagerIface);
|
||||
|
||||
const Key = new Lang.Class({
|
||||
Name: 'Key',
|
||||
|
||||
_init : function(key) {
|
||||
this._key = key;
|
||||
|
||||
this.actor = this._makeKey();
|
||||
this.actor = this._makeKey(key, GLib.markup_escape_text(key.label, -1));
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._extended_keys = this._key.get_extended_keys();
|
||||
this._extended_keyboard = null;
|
||||
@ -76,20 +98,26 @@ const Key = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_makeKey: function () {
|
||||
let label = GLib.markup_escape_text(this._key.label, -1);
|
||||
_onDestroy: function() {
|
||||
if (this._boxPointer) {
|
||||
this._boxPointer.actor.destroy();
|
||||
this._boxPointer = null;
|
||||
}
|
||||
},
|
||||
|
||||
_makeKey: function (key, label) {
|
||||
let button = new St.Button ({ label: label,
|
||||
style_class: 'keyboard-key' });
|
||||
|
||||
button.key_width = this._key.width;
|
||||
button.connect('button-press-event', Lang.bind(this,
|
||||
function () {
|
||||
this._key.press();
|
||||
key.press();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
button.connect('button-release-event', Lang.bind(this,
|
||||
function () {
|
||||
this._key.release();
|
||||
key.release();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
|
||||
@ -112,18 +140,9 @@ const Key = new Lang.Class({
|
||||
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' });
|
||||
let key = this._makeKey(extended_key, label);
|
||||
|
||||
key.extended_key = extended_key;
|
||||
key.connect('button-press-event', Lang.bind(this,
|
||||
function () {
|
||||
extended_key.press();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
key.connect('button-release-event', Lang.bind(this,
|
||||
function () {
|
||||
extended_key.release();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}));
|
||||
this._extended_keyboard.add(key);
|
||||
}
|
||||
this._boxPointer.bin.add_actor(this._extended_keyboard);
|
||||
@ -162,10 +181,32 @@ const Keyboard = new Lang.Class({
|
||||
this._timestamp = global.display.get_current_time_roundtrip();
|
||||
|
||||
this._keyboardSettings = new Gio.Settings({ schema_id: KEYBOARD_SCHEMA });
|
||||
this._keyboardSettings.connect('changed', Lang.bind(this, this._settingsChanged));
|
||||
this._keyboardSettings.connect('changed', Lang.bind(this, this._sync));
|
||||
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
|
||||
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._settingsChanged));
|
||||
this._settingsChanged();
|
||||
this._a11yApplicationsSettings.connect('changed', Lang.bind(this, this._sync));
|
||||
this._watchNameId = Gio.bus_watch_name(Gio.BusType.SESSION, CURSOR_BUS_NAME, 0,
|
||||
Lang.bind(this, this._sync),
|
||||
Lang.bind(this, this._sync));
|
||||
this._daemonProxy = new CaribouDaemonProxy(Gio.DBus.session, CARIBOU_BUS_NAME,
|
||||
CARIBOU_OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
}));
|
||||
this._cursorProxy = new CursorManagerProxy(Gio.DBus.session, CURSOR_BUS_NAME,
|
||||
CURSOR_OBJECT_PATH,
|
||||
Lang.bind(this, function(proxy, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
this._cursorProxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._sync));
|
||||
this._sync();
|
||||
}));
|
||||
this._sync();
|
||||
|
||||
this._showIdleId = 0;
|
||||
this._subkeysBoxPointer = null;
|
||||
@ -183,8 +224,9 @@ const Keyboard = new Lang.Class({
|
||||
this._redraw();
|
||||
},
|
||||
|
||||
_settingsChanged: function (settings, key) {
|
||||
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
|
||||
_sync: function () {
|
||||
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD) ||
|
||||
this._cursorProxy.ShowOSK;
|
||||
if (!this._enableKeyboard && !this._keyboard)
|
||||
return;
|
||||
if (this._enableKeyboard && this._keyboard &&
|
||||
@ -214,9 +256,22 @@ const Keyboard = new Lang.Class({
|
||||
this.actor = null;
|
||||
|
||||
this._destroySource();
|
||||
this._daemonProxy.QuitRemote(function (result, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_setupKeyboard: function() {
|
||||
this._daemonProxy.RunRemote(function (result, error) {
|
||||
if (error) {
|
||||
log(error.message);
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
|
||||
Main.layoutManager.keyboardBox.add_actor(this.actor);
|
||||
Main.layoutManager.trackChrome(this.actor);
|
||||
@ -555,7 +610,7 @@ const Keyboard = new Lang.Class({
|
||||
|
||||
_moveTemporarily: function () {
|
||||
let currentWindow = global.screen.get_display().focus_window;
|
||||
let rect = currentWindow.get_outer_rect();
|
||||
let rect = currentWindow.get_frame_rect();
|
||||
|
||||
let newX = rect.x;
|
||||
let newY = 3 * this.actor.height / 2;
|
||||
|
@ -20,7 +20,6 @@ const Tweener = imports.ui.tweener;
|
||||
const STARTUP_ANIMATION_TIME = 0.5;
|
||||
const KEYBOARD_ANIMATION_TIME = 0.15;
|
||||
const BACKGROUND_FADE_ANIMATION_TIME = 1.0;
|
||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
||||
|
||||
// The message tray takes this much pressure
|
||||
// in the pressure barrier at once to release it.
|
||||
@ -160,10 +159,10 @@ const LayoutManager = new Lang.Class({
|
||||
this._isPopupWindowVisible = false;
|
||||
this._startingUp = true;
|
||||
|
||||
// Normally, the stage is always covered so Clutter doesn't need to clear
|
||||
// it; however it becomes visible during the startup animation
|
||||
// See the comment below for a longer explanation
|
||||
global.stage.background_color = DEFAULT_BACKGROUND_COLOR;
|
||||
// We don't want to paint the stage background color because either
|
||||
// the SystemBackground we create or the MetaBackgroundActor inside
|
||||
// global.window_group covers the entirety of the screen.
|
||||
global.stage.no_clear_hint = true;
|
||||
|
||||
// Set up stage hierarchy to group all UI actors under one container.
|
||||
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
|
||||
@ -230,6 +229,10 @@ const LayoutManager = new Lang.Class({
|
||||
global.stage.remove_actor(global.top_window_group);
|
||||
this.uiGroup.add_actor(global.top_window_group);
|
||||
|
||||
let feedbackGroup = Meta.get_feedback_group_for_screen(global.screen);
|
||||
global.stage.remove_actor(feedbackGroup);
|
||||
this.uiGroup.add_actor(feedbackGroup);
|
||||
|
||||
this._backgroundGroup = new Meta.BackgroundGroup();
|
||||
global.window_group.add_child(this._backgroundGroup);
|
||||
this._backgroundGroup.lower_bottom();
|
||||
@ -259,7 +262,6 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
this._inOverview = true;
|
||||
this._updateVisibility();
|
||||
this._updateRegions();
|
||||
},
|
||||
|
||||
hideOverview: function() {
|
||||
@ -267,7 +269,6 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
this._inOverview = false;
|
||||
this._updateVisibility();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_sessionUpdated: function() {
|
||||
@ -361,7 +362,7 @@ const LayoutManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_addBackgroundMenu: function(bgManager) {
|
||||
BackgroundMenu.addBackgroundMenu(bgManager.background.actor, this);
|
||||
BackgroundMenu.addBackgroundMenu(bgManager.backgroundActor, this);
|
||||
},
|
||||
|
||||
_createBackgroundManager: function(monitorIndex) {
|
||||
@ -378,10 +379,10 @@ const LayoutManager = new Lang.Class({
|
||||
_showSecondaryBackgrounds: function() {
|
||||
for (let i = 0; i < this.monitors.length; i++) {
|
||||
if (i != this.primaryIndex) {
|
||||
let background = this._bgManagers[i].background;
|
||||
background.actor.show();
|
||||
background.actor.opacity = 0;
|
||||
Tweener.addTween(background.actor,
|
||||
let backgroundActor = this._bgManagers[i].backgroundActor;
|
||||
backgroundActor.show();
|
||||
backgroundActor.opacity = 0;
|
||||
Tweener.addTween(backgroundActor,
|
||||
{ opacity: 255,
|
||||
time: BACKGROUND_FADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad' });
|
||||
@ -404,10 +405,16 @@ const LayoutManager = new Lang.Class({
|
||||
this._bgManagers.push(bgManager);
|
||||
|
||||
if (i != this.primaryIndex && this._startingUp)
|
||||
bgManager.background.actor.hide();
|
||||
bgManager.backgroundActor.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_updateKeyboardBox: function() {
|
||||
this.keyboardBox.set_position(this.keyboardMonitor.x,
|
||||
this.keyboardMonitor.y + this.keyboardMonitor.height);
|
||||
this.keyboardBox.set_size(this.keyboardMonitor.width, -1);
|
||||
},
|
||||
|
||||
_updateBoxes: function() {
|
||||
this.screenShieldGroup.set_position(0, 0);
|
||||
this.screenShieldGroup.set_size(global.screen_width, global.screen_height);
|
||||
@ -417,6 +424,8 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
if (this.keyboardIndex < 0)
|
||||
this.keyboardIndex = this.primaryIndex;
|
||||
else
|
||||
this._updateKeyboardBox();
|
||||
|
||||
this.trayBox.set_position(this.bottomMonitor.x,
|
||||
this.bottomMonitor.y + this.bottomMonitor.height);
|
||||
@ -541,9 +550,7 @@ const LayoutManager = new Lang.Class({
|
||||
|
||||
set keyboardIndex(v) {
|
||||
this._keyboardIndex = v;
|
||||
this.keyboardBox.set_position(this.keyboardMonitor.x,
|
||||
this.keyboardMonitor.y + this.keyboardMonitor.height);
|
||||
this.keyboardBox.set_size(this.keyboardMonitor.width, -1);
|
||||
this._updateKeyboardBox();
|
||||
},
|
||||
|
||||
get keyboardIndex() {
|
||||
@ -583,10 +590,6 @@ const LayoutManager = new Lang.Class({
|
||||
//
|
||||
// When starting a normal user session, we want to grow it out of the middle
|
||||
// of the screen.
|
||||
//
|
||||
// Usually, we don't want to paint the stage background color because the
|
||||
// MetaBackgroundActor inside global.window_group covers the entirety of the
|
||||
// screen. So, we set no_clear_hint at the end of the animation.
|
||||
|
||||
_prepareStartupAnimation: function() {
|
||||
// During the initial transition, add a simple actor to block all events,
|
||||
@ -667,10 +670,6 @@ const LayoutManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_startupAnimationComplete: function() {
|
||||
// At this point, the UI group is covering everything, so
|
||||
// we no longer need to clear the stage
|
||||
global.stage.no_clear_hint = true;
|
||||
|
||||
this._coverPane.destroy();
|
||||
this._coverPane = null;
|
||||
|
||||
@ -909,9 +908,6 @@ const LayoutManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_queueUpdateRegions: function() {
|
||||
if (Main.sessionMode.isGreeter)
|
||||
return;
|
||||
|
||||
if (this._startingUp)
|
||||
return;
|
||||
|
||||
@ -945,13 +941,16 @@ const LayoutManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateRegions: function() {
|
||||
let rects = [], struts = [], i;
|
||||
|
||||
if (this._updateRegionIdle) {
|
||||
Meta.later_remove(this._updateRegionIdle);
|
||||
delete this._updateRegionIdle;
|
||||
}
|
||||
|
||||
// No need to update when we have a modal.
|
||||
if (Main.modalCount > 0)
|
||||
return GLib.SOURCE_REMOVE;
|
||||
|
||||
let rects = [], struts = [], i;
|
||||
let isPopupMenuVisible = global.top_window_group.get_children().some(isPopupMetaWindow);
|
||||
let wantsInputRegion = !isPopupMenuVisible;
|
||||
|
||||
@ -1037,7 +1036,13 @@ const LayoutManager = new Lang.Class({
|
||||
}
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}
|
||||
},
|
||||
|
||||
modalEnded: function() {
|
||||
// We don't update the stage input region while in a modal,
|
||||
// so queue an update now.
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
});
|
||||
Signals.addSignalMethods(LayoutManager.prototype);
|
||||
|
||||
|
@ -105,8 +105,8 @@ const Lightbox = new Lang.Class({
|
||||
this._container = container;
|
||||
this._children = container.get_children();
|
||||
this._fadeFactor = params.fadeFactor;
|
||||
this._radialEffect = params.radialEffect;
|
||||
if (params.radialEffect)
|
||||
this._radialEffect = Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL) && params.radialEffect;
|
||||
if (this._radialEffect)
|
||||
this.actor = new RadialShaderQuad({ x: 0,
|
||||
y: 0,
|
||||
reactive: params.inhibitEvents });
|
||||
|
@ -1198,12 +1198,7 @@ const ZoomRegion = new Lang.Class({
|
||||
|
||||
// Add a background for when the magnified uiGroup is scrolled
|
||||
// out of view (don't want to see desktop showing through).
|
||||
this._background = new Clutter.Actor({ background_color: Main.DEFAULT_BACKGROUND_COLOR,
|
||||
layout_manager: new Clutter.BinLayout(),
|
||||
width: global.screen_width,
|
||||
height: global.screen_height });
|
||||
let noiseTexture = (new Background.SystemBackground()).actor;
|
||||
this._background.add_actor(noiseTexture);
|
||||
this._background = (new Background.SystemBackground()).actor;
|
||||
mainGroup.add_actor(this._background);
|
||||
|
||||
// Clone the group that contains all of UI on the screen. This is the
|
||||
|
@ -40,8 +40,6 @@ const Magnifier = imports.ui.magnifier;
|
||||
const XdndHandler = imports.ui.xdndHandler;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
|
||||
|
||||
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
|
||||
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
|
||||
const GNOMESHELL_STARTED_MESSAGE_ID = 'f3ea493c22934e26811cd62abe8e203a';
|
||||
@ -204,24 +202,24 @@ function _initializeUI() {
|
||||
}
|
||||
|
||||
layoutManager.connect('startup-complete', function() {
|
||||
if (keybindingMode == Shell.KeyBindingMode.NONE) {
|
||||
keybindingMode = Shell.KeyBindingMode.NORMAL;
|
||||
}
|
||||
if (screenShield) {
|
||||
screenShield.lockIfWasLocked();
|
||||
}
|
||||
if (LoginManager.haveSystemd() &&
|
||||
sessionMode.currentMode != 'gdm' &&
|
||||
sessionMode.currentMode != 'initial-setup') {
|
||||
// Do not import globally to not depend
|
||||
// on systemd on non-systemd systems.
|
||||
let GSystem = imports.gi.GSystem;
|
||||
GSystem.log_structured_print('GNOME Shell started at ' + _startDate,
|
||||
['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]);
|
||||
} else {
|
||||
log('GNOME Shell started at ' + _startDate);
|
||||
}
|
||||
});
|
||||
if (keybindingMode == Shell.KeyBindingMode.NONE) {
|
||||
keybindingMode = Shell.KeyBindingMode.NORMAL;
|
||||
}
|
||||
if (screenShield) {
|
||||
screenShield.lockIfWasLocked();
|
||||
}
|
||||
if (LoginManager.haveSystemd() &&
|
||||
sessionMode.currentMode != 'gdm' &&
|
||||
sessionMode.currentMode != 'initial-setup') {
|
||||
// Do not import globally to not depend
|
||||
// on systemd on non-systemd systems.
|
||||
let GSystem = imports.gi.GSystem;
|
||||
GSystem.log_structured_print('GNOME Shell started at ' + _startDate,
|
||||
['MESSAGE_ID=' + GNOMESHELL_STARTED_MESSAGE_ID]);
|
||||
} else {
|
||||
log('GNOME Shell started at ' + _startDate);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _loadDefaultStylesheet() {
|
||||
@ -454,6 +452,7 @@ function popModal(actor, timestamp) {
|
||||
if (modalCount > 0)
|
||||
return;
|
||||
|
||||
layoutManager.modalEnded();
|
||||
global.end_modal(timestamp);
|
||||
Meta.enable_unredirect_for_screen(global.screen);
|
||||
keybindingMode = Shell.KeyBindingMode.NORMAL;
|
||||
|
@ -15,6 +15,7 @@ const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
|
||||
const EdgeDragAction = imports.ui.edgeDragAction;
|
||||
const BoxPointer = imports.ui.boxpointer;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
@ -26,6 +27,7 @@ const PopupMenu = imports.ui.popupMenu;
|
||||
const Params = imports.misc.params;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Util = imports.misc.util;
|
||||
const ViewSelector = imports.ui.viewSelector;
|
||||
|
||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||
|
||||
@ -922,7 +924,7 @@ const Notification = new Lang.Class({
|
||||
let [titleMinH, titleNatH] = this._titleLabel.get_preferred_height(availWidth);
|
||||
let [bannerMinW, bannerNatW] = this._bannerLabel.get_preferred_width(availWidth);
|
||||
|
||||
let rtl = (this._titleDirection == Clutter.TextDirection.RTL);
|
||||
let rtl = (this._table.text_direction == Clutter.TextDirection.RTL);
|
||||
let x = rtl ? availWidth : 0;
|
||||
|
||||
if (this._secondaryIcon) {
|
||||
@ -1157,6 +1159,7 @@ const SourceActor = new Lang.Class({
|
||||
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._source.disconnect(this._iconUpdatedId);
|
||||
this._actorDestroyed = true;
|
||||
}));
|
||||
this._actorDestroyed = false;
|
||||
@ -1168,7 +1171,7 @@ const SourceActor = new Lang.Class({
|
||||
|
||||
this.actor.add_actor(this._iconBin);
|
||||
|
||||
this._source.connect('icon-updated', Lang.bind(this, this._updateIcon));
|
||||
this._iconUpdatedId = this._source.connect('icon-updated', Lang.bind(this, this._updateIcon));
|
||||
this._updateIcon();
|
||||
},
|
||||
|
||||
@ -1226,8 +1229,12 @@ const SourceActorWithLabel = new Lang.Class({
|
||||
|
||||
this.actor.add_actor(this._counterBin);
|
||||
|
||||
this._source.connect('count-updated', Lang.bind(this, this._updateCount));
|
||||
this._countUpdatedId = this._source.connect('count-updated', Lang.bind(this, this._updateCount));
|
||||
this._updateCount();
|
||||
|
||||
this.actor.connect('destroy', function() {
|
||||
this._source.disconnect(this._countUpdatedId);
|
||||
});
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
@ -1810,6 +1817,13 @@ const MessageTray = new Lang.Class({
|
||||
y_expand: true });
|
||||
this.actor.add_actor(this._summary);
|
||||
|
||||
this._focusTrap = new ViewSelector.FocusTrap({ can_focus: true });
|
||||
this._focusTrap.connect('key-focus-in', Lang.bind(this,
|
||||
function() {
|
||||
this._messageTrayMenuButton.actor.grab_key_focus();
|
||||
}));
|
||||
this._summary.add_actor(this._focusTrap);
|
||||
|
||||
this._summaryMotionId = 0;
|
||||
|
||||
this._summaryBoxPointer = new BoxPointer.BoxPointer(St.Side.BOTTOM,
|
||||
@ -1933,6 +1947,13 @@ const MessageTray = new Lang.Class({
|
||||
|
||||
this._messageTrayMenuButton = new MessageTrayMenuButton(this);
|
||||
this.actor.add_actor(this._messageTrayMenuButton.actor);
|
||||
|
||||
this._messageTrayMenuButton.actor.connect('key-press-event',
|
||||
Lang.bind(this, this._onTrayButtonKeyPress));
|
||||
|
||||
let gesture = new EdgeDragAction.EdgeDragAction(St.Side.BOTTOM);
|
||||
gesture.connect('activated', Lang.bind(this, this.toggle));
|
||||
global.stage.add_action(gesture);
|
||||
},
|
||||
|
||||
close: function() {
|
||||
@ -2025,6 +2046,16 @@ const MessageTray = new Lang.Class({
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
|
||||
_onTrayButtonKeyPress: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.ISO_Left_Tab) {
|
||||
this._focusTrap.can_focus = false;
|
||||
this._summary.navigate_focus(null, Gtk.DirectionType.TAB_BACKWARD, false);
|
||||
this._focusTrap.can_focus = true;
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onNotificationKeyRelease: function(actor, event) {
|
||||
if (event.get_key_symbol() == Clutter.KEY_Escape && event.get_state() == 0) {
|
||||
this._expireNotification();
|
||||
@ -2401,8 +2432,22 @@ const MessageTray = new Lang.Class({
|
||||
if (shouldShowNotification && nextNotification) {
|
||||
let limited = this._busy || Main.layoutManager.bottomMonitor.inFullscreen;
|
||||
let showNextNotification = (!limited || nextNotification.forFeedback || nextNotification.urgency == Urgency.CRITICAL);
|
||||
if (showNextNotification)
|
||||
this._showNotification();
|
||||
if (showNextNotification) {
|
||||
let len = this._notificationQueue.length;
|
||||
if (len > 1) {
|
||||
this._notificationQueue.length = 0;
|
||||
let source = new SystemNotificationSource();
|
||||
this.add(source);
|
||||
let notification = new Notification(source, ngettext("%d new message", "%d new messages", len).format(len));
|
||||
notification.setTransient(true);
|
||||
notification.connect('clicked', Lang.bind(this, function() {
|
||||
this.openTray();
|
||||
}));
|
||||
source.notify(notification);
|
||||
} else {
|
||||
this._showNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this._notificationState == State.SHOWN) {
|
||||
let expired = (this._userActiveWhileNotificationShown &&
|
||||
|
@ -185,7 +185,7 @@ const Overview = new Lang.Class({
|
||||
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
|
||||
let bgManager = new Background.BackgroundManager({ container: this._backgroundGroup,
|
||||
monitorIndex: i,
|
||||
effects: Meta.BackgroundEffects.VIGNETTE });
|
||||
vignette: true });
|
||||
this._bgManagers.push(bgManager);
|
||||
}
|
||||
},
|
||||
@ -193,11 +193,9 @@ const Overview = new Lang.Class({
|
||||
_unshadeBackgrounds: function() {
|
||||
let backgrounds = this._backgroundGroup.get_children();
|
||||
for (let i = 0; i < backgrounds.length; i++) {
|
||||
let background = backgrounds[i]._delegate;
|
||||
|
||||
Tweener.addTween(background,
|
||||
Tweener.addTween(backgrounds[i],
|
||||
{ brightness: 1.0,
|
||||
vignetteSharpness: 0.0,
|
||||
vignette_sharpness: 0.0,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
@ -207,11 +205,9 @@ const Overview = new Lang.Class({
|
||||
_shadeBackgrounds: function() {
|
||||
let backgrounds = this._backgroundGroup.get_children();
|
||||
for (let i = 0; i < backgrounds.length; i++) {
|
||||
let background = backgrounds[i]._delegate;
|
||||
|
||||
Tweener.addTween(background,
|
||||
Tweener.addTween(backgrounds[i],
|
||||
{ brightness: Lightbox.VIGNETTE_BRIGHTNESS,
|
||||
vignetteSharpness: Lightbox.VIGNETTE_SHARPNESS,
|
||||
vignette_sharpness: Lightbox.VIGNETTE_SHARPNESS,
|
||||
time: SHADE_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
@ -242,7 +238,7 @@ const Overview = new Lang.Class({
|
||||
opacity: 0 });
|
||||
this._overview.add_actor(this._panelGhost);
|
||||
|
||||
this._searchEntry = new St.Entry({ name: 'searchEntry',
|
||||
this._searchEntry = new St.Entry({ style_class: 'search-entry',
|
||||
/* Translators: this is the text displayed
|
||||
in the search entry when no search is
|
||||
active; it should not exceed ~30
|
||||
@ -439,17 +435,17 @@ const Overview = new Lang.Class({
|
||||
this._inDrag = false;
|
||||
},
|
||||
|
||||
beginWindowDrag: function(clone) {
|
||||
this.emit('window-drag-begin', clone);
|
||||
beginWindowDrag: function(window) {
|
||||
this.emit('window-drag-begin', window);
|
||||
this._inDrag = true;
|
||||
},
|
||||
|
||||
cancelledWindowDrag: function(clone) {
|
||||
this.emit('window-drag-cancelled', clone);
|
||||
cancelledWindowDrag: function(window) {
|
||||
this.emit('window-drag-cancelled', window);
|
||||
},
|
||||
|
||||
endWindowDrag: function(clone) {
|
||||
this.emit('window-drag-end', clone);
|
||||
endWindowDrag: function(window) {
|
||||
this.emit('window-drag-end', window);
|
||||
this._inDrag = false;
|
||||
},
|
||||
|
||||
@ -623,7 +619,7 @@ const Overview = new Lang.Class({
|
||||
this.animationInProgress = true;
|
||||
this.visibleTarget = false;
|
||||
|
||||
this.viewSelector.zoomFromOverview();
|
||||
this.viewSelector.animateFromOverview();
|
||||
|
||||
// Make other elements fade out.
|
||||
Tweener.addTween(this._stack,
|
||||
@ -675,6 +671,10 @@ const Overview = new Lang.Class({
|
||||
this.hide();
|
||||
else
|
||||
this.show();
|
||||
},
|
||||
|
||||
getShowAppsButton: function() {
|
||||
return this._dash.showAppsButton;
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(Overview.prototype);
|
||||
|
@ -36,7 +36,7 @@ const SlideLayout = new Lang.Class({
|
||||
|
||||
_init: function(params) {
|
||||
this._slideX = 1;
|
||||
this._translationX = 0;
|
||||
this._translationX = undefined;
|
||||
this._direction = SlideDirection.LEFT;
|
||||
|
||||
this.parent(params);
|
||||
@ -64,7 +64,8 @@ const SlideLayout = new Lang.Class({
|
||||
// flags only determine what to do if the allocated box is bigger
|
||||
// than the actor's box.
|
||||
let realDirection = getRtlSlideDirection(this._direction, child);
|
||||
let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth) : 0;
|
||||
let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth)
|
||||
: (availWidth - natWidth * this._slideX);
|
||||
|
||||
let actorBox = new Clutter.ActorBox();
|
||||
actorBox.x1 = box.x1 + alignX + this._translationX;
|
||||
@ -118,7 +119,6 @@ const SlidingControl = new Lang.Class({
|
||||
style_class: 'overview-controls',
|
||||
clip_to_allocation: true });
|
||||
|
||||
Main.overview.connect('showing', Lang.bind(this, this._onOverviewShowing));
|
||||
Main.overview.connect('hiding', Lang.bind(this, this._onOverviewHiding));
|
||||
|
||||
Main.overview.connect('item-drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
@ -162,7 +162,8 @@ const SlidingControl = new Lang.Class({
|
||||
let translationEnd = 0;
|
||||
let translation = this._getTranslation();
|
||||
|
||||
if (this._visible) {
|
||||
let shouldShow = (this._getSlide() > 0);
|
||||
if (shouldShow) {
|
||||
translationStart = translation;
|
||||
} else {
|
||||
translationEnd = translation;
|
||||
@ -177,14 +178,9 @@ const SlidingControl = new Lang.Class({
|
||||
transition: 'easeOutQuad' });
|
||||
},
|
||||
|
||||
_onOverviewShowing: function() {
|
||||
this._visible = true;
|
||||
this.layout.slideX = this._getSlide();
|
||||
this.layout.translationX = this._getTranslation();
|
||||
this.slideIn();
|
||||
},
|
||||
|
||||
_onOverviewHiding: function() {
|
||||
// We need to explicitly slideOut since showing pages
|
||||
// doesn't imply sliding out, instead, hiding the overview does.
|
||||
this.slideOut();
|
||||
},
|
||||
|
||||
@ -198,7 +194,7 @@ const SlidingControl = new Lang.Class({
|
||||
|
||||
_onDragBegin: function() {
|
||||
this._inDrag = true;
|
||||
this.layout.translationX = 0;
|
||||
this._updateTranslation();
|
||||
this._updateSlide();
|
||||
},
|
||||
|
||||
@ -223,7 +219,6 @@ const SlidingControl = new Lang.Class({
|
||||
|
||||
slideIn: function() {
|
||||
this._visible = true;
|
||||
this._updateTranslation();
|
||||
// we will update slideX and the translation from pageEmpty
|
||||
},
|
||||
|
||||
|
@ -571,7 +571,6 @@ const ActivitiesButton = new Lang.Class({
|
||||
this.actor.label_actor = this._label;
|
||||
|
||||
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() {
|
||||
@ -600,16 +599,21 @@ const ActivitiesButton = new Lang.Class({
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS ||
|
||||
event.type() == Clutter.EventType.TOUCH_BEGIN) {
|
||||
if (!Main.overview.shouldToggleByCornerOrButton())
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onButtonRelease: function() {
|
||||
Main.overview.toggle();
|
||||
this.menu.close();
|
||||
_onEvent: function(actor, event) {
|
||||
this.parent(actor, event);
|
||||
|
||||
if (event.type() == Clutter.EventType.TOUCH_END ||
|
||||
event.type() == Clutter.EventType.BUTTON_RELEASE)
|
||||
Main.overview.toggle();
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
@ -1015,7 +1019,7 @@ const Panel = new Lang.Class({
|
||||
if (!dragWindow)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let rect = dragWindow.get_outer_rect();
|
||||
let rect = dragWindow.get_frame_rect();
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
|
||||
let allowDrag = dragWindow.maximized_vertically &&
|
||||
|
@ -100,8 +100,7 @@ const Button = new Lang.Class({
|
||||
accessible_name: nameText ? nameText : "",
|
||||
accessible_role: Atk.Role.MENU });
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
|
||||
this.actor.connect('event', Lang.bind(this, this._onEvent));
|
||||
this.actor.connect('notify::visible', Lang.bind(this, this._onVisibilityChanged));
|
||||
|
||||
if (dontCreateMenu)
|
||||
@ -131,32 +130,13 @@ const Button = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (!this.menu)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
this.menu.toggle();
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onSourceKeyPress: function(actor, event) {
|
||||
if (!this.menu)
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||
_onEvent: function(actor, event) {
|
||||
if (this.menu &&
|
||||
(event.type() == Clutter.EventType.TOUCH_BEGIN ||
|
||||
event.type() == Clutter.EventType.BUTTON_PRESS))
|
||||
this.menu.toggle();
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) {
|
||||
this.menu.close();
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (symbol == Clutter.KEY_Down) {
|
||||
if (!this.menu.isOpen)
|
||||
this.menu.toggle();
|
||||
this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false);
|
||||
return Clutter.EVENT_STOP;
|
||||
} else
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onVisibilityChanged: function() {
|
||||
|
@ -1,9 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
@ -15,7 +13,6 @@ const GrabHelper = imports.ui.grabHelper;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Separator = imports.ui.separator;
|
||||
const Slider = imports.ui.slider;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const Ornament = {
|
||||
@ -24,17 +21,6 @@ const Ornament = {
|
||||
CHECK: 2,
|
||||
};
|
||||
|
||||
function _ensureStyle(actor) {
|
||||
if (actor.get_children) {
|
||||
let children = actor.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
_ensureStyle(children[i]);
|
||||
}
|
||||
|
||||
if (actor instanceof St.Widget)
|
||||
actor.ensure_style();
|
||||
}
|
||||
|
||||
function isPopupMenuItemVisible(child) {
|
||||
if (child._delegate instanceof PopupMenuSection)
|
||||
if (child._delegate.isEmpty())
|
||||
@ -106,6 +92,7 @@ const PopupBaseMenuItem = new Lang.Class({
|
||||
|
||||
if (this._activatable) {
|
||||
this.actor.connect('button-release-event', Lang.bind(this, this._onButtonReleaseEvent));
|
||||
this.actor.connect('touch-event', Lang.bind(this, this._onTouchEvent));
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._onKeyPressEvent));
|
||||
}
|
||||
if (params.reactive && params.hover)
|
||||
@ -132,6 +119,14 @@ const PopupBaseMenuItem = new Lang.Class({
|
||||
return Clutter.EVENT_STOP;
|
||||
},
|
||||
|
||||
_onTouchEvent: function (actor, event) {
|
||||
if (event.type() == Clutter.EventType.TOUCH_END) {
|
||||
this.activate(event);
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_onKeyPressEvent: function (actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
|
||||
@ -736,6 +731,10 @@ const PopupMenu = new Lang.Class({
|
||||
global.focus_manager.add_group(this.actor);
|
||||
this.actor.reactive = true;
|
||||
|
||||
if (this.sourceActor)
|
||||
this._keyPressId = this.sourceActor.connect('key-press-event',
|
||||
Lang.bind(this, this._onKeyPress));
|
||||
|
||||
this._openedSubMenu = null;
|
||||
},
|
||||
|
||||
@ -746,6 +745,40 @@ const PopupMenu = new Lang.Class({
|
||||
this._openedSubMenu = submenu;
|
||||
},
|
||||
|
||||
_onKeyPress: function(actor, event) {
|
||||
let navKey;
|
||||
switch (this._boxPointer.arrowSide) {
|
||||
case St.Side.TOP:
|
||||
navKey = Clutter.KEY_Down;
|
||||
break;
|
||||
case St.Side.BOTTOM:
|
||||
navKey = Clutter.KEY_Up;
|
||||
break;
|
||||
case St.Side.LEFT:
|
||||
navKey = Clutter.KEY_Right;
|
||||
break;
|
||||
case St.Side.RIGHT:
|
||||
navKey = Clutter.KEY_Left;
|
||||
break;
|
||||
}
|
||||
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
|
||||
this.toggle();
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (symbol == Clutter.KEY_Escape && this.isOpen) {
|
||||
this.close();
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (symbol == navKey) {
|
||||
if (!this.isOpen)
|
||||
this.toggle();
|
||||
this.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
return Clutter.EVENT_STOP;
|
||||
} else
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
|
||||
setArrowOrigin: function(origin) {
|
||||
this._boxPointer.setArrowOrigin(origin);
|
||||
},
|
||||
@ -786,6 +819,12 @@ const PopupMenu = new Lang.Class({
|
||||
|
||||
this.isOpen = false;
|
||||
this.emit('open-state-changed', false);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
if (this._keyPressId)
|
||||
this.sourceActor.disconnect(this._keyPressId);
|
||||
this.parent();
|
||||
}
|
||||
});
|
||||
|
||||
@ -879,12 +918,14 @@ const PopupSubMenu = new Lang.Class({
|
||||
if (animate && needsScrollbar)
|
||||
animate = false;
|
||||
|
||||
let targetAngle = this.actor.text_direction == Clutter.TextDirection.RTL ? -90 : 90;
|
||||
|
||||
if (animate) {
|
||||
let [minHeight, naturalHeight] = this.actor.get_preferred_height(-1);
|
||||
this.actor.height = 0;
|
||||
this.actor._arrowRotation = this._arrow.rotation_angle_z;
|
||||
Tweener.addTween(this.actor,
|
||||
{ _arrowRotation: this.actor._arrowRotation + 90,
|
||||
{ _arrowRotation: targetAngle,
|
||||
height: naturalHeight,
|
||||
time: 0.25,
|
||||
onUpdateScope: this,
|
||||
@ -897,7 +938,7 @@ const PopupSubMenu = new Lang.Class({
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this._arrow.rotation_angle_z = this.actor._arrowRotation + 90;
|
||||
this._arrow.rotation_angle_z = targetAngle;
|
||||
}
|
||||
},
|
||||
|
||||
@ -917,7 +958,7 @@ const PopupSubMenu = new Lang.Class({
|
||||
if (animate) {
|
||||
this.actor._arrowRotation = this._arrow.rotation_angle_z;
|
||||
Tweener.addTween(this.actor,
|
||||
{ _arrowRotation: this.actor._arrowRotation - 90,
|
||||
{ _arrowRotation: 0,
|
||||
height: 0,
|
||||
time: 0.25,
|
||||
onUpdateScope: this,
|
||||
@ -931,7 +972,7 @@ const PopupSubMenu = new Lang.Class({
|
||||
},
|
||||
});
|
||||
} else {
|
||||
this._arrow.rotation_angle_z = this.actor._arrowRotation - 90;
|
||||
this._arrow.rotation_angle_z = 0;
|
||||
this.actor.hide();
|
||||
}
|
||||
},
|
||||
@ -1009,8 +1050,6 @@ const PopupSubMenuMenuItem = new Lang.Class({
|
||||
this._triangleBin = new St.Widget({ y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this._triangleBin.add_child(this._triangle);
|
||||
if (this._triangleBin.get_text_direction() == Clutter.TextDirection.RTL)
|
||||
this._triangleBin.set_scale(-1.0, 1.0);
|
||||
|
||||
this.actor.add_child(this._triangleBin);
|
||||
this.actor.add_accessible_state (Atk.StateType.EXPANDABLE);
|
||||
|
@ -110,6 +110,13 @@ function loadRemoteSearchProviders(callback) {
|
||||
else
|
||||
remoteProvider = new RemoteSearchProvider(appInfo, busName, objectPath);
|
||||
|
||||
remoteProvider.defaultEnabled = true;
|
||||
try {
|
||||
remoteProvider.defaultEnabled = !keyfile.get_boolean(group, 'DefaultDisabled');
|
||||
} catch(e) {
|
||||
// ignore error
|
||||
}
|
||||
|
||||
objectPaths[objectPath] = remoteProvider;
|
||||
loadedProviders.push(remoteProvider);
|
||||
} catch(e) {
|
||||
@ -132,8 +139,14 @@ function loadRemoteSearchProviders(callback) {
|
||||
|
||||
loadedProviders = loadedProviders.filter(function(provider) {
|
||||
let appId = provider.appInfo.get_id();
|
||||
let disabled = searchSettings.get_strv('disabled');
|
||||
return disabled.indexOf(appId) == -1;
|
||||
|
||||
if (provider.defaultEnabled) {
|
||||
let disabled = searchSettings.get_strv('disabled');
|
||||
return disabled.indexOf(appId) == -1;
|
||||
} else {
|
||||
let enabled = searchSettings.get_strv('enabled');
|
||||
return enabled.indexOf(appId) != -1;
|
||||
}
|
||||
});
|
||||
|
||||
loadedProviders.sort(function(providerA, providerB) {
|
||||
|
@ -182,6 +182,10 @@ const RunDialog = new Lang.Class({
|
||||
let results = someResults.reduce(function(a, b) {
|
||||
return a.concat(b);
|
||||
}, []);
|
||||
|
||||
if (!results.length)
|
||||
return null;
|
||||
|
||||
let common = results.reduce(_getCommon, null);
|
||||
return common.substr(text.length);
|
||||
},
|
||||
|
@ -444,14 +444,12 @@ function clamp(value, min, max) {
|
||||
}
|
||||
|
||||
/**
|
||||
* To test screen shield, make sure to kill gnome-screensaver.
|
||||
*
|
||||
* If you are setting org.gnome.desktop.session.idle-delay directly in dconf,
|
||||
* rather than through System Settings, you also need to set
|
||||
* org.gnome.settings-daemon.plugins.power.sleep-display-ac and
|
||||
* org.gnome.settings-daemon.plugins.power.sleep-display-battery to the same value.
|
||||
* This will ensure that the screen blanks at the right time when it fades out.
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependance.
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=668703 explains the dependency.
|
||||
*/
|
||||
const ScreenShield = new Lang.Class({
|
||||
Name: 'ScreenShield',
|
||||
@ -689,10 +687,10 @@ const ScreenShield = new Lang.Class({
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
|
||||
let delta = 0;
|
||||
if (event.get_scroll_direction() == Clutter.ScrollDirection.UP)
|
||||
if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
|
||||
delta = Math.abs(event.get_scroll_delta()[0]);
|
||||
else
|
||||
delta = 5;
|
||||
else if (event.get_scroll_direction() == Clutter.ScrollDirection.SMOOTH)
|
||||
delta = Math.max(0, event.get_scroll_delta()[0]);
|
||||
|
||||
this._lockScreenScrollCounter += delta;
|
||||
|
||||
@ -902,17 +900,11 @@ const ScreenShield = new Lang.Class({
|
||||
},
|
||||
|
||||
showDialog: function() {
|
||||
// Ensure that the stage window is mapped, before taking a grab
|
||||
// otherwise X errors out
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this, function() {
|
||||
if (!this._becomeModal()) {
|
||||
// In the login screen, this is a hard error. Fail-whale
|
||||
log('Could not acquire modal grab for the login screen. Aborting login process.');
|
||||
Meta.quit(Meta.ExitCode.ERROR);
|
||||
}
|
||||
|
||||
return false;
|
||||
}));
|
||||
if (!this._becomeModal()) {
|
||||
// In the login screen, this is a hard error. Fail-whale
|
||||
log('Could not acquire modal grab for the login screen. Aborting login process.');
|
||||
Meta.quit(Meta.ExitCode.ERROR);
|
||||
}
|
||||
|
||||
this.actor.show();
|
||||
this._isGreeter = Main.sessionMode.isGreeter;
|
||||
@ -927,6 +919,11 @@ const ScreenShield = new Lang.Class({
|
||||
|
||||
this._lockScreenState = MessageTray.State.HIDDEN;
|
||||
this._lockScreenGroup.hide();
|
||||
|
||||
if (this._dialog) {
|
||||
this._dialog.actor.grab_key_focus();
|
||||
this._dialog.actor.navigate_focus(null, Gtk.DirectionType.TAB_FORWARD, false);
|
||||
}
|
||||
},
|
||||
|
||||
_hideLockScreen: function(animate, velocity) {
|
||||
|
@ -43,6 +43,8 @@ const ScreencastService = new Lang.Class({
|
||||
|
||||
this._recorders = new Map();
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' });
|
||||
|
||||
Main.sessionMode.connect('updated', Lang.bind(this, this._sessionUpdated));
|
||||
},
|
||||
|
||||
@ -68,8 +70,8 @@ const ScreencastService = new Lang.Class({
|
||||
if (Main.sessionMode.allowScreencast)
|
||||
return;
|
||||
|
||||
this._recorders.clear();
|
||||
this.emit('updated');
|
||||
for (let sender of this._recorders.keys())
|
||||
this._stopRecordingForSender(sender);
|
||||
},
|
||||
|
||||
_onNameVanished: function(connection, name) {
|
||||
@ -103,7 +105,8 @@ const ScreencastService = new Lang.Class({
|
||||
|
||||
ScreencastAsync: function(params, invocation) {
|
||||
let returnValue = [false, ''];
|
||||
if (!Main.sessionMode.allowScreencast) {
|
||||
if (!Main.sessionMode.allowScreencast ||
|
||||
this._lockdownSettings.get_boolean('disable-save-to-disk')) {
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
return;
|
||||
}
|
||||
@ -117,6 +120,8 @@ const ScreencastService = new Lang.Class({
|
||||
this._applyOptionalParameters(recorder, options);
|
||||
let [success, fileName] = recorder.record();
|
||||
returnValue = [success, fileName ? fileName : ''];
|
||||
if (!success)
|
||||
this._stopRecordingForSender(sender);
|
||||
}
|
||||
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
@ -124,7 +129,8 @@ const ScreencastService = new Lang.Class({
|
||||
|
||||
ScreencastAreaAsync: function(params, invocation) {
|
||||
let returnValue = [false, ''];
|
||||
if (!Main.sessionMode.allowScreencast) {
|
||||
if (!Main.sessionMode.allowScreencast ||
|
||||
this._lockdownSettings.get_boolean('disable-save-to-disk')) {
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
return;
|
||||
}
|
||||
@ -150,6 +156,8 @@ const ScreencastService = new Lang.Class({
|
||||
this._applyOptionalParameters(recorder, options);
|
||||
let [success, fileName] = recorder.record();
|
||||
returnValue = [success, fileName ? fileName : ''];
|
||||
if (!success)
|
||||
this._stopRecordingForSender(sender);
|
||||
}
|
||||
|
||||
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
|
||||
|
@ -65,9 +65,44 @@ const ScreenshotService = new Lang.Class({
|
||||
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenshotIface, this);
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot');
|
||||
|
||||
this._screenShooter = new Map();
|
||||
|
||||
this._lockdownSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.lockdown' });
|
||||
|
||||
Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
|
||||
},
|
||||
|
||||
_createScreenshot: function(invocation) {
|
||||
let sender = invocation.get_sender();
|
||||
if (this._screenShooter.has(sender) ||
|
||||
this._lockdownSettings.get_boolean('disable-save-to-disk')) {
|
||||
invocation.return_value(GLib.Variant.new('(bs)', [false, '']));
|
||||
return null;
|
||||
}
|
||||
|
||||
let shooter = new Shell.Screenshot();
|
||||
shooter._watchNameId =
|
||||
Gio.bus_watch_name(Gio.BusType.SESSION, sender, 0, null,
|
||||
Lang.bind(this, this._onNameVanished));
|
||||
|
||||
this._screenShooter.set(sender, shooter);
|
||||
|
||||
return shooter;
|
||||
},
|
||||
|
||||
_onNameVanished: function(connection, name) {
|
||||
this._removeShooterForSender(name);
|
||||
},
|
||||
|
||||
_removeShooterForSender: function(sender) {
|
||||
let shooter = this._screenShooter.get(sender);
|
||||
if (!shooter)
|
||||
return;
|
||||
|
||||
Gio.bus_unwatch_name(shooter._watchNameId);
|
||||
this._screenShooter.delete(sender);
|
||||
},
|
||||
|
||||
_checkArea: function(x, y, width, height) {
|
||||
return x >= 0 && y >= 0 &&
|
||||
width > 0 && height > 0 &&
|
||||
@ -76,9 +111,15 @@ const ScreenshotService = new Lang.Class({
|
||||
},
|
||||
|
||||
_onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
|
||||
if (flash && result) {
|
||||
let flashspot = new Flashspot(area);
|
||||
flashspot.fire();
|
||||
if (result) {
|
||||
if (flash) {
|
||||
let flashspot = new Flashspot(area);
|
||||
flashspot.fire(Lang.bind(this, function() {
|
||||
this._removeShooterForSender(invocation.get_sender());
|
||||
}));
|
||||
}
|
||||
else
|
||||
this._removeShooterForSender(invocation.get_sender());
|
||||
}
|
||||
|
||||
let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
|
||||
@ -112,7 +153,9 @@ const ScreenshotService = new Lang.Class({
|
||||
"Invalid params");
|
||||
return;
|
||||
}
|
||||
let screenshot = new Shell.Screenshot();
|
||||
let screenshot = this._createScreenshot(invocation);
|
||||
if (!screenshot)
|
||||
return;
|
||||
screenshot.screenshot_area (x, y, width, height, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
@ -120,7 +163,9 @@ const ScreenshotService = new Lang.Class({
|
||||
|
||||
ScreenshotWindowAsync : function (params, invocation) {
|
||||
let [include_frame, include_cursor, flash, filename] = params;
|
||||
let screenshot = new Shell.Screenshot();
|
||||
let screenshot = this._createScreenshot(invocation);
|
||||
if (!screenshot)
|
||||
return;
|
||||
screenshot.screenshot_window (include_frame, include_cursor, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
@ -128,7 +173,9 @@ const ScreenshotService = new Lang.Class({
|
||||
|
||||
ScreenshotAsync : function (params, invocation) {
|
||||
let [include_cursor, flash, filename] = params;
|
||||
let screenshot = new Shell.Screenshot();
|
||||
let screenshot = this._createScreenshot(invocation);
|
||||
if (!screenshot)
|
||||
return;
|
||||
screenshot.screenshot(include_cursor, filename,
|
||||
Lang.bind(this, this._onScreenshotComplete,
|
||||
flash, invocation));
|
||||
@ -302,7 +349,7 @@ const Flashspot = new Lang.Class({
|
||||
this.actor.set_position(area.x, area.y);
|
||||
},
|
||||
|
||||
fire: function() {
|
||||
fire: function(doneCallback) {
|
||||
this.actor.show();
|
||||
this.actor.opacity = 255;
|
||||
Tweener.addTween(this.actor,
|
||||
@ -310,6 +357,8 @@ const Flashspot = new Lang.Class({
|
||||
time: FLASHSPOT_ANIMATION_OUT_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
if (doneCallback)
|
||||
doneCallback();
|
||||
this.destroy();
|
||||
})
|
||||
});
|
||||
|
424
js/ui/search.js
424
js/ui/search.js
@ -2,10 +2,12 @@
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Signals = imports.signals;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Atk = imports.gi.Atk;
|
||||
|
||||
@ -23,107 +25,6 @@ const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
|
||||
const MAX_LIST_SEARCH_RESULTS_ROWS = 3;
|
||||
const MAX_GRID_SEARCH_RESULTS_ROWS = 1;
|
||||
|
||||
const SearchSystem = new Lang.Class({
|
||||
Name: 'SearchSystem',
|
||||
|
||||
_init: function() {
|
||||
this._providers = [];
|
||||
|
||||
this._registerProvider(new AppDisplay.AppSearchProvider());
|
||||
|
||||
this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA });
|
||||
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
|
||||
|
||||
this._reloadRemoteProviders();
|
||||
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
},
|
||||
|
||||
addProvider: function(provider) {
|
||||
this._providers.push(provider);
|
||||
this.emit('providers-changed');
|
||||
},
|
||||
|
||||
_reloadRemoteProviders: function() {
|
||||
let remoteProviders = this._providers.filter(function(provider) {
|
||||
return provider.isRemoteProvider;
|
||||
});
|
||||
remoteProviders.forEach(Lang.bind(this, function(provider) {
|
||||
this._unregisterProvider(provider);
|
||||
}));
|
||||
|
||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, function(providers) {
|
||||
providers.forEach(Lang.bind(this, this._registerProvider));
|
||||
}));
|
||||
|
||||
this.emit('providers-changed');
|
||||
},
|
||||
|
||||
_registerProvider: function (provider) {
|
||||
this._providers.push(provider);
|
||||
},
|
||||
|
||||
_unregisterProvider: function (provider) {
|
||||
let index = this._providers.indexOf(provider);
|
||||
this._providers.splice(index, 1);
|
||||
|
||||
if (provider.display)
|
||||
provider.display.destroy();
|
||||
},
|
||||
|
||||
getProviders: function() {
|
||||
return this._providers;
|
||||
},
|
||||
|
||||
getTerms: function() {
|
||||
return this._terms;
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this._terms = [];
|
||||
this._results = {};
|
||||
},
|
||||
|
||||
_gotResults: function(results, provider) {
|
||||
this._results[provider.id] = results;
|
||||
this.emit('search-updated', provider, results);
|
||||
},
|
||||
|
||||
setTerms: function(terms) {
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
|
||||
let previousResults = this._results;
|
||||
let previousTerms = this._terms;
|
||||
this.reset();
|
||||
|
||||
if (!terms)
|
||||
return;
|
||||
|
||||
let searchString = terms.join(' ');
|
||||
let previousSearchString = previousTerms.join(' ');
|
||||
if (searchString == previousSearchString)
|
||||
return;
|
||||
|
||||
let isSubSearch = false;
|
||||
if (previousTerms.length > 0)
|
||||
isSubSearch = searchString.indexOf(previousSearchString) == 0;
|
||||
|
||||
this._terms = terms;
|
||||
|
||||
this._providers.forEach(Lang.bind(this, function(provider) {
|
||||
let previousProviderResults = previousResults[provider.id];
|
||||
if (isSubSearch && previousProviderResults)
|
||||
provider.getSubsearchResultSet(previousProviderResults, terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||
else
|
||||
provider.getInitialResultSet(terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||
}));
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SearchSystem.prototype);
|
||||
|
||||
const MaxWidthBin = new Lang.Class({
|
||||
Name: 'MaxWidthBin',
|
||||
Extends: St.Bin,
|
||||
@ -163,13 +64,6 @@ const SearchResult = new Lang.Class({
|
||||
|
||||
activate: function() {
|
||||
this.emit('activate', this.metaInfo.id);
|
||||
},
|
||||
|
||||
setSelected: function(selected) {
|
||||
if (selected)
|
||||
this.actor.add_style_pseudo_class('selected');
|
||||
else
|
||||
this.actor.remove_style_pseudo_class('selected');
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(SearchResult.prototype);
|
||||
@ -230,59 +124,11 @@ const GridSearchResult = new Lang.Class({
|
||||
|
||||
this.actor.style_class = 'grid-search-result';
|
||||
|
||||
let content = provider.createResultObject(metaInfo);
|
||||
let dragSource = null;
|
||||
|
||||
if (content == null) {
|
||||
let actor = new St.Bin();
|
||||
let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||
{ createIcon: this.metaInfo['createIcon'] });
|
||||
actor.set_child(icon.actor);
|
||||
actor.label_actor = icon.label;
|
||||
dragSource = icon.icon;
|
||||
content = { actor: actor, icon: icon };
|
||||
} else {
|
||||
if (content._delegate && content._delegate.getDragActorSource)
|
||||
dragSource = content._delegate.getDragActorSource();
|
||||
}
|
||||
|
||||
this.actor.set_child(content.actor);
|
||||
this.actor.label_actor = content.actor.label_actor;
|
||||
this.icon = content.icon;
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
draggable.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledItemDrag(this);
|
||||
}));
|
||||
draggable.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endItemDrag(this);
|
||||
}));
|
||||
|
||||
if (!dragSource)
|
||||
// not exactly right, but alignment problems are hard to notice
|
||||
dragSource = content;
|
||||
this._dragActorSource = dragSource;
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
return this._dragActorSource;
|
||||
},
|
||||
|
||||
getDragActor: function() {
|
||||
return this.metaInfo['createIcon'](Main.overview.dashIconSize);
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch: function(params) {
|
||||
if (this.provider.dragActivateResult)
|
||||
this.provider.dragActivateResult(this.metaInfo.id, params);
|
||||
else
|
||||
this.provider.activateResult(this.metaInfo.id, this.terms);
|
||||
this.icon = new IconGrid.BaseIcon(this.metaInfo['name'],
|
||||
{ createIcon: this.metaInfo['createIcon'] });
|
||||
let content = new St.Bin({ child: this.icon.actor });
|
||||
this.actor.set_child(content);
|
||||
this.actor.label_actor = this.icon.label;
|
||||
}
|
||||
});
|
||||
|
||||
@ -314,7 +160,11 @@ const SearchResultsBase = new Lang.Class({
|
||||
this._terms = [];
|
||||
},
|
||||
|
||||
_clearResultDisplay: function() {
|
||||
_createResultDisplay: function(meta) {
|
||||
if (this.provider.createResultObject)
|
||||
return this.provider.createResultObject(meta);
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
clear: function() {
|
||||
@ -384,9 +234,10 @@ const SearchResultsBase = new Lang.Class({
|
||||
let hasMoreResults = results.length < providerResults.length;
|
||||
|
||||
this._ensureResultActors(results, Lang.bind(this, function(successful) {
|
||||
this._clearResultDisplay();
|
||||
if (!successful)
|
||||
if (!successful) {
|
||||
this._clearResultDisplay();
|
||||
return;
|
||||
}
|
||||
|
||||
// To avoid CSS transitions causing flickering when
|
||||
// the first search result stays the same, we hide the
|
||||
@ -416,6 +267,7 @@ const ListSearchResults = new Lang.Class({
|
||||
this.providerIcon.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this.providerIcon.connect('clicked', Lang.bind(this,
|
||||
function() {
|
||||
this.providerIcon.animateLaunch();
|
||||
provider.launchSearch(this._terms);
|
||||
Main.overview.toggle();
|
||||
}));
|
||||
@ -433,7 +285,7 @@ const ListSearchResults = new Lang.Class({
|
||||
},
|
||||
|
||||
_setMoreIconVisible: function(visible) {
|
||||
this.providerIcon.moreIcon.visible = true;
|
||||
this.providerIcon.moreIcon.visible = visible;
|
||||
},
|
||||
|
||||
_getMaxDisplayedResults: function() {
|
||||
@ -445,7 +297,7 @@ const ListSearchResults = new Lang.Class({
|
||||
},
|
||||
|
||||
_createResultDisplay: function(meta) {
|
||||
return new ListSearchResult(this.provider, meta);
|
||||
return this.parent(meta) || new ListSearchResult(this.provider, meta);
|
||||
},
|
||||
|
||||
_addItem: function(display) {
|
||||
@ -488,21 +340,12 @@ const GridSearchResults = new Lang.Class({
|
||||
return this._grid.columnsForWidth(availableWidth) * this._grid.getRowLimit();
|
||||
},
|
||||
|
||||
_renderResults: function(metas) {
|
||||
for (let i = 0; i < metas.length; i++) {
|
||||
let display = new GridSearchResult(this.provider, metas[i]);
|
||||
display.connect('activate', Lang.bind(this, this._activateResult));
|
||||
display.actor.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
this._grid.addItem(display);
|
||||
}
|
||||
},
|
||||
|
||||
_clearResultDisplay: function () {
|
||||
this._grid.removeAll();
|
||||
},
|
||||
|
||||
_createResultDisplay: function(meta) {
|
||||
return new GridSearchResult(this.provider, meta);
|
||||
return this.parent(meta) || new GridSearchResult(this.provider, meta);
|
||||
},
|
||||
|
||||
_addItem: function(display) {
|
||||
@ -554,16 +397,136 @@ const SearchResults = new Lang.Class({
|
||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
|
||||
y_align: St.Align.MIDDLE });
|
||||
this._content.add(this._statusBin, { expand: true });
|
||||
this.actor.add(this._statusBin, { expand: true });
|
||||
this._statusBin.add_actor(this._statusText);
|
||||
|
||||
this._highlightDefault = false;
|
||||
this._defaultResult = null;
|
||||
this._startingSearch = false;
|
||||
|
||||
this._searchSystem = new SearchSystem();
|
||||
this._searchSystem.connect('search-updated', Lang.bind(this, this._updateResults));
|
||||
this._searchSystem.connect('providers-changed', Lang.bind(this, this._updateProviderDisplays));
|
||||
this._updateProviderDisplays();
|
||||
this._terms = [];
|
||||
this._results = {};
|
||||
|
||||
this._providers = [];
|
||||
|
||||
this._searchSettings = new Gio.Settings({ schema_id: SEARCH_PROVIDERS_SCHEMA });
|
||||
this._searchSettings.connect('changed::disabled', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::disable-external', Lang.bind(this, this._reloadRemoteProviders));
|
||||
this._searchSettings.connect('changed::sort-order', Lang.bind(this, this._reloadRemoteProviders));
|
||||
|
||||
this._searchTimeoutId = 0;
|
||||
this._cancellable = new Gio.Cancellable();
|
||||
|
||||
this._registerProvider(new AppDisplay.AppSearchProvider());
|
||||
this._reloadRemoteProviders();
|
||||
},
|
||||
|
||||
_reloadRemoteProviders: function() {
|
||||
let remoteProviders = this._providers.filter(function(provider) {
|
||||
return provider.isRemoteProvider;
|
||||
});
|
||||
remoteProviders.forEach(Lang.bind(this, function(provider) {
|
||||
this._unregisterProvider(provider);
|
||||
}));
|
||||
|
||||
RemoteSearch.loadRemoteSearchProviders(Lang.bind(this, function(providers) {
|
||||
providers.forEach(Lang.bind(this, this._registerProvider));
|
||||
}));
|
||||
},
|
||||
|
||||
_registerProvider: function (provider) {
|
||||
this._providers.push(provider);
|
||||
this._ensureProviderDisplay(provider);
|
||||
},
|
||||
|
||||
_unregisterProvider: function (provider) {
|
||||
let index = this._providers.indexOf(provider);
|
||||
this._providers.splice(index, 1);
|
||||
|
||||
if (provider.display)
|
||||
provider.display.destroy();
|
||||
},
|
||||
|
||||
_gotResults: function(results, provider) {
|
||||
this._results[provider.id] = results;
|
||||
this._updateResults(provider, results);
|
||||
},
|
||||
|
||||
_clearSearchTimeout: function() {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
GLib.source_remove(this._searchTimeoutId);
|
||||
this._searchTimeoutId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_reset: function() {
|
||||
this._terms = [];
|
||||
this._results = {};
|
||||
this._clearDisplay();
|
||||
this._clearSearchTimeout();
|
||||
this._defaultResult = null;
|
||||
this._startingSearch = false;
|
||||
|
||||
this._updateSearchProgress();
|
||||
},
|
||||
|
||||
_doSearch: function() {
|
||||
this._startingSearch = false;
|
||||
|
||||
let previousResults = this._results;
|
||||
this._results = {};
|
||||
|
||||
this._providers.forEach(Lang.bind(this, function(provider) {
|
||||
provider.searchInProgress = true;
|
||||
|
||||
let previousProviderResults = previousResults[provider.id];
|
||||
if (this._isSubSearch && previousProviderResults)
|
||||
provider.getSubsearchResultSet(previousProviderResults, this._terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||
else
|
||||
provider.getInitialResultSet(this._terms, Lang.bind(this, this._gotResults, provider), this._cancellable);
|
||||
}));
|
||||
|
||||
this._updateSearchProgress();
|
||||
|
||||
this._clearSearchTimeout();
|
||||
},
|
||||
|
||||
_onSearchTimeout: function() {
|
||||
this._searchTimeoutId = 0;
|
||||
this._doSearch();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
|
||||
setTerms: function(terms) {
|
||||
// Check for the case of making a duplicate previous search before
|
||||
// setting state of the current search or cancelling the search.
|
||||
// This will prevent incorrect state being as a result of a duplicate
|
||||
// search while the previous search is still active.
|
||||
let searchString = terms.join(' ');
|
||||
let previousSearchString = this._terms.join(' ');
|
||||
if (searchString == previousSearchString)
|
||||
return;
|
||||
|
||||
this._startingSearch = true;
|
||||
|
||||
this._cancellable.cancel();
|
||||
this._cancellable.reset();
|
||||
|
||||
if (terms.length == 0) {
|
||||
this._reset();
|
||||
return;
|
||||
}
|
||||
|
||||
let isSubSearch = false;
|
||||
if (this._terms.length > 0)
|
||||
isSubSearch = searchString.indexOf(previousSearchString) == 0;
|
||||
|
||||
this._terms = terms;
|
||||
this._isSubSearch = isSubSearch;
|
||||
this._updateSearchProgress();
|
||||
|
||||
if (this._searchTimeoutId == 0)
|
||||
this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 150, Lang.bind(this, this._onSearchTimeout));
|
||||
},
|
||||
|
||||
_onPan: function(action) {
|
||||
@ -585,44 +548,24 @@ const SearchResults = new Lang.Class({
|
||||
if (provider.appInfo)
|
||||
providerDisplay = new ListSearchResults(provider);
|
||||
else
|
||||
providerDisplay = new GridSearchResults(provider, this._content);
|
||||
providerDisplay = new GridSearchResults(provider, this.actor);
|
||||
|
||||
providerDisplay.connect('key-focus-in', Lang.bind(this, this._keyFocusIn));
|
||||
providerDisplay.actor.hide();
|
||||
this._content.add(providerDisplay.actor);
|
||||
provider.display = providerDisplay;
|
||||
},
|
||||
|
||||
_updateProviderDisplays: function() {
|
||||
this._searchSystem.getProviders().forEach(Lang.bind(this, this._ensureProviderDisplay));
|
||||
},
|
||||
|
||||
_clearDisplay: function() {
|
||||
this._searchSystem.getProviders().forEach(function(provider) {
|
||||
this._providers.forEach(function(provider) {
|
||||
provider.display.clear();
|
||||
});
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this._searchSystem.reset();
|
||||
this._statusBin.hide();
|
||||
this._clearDisplay();
|
||||
this._defaultResult = null;
|
||||
},
|
||||
|
||||
startingSearch: function() {
|
||||
this.reset();
|
||||
this._statusText.set_text(_("Searching…"));
|
||||
this._statusBin.show();
|
||||
},
|
||||
|
||||
setTerms: function(terms) {
|
||||
this._searchSystem.setTerms(terms);
|
||||
},
|
||||
|
||||
_maybeSetInitialSelection: function() {
|
||||
let newDefaultResult = null;
|
||||
|
||||
let providers = this._searchSystem.getProviders();
|
||||
let providers = this._providers;
|
||||
for (let i = 0; i < providers.length; i++) {
|
||||
let provider = providers[i];
|
||||
let display = provider.display;
|
||||
@ -638,54 +581,64 @@ const SearchResults = new Lang.Class({
|
||||
}
|
||||
|
||||
if (newDefaultResult != this._defaultResult) {
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.setSelected(false);
|
||||
if (newDefaultResult) {
|
||||
newDefaultResult.setSelected(this._highlightDefault);
|
||||
if (this._highlightDefault)
|
||||
Util.ensureActorVisibleInScrollView(this._scrollView, newDefaultResult.actor);
|
||||
}
|
||||
this._setSelected(this._defaultResult, false);
|
||||
this._setSelected(newDefaultResult, this._highlightDefault);
|
||||
|
||||
this._defaultResult = newDefaultResult;
|
||||
}
|
||||
},
|
||||
|
||||
_updateStatusText: function () {
|
||||
let haveResults = this._searchSystem.getProviders().some(function(provider) {
|
||||
get searchInProgress() {
|
||||
if (this._startingSearch)
|
||||
return true;
|
||||
|
||||
return this._providers.some(function(provider) {
|
||||
return provider.searchInProgress;
|
||||
});
|
||||
},
|
||||
|
||||
_updateSearchProgress: function () {
|
||||
let haveResults = this._providers.some(function(provider) {
|
||||
let display = provider.display;
|
||||
return (display.getFirstResult() != null);
|
||||
});
|
||||
|
||||
this._scrollView.visible = haveResults;
|
||||
this._statusBin.visible = !haveResults;
|
||||
|
||||
if (!haveResults) {
|
||||
this._statusText.set_text(_("No results."));
|
||||
this._statusBin.show();
|
||||
} else {
|
||||
this._statusBin.hide();
|
||||
if (this.searchInProgress) {
|
||||
this._statusText.set_text(_("Searching…"));
|
||||
} else {
|
||||
this._statusText.set_text(_("No results."));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_updateResults: function(searchSystem, provider, results) {
|
||||
let terms = searchSystem.getTerms();
|
||||
_updateResults: function(provider, results) {
|
||||
let terms = this._terms;
|
||||
let display = provider.display;
|
||||
|
||||
display.updateSearch(results, terms, Lang.bind(this, function() {
|
||||
provider.searchInProgress = false;
|
||||
|
||||
this._maybeSetInitialSelection();
|
||||
this._updateStatusText();
|
||||
this._updateSearchProgress();
|
||||
}));
|
||||
},
|
||||
|
||||
activateDefault: function() {
|
||||
// If we have a search queued up, force the search now.
|
||||
if (this._searchTimeoutId > 0)
|
||||
this._doSearch();
|
||||
|
||||
if (this._defaultResult)
|
||||
this._defaultResult.activate();
|
||||
},
|
||||
|
||||
highlightDefault: function(highlight) {
|
||||
this._highlightDefault = highlight;
|
||||
if (this._defaultResult) {
|
||||
this._defaultResult.setSelected(highlight);
|
||||
if (highlight)
|
||||
Util.ensureActorVisibleInScrollView(this._scrollView, this._defaultResult.actor);
|
||||
}
|
||||
this._setSelected(this._defaultResult, highlight);
|
||||
},
|
||||
|
||||
navigateFocus: function(direction) {
|
||||
@ -700,6 +653,18 @@ const SearchResults = new Lang.Class({
|
||||
|
||||
let from = this._defaultResult ? this._defaultResult.actor : null;
|
||||
this.actor.navigate_focus(from, direction, false);
|
||||
},
|
||||
|
||||
_setSelected: function(result, selected) {
|
||||
if (!result)
|
||||
return;
|
||||
|
||||
if (selected) {
|
||||
result.actor.add_style_pseudo_class('selected');
|
||||
Util.ensureActorVisibleInScrollView(this._scrollView, result.actor);
|
||||
} else {
|
||||
result.actor.remove_style_pseudo_class('selected');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -733,5 +698,12 @@ const ProviderIcon = new Lang.Class({
|
||||
gicon: provider.appInfo.get_icon() });
|
||||
this._content.add_actor(icon);
|
||||
this._content.add_actor(this.moreIcon);
|
||||
},
|
||||
|
||||
animateLaunch: function() {
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let app = appSys.lookup_app(this.provider.appInfo.get_id());
|
||||
if (app.state == Shell.AppState.STOPPED)
|
||||
IconGrid.zoomOutActor(this._content);
|
||||
}
|
||||
});
|
||||
|
@ -17,8 +17,6 @@ const EntryMenu = new Lang.Class({
|
||||
_init: function(entry) {
|
||||
this.parent(entry, 0, St.Side.TOP);
|
||||
|
||||
this.actor.add_style_class_name('entry-context-menu');
|
||||
|
||||
this._entry = entry;
|
||||
this._clipboard = St.Clipboard.get_default();
|
||||
|
||||
|
@ -24,6 +24,7 @@ const Slider = new Lang.Class({
|
||||
accessible_role: Atk.Role.SLIDER });
|
||||
this.actor.connect('repaint', Lang.bind(this, this._sliderRepaint));
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._startDragging));
|
||||
this.actor.connect('touch-event', Lang.bind(this, this._touchDragging));
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this.onKeyPressEvent));
|
||||
|
||||
@ -121,11 +122,21 @@ const Slider = new Lang.Class({
|
||||
this._dragging = true;
|
||||
|
||||
let device = event.get_device();
|
||||
device.grab(this.actor);
|
||||
this._grabbedDevice = device;
|
||||
let sequence = event.get_event_sequence();
|
||||
|
||||
if (sequence != null)
|
||||
device.sequence_grab(sequence, this.actor);
|
||||
else
|
||||
device.grab(this.actor);
|
||||
|
||||
this._grabbedDevice = device;
|
||||
this._grabbedSequence = sequence;
|
||||
|
||||
if (sequence == null) {
|
||||
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._releaseId = this.actor.connect('button-release-event', Lang.bind(this, this._endDragging));
|
||||
this._motionId = this.actor.connect('motion-event', Lang.bind(this, this._motionEvent));
|
||||
let absX, absY;
|
||||
[absX, absY] = event.get_coords();
|
||||
this._moveHandle(absX, absY);
|
||||
@ -134,10 +145,17 @@ const Slider = new Lang.Class({
|
||||
|
||||
_endDragging: function() {
|
||||
if (this._dragging) {
|
||||
this.actor.disconnect(this._releaseId);
|
||||
this.actor.disconnect(this._motionId);
|
||||
if (this._releaseId)
|
||||
this.actor.disconnect(this._releaseId);
|
||||
if (this._motionId)
|
||||
this.actor.disconnect(this._motionId);
|
||||
|
||||
this._grabbedDevice.ungrab();
|
||||
if (this._grabbedSequence != null)
|
||||
this._grabbedDevice.sequence_ungrab(this._grabbedSequence);
|
||||
else
|
||||
this._grabbedDevice.ungrab();
|
||||
|
||||
this._grabbedSequence = null;
|
||||
this._grabbedDevice = null;
|
||||
this._dragging = false;
|
||||
|
||||
@ -146,6 +164,24 @@ const Slider = new Lang.Class({
|
||||
return Clutter.EVENT_STOP;
|
||||
},
|
||||
|
||||
_touchDragging: function(actor, event) {
|
||||
let device = event.get_device();
|
||||
let sequence = event.get_event_sequence();
|
||||
|
||||
if (!this._dragging &&
|
||||
event.type() == Clutter.EventType.TOUCH_BEGIN) {
|
||||
this.startDragging(event);
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (device.sequence_get_grabbed_actor(sequence) == actor) {
|
||||
if (event.type() == Clutter.EventType.TOUCH_UPDATE)
|
||||
return this._motionEvent(actor, event);
|
||||
else if (event.type() == Clutter.EventType.TOUCH_END)
|
||||
return this._endDragging();
|
||||
}
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
scroll: function(event) {
|
||||
let direction = event.get_scroll_direction();
|
||||
let delta;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,8 +9,18 @@ const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const LOCATION_SCHEMA = 'org.gnome.shell.location';
|
||||
const LOCATION_SCHEMA = 'org.gnome.system.location';
|
||||
const MAX_ACCURACY_LEVEL = 'max-accuracy-level';
|
||||
const ENABLED = 'enabled';
|
||||
|
||||
const GeoclueAccuracyLevel = {
|
||||
NONE: 0,
|
||||
COUNTRY: 1,
|
||||
CITY: 4,
|
||||
NEIGHBORHOOD: 5,
|
||||
STREET: 6,
|
||||
EXACT: 8
|
||||
};
|
||||
|
||||
var GeoclueIface = '<node> \
|
||||
<interface name="org.freedesktop.GeoClue2.Manager"> \
|
||||
@ -44,6 +54,8 @@ const Indicator = new Lang.Class({
|
||||
this.parent();
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: LOCATION_SCHEMA });
|
||||
this._settings.connect('changed::' + ENABLED,
|
||||
Lang.bind(this, this._onMaxAccuracyLevelChanged));
|
||||
this._settings.connect('changed::' + MAX_ACCURACY_LEVEL,
|
||||
Lang.bind(this, this._onMaxAccuracyLevelChanged));
|
||||
|
||||
@ -58,6 +70,7 @@ const Indicator = new Lang.Class({
|
||||
|
||||
this._item.status.text = _("Enabled");
|
||||
this._onOffAction = this._item.menu.addAction(_("Disable"), Lang.bind(this, this._onOnOffAction));
|
||||
this._item.menu.addSettingsAction(_("Privacy Settings"), 'gnome-privacy-panel.desktop');
|
||||
|
||||
this.menu.addMenuItem(this._item);
|
||||
|
||||
@ -93,10 +106,12 @@ const Indicator = new Lang.Class({
|
||||
_syncIndicator: function() {
|
||||
if (this._proxy == null) {
|
||||
this._indicator.visible = false;
|
||||
this._item.actor.visible = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this._indicator.visible = this._proxy.InUse;
|
||||
this._item.actor.visible = this._indicator.visible;
|
||||
this._updateMenuLabels();
|
||||
},
|
||||
|
||||
@ -123,7 +138,6 @@ const Indicator = new Lang.Class({
|
||||
this._propertiesChangedId = this._proxy.connect('g-properties-changed',
|
||||
Lang.bind(this, this._onGeocluePropsChanged));
|
||||
|
||||
this._availableAccuracyLevel = this._proxy.AvailableAccuracyLevel;
|
||||
this._syncIndicator();
|
||||
|
||||
this._proxy.AddAgentRemote('gnome-shell', Lang.bind(this, this._onAgentRegistered));
|
||||
@ -148,10 +162,8 @@ const Indicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_onOnOffAction: function() {
|
||||
if (this._getMaxAccuracyLevel() == 0)
|
||||
this._settings.set_enum(MAX_ACCURACY_LEVEL, this._availableAccuracyLevel);
|
||||
else
|
||||
this._settings.set_enum(MAX_ACCURACY_LEVEL, 0);
|
||||
let enabled = this._settings.get_boolean(ENABLED);
|
||||
this._settings.set_boolean(ENABLED, !enabled);
|
||||
},
|
||||
|
||||
_onSessionUpdated: function() {
|
||||
@ -160,12 +172,12 @@ const Indicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_updateMenuLabels: function() {
|
||||
if (this._getMaxAccuracyLevel() == 0) {
|
||||
this._item.status.text = _("Disabled");
|
||||
this._onOffAction.label.text = _("Enable");
|
||||
} else {
|
||||
if (this._settings.get_boolean(ENABLED)) {
|
||||
this._item.status.text = this._indicator.visible ? _("In Use") : _("Enabled");
|
||||
this._onOffAction.label.text = _("Disable");
|
||||
} else {
|
||||
this._item.status.text = _("Disabled");
|
||||
this._onOffAction.label.text = _("Enable");
|
||||
}
|
||||
},
|
||||
|
||||
@ -179,7 +191,14 @@ const Indicator = new Lang.Class({
|
||||
},
|
||||
|
||||
_getMaxAccuracyLevel: function() {
|
||||
return this._settings.get_enum(MAX_ACCURACY_LEVEL);
|
||||
if (this._settings.get_boolean(ENABLED)) {
|
||||
let level = this._settings.get_string(MAX_ACCURACY_LEVEL);
|
||||
|
||||
return GeoclueAccuracyLevel[level.toUpperCase()] ||
|
||||
GeoclueAccuracyLevel.NONE;
|
||||
} else {
|
||||
return GeoclueAccuracyLevel.NONE;
|
||||
}
|
||||
},
|
||||
|
||||
_notifyMaxAccuracyLevel: function() {
|
||||
@ -191,12 +210,6 @@ const Indicator = new Lang.Class({
|
||||
let unpacked = properties.deep_unpack();
|
||||
if ("InUse" in unpacked)
|
||||
this._syncIndicator();
|
||||
if ("AvailableAccuracyLevel" in unpacked) {
|
||||
this._availableAccuracyLevel = this._proxy.AvailableAccuracyLevel;
|
||||
|
||||
if (this._getMaxAccuracyLevel() != 0)
|
||||
this._settings.set_enum(MAX_ACCURACY_LEVEL, this._availableAccuracyLevel);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -102,16 +102,17 @@ const SwitcherPopup = new Lang.Class({
|
||||
this._switcherList.actor.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
_createSwitcher: function() {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
_initialSelection: function(backward, binding) {
|
||||
throw new Error('Not implemented');
|
||||
if (backward)
|
||||
this._select(this._items.length - 1);
|
||||
else if (this._items.length == 1)
|
||||
this._select(0);
|
||||
else
|
||||
this._select(1);
|
||||
},
|
||||
|
||||
show: function(backward, binding, mask) {
|
||||
if (!this._createSwitcher())
|
||||
if (this._items.length == 0)
|
||||
return false;
|
||||
|
||||
if (!Main.pushModal(this.actor)) {
|
||||
@ -139,11 +140,6 @@ const SwitcherPopup = new Lang.Class({
|
||||
this.actor.show();
|
||||
this.actor.get_allocation_box();
|
||||
|
||||
if (this._items.length > 1)
|
||||
this._selectedIndex = 1;
|
||||
else
|
||||
this._selectedIndex = 0;
|
||||
|
||||
this._initialSelection(backward, binding);
|
||||
|
||||
// There's a race condition; if the user released Alt before
|
||||
@ -178,19 +174,17 @@ const SwitcherPopup = new Lang.Class({
|
||||
return mod(this._selectedIndex - 1, this._items.length);
|
||||
},
|
||||
|
||||
_keyPressHandler: function(keysym, backwards, action) {
|
||||
_keyPressHandler: function(keysym, action) {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
_keyPressEvent: function(actor, event) {
|
||||
let keysym = event.get_key_symbol();
|
||||
let event_state = event.get_state();
|
||||
let backwards = event_state & Clutter.ModifierType.SHIFT_MASK;
|
||||
let action = global.display.get_keybinding_action(event.get_key_code(), event_state);
|
||||
let action = global.display.get_keybinding_action(event.get_key_code(), event.get_state());
|
||||
|
||||
this._disableHover();
|
||||
|
||||
if (this._keyPressHandler(keysym, backwards, action) != Clutter.EVENT_PROPAGATE)
|
||||
if (this._keyPressHandler(keysym, action) != Clutter.EVENT_PROPAGATE)
|
||||
return Clutter.EVENT_STOP;
|
||||
|
||||
if (keysym == Clutter.Escape)
|
||||
|
@ -53,8 +53,10 @@ function _wrapTweening(target, tweeningParameters) {
|
||||
}
|
||||
}
|
||||
|
||||
if (!Gtk.Settings.get_default().gtk_enable_animations)
|
||||
if (!Gtk.Settings.get_default().gtk_enable_animations) {
|
||||
tweeningParameters['time'] = 0.000001;
|
||||
tweeningParameters['delay'] = 0.000001;
|
||||
}
|
||||
|
||||
_addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
|
||||
}
|
||||
|
@ -28,11 +28,12 @@ const Avatar = new Lang.Class({
|
||||
styleClass: 'framed-user-icon' });
|
||||
this._iconSize = params.iconSize;
|
||||
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this.actor = new St.Bin({ style_class: params.styleClass,
|
||||
track_hover: params.reactive,
|
||||
reactive: params.reactive,
|
||||
width: this._iconSize,
|
||||
height: this._iconSize });
|
||||
width: this._iconSize * scaleFactor,
|
||||
height: this._iconSize * scaleFactor });
|
||||
},
|
||||
|
||||
setSensitive: function(sensitive) {
|
||||
|
@ -19,6 +19,8 @@ const Search = imports.ui.search;
|
||||
const ShellEntry = imports.ui.shellEntry;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WorkspacesView = imports.ui.workspacesView;
|
||||
const EdgeDragAction = imports.ui.edgeDragAction;
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
|
||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||
|
||||
@ -49,77 +51,6 @@ function getTermsForSearchString(searchString) {
|
||||
return terms;
|
||||
}
|
||||
|
||||
const EDGE_THRESHOLD = 20;
|
||||
const DRAG_DISTANCE = 80;
|
||||
|
||||
const EdgeDragAction = new Lang.Class({
|
||||
Name: 'EdgeDragAction',
|
||||
Extends: Clutter.GestureAction,
|
||||
|
||||
_init : function(side) {
|
||||
this.parent();
|
||||
this._side = side;
|
||||
this.set_n_touch_points(1);
|
||||
|
||||
global.display.connect('grab-op-begin', Lang.bind(this, function() {
|
||||
this.cancel();
|
||||
}));
|
||||
},
|
||||
|
||||
_getMonitorRect : function (x, y) {
|
||||
let rect = new Meta.Rectangle({ x: x - 1, y: y - 1, width: 1, height: 1 });
|
||||
let monitorIndex = global.screen.get_monitor_index_for_rect(rect);
|
||||
|
||||
return global.screen.get_monitor_geometry(monitorIndex);
|
||||
},
|
||||
|
||||
vfunc_gesture_prepare : function(action, actor) {
|
||||
if (this.get_n_current_points() == 0)
|
||||
return false;
|
||||
|
||||
let [x, y] = this.get_press_coords(0);
|
||||
let monitorRect = this._getMonitorRect(x, y);
|
||||
|
||||
return ((this._side == St.Side.LEFT && x < monitorRect.x + EDGE_THRESHOLD) ||
|
||||
(this._side == St.Side.RIGHT && x > monitorRect.x + monitorRect.width - EDGE_THRESHOLD) ||
|
||||
(this._side == St.Side.TOP && y < monitorRect.y + EDGE_THRESHOLD) ||
|
||||
(this._side == St.Side.BOTTOM && y > monitorRect.y + monitorRect.height - EDGE_THRESHOLD));
|
||||
},
|
||||
|
||||
vfunc_gesture_progress : function (action, actor) {
|
||||
let [startX, startY] = this.get_press_coords(0);
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let offsetX = Math.abs (x - startX);
|
||||
let offsetY = Math.abs (y - startY);
|
||||
|
||||
if (offsetX < EDGE_THRESHOLD && offsetY < EDGE_THRESHOLD)
|
||||
return true;
|
||||
|
||||
if ((offsetX > offsetY &&
|
||||
(this._side == St.Side.TOP || this._side == St.Side.BOTTOM)) ||
|
||||
(offsetY > offsetX &&
|
||||
(this._side == St.Side.LEFT || this._side == St.Side.RIGHT))) {
|
||||
this.cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
vfunc_gesture_end : function (action, actor) {
|
||||
let [startX, startY] = this.get_press_coords(0);
|
||||
let [x, y] = this.get_motion_coords(0);
|
||||
let monitorRect = this._getMonitorRect(startX, startY);
|
||||
|
||||
if ((this._side == St.Side.TOP && y > monitorRect.y + DRAG_DISTANCE) ||
|
||||
(this._side == St.Side.BOTTOM && y < monitorRect.y + monitorRect.height - DRAG_DISTANCE) ||
|
||||
(this._side == St.Side.LEFT && x > monitorRect.x + DRAG_DISTANCE) ||
|
||||
(this._side == St.Side.RIGHT && x < monitorRect.x + monitorRect.width - DRAG_DISTANCE))
|
||||
this.emit('activated');
|
||||
}
|
||||
});
|
||||
Signals.addSignalMethods(EdgeDragAction.prototype);
|
||||
|
||||
const ShowOverviewAction = new Lang.Class({
|
||||
Name: 'ShowOverviewAction',
|
||||
Extends: Clutter.GestureAction,
|
||||
@ -188,14 +119,12 @@ const ViewSelector = new Lang.Class({
|
||||
_init : function(searchEntry, showAppsButton) {
|
||||
this.actor = new Shell.Stack({ name: 'viewSelector' });
|
||||
|
||||
this._showAppsBlocked = false;
|
||||
this._showAppsButton = showAppsButton;
|
||||
this._showAppsButton.connect('notify::checked', Lang.bind(this, this._onShowAppsButtonToggled));
|
||||
|
||||
this._activePage = null;
|
||||
|
||||
this._searchActive = false;
|
||||
this._searchTimeoutId = 0;
|
||||
|
||||
this._entry = searchEntry;
|
||||
ShellEntry.addContextMenu(this._entry);
|
||||
@ -214,12 +143,8 @@ const ViewSelector = new Lang.Class({
|
||||
|
||||
this._entry.set_primary_icon(new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-find-symbolic' }));
|
||||
if (this._entry.get_text_direction() == Clutter.TextDirection.RTL)
|
||||
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-clear-symbolic-rtl' });
|
||||
else
|
||||
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-clear-symbolic-ltr' });
|
||||
this._clearIcon = new St.Icon({ style_class: 'search-entry-icon',
|
||||
icon_name: 'edit-clear-symbolic' });
|
||||
|
||||
this._iconClickedId = 0;
|
||||
this._capturedEventId = 0;
|
||||
@ -251,18 +176,28 @@ const ViewSelector = new Lang.Class({
|
||||
this._stageKeyPressId = 0;
|
||||
Main.overview.connect('showing', Lang.bind(this,
|
||||
function () {
|
||||
this._resetShowAppsButton();
|
||||
this._stageKeyPressId = global.stage.connect('key-press-event',
|
||||
Lang.bind(this, this._onStageKeyPress));
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this,
|
||||
function () {
|
||||
this._resetShowAppsButton();
|
||||
if (this._stageKeyPressId != 0) {
|
||||
global.stage.disconnect(this._stageKeyPressId);
|
||||
this._stageKeyPressId = 0;
|
||||
}
|
||||
}));
|
||||
Main.overview.connect('shown', Lang.bind(this,
|
||||
function() {
|
||||
// If we were animating from the desktop view to the
|
||||
// apps page the workspace page was visible, allowing
|
||||
// the windows to animate, but now we no longer want to
|
||||
// show it given that we are now on the apps page or
|
||||
// search page.
|
||||
if (this._activePage != this._workspacesPage) {
|
||||
this._workspacesPage.opacity = 0;
|
||||
this._workspacesPage.hide();
|
||||
}
|
||||
}));
|
||||
|
||||
Main.wm.addKeybinding('toggle-application-view',
|
||||
new Gio.Settings({ schema_id: SHELL_KEYBINDINGS_SCHEMA }),
|
||||
@ -280,7 +215,7 @@ const ViewSelector = new Lang.Class({
|
||||
|
||||
let gesture;
|
||||
|
||||
gesture = new EdgeDragAction(St.Side.LEFT);
|
||||
gesture = new EdgeDragAction.EdgeDragAction(St.Side.LEFT);
|
||||
gesture.connect('activated', Lang.bind(this, function() {
|
||||
if (Main.overview.visible)
|
||||
Main.overview.hide();
|
||||
@ -298,28 +233,36 @@ const ViewSelector = new Lang.Class({
|
||||
},
|
||||
|
||||
_toggleAppsPage: function() {
|
||||
Main.overview.show();
|
||||
this._showAppsButton.checked = !this._showAppsButton.checked;
|
||||
Main.overview.show();
|
||||
},
|
||||
|
||||
showApps: function() {
|
||||
Main.overview.show();
|
||||
this._showAppsButton.checked = true;
|
||||
Main.overview.show();
|
||||
},
|
||||
|
||||
show: function() {
|
||||
this.reset();
|
||||
|
||||
this._workspacesDisplay.show();
|
||||
this._workspacesDisplay.show(this._showAppsButton.checked);
|
||||
this._activePage = null;
|
||||
this._showPage(this._workspacesPage);
|
||||
if (this._showAppsButton.checked)
|
||||
this._showPage(this._appsPage);
|
||||
else
|
||||
this._showPage(this._workspacesPage);
|
||||
|
||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
|
||||
Main.overview.fadeOutDesktop();
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
this._workspacesDisplay.zoomFromOverview();
|
||||
animateFromOverview: function() {
|
||||
// Make sure workspace page is fully visible to allow
|
||||
// workspace.js do the animation of the windows
|
||||
this._workspacesPage.opacity = 255;
|
||||
|
||||
this._workspacesDisplay.animateFromOverview(this._activePage != this._workspacesPage);
|
||||
|
||||
this._showAppsButton.checked = false;
|
||||
|
||||
if (!this._workspacesDisplay.activeWorkspaceHasMaximizedWindows())
|
||||
Main.overview.fadeInDesktop();
|
||||
@ -356,21 +299,61 @@ const ViewSelector = new Lang.Class({
|
||||
return page;
|
||||
},
|
||||
|
||||
_fadePageIn: function(oldPage) {
|
||||
_fadePageIn: function() {
|
||||
Tweener.addTween(this._activePage,
|
||||
{ opacity: 255,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
},
|
||||
|
||||
_fadePageOut: function(page) {
|
||||
let oldPage = page;
|
||||
Tweener.addTween(page,
|
||||
{ opacity: 0,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this._animateIn(oldPage);
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
_animateIn: function(oldPage) {
|
||||
if (oldPage)
|
||||
oldPage.hide();
|
||||
|
||||
this.emit('page-empty');
|
||||
|
||||
this._activePage.show();
|
||||
Tweener.addTween(this._activePage,
|
||||
{ opacity: 255,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
|
||||
if (this._activePage == this._appsPage && oldPage == this._workspacesPage) {
|
||||
// Restore opacity, in case we animated via _fadePageOut
|
||||
this._activePage.opacity = 255;
|
||||
this.appDisplay.animate(IconGrid.AnimationDirection.IN);
|
||||
} else {
|
||||
this._fadePageIn();
|
||||
}
|
||||
},
|
||||
|
||||
_showPage: function(page, noFade) {
|
||||
_animateOut: function(page) {
|
||||
let oldPage = page;
|
||||
if (page == this._appsPage &&
|
||||
this._activePage == this._workspacesPage &&
|
||||
!Main.overview.animationInProgress) {
|
||||
this.appDisplay.animate(IconGrid.AnimationDirection.OUT, Lang.bind(this,
|
||||
function() {
|
||||
this._animateIn(oldPage)
|
||||
}));
|
||||
} else {
|
||||
this._fadePageOut(page);
|
||||
}
|
||||
},
|
||||
|
||||
_showPage: function(page) {
|
||||
if (!Main.overview.visible)
|
||||
return;
|
||||
|
||||
if (page == this._activePage)
|
||||
return;
|
||||
|
||||
@ -378,18 +361,10 @@ const ViewSelector = new Lang.Class({
|
||||
this._activePage = page;
|
||||
this.emit('page-changed');
|
||||
|
||||
if (oldPage && !noFade)
|
||||
Tweener.addTween(oldPage,
|
||||
{ opacity: 0,
|
||||
time: OverviewControls.SIDE_CONTROLS_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this,
|
||||
function() {
|
||||
this._fadePageIn(oldPage);
|
||||
})
|
||||
});
|
||||
if (oldPage)
|
||||
this._animateOut(oldPage)
|
||||
else
|
||||
this._fadePageIn(oldPage);
|
||||
this._animateIn();
|
||||
},
|
||||
|
||||
_a11yFocusPage: function(page) {
|
||||
@ -398,21 +373,10 @@ const ViewSelector = new Lang.Class({
|
||||
},
|
||||
|
||||
_onShowAppsButtonToggled: function() {
|
||||
if (this._showAppsBlocked)
|
||||
return;
|
||||
|
||||
this._showPage(this._showAppsButton.checked ?
|
||||
this._appsPage : this._workspacesPage);
|
||||
},
|
||||
|
||||
_resetShowAppsButton: function() {
|
||||
this._showAppsBlocked = true;
|
||||
this._showAppsButton.checked = false;
|
||||
this._showAppsBlocked = false;
|
||||
|
||||
this._showPage(this._workspacesPage, true);
|
||||
},
|
||||
|
||||
_onStageKeyPress: function(actor, event) {
|
||||
// Ignore events while anything but the overview has
|
||||
// pushed a modal (system modals, looking glass, ...)
|
||||
@ -522,36 +486,23 @@ const ViewSelector = new Lang.Class({
|
||||
_onTextChanged: function (se, prop) {
|
||||
let terms = getTermsForSearchString(this._entry.get_text());
|
||||
|
||||
let searchPreviouslyActive = this._searchActive;
|
||||
this._searchActive = (terms.length > 0);
|
||||
|
||||
let startSearch = this._searchActive && !searchPreviouslyActive;
|
||||
if (startSearch)
|
||||
this._searchResults.startingSearch();
|
||||
this._searchResults.setTerms(terms);
|
||||
|
||||
if (this._searchActive) {
|
||||
this._showPage(this._searchPage);
|
||||
|
||||
this._entry.set_secondary_icon(this._clearIcon);
|
||||
|
||||
if (this._iconClickedId == 0)
|
||||
this._iconClickedId = this._entry.connect('secondary-icon-clicked',
|
||||
Lang.bind(this, this.reset));
|
||||
|
||||
if (this._searchTimeoutId == 0) {
|
||||
this._searchTimeoutId = Mainloop.timeout_add(150,
|
||||
Lang.bind(this, this._doSearch));
|
||||
GLib.Source.set_name_by_id(this._searchTimeoutId, '[gnome-shell] this._doSearch');
|
||||
}
|
||||
} else {
|
||||
if (this._iconClickedId > 0) {
|
||||
this._entry.disconnect(this._iconClickedId);
|
||||
this._iconClickedId = 0;
|
||||
}
|
||||
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._searchTimeoutId = 0;
|
||||
}
|
||||
|
||||
this._entry.set_secondary_icon(null);
|
||||
this._searchCancelled();
|
||||
}
|
||||
@ -589,12 +540,6 @@ const ViewSelector = new Lang.Class({
|
||||
this._searchResults.navigateFocus(nextDirection);
|
||||
return Clutter.EVENT_STOP;
|
||||
} else if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
|
||||
// We can't connect to 'activate' here because search providers
|
||||
// might want to do something with the modifiers in activateDefault.
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._doSearch();
|
||||
}
|
||||
this._searchResults.activateDefault();
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
@ -617,17 +562,6 @@ const ViewSelector = new Lang.Class({
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
},
|
||||
|
||||
_doSearch: function () {
|
||||
this._searchTimeoutId = 0;
|
||||
|
||||
let terms = getTermsForSearchString(this._entry.get_text());
|
||||
|
||||
this._searchResults.setTerms(terms);
|
||||
this._showPage(this._searchPage);
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
},
|
||||
|
||||
getActivePage: function() {
|
||||
if (this._activePage == this._workspacesPage)
|
||||
return ViewPage.WINDOWS;
|
||||
|
@ -19,6 +19,13 @@ const Tweener = imports.ui.tweener;
|
||||
const WindowMenu = imports.ui.windowMenu;
|
||||
|
||||
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
|
||||
const MAXIMIZE_WINDOW_ANIMATION_TIME = 0.15;
|
||||
const UNMAXIMIZE_WINDOW_ANIMATION_TIME = 0.15;
|
||||
const MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
|
||||
const SHOW_WINDOW_ANIMATION_TIME = 0.15;
|
||||
const DIALOG_SHOW_WINDOW_ANIMATION_TIME = 0.1;
|
||||
const DESTROY_WINDOW_ANIMATION_TIME = 0.15;
|
||||
const DIALOG_DESTROY_WINDOW_ANIMATION_TIME = 0.1;
|
||||
const WINDOW_ANIMATION_TIME = 0.25;
|
||||
const DIM_BRIGHTNESS = -0.3;
|
||||
const DIM_TIME = 0.500;
|
||||
@ -406,7 +413,7 @@ const TilePreview = new Lang.Class({
|
||||
y: monitor.y,
|
||||
width: monitor.width,
|
||||
height: monitor.height });
|
||||
let [, rect] = window.get_outer_rect().intersect(monitorRect);
|
||||
let [, rect] = window.get_frame_rect().intersect(monitorRect);
|
||||
this.actor.set_size(rect.width, rect.height);
|
||||
this.actor.set_position(rect.x, rect.y);
|
||||
this.actor.opacity = 0;
|
||||
@ -519,6 +526,11 @@ const AppSwitchAction = new Lang.Class({
|
||||
},
|
||||
|
||||
vfunc_gesture_prepare : function(action, actor) {
|
||||
if (Main.overview.visible) {
|
||||
this.cancel();
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.get_n_current_points() <= 4;
|
||||
},
|
||||
|
||||
@ -874,12 +886,12 @@ const WindowManager = new Lang.Class({
|
||||
return !Main.overview.visible;
|
||||
},
|
||||
|
||||
_shouldAnimateActor: function(actor) {
|
||||
_shouldAnimateActor: function(actor, types) {
|
||||
if (!this._shouldAnimate())
|
||||
return false;
|
||||
let windowType = actor.meta_window.get_window_type();
|
||||
return windowType == Meta.WindowType.NORMAL ||
|
||||
windowType == Meta.WindowType.MODAL_DIALOG;
|
||||
|
||||
let type = actor.meta_window.get_window_type();
|
||||
return types.indexOf(type) >= 0;
|
||||
},
|
||||
|
||||
_removeEffect : function(list, actor) {
|
||||
@ -892,7 +904,10 @@ const WindowManager = new Lang.Class({
|
||||
},
|
||||
|
||||
_minimizeWindow : function(shellwm, actor) {
|
||||
if (!this._shouldAnimateActor(actor)) {
|
||||
let types = [Meta.WindowType.NORMAL,
|
||||
Meta.WindowType.MODAL_DIALOG,
|
||||
Meta.WindowType.DIALOG];
|
||||
if (!this._shouldAnimateActor(actor, types)) {
|
||||
shellwm.completed_minimize(actor);
|
||||
return;
|
||||
}
|
||||
@ -904,7 +919,7 @@ const WindowManager = new Lang.Class({
|
||||
if (actor.meta_window.is_monitor_sized()) {
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 0,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
time: MINIMIZE_WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this._minimizeWindowDone,
|
||||
onCompleteScope: this,
|
||||
@ -936,8 +951,8 @@ const WindowManager = new Lang.Class({
|
||||
scale_y: yScale,
|
||||
x: xDest,
|
||||
y: yDest,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
time: MINIMIZE_WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeInExpo',
|
||||
onComplete: this._minimizeWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [shellwm, actor],
|
||||
@ -953,7 +968,7 @@ const WindowManager = new Lang.Class({
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.set_opacity(255);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
|
||||
actor.set_pivot_point(0, 0);
|
||||
|
||||
shellwm.completed_minimize(actor);
|
||||
}
|
||||
@ -1051,7 +1066,10 @@ const WindowManager = new Lang.Class({
|
||||
actor._windowType = type;
|
||||
}));
|
||||
|
||||
if (!this._shouldAnimateActor(actor)) {
|
||||
let types = [Meta.WindowType.NORMAL,
|
||||
Meta.WindowType.DIALOG,
|
||||
Meta.WindowType.MODAL_DIALOG];
|
||||
if (!this._shouldAnimateActor(actor, types)) {
|
||||
shellwm.completed_map(actor);
|
||||
return;
|
||||
}
|
||||
@ -1059,15 +1077,23 @@ const WindowManager = new Lang.Class({
|
||||
if (actor.meta_window.is_attached_dialog()) {
|
||||
/* Scale the window from the center of the parent */
|
||||
this._checkDimming(actor.get_meta_window().get_transient_for());
|
||||
actor.set_scale(1.0, 0.0);
|
||||
actor.set_pivot_point(0.5, 0.5);
|
||||
}
|
||||
|
||||
switch (actor._windowType) {
|
||||
case Meta.WindowType.NORMAL:
|
||||
actor.set_pivot_point(0.5, 1.0);
|
||||
actor.scale_x = 0.01;
|
||||
actor.scale_y = 0.05;
|
||||
actor.opacity = 0;
|
||||
actor.show();
|
||||
this._mapping.push(actor);
|
||||
|
||||
Tweener.addTween(actor,
|
||||
{ scale_y: 1,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
{ opacity: 255,
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
time: SHOW_WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutExpo',
|
||||
onComplete: this._mapWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [shellwm, actor],
|
||||
@ -1075,15 +1101,20 @@ const WindowManager = new Lang.Class({
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
} else {
|
||||
/* Fade window in */
|
||||
break;
|
||||
case Meta.WindowType.MODAL_DIALOG:
|
||||
case Meta.WindowType.DIALOG:
|
||||
actor.set_pivot_point(0.5, 0.5);
|
||||
actor.scale_y = 0;
|
||||
actor.opacity = 0;
|
||||
actor.show();
|
||||
this._mapping.push(actor);
|
||||
|
||||
Tweener.addTween(actor,
|
||||
{ opacity: 255,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
scale_x: 1,
|
||||
scale_y: 1,
|
||||
time: DIALOG_SHOW_WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this._mapWindowDone,
|
||||
onCompleteScope: this,
|
||||
@ -1092,6 +1123,10 @@ const WindowManager = new Lang.Class({
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
break;
|
||||
default:
|
||||
shellwm.completed_map(actor);
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
@ -1099,7 +1134,11 @@ const WindowManager = new Lang.Class({
|
||||
if (this._removeEffect(this._mapping, actor)) {
|
||||
Tweener.removeTweens(actor);
|
||||
actor.opacity = 255;
|
||||
actor.set_pivot_point(0, 0);
|
||||
actor.scale_y = 1;
|
||||
actor.scale_x = 1;
|
||||
actor.translation_y = 0;
|
||||
actor.translation_x = 0;
|
||||
shellwm.completed_map(actor);
|
||||
}
|
||||
},
|
||||
@ -1122,30 +1161,25 @@ const WindowManager = new Lang.Class({
|
||||
});
|
||||
}
|
||||
|
||||
if (!this._shouldAnimateActor(actor)) {
|
||||
let types = [Meta.WindowType.NORMAL,
|
||||
Meta.WindowType.DIALOG,
|
||||
Meta.WindowType.MODAL_DIALOG];
|
||||
if (!this._shouldAnimateActor(actor, types)) {
|
||||
shellwm.completed_destroy(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
this._destroying.push(actor);
|
||||
|
||||
if (window.is_attached_dialog()) {
|
||||
let parent = window.get_transient_for();
|
||||
this._checkDimming(parent, window);
|
||||
|
||||
actor.set_scale(1.0, 1.0);
|
||||
switch (actor._windowType) {
|
||||
case Meta.WindowType.NORMAL:
|
||||
actor.set_pivot_point(0.5, 0.5);
|
||||
actor.show();
|
||||
|
||||
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
|
||||
Tweener.removeTweens(actor);
|
||||
this._destroyWindowDone(shellwm, actor);
|
||||
}));
|
||||
this._destroying.push(actor);
|
||||
|
||||
Tweener.addTween(actor,
|
||||
{ scale_y: 0,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
{ opacity: 0,
|
||||
scale_x: 0.8,
|
||||
scale_y: 0.8,
|
||||
time: DESTROY_WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this._destroyWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [shellwm, actor],
|
||||
@ -1153,9 +1187,37 @@ const WindowManager = new Lang.Class({
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
break;
|
||||
case Meta.WindowType.MODAL_DIALOG:
|
||||
case Meta.WindowType.DIALOG:
|
||||
actor.set_pivot_point(0.5, 0.5);
|
||||
this._destroying.push(actor);
|
||||
|
||||
if (window.is_attached_dialog()) {
|
||||
let parent = window.get_transient_for();
|
||||
this._checkDimming(parent, window);
|
||||
actor._parentDestroyId = parent.connect('unmanaged', Lang.bind(this, function () {
|
||||
Tweener.removeTweens(actor);
|
||||
this._destroyWindowDone(shellwm, actor);
|
||||
}));
|
||||
}
|
||||
|
||||
Tweener.addTween(actor,
|
||||
{ scale_y: 0,
|
||||
time: DIALOG_DESTROY_WINDOW_ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: this._destroyWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [shellwm, actor],
|
||||
onOverwrite: this._destroyWindowDone,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
break;
|
||||
default:
|
||||
shellwm.completed_destroy(actor);
|
||||
return;
|
||||
}
|
||||
shellwm.completed_destroy(actor);
|
||||
},
|
||||
|
||||
_destroyWindowDone : function(shellwm, actor) {
|
||||
@ -1328,9 +1390,7 @@ const WindowManager = new Lang.Class({
|
||||
|
||||
let tabPopup = new AltTab.AppSwitcherPopup();
|
||||
|
||||
let modifiers = binding.get_modifiers();
|
||||
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
|
||||
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
|
||||
if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
|
||||
tabPopup.destroy();
|
||||
},
|
||||
|
||||
@ -1341,16 +1401,12 @@ const WindowManager = new Lang.Class({
|
||||
|
||||
let tabPopup = new AltTab.WindowSwitcherPopup();
|
||||
|
||||
let modifiers = binding.get_modifiers();
|
||||
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
|
||||
if (!tabPopup.show(backwards, binding.get_name(), binding.get_mask()))
|
||||
if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
|
||||
tabPopup.destroy();
|
||||
},
|
||||
|
||||
_startA11ySwitcher : function(display, screen, window, binding) {
|
||||
let modifiers = binding.get_modifiers();
|
||||
let backwards = modifiers & Meta.VirtualModifier.SHIFT_MASK;
|
||||
Main.ctrlAltTabManager.popup(backwards, binding.get_name(), binding.get_mask());
|
||||
Main.ctrlAltTabManager.popup(binding.is_reversed(), binding.get_name(), binding.get_mask());
|
||||
},
|
||||
|
||||
_toggleAppMenu : function(display, screen, window, event, binding) {
|
||||
|
@ -75,7 +75,7 @@ const WindowMenu = new Lang.Class({
|
||||
}));
|
||||
if (window.is_above())
|
||||
item.setOrnament(PopupMenu.Ornament.DOT);
|
||||
if (window.get_maximized() ||
|
||||
if (window.get_maximized() == Meta.MaximizeFlags.BOTH ||
|
||||
type == Meta.WindowType.DOCK ||
|
||||
type == Meta.WindowType.DESKTOP ||
|
||||
type == Meta.WindowType.SPLASHSCREEN)
|
||||
|
@ -34,6 +34,8 @@ const DRAGGING_WINDOW_OPACITY = 100;
|
||||
const LAYOUT_SCALE_WEIGHT = 1;
|
||||
const LAYOUT_SPACE_WEIGHT = 0.1;
|
||||
|
||||
const WINDOW_ANIMATION_MAX_NUMBER_BLENDING = 3;
|
||||
|
||||
function _interpolate(start, end, step) {
|
||||
return start + (end - start) * step;
|
||||
}
|
||||
@ -87,7 +89,7 @@ const WindowCloneLayout = new Lang.Class({
|
||||
},
|
||||
|
||||
vfunc_allocate: function(container, box, flags) {
|
||||
let clone = container.get_children().forEach(function (child) {
|
||||
container.get_children().forEach(Lang.bind(this, function (child) {
|
||||
let realWindow;
|
||||
if (child == container._delegate._windowClone)
|
||||
realWindow = container._delegate.realWindow;
|
||||
@ -96,8 +98,8 @@ const WindowCloneLayout = new Lang.Class({
|
||||
|
||||
child.allocate(this._makeBoxForWindow(realWindow.meta_window),
|
||||
flags);
|
||||
}, this);
|
||||
},
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
const WindowClone = new Lang.Class({
|
||||
@ -252,7 +254,7 @@ const WindowClone = new Lang.Class({
|
||||
},
|
||||
|
||||
_computeBoundingBox: function() {
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
let rect = this.metaWindow.get_frame_rect();
|
||||
|
||||
this.actor.get_children().forEach(function (child) {
|
||||
let realWindow;
|
||||
@ -262,7 +264,7 @@ const WindowClone = new Lang.Class({
|
||||
realWindow = child.source;
|
||||
|
||||
let metaWindow = realWindow.meta_window;
|
||||
rect = rect.union(metaWindow.get_outer_rect());
|
||||
rect = rect.union(metaWindow.get_frame_rect());
|
||||
}, this);
|
||||
|
||||
// Convert from a MetaRectangle to a native JS object
|
||||
@ -517,6 +519,7 @@ const WindowOverlay = new Lang.Class({
|
||||
|
||||
Tweener.removeTweens(button);
|
||||
Tweener.removeTweens(border);
|
||||
Tweener.removeTweens(title);
|
||||
|
||||
let [cloneX, cloneY, cloneWidth, cloneHeight] = this._windowClone.slot;
|
||||
|
||||
@ -1206,14 +1209,18 @@ const Workspace = new Lang.Class({
|
||||
return this._windows.length == 0;
|
||||
},
|
||||
|
||||
setReservedSlot: function(clone) {
|
||||
if (this._reservedSlot == clone)
|
||||
setReservedSlot: function(metaWindow) {
|
||||
if (this._reservedSlotWindow == metaWindow)
|
||||
return;
|
||||
|
||||
if (clone && this.containsMetaWindow(clone.metaWindow))
|
||||
clone = null;
|
||||
if (!metaWindow || this.containsMetaWindow(metaWindow)) {
|
||||
this._reservedSlotWindow = null;
|
||||
this._reservedSlot = null;
|
||||
} else {
|
||||
this._reservedSlotWindow = metaWindow;
|
||||
this._reservedSlot = this._windows[this._lookupIndex(metaWindow)];
|
||||
}
|
||||
|
||||
this._reservedSlot = clone;
|
||||
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE);
|
||||
},
|
||||
|
||||
@ -1258,10 +1265,11 @@ const Workspace = new Lang.Class({
|
||||
return;
|
||||
}
|
||||
|
||||
// We will reposition windows when enter again overview anyway.
|
||||
// We will reposition windows anyway when enter again overview or when ending the windows
|
||||
// animations whith fade animation.
|
||||
// In this way we avoid unwanted animations of windows repositioning while
|
||||
// animating overview
|
||||
if (this.leavingOverview)
|
||||
// animating overview.
|
||||
if (this.leavingOverview || this._animatingWindowsFade)
|
||||
return;
|
||||
|
||||
let initialPositioning = flags & WindowPositionFlags.INITIAL;
|
||||
@ -1326,7 +1334,7 @@ const Workspace = new Lang.Class({
|
||||
});
|
||||
}
|
||||
|
||||
this._animateClone(clone, overlay, x, y, scale, initialPositioning);
|
||||
this._animateClone(clone, overlay, x, y, scale);
|
||||
} else {
|
||||
// cancel any active tweens (otherwise they might override our changes)
|
||||
Tweener.removeTweens(clone.actor);
|
||||
@ -1355,7 +1363,7 @@ const Workspace = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_animateClone: function(clone, overlay, x, y, scale, initialPositioning) {
|
||||
_animateClone: function(clone, overlay, x, y, scale) {
|
||||
Tweener.addTween(clone.actor,
|
||||
{ x: x,
|
||||
y: y,
|
||||
@ -1413,10 +1421,6 @@ const Workspace = new Lang.Class({
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
// Check if window still should be here
|
||||
if (win && this._isMyWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._windows[index];
|
||||
|
||||
this._windows.splice(index, 1);
|
||||
@ -1562,14 +1566,141 @@ const Workspace = new Lang.Class({
|
||||
return false;
|
||||
},
|
||||
|
||||
// Animate the full-screen to Overview transition.
|
||||
zoomToOverview : function() {
|
||||
fadeToOverview: function() {
|
||||
// We don't want to reposition windows while animating in this way.
|
||||
this._animatingWindowsFade = true;
|
||||
this._overviewShownId = Main.overview.connect('shown', Lang.bind(this,
|
||||
this._doneShowingOverview));
|
||||
if (this._windows.length == 0)
|
||||
return;
|
||||
|
||||
if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
|
||||
return;
|
||||
|
||||
// Special case maximized windows, since it doesn't make sense
|
||||
// to animate windows below in the stack
|
||||
let topMaximizedWindow;
|
||||
// It is ok to treat the case where there is no maximized
|
||||
// window as if the bottom-most window was maximized given that
|
||||
// it won't affect the result of the animation
|
||||
for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
|
||||
let metaWindow = this._windows[topMaximizedWindow].metaWindow;
|
||||
if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
|
||||
break;
|
||||
}
|
||||
|
||||
let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
|
||||
let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
|
||||
|
||||
let topIndex = this._windows.length - 1;
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
if (i < topMaximizedWindow) {
|
||||
// below top-most maximized window, don't animate
|
||||
let overlay = this._windowOverlays[i];
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
this._windows[i].actor.opacity = 0;
|
||||
} else {
|
||||
let fromTop = topIndex - i;
|
||||
let time;
|
||||
if (fromTop < nTimeSlots) // animate top-most windows gradually
|
||||
time = windowBaseTime * (nTimeSlots - fromTop);
|
||||
else
|
||||
time = windowBaseTime;
|
||||
|
||||
this._windows[i].actor.opacity = 255;
|
||||
this._fadeWindow(i, time, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
fadeFromOverview: function() {
|
||||
this.leavingOverview = true;
|
||||
this._overviewHiddenId = Main.overview.connect('hidden', Lang.bind(this,
|
||||
this._doneLeavingOverview));
|
||||
if (this._windows.length == 0)
|
||||
return;
|
||||
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
Tweener.removeTweens(clone.actor);
|
||||
}
|
||||
|
||||
if (this._repositionWindowsId > 0) {
|
||||
Mainloop.source_remove(this._repositionWindowsId);
|
||||
this._repositionWindowsId = 0;
|
||||
}
|
||||
|
||||
if (this.metaWorkspace != null && this.metaWorkspace != global.screen.get_active_workspace())
|
||||
return;
|
||||
|
||||
// Special case maximized windows, since it doesn't make sense
|
||||
// to animate windows below in the stack
|
||||
let topMaximizedWindow;
|
||||
// It is ok to treat the case where there is no maximized
|
||||
// window as if the bottom-most window was maximized given that
|
||||
// it won't affect the result of the animation
|
||||
for (topMaximizedWindow = this._windows.length - 1; topMaximizedWindow > 0; topMaximizedWindow--) {
|
||||
let metaWindow = this._windows[topMaximizedWindow].metaWindow;
|
||||
if (metaWindow.maximized_horizontally && metaWindow.maximized_vertically)
|
||||
break;
|
||||
}
|
||||
|
||||
let nTimeSlots = Math.min(WINDOW_ANIMATION_MAX_NUMBER_BLENDING + 1, this._windows.length - topMaximizedWindow);
|
||||
let windowBaseTime = Overview.ANIMATION_TIME / nTimeSlots;
|
||||
|
||||
let topIndex = this._windows.length - 1;
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
if (i < topMaximizedWindow) {
|
||||
// below top-most maximized window, don't animate
|
||||
let overlay = this._windowOverlays[i];
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
this._windows[i].actor.opacity = 0;
|
||||
} else {
|
||||
let fromTop = topIndex - i;
|
||||
let time;
|
||||
if (fromTop < nTimeSlots) // animate top-most windows gradually
|
||||
time = windowBaseTime * (fromTop + 1);
|
||||
else
|
||||
time = windowBaseTime * nTimeSlots;
|
||||
|
||||
this._windows[i].actor.opacity = 0;
|
||||
this._fadeWindow(i, time, 255);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_fadeWindow: function(index, time, opacity) {
|
||||
let clone = this._windows[index];
|
||||
let overlay = this._windowOverlays[index];
|
||||
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
|
||||
if (clone.metaWindow.showing_on_its_workspace()) {
|
||||
let [origX, origY] = clone.getOriginalPosition();
|
||||
clone.actor.scale_x = 1;
|
||||
clone.actor.scale_y = 1;
|
||||
clone.actor.x = origX;
|
||||
clone.actor.y = origY;
|
||||
Tweener.addTween(clone.actor,
|
||||
{ time: time,
|
||||
opacity: opacity,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
} else {
|
||||
// The window is hidden
|
||||
clone.actor.opacity = 0;
|
||||
}
|
||||
},
|
||||
|
||||
zoomToOverview: function() {
|
||||
// Position and scale the windows.
|
||||
this._recalculateWindowPositions(WindowPositionFlags.ANIMATE | WindowPositionFlags.INITIAL);
|
||||
},
|
||||
|
||||
// Animates the return from Overview mode
|
||||
zoomFromOverview : function() {
|
||||
zoomFromOverview: function() {
|
||||
let currentWorkspace = global.screen.get_active_workspace();
|
||||
|
||||
this.leavingOverview = true;
|
||||
@ -1590,35 +1721,37 @@ const Workspace = new Lang.Class({
|
||||
return;
|
||||
|
||||
// Position and scale the windows.
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let overlay = this._windowOverlays[i];
|
||||
for (let i = 0; i < this._windows.length; i++)
|
||||
this._zoomWindowFromOverview(i);
|
||||
},
|
||||
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
_zoomWindowFromOverview: function(index) {
|
||||
let clone = this._windows[index];
|
||||
let overlay = this._windowOverlays[index];
|
||||
|
||||
if (clone.metaWindow.showing_on_its_workspace()) {
|
||||
let [origX, origY] = clone.getOriginalPosition();
|
||||
if (overlay)
|
||||
overlay.hide();
|
||||
|
||||
Tweener.addTween(clone.actor,
|
||||
{ x: origX,
|
||||
y: origY,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
opacity: 255,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
} else {
|
||||
// The window is hidden, make it shrink and fade it out
|
||||
Tweener.addTween(clone.actor,
|
||||
{ scale_x: 0,
|
||||
scale_y: 0,
|
||||
opacity: 0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
if (clone.metaWindow.showing_on_its_workspace()) {
|
||||
let [origX, origY] = clone.getOriginalPosition();
|
||||
Tweener.addTween(clone.actor,
|
||||
{ x: origX,
|
||||
y: origY,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
opacity: 255,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
} else {
|
||||
// The window is hidden, make it shrink and fade it out
|
||||
Tweener.addTween(clone.actor,
|
||||
{ scale_x: 0,
|
||||
scale_y: 0,
|
||||
opacity: 0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
@ -1657,6 +1790,11 @@ const Workspace = new Lang.Class({
|
||||
this.leavingOverview = false;
|
||||
},
|
||||
|
||||
_doneShowingOverview: function() {
|
||||
this._animatingWindowsFade = false;
|
||||
this._recalculateWindowPositions(WindowPositionFlags.INITIAL);
|
||||
},
|
||||
|
||||
// Tests if @actor belongs to this workspaces and monitor
|
||||
_isMyWindow : function (actor) {
|
||||
let win = actor.meta_window;
|
||||
@ -1680,16 +1818,16 @@ const Workspace = new Lang.Class({
|
||||
Lang.bind(this, this._onCloneSelected));
|
||||
clone.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginWindowDrag(clone);
|
||||
Main.overview.beginWindowDrag(clone.metaWindow);
|
||||
overlay.hide();
|
||||
}));
|
||||
clone.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledWindowDrag(clone);
|
||||
Main.overview.cancelledWindowDrag(clone.metaWindow);
|
||||
}));
|
||||
clone.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endWindowDrag(clone);
|
||||
Main.overview.endWindowDrag(clone.metaWindow);
|
||||
overlay.show();
|
||||
}));
|
||||
clone.connect('size-changed',
|
||||
|
@ -161,14 +161,14 @@ const WindowClone = new Lang.Class({
|
||||
|
||||
_updateDialogPosition: function(realDialog, cloneDialog) {
|
||||
let metaDialog = realDialog.meta_window;
|
||||
let dialogRect = metaDialog.get_outer_rect();
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
let dialogRect = metaDialog.get_frame_rect();
|
||||
let rect = this.metaWindow.get_frame_rect();
|
||||
|
||||
cloneDialog.set_position(dialogRect.x - rect.x, dialogRect.y - rect.y);
|
||||
},
|
||||
|
||||
_onPositionChanged: function() {
|
||||
let rect = this.metaWindow.get_outer_rect();
|
||||
let rect = this.metaWindow.get_frame_rect();
|
||||
this.actor.set_position(this.realWindow.x, this.realWindow.y);
|
||||
},
|
||||
|
||||
@ -306,7 +306,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
_createBackground: function() {
|
||||
this._bgManager = new Background.BackgroundManager({ monitorIndex: Main.layoutManager.primaryIndex,
|
||||
container: this._contents,
|
||||
effects: Meta.BackgroundEffects.NONE });
|
||||
vignette: false });
|
||||
},
|
||||
|
||||
setPorthole: function(x, y, width, height) {
|
||||
@ -332,7 +332,7 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
let clone = this._windows[i];
|
||||
let metaWindow = clone.metaWindow;
|
||||
if (i == 0) {
|
||||
clone.setStackAbove(this._bgManager.background.actor);
|
||||
clone.setStackAbove(this._bgManager.backgroundActor);
|
||||
} else {
|
||||
let previousClone = this._windows[i - 1];
|
||||
clone.setStackAbove(previousClone.actor);
|
||||
@ -367,10 +367,6 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
// Check if window still should be here
|
||||
if (win && this._isMyWindow(win) && this._isOverviewWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._windows[index];
|
||||
this._windows.splice(index, 1);
|
||||
|
||||
@ -522,20 +518,20 @@ const WorkspaceThumbnail = new Lang.Class({
|
||||
}));
|
||||
clone.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.beginWindowDrag(clone);
|
||||
Main.overview.beginWindowDrag(clone.metaWindow);
|
||||
}));
|
||||
clone.connect('drag-cancelled',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.cancelledWindowDrag(clone);
|
||||
Main.overview.cancelledWindowDrag(clone.metaWindow);
|
||||
}));
|
||||
clone.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
Main.overview.endWindowDrag(clone);
|
||||
Main.overview.endWindowDrag(clone.metaWindow);
|
||||
}));
|
||||
this._contents.add_actor(clone.actor);
|
||||
|
||||
if (this._windows.length == 0)
|
||||
clone.setStackAbove(this._bgManager.background.actor);
|
||||
clone.setStackAbove(this._bgManager.backgroundActor);
|
||||
else
|
||||
clone.setStackAbove(this._windows[this._windows.length - 1].actor);
|
||||
|
||||
@ -878,9 +874,6 @@ const ThumbnailsBox = new Lang.Class({
|
||||
for (let key in ThumbnailState)
|
||||
this._stateCounts[ThumbnailState[key]] = 0;
|
||||
|
||||
// The "porthole" is the portion of the screen that we show in the workspaces
|
||||
this._porthole = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
|
||||
this.addThumbnails(0, global.screen.n_workspaces);
|
||||
|
||||
this._updateSwitcherVisibility();
|
||||
@ -904,6 +897,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
for (let w = 0; w < this._thumbnails.length; w++)
|
||||
this._thumbnails[w].destroy();
|
||||
this._thumbnails = [];
|
||||
this._porthole = null;
|
||||
},
|
||||
|
||||
_workspacesChanged: function() {
|
||||
@ -934,6 +928,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
},
|
||||
|
||||
addThumbnails: function(start, count) {
|
||||
this._ensurePorthole();
|
||||
for (let k = start; k < start + count; k++) {
|
||||
let metaWorkspace = global.screen.get_workspace_by_index(k);
|
||||
let thumbnail = new WorkspaceThumbnail(metaWorkspace);
|
||||
@ -1121,9 +1116,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
// the size request to our children because we know how big they are and know
|
||||
// that the actors aren't depending on the virtual functions being called.
|
||||
|
||||
if (this._thumbnails.length == 0)
|
||||
return;
|
||||
|
||||
this._ensurePorthole();
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
|
||||
let spacing = themeNode.get_length('spacing');
|
||||
@ -1135,8 +1128,7 @@ const ThumbnailsBox = new Lang.Class({
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
if (this._thumbnails.length == 0)
|
||||
return;
|
||||
this._ensurePorthole();
|
||||
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
|
||||
@ -1154,6 +1146,13 @@ const ThumbnailsBox = new Lang.Class({
|
||||
alloc.natural_size = width;
|
||||
},
|
||||
|
||||
// The "porthole" is the portion of the screen that we show in the
|
||||
// workspaces
|
||||
_ensurePorthole: function() {
|
||||
if (!this._porthole)
|
||||
this._porthole = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let rtl = (Clutter.get_default_text_direction () == Clutter.TextDirection.RTL);
|
||||
|
||||
|
@ -21,6 +21,11 @@ const WORKSPACE_SWITCH_TIME = 0.25;
|
||||
// Note that mutter has a compile-time limit of 36
|
||||
const MAX_WORKSPACES = 16;
|
||||
|
||||
const AnimationType = {
|
||||
ZOOM: 0,
|
||||
FADE: 1
|
||||
};
|
||||
|
||||
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
|
||||
|
||||
const WorkspacesViewBase = new Lang.Class({
|
||||
@ -58,9 +63,9 @@ const WorkspacesViewBase = new Lang.Class({
|
||||
}
|
||||
},
|
||||
|
||||
_dragBegin: function(overview, clone) {
|
||||
_dragBegin: function(overview, window) {
|
||||
this._inDrag = true;
|
||||
this._setReservedSlot(clone);
|
||||
this._setReservedSlot(window);
|
||||
},
|
||||
|
||||
_dragEnd: function() {
|
||||
@ -122,9 +127,9 @@ const WorkspacesView = new Lang.Class({
|
||||
Lang.bind(this, this._activeWorkspaceChanged));
|
||||
},
|
||||
|
||||
_setReservedSlot: function(clone) {
|
||||
_setReservedSlot: function(window) {
|
||||
for (let i = 0; i < this._workspaces.length; i++)
|
||||
this._workspaces[i].setReservedSlot(clone);
|
||||
this._workspaces[i].setReservedSlot(window);
|
||||
},
|
||||
|
||||
_syncFullGeometry: function() {
|
||||
@ -142,17 +147,25 @@ const WorkspacesView = new Lang.Class({
|
||||
return this._workspaces[active];
|
||||
},
|
||||
|
||||
zoomToOverview: function() {
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomToOverview();
|
||||
animateToOverview: function(animationType) {
|
||||
for (let w = 0; w < this._workspaces.length; w++) {
|
||||
if (animationType == AnimationType.ZOOM)
|
||||
this._workspaces[w].zoomToOverview();
|
||||
else
|
||||
this._workspaces[w].fadeToOverview();
|
||||
}
|
||||
this._updateWorkspaceActors(false);
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
animateFromOverview: function(animationType) {
|
||||
this.actor.remove_clip();
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomFromOverview();
|
||||
for (let w = 0; w < this._workspaces.length; w++) {
|
||||
if (animationType == AnimationType.ZOOM)
|
||||
this._workspaces[w].zoomFromOverview();
|
||||
else
|
||||
this._workspaces[w].fadeFromOverview();
|
||||
}
|
||||
},
|
||||
|
||||
syncStacking: function(stackIndices) {
|
||||
@ -353,8 +366,8 @@ const ExtraWorkspaceView = new Lang.Class({
|
||||
this.actor.add_actor(this._workspace.actor);
|
||||
},
|
||||
|
||||
_setReservedSlot: function(clone) {
|
||||
this._workspace.setReservedSlot(clone);
|
||||
_setReservedSlot: function(window) {
|
||||
this._workspace.setReservedSlot(window);
|
||||
},
|
||||
|
||||
_syncFullGeometry: function() {
|
||||
@ -365,12 +378,18 @@ const ExtraWorkspaceView = new Lang.Class({
|
||||
this._workspace.setActualGeometry(this._actualGeometry);
|
||||
},
|
||||
|
||||
zoomToOverview: function() {
|
||||
this._workspace.zoomToOverview();
|
||||
animateToOverview: function(animationType) {
|
||||
if (animationType == AnimationType.ZOOM)
|
||||
this._workspace.zoomToOverview();
|
||||
else
|
||||
this._workspace.fadeToOverview();
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
this._workspace.zoomFromOverview();
|
||||
animateFromOverview: function(animationType) {
|
||||
if (animationType == AnimationType.ZOOM)
|
||||
this._workspace.zoomFromOverview();
|
||||
else
|
||||
this._workspace.fadeFromOverview();
|
||||
},
|
||||
|
||||
syncStacking: function(stackIndices) {
|
||||
@ -462,10 +481,16 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
return this._getPrimaryView().actor.navigate_focus(from, direction, false);
|
||||
},
|
||||
|
||||
show: function() {
|
||||
show: function(fadeOnPrimary) {
|
||||
this._updateWorkspacesViews();
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].zoomToOverview();
|
||||
for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||
let animationType;
|
||||
if (fadeOnPrimary && i == this._primaryIndex)
|
||||
animationType = AnimationType.FADE;
|
||||
else
|
||||
animationType = AnimationType.ZOOM;
|
||||
this._workspacesViews[i].animateToOverview(animationType);
|
||||
}
|
||||
|
||||
this._restackedNotifyId =
|
||||
Main.overview.connect('windows-restacked',
|
||||
@ -474,9 +499,15 @@ const WorkspacesDisplay = new Lang.Class({
|
||||
this._scrollEventId = Main.overview.connect('scroll-event', Lang.bind(this, this._onScrollEvent));
|
||||
},
|
||||
|
||||
zoomFromOverview: function() {
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].zoomFromOverview();
|
||||
animateFromOverview: function(fadeOnPrimary) {
|
||||
for (let i = 0; i < this._workspacesViews.length; i++) {
|
||||
let animationType;
|
||||
if (fadeOnPrimary && i == this._primaryIndex)
|
||||
animationType = AnimationType.FADE;
|
||||
else
|
||||
animationType = AnimationType.ZOOM;
|
||||
this._workspacesViews[i].animateFromOverview(animationType);
|
||||
}
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
|
@ -45,6 +45,7 @@ mk
|
||||
mr
|
||||
ms
|
||||
nb
|
||||
ne
|
||||
nl
|
||||
nn
|
||||
or
|
||||
|
2041
po/bn_IN.po
2041
po/bn_IN.po
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user