Compare commits
326 Commits
gbsneto/ea
...
wip/ewlsh/
Author | SHA1 | Date | |
---|---|---|---|
170fe945a9 | |||
08a5f41505 | |||
ec36762309 | |||
aa70020bc8 | |||
1e77e6fc79 | |||
68203e7091 | |||
cff0752bcc | |||
45d8e11123 | |||
5aee714b70 | |||
3c3c3b7c69 | |||
6ba2913075 | |||
75c4e1cd63 | |||
fb4a4ca4a2 | |||
4c2c1297be | |||
c5dbdad5fc | |||
4e05bcd3b6 | |||
3555550d5e | |||
8e05fa2728 | |||
d7c3050e2d | |||
89ba8562c3 | |||
82da73baff | |||
b2eeda9b46 | |||
0db41a3773 | |||
8d7f7e61dd | |||
3f4b253dac | |||
e4cbe5126a | |||
8357739ef8 | |||
6bef9334b7 | |||
8c49f45ac8 | |||
46600740fe | |||
c281e868a0 | |||
039431a73f | |||
d4f8ea1c53 | |||
96f5e2b33e | |||
93a542d52c | |||
f4fcba74ff | |||
cadbf7cd8b | |||
dd8e1aef51 | |||
15dc37a139 | |||
c23ad83c59 | |||
4a6f550acb | |||
8078d78c30 | |||
d7185d71c6 | |||
522ecba180 | |||
9b22f6183f | |||
b2c35e4fb0 | |||
af543daf1c | |||
baeb4079ee | |||
f91f9801b4 | |||
c5634335b0 | |||
2b4317349f | |||
96bfd1f8be | |||
33ab53068e | |||
40123ae6da | |||
df149524d4 | |||
f0ee9cdcf8 | |||
a3257e8df5 | |||
d2cf13eff4 | |||
8cd352b72b | |||
c210052dc6 | |||
0561af66e7 | |||
1e9b170d87 | |||
be02f76aa7 | |||
687928e7b7 | |||
ffdf3feb04 | |||
a60b8b3b50 | |||
3d6add68c7 | |||
85e055ffe3 | |||
1691e422e7 | |||
f442c9510e | |||
0de98eb772 | |||
30172b5625 | |||
8ae99a6898 | |||
5cfe5bf8c8 | |||
c790c01a3b | |||
d4a947b475 | |||
60d7999b6a | |||
c040d08b97 | |||
3a53b25873 | |||
d8e6f654a3 | |||
fdfcacf1db | |||
d3efbcce9b | |||
ac34dbe353 | |||
e0f3e13456 | |||
fdd9def922 | |||
771050f4d7 | |||
8451df977c | |||
ff55cf017e | |||
d36a180852 | |||
12c7f693d0 | |||
e0a8cb565e | |||
46547ae027 | |||
68745328df | |||
4582d7a183 | |||
cc5ed2fbf5 | |||
a2545d186a | |||
1ea22a5281 | |||
090057d2df | |||
b3aab7f401 | |||
8154728d09 | |||
5569090d1c | |||
fc3bc7678d | |||
8914a46669 | |||
e7ec373aee | |||
fe131f926d | |||
35d21c0bca | |||
b487846c0a | |||
7bbce1d5ad | |||
bf40d96a83 | |||
2d650e51a5 | |||
85d2837466 | |||
25985868e8 | |||
393c6c6805 | |||
775d6ec431 | |||
988f996407 | |||
315c8820ca | |||
8a89de04a2 | |||
63abfc163d | |||
f58cb34065 | |||
ece1329145 | |||
989118981b | |||
c511c469fe | |||
dac05c7e53 | |||
c90e7ce258 | |||
963f96292d | |||
989ee6593b | |||
2a8eea1ff5 | |||
55c287280b | |||
1fdd4ff313 | |||
3522338b3d | |||
61e3349dc7 | |||
dc27db0897 | |||
f09fbb19cf | |||
846fa77b37 | |||
b57bcf823f | |||
548e19a7cd | |||
4ae04d5aa8 | |||
5d5ca80d17 | |||
d81237b9d6 | |||
71b3b03b2f | |||
8c909e37e9 | |||
6508fa4349 | |||
ce8fb83c36 | |||
58ec607818 | |||
f06223df48 | |||
9a8ced9f5b | |||
67c45e5648 | |||
b88ed3f251 | |||
669b0f193a | |||
9cad7ae975 | |||
48e6a58250 | |||
d2583aa47b | |||
0ab34fe21f | |||
0f947d4ff9 | |||
9dc421875b | |||
9c3c9a155e | |||
faaed642a7 | |||
9b99b67fea | |||
693dd79d28 | |||
400d045a6a | |||
e20cf1ac78 | |||
8d4e650a95 | |||
82fd68b985 | |||
6ddd43f361 | |||
4e2ae30a47 | |||
32bc064d10 | |||
87606c6a6b | |||
955afb8711 | |||
3309031fd1 | |||
a2235c269a | |||
1cf2c9edd0 | |||
64a3ecf9b1 | |||
f144ed6e87 | |||
a47e0f9845 | |||
0737c8f416 | |||
fba350eaad | |||
6d5e93b00b | |||
f526e592fe | |||
751a94ab5d | |||
e0e128e207 | |||
137e6c8493 | |||
72751c2d92 | |||
b84fa852f6 | |||
d20961f323 | |||
5a01395a2b | |||
e59ca7053b | |||
6895592a7b | |||
eed27a2a4c | |||
43c6afa80f | |||
7d60f418e7 | |||
94dca1606f | |||
27774582b6 | |||
7dc08b06b1 | |||
a9d73b1017 | |||
25e4d0ba8b | |||
2d56395921 | |||
0ecddafc20 | |||
af34c8d2f4 | |||
5223599145 | |||
c96af776d6 | |||
34da48453e | |||
13dcd78be1 | |||
3bfa9916da | |||
b17017679b | |||
9d7832ea44 | |||
49605c7b00 | |||
bf8b9cecf5 | |||
c291291304 | |||
e08a4acd06 | |||
0397a104ba | |||
a41c1d4fda | |||
8ae3ed907a | |||
31cd8f738c | |||
a4cd9e0038 | |||
e06109c23c | |||
05485fe04c | |||
13062af7ef | |||
5e254666b0 | |||
d29eb8646a | |||
f1af37f220 | |||
d3880c0bff | |||
4dfa39457e | |||
325ff73c5b | |||
1fa4e3b1b2 | |||
f89091d0f0 | |||
859927df39 | |||
e7512fcd79 | |||
2b70151794 | |||
153b7d525d | |||
2e80995f19 | |||
9232cbf8a7 | |||
55f74bb863 | |||
b02e3719b3 | |||
3ba4304da9 | |||
49d6db34b7 | |||
63a0e521fd | |||
c00d79bae2 | |||
30d902f898 | |||
8f9da6f801 | |||
20648e9207 | |||
614fe202e0 | |||
c3646a7642 | |||
772df91762 | |||
c90910731f | |||
ba69cd99d1 | |||
fb6e341efd | |||
3dc4f01113 | |||
d94d0f60c8 | |||
8d79f6f4c8 | |||
c5e5bb0be1 | |||
8d139bbd95 | |||
fb1bb291eb | |||
3199620a83 | |||
c88bb66369 | |||
a60d57ea1f | |||
527ce66cd4 | |||
40415a6849 | |||
1ff638a51f | |||
2a9ccf2e2c | |||
2909d91c13 | |||
0dba12193d | |||
02f40b3b63 | |||
1fd51efc7f | |||
6f881f232e | |||
be12c71534 | |||
6aa1b817c9 | |||
300961e19e | |||
b191e9ef91 | |||
5ec5978d4a | |||
f4d90bc127 | |||
bfa34914db | |||
8d1e4659d1 | |||
b3b91f1699 | |||
ff4c5270d3 | |||
e240f7ea59 | |||
9f1ad5d86d | |||
a1ab32af0f | |||
3fac0632a8 | |||
c2b518929d | |||
c422d82752 | |||
da0c7fc2b6 | |||
167bc080d9 | |||
7d7a15f978 | |||
1b5cf0b8a8 | |||
306b005943 | |||
d229abf07d | |||
6f6251c0bc | |||
fd034e3551 | |||
f9bee05d49 | |||
37c6fbc6b2 | |||
9719604b79 | |||
b6262f0666 | |||
6c0bd207e9 | |||
91b13effc8 | |||
143ab6ac7f | |||
3e5b90dbba | |||
b82039e324 | |||
83862d04a0 | |||
52d07f6d9b | |||
21de88c3ba | |||
456ca3d3e0 | |||
f4ba3e4ab8 | |||
d4db5a59c1 | |||
4aee87a31b | |||
e8f5a842b1 | |||
5c681a76b6 | |||
53a24e6ddd | |||
b27c89f836 | |||
9f870aa1c7 | |||
c9cfeb8318 | |||
497e66ce6a | |||
bc973b80d7 | |||
85846d88f0 | |||
6b7c85b079 | |||
d80ef67d1d | |||
62f3457a95 | |||
636ab4b0e9 | |||
23e382dd33 | |||
f5a170ce46 | |||
fbd6beea2c | |||
360f5b1642 | |||
f0a785df9d | |||
e2c1bfbedd | |||
7e5a1cfd90 | |||
07deda593a | |||
1ca39e8586 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -60,7 +60,6 @@ src/calendar-server/evolution-calendar.desktop
|
||||
src/calendar-server/org.gnome.Shell.CalendarServer.service
|
||||
src/gnome-shell
|
||||
src/gnome-shell-calendar-server
|
||||
src/gnome-shell-extension-prefs
|
||||
src/gnome-shell-extension-tool
|
||||
src/gnome-shell-hotplug-sniffer
|
||||
src/gnome-shell-perf-helper
|
||||
|
@ -18,7 +18,7 @@ variables:
|
||||
- merge_requests
|
||||
|
||||
check_commit_log:
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||
stage: review
|
||||
variables:
|
||||
GIT_DEPTH: "100"
|
||||
@ -28,10 +28,10 @@ check_commit_log:
|
||||
- merge_requests
|
||||
|
||||
js_check:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
|
||||
stage: review
|
||||
script:
|
||||
- find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
|
||||
- find js -name '*.js' -exec js68 -c -s '{}' ';' 2>&1 | tee $JS_LOG
|
||||
- (! grep -q . $JS_LOG)
|
||||
<<: *only_default
|
||||
artifacts:
|
||||
@ -40,7 +40,7 @@ js_check:
|
||||
when: on_failure
|
||||
|
||||
eslint:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
|
||||
stage: review
|
||||
script:
|
||||
- ./.gitlab-ci/run-eslint.sh
|
||||
@ -51,21 +51,21 @@ eslint:
|
||||
when: always
|
||||
|
||||
potfile_check:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
|
||||
stage: review
|
||||
script:
|
||||
- ./.gitlab-ci/check-potfiles.sh
|
||||
<<: *only_default
|
||||
|
||||
no_template_check:
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
|
||||
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
|
||||
stage: review
|
||||
script:
|
||||
- ./.gitlab-ci/check-template-strings.sh
|
||||
<<: *only_default
|
||||
|
||||
build:
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||
stage: build
|
||||
before_script:
|
||||
- .gitlab-ci/checkout-mutter.sh
|
||||
@ -83,7 +83,7 @@ build:
|
||||
- build
|
||||
|
||||
test:
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||
stage: test
|
||||
variables:
|
||||
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
|
||||
@ -100,7 +100,7 @@ test:
|
||||
when: on_failure
|
||||
|
||||
test-pot:
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||
stage: test
|
||||
before_script:
|
||||
- ninja -C mutter/build install
|
||||
@ -124,11 +124,7 @@ flatpak:
|
||||
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
|
||||
FLATPAK_MODULE: "gnome-extensions-app"
|
||||
APP_ID: "org.gnome.Extensions"
|
||||
MESON_ARGS: "$SUBPROJECT"
|
||||
extends: .flatpak
|
||||
before_script:
|
||||
- flatpak run --command=$SUBPROJECT/generate-translations.sh
|
||||
--filesystem=host org.gnome.Sdk//master
|
||||
<<: *only_default
|
||||
|
||||
nightly:
|
||||
|
24
.gitlab-ci/Dockerfile
Normal file
24
.gitlab-ci/Dockerfile
Normal file
@ -0,0 +1,24 @@
|
||||
# Rebuild and push with
|
||||
#
|
||||
# cd .gitlab-ci/
|
||||
# podman build --format docker --no-cache -t registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 .
|
||||
# podman push registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
|
||||
#
|
||||
|
||||
FROM registry.fedoraproject.org/fedora:32
|
||||
|
||||
RUN dnf -y update && dnf -y upgrade && \
|
||||
dnf install -y 'dnf-command(copr)' git && \
|
||||
|
||||
# For syntax checks with `find . -name '*.js' -exec js68 -c -s '{}' ';'`
|
||||
dnf install -y findutils mozjs68-devel && \
|
||||
|
||||
# For static analysis with eslint
|
||||
dnf install -y nodejs && \
|
||||
npm install -g eslint && \
|
||||
|
||||
# Shameless plug for my own tooling; useful for generating zip
|
||||
dnf copr enable -y fmuellner/gnome-shell-ci && \
|
||||
dnf install -y gnome-extensions-tool meson && \
|
||||
|
||||
dnf clean all
|
@ -1,18 +0,0 @@
|
||||
FROM registry.fedoraproject.org/fedora:latest
|
||||
|
||||
RUN dnf -y update && dnf -y upgrade && \
|
||||
dnf install -y 'dnf-command(copr)' git && \
|
||||
|
||||
# For syntax checks with `find . -name '*.js' -exec js60 -c -s '{}' ';'`
|
||||
dnf install -y findutils mozjs60-devel && \
|
||||
|
||||
# For static analysis with eslint
|
||||
dnf install -y nodejs && \
|
||||
npm install -g eslint && \
|
||||
|
||||
# Shameless plug for my own tooling; useful for generating zip
|
||||
dnf copr enable -y fmuellner/gnome-shell-ci && \
|
||||
dnf install -y gnome-extensions-tool meson && \
|
||||
|
||||
dnf clean all && \
|
||||
rm -rf /var/cache/dnf
|
@ -6,6 +6,11 @@ globs=('*.js' '*.c')
|
||||
# find source files that contain gettext keywords
|
||||
files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs)
|
||||
|
||||
# filter out excluded files
|
||||
if [ -f po/POTFILES.skip ]; then
|
||||
files=$(for f in $files; do ! grep -q ^$f po/POTFILES.skip && echo $f; done)
|
||||
fi
|
||||
|
||||
# find those that aren't listed in POTFILES.in
|
||||
missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done)
|
||||
|
||||
|
@ -18,12 +18,14 @@ run_eslint() {
|
||||
local extra_args=ARGS_$1
|
||||
local output_var=OUTPUT_$1
|
||||
local output=${!output_var}
|
||||
local cache=.eslintcache-${1,,}
|
||||
|
||||
# ensure output exists even if eslint doesn't report any errors
|
||||
mkdir -p $(dirname $output)
|
||||
touch $output
|
||||
|
||||
eslint -f unix ${!extra_args} -o $output js subprojects/extensions-app/js
|
||||
eslint -f unix --cache --cache-location $cache ${!extra_args} -o $output \
|
||||
js subprojects/extensions-app/js
|
||||
}
|
||||
|
||||
list_commit_range_additions() {
|
||||
|
85
NEWS
85
NEWS
@ -1,3 +1,88 @@
|
||||
3.37.2
|
||||
======
|
||||
* Add support for "PrefersNonDefaultGPU" desktop key [Bastien; !1226]
|
||||
* Only start systemd units when running under systemd
|
||||
[Carlos, Florian; #2755, !1242, !1252]
|
||||
* Fix "ghost" media controls [Bryan; #2776]
|
||||
* Fix zombie sockets from extensions downloader [Michael; #2774]
|
||||
* Update world clocks offsets when timezone changes [Bryan; #2209]
|
||||
* Support scrolling anywhere in slider menu items [Peter; #2795]
|
||||
* Fix "Do Not Disturb" setting getting reset on startup [Florian; #2804]
|
||||
* Only allow updates for extensions that aren't cached [Florian; !1248]
|
||||
* Fix matching notifications by PID [Florian; #2592]
|
||||
* Indicate extension errors in Extensions app [Florian; #2337]
|
||||
* Add clipboard API for querying supported mimetypes [Andy; #2819]
|
||||
* Add preview to color picker [Florian; #451]
|
||||
* Improve world clocks styling [PrOF-kk; #2825]
|
||||
* Remove Frequent view from app picker [Georges; !880]
|
||||
* Fix pad OSD glitches [Carlos; !1290]
|
||||
* Expose actor tree in looking glass [Georges; !1292]
|
||||
* Fixed crashes [Jonas D., Florian; #2709, #2757]
|
||||
* Misc. bug fixes and cleanups [Florian, AsciiWolf, Michael, Piotr, Ting-Wei,
|
||||
Amr, Alexander, Bryan, Georges, Jonas D., Andy, Björn, Koki, Carlos; !1229,
|
||||
!1231, !1233, !1235, #2578, #2735, #2751, #2602, #2777, !1249, #2796, !1268,
|
||||
!1269, !1265, !1245, !1273, #2816, !1274, !1263, !1188, !1276, #2652, !1277,
|
||||
!1281, #2286, !1267, !1286, !1279, !1288, !1293, !1294, !1291]
|
||||
|
||||
Contributors:
|
||||
AsciiWolf, Michael Catanzaro, Björn Daase, Jonas Dreßler, Bryan Dunsmore,
|
||||
Koki Fukuda, Carlos Garnacho, Andy Holmes, Amr Ibrahim, Soslan Khubulov,
|
||||
Ting-Wei Lan, Michael Lass, Alexander Mikhaylenko, Florian Müllner,
|
||||
Georges Basile Stavracas Neto, Bastien Nocera, PrOF-kk, Peter Simonyi
|
||||
|
||||
Translators:
|
||||
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Yuri Chornoivan [uk],
|
||||
Dušan Kazik [sk], Piotr Drąg [pl], Soslan Khubulov [os],
|
||||
Daniel Mustieles [es], Nathan Follens [nl], Bruce Cowan [en_GB],
|
||||
Florentina Mușat [ro], Milo Casagrande [it], Anders Jonsson [sv],
|
||||
Charles Monzat [fr], Danial Behzadi [fa], sicklylife [ja], Kukuh Syafaat [id],
|
||||
Jordi Mas [ca], Emin Tufan Çetin [tr], Jiri Grönroos [fi], Марко Костић [sr],
|
||||
Christian Kirbach [de], Changwoo Ryu [ko], Matej Urbančič [sl]
|
||||
|
||||
3.37.1
|
||||
======
|
||||
* Improve bluetooth submenu title [Mariana; #2340]
|
||||
* Add openPrefs() convenience method for extensions [Florian; !1163]
|
||||
* Bring back support for empty StIcons [Andre, Jonas D.; !1173, !1178]
|
||||
* Wake up screen when unlocking programmatically [Florian; !1158]
|
||||
* Improve extensions tool error reporting [Florian; #2391]
|
||||
* Improve handling of scale-factor changes [Georges; !1176]
|
||||
* Tone down weekend days with events in calendar [Jakub; #2588]
|
||||
* Fix showing bluetooth submenu when devices were set up [Florian; !1174]
|
||||
* Add support for parental controls filtering [Philip W.; !465]
|
||||
* Provide alternative extension templates [Florian; !812]
|
||||
* Improve weather section's empty state [Mariana; #2179]
|
||||
* Fix translations of folder names [Florian; #2623]
|
||||
* Drop Tweener [Jonas Å.; !1200]
|
||||
* Match ASCII alternatives of system actions [Will; #2688]
|
||||
* Fix delay on lock screen after entering wrong password [Jonas D.; #2655]
|
||||
* Use globalThis instead of window [Andy; #2322]
|
||||
* Inhibit remote access when disabled by session mode [Jonas Å.; !1210]
|
||||
* Improve calendar-server performance [Milan; #1875]
|
||||
* Add gnome-shell-extension-prefs wrapper for compatibility [Florian; !1220]
|
||||
* Fix stuck lock screen after unlock [Jonas D., Florian; #2446]
|
||||
* Fixed crashes [Jonas D., Florian, Carlos; #2584, #2625, !1223, !1218]
|
||||
* Misc. bug fixes and cleanups [Florian, Jonas Å., Marco, Andre, Georges,
|
||||
Jonas D., Jan, Philip Ch.,, Xiaoguang, Will, Jordan, Matthew, qarmin;
|
||||
!1126, !1155, !1156, !1165, !1168, !1169, #2551, #2563, !1172, !1175, !1179,
|
||||
!1160, #2562, #2578, !1184, #2559, !1186, #2607, !1191, !1194, !1199, !1203,
|
||||
#2649, #2628, !1205, !1206, !1208, !1207, !1211, !1214, !1213, !1192, !1217,
|
||||
!1219, #1615, #2691, !1094, !1177]
|
||||
|
||||
Contributors:
|
||||
Marco Trevisan (Treviño), Philip Chimento, Milan Crha, Jonas Dreßler,
|
||||
Carlos Garnacho, Andy Holmes, Matthew Leeds, Andre Moreira Magalhaes,
|
||||
Florian Müllner, Georges Basile Stavracas Neto, Jordan Petridis,
|
||||
Mariana Picolo, Jakub Steiner, Will Thompson, Jan Tojnar, Xiaoguang Wang,
|
||||
Philip Withnall, qarmin, Jonas Ådahl
|
||||
|
||||
Translators:
|
||||
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Danial Behzadi [fa],
|
||||
Jiri Grönroos [fi], Ibai Oihanguren Sala [eu], Марко Костић [sr],
|
||||
Rūdolfs Mazurs [lv], Yuri Chornoivan [uk], Carmen Bianca BAKKER [eo],
|
||||
Dingzhong Chen [zh_CN], Rafael Fontenelle [pt_BR], Petr Kovář [cs],
|
||||
Asier Sarasua Garmendia [eu], Daniel Mustieles [es], Emin Tufan Çetin [tr]
|
||||
|
||||
3.36.0
|
||||
======
|
||||
* Fix off-by-1900 error in date conversions [Florian; !1061]
|
||||
|
@ -1,12 +1,19 @@
|
||||
<node>
|
||||
<interface name="org.gnome.Shell.CalendarServer">
|
||||
<method name="GetEvents">
|
||||
<arg type="x" direction="in" />
|
||||
<arg type="x" direction="in" />
|
||||
<arg type="b" direction="in" />
|
||||
<arg type="a(sssbxxa{sv})" direction="out" />
|
||||
<method name="SetTimeRange">
|
||||
<arg type="x" name="since" direction="in"/>
|
||||
<arg type="x" name="until" direction="in"/>
|
||||
<arg type="b" name="force_reload" direction="in"/>
|
||||
</method>
|
||||
<signal name="EventsAddedOrUpdated">
|
||||
<arg type="a(ssbxxa{sv})" name="events" direction="out"/>
|
||||
</signal>
|
||||
<signal name="EventsRemoved">
|
||||
<arg type="as" name="ids" direction="out"/>
|
||||
</signal>
|
||||
<signal name="ClientDisappeared">
|
||||
<arg type="s" name="source_uid" direction="out"/>
|
||||
</signal>
|
||||
<property name="HasCalendars" type="b" access="read" />
|
||||
<signal name="Changed" />
|
||||
</interface>
|
||||
</node>
|
||||
|
@ -2,7 +2,6 @@
|
||||
<gresources>
|
||||
<gresource prefix="/org/gnome/shell/dbus-interfaces">
|
||||
<file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file>
|
||||
<file preprocess="xml-stripblanks">net.hadess.SwitcherooControl.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.freedesktop.Application.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Device.xml</file>
|
||||
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Manager.xml</file>
|
||||
|
@ -6,6 +6,7 @@
|
||||
<file>checkbox-off-focused.svg</file>
|
||||
<file>checkbox-off.svg</file>
|
||||
<file>checkbox.svg</file>
|
||||
<file alias="icons/color-pick.svg">color-pick.svg</file>
|
||||
<file>dash-placeholder.svg</file>
|
||||
<file>gnome-shell.css</file>
|
||||
<file>gnome-shell-high-contrast.css</file>
|
||||
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 6.1 KiB |
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M6.5 1.031c-.371 0-.742-.035-1.11.016-.367.05-.73.203-.972.476-.125.141-.215.309-.266.485-.047.18-.054.367-.02.55.032.184.102.356.192.516.09.164.203.309.317.457L5 4H2a1.8 1.8 0 00-.41.035.791.791 0 00-.36.195.791.791 0 00-.195.36C1 4.723 1 4.863 1 5v2.75l.77-.344c.265-.117.542-.23.832-.242.289-.016.586.074.812.254.227.18.383.441.465.723.082.277.101.57.121.859.02.316.04.637-.016.95-.058.312-.199.616-.43.831a1.264 1.264 0 01-.874.32c-.317-.007-.618-.128-.91-.257L1 10.5V14c0 .137.004.277.035.41a.791.791 0 00.195.36c.098.097.227.16.36.195.133.035.273.035.41.035h3l-.328-.68c-.14-.293-.274-.597-.29-.922-.015-.32.095-.652.31-.894.214-.242.523-.39.84-.453.316-.067.644-.059.968-.059.324 0 .652-.008.969.059.316.062.625.21.84.453.214.242.324.574.308.894-.015.325-.148.63-.289.922L8 15h3a1.8 1.8 0 00.41-.035.791.791 0 00.36-.195.791.791 0 00.195-.36C12 14.277 12 14.137 12 14v-3.563l.703.297c.29.125.59.239.902.246.313.004.63-.101.864-.308.238-.203.386-.496.46-.8C15 9.565 15 9.25 15 8.937c0-.313 0-.63-.07-.934-.075-.305-.223-.598-.461-.8a1.288 1.288 0 00-.864-.31c-.312.008-.613.122-.902.247L12 7.437V5a1.8 1.8 0 00-.035-.41.791.791 0 00-.195-.36.791.791 0 00-.36-.195C11.277 4 11.137 4 11 4H8l.36-.469c.113-.148.226-.293.316-.457.09-.16.16-.332.191-.515a1.248 1.248 0 00-.02-.551 1.256 1.256 0 00-.265-.485c-.242-.273-.605-.425-.973-.476-.367-.05-.738-.016-1.109-.016zm0 0" fill="#474747"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
data/icons/meson.build
Normal file
1
data/icons/meson.build
Normal file
@ -0,0 +1 @@
|
||||
install_subdir('hicolor', install_dir: icondir)
|
@ -1,5 +1,6 @@
|
||||
desktop_files = [
|
||||
'org.gnome.Shell.desktop',
|
||||
'org.gnome.Shell.Extensions.desktop',
|
||||
]
|
||||
service_files = []
|
||||
|
||||
@ -42,6 +43,7 @@ endforeach
|
||||
|
||||
|
||||
subdir('dbus-interfaces')
|
||||
subdir('icons')
|
||||
subdir('theme')
|
||||
|
||||
data_resources = [
|
||||
|
10
data/org.gnome.Shell.Extensions.desktop.in.in
Normal file
10
data/org.gnome.Shell.Extensions.desktop.in.in
Normal file
@ -0,0 +1,10 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
# Keep in sync with subprojects/extensions-app
|
||||
Name=Extensions
|
||||
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
|
||||
Icon=org.gnome.Shell.Extensions
|
||||
# Never launch this, just provide name+icon to portal dialog
|
||||
Exec=false
|
||||
OnlyShowIn=GNOME;
|
||||
NoDisplay=true
|
94
data/theme/color-pick.svg
Normal file
94
data/theme/color-pick.svg
Normal file
@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="5.4116011mm"
|
||||
height="5.1374583mm"
|
||||
viewBox="0 0 5.4116011 5.1374583"
|
||||
version="1.1"
|
||||
id="svg5595"
|
||||
inkscape:version="0.92.4 (unknown)"
|
||||
sodipodi:docname="color-pick.svg">
|
||||
<defs
|
||||
id="defs5589">
|
||||
<filter
|
||||
inkscape:collect="always"
|
||||
x="-0.10291173"
|
||||
width="1.2058235"
|
||||
y="-0.065432459"
|
||||
height="1.1308649"
|
||||
id="filter5601"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
inkscape:collect="always"
|
||||
stdDeviation="0.610872"
|
||||
id="feGaussianBlur5603" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="15.839192"
|
||||
inkscape:cx="39.387731"
|
||||
inkscape:cy="12.554326"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1016"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<metadata
|
||||
id="metadata5592">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-103.12753,-146.26461)">
|
||||
<circle
|
||||
r="8.4810486"
|
||||
cy="9.82623"
|
||||
cx="10.226647"
|
||||
id="circle7584"
|
||||
style="color:#000000;display:inline;overflow:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;filter:url(#filter5601)"
|
||||
transform="matrix(0.26458333,0,0,0.26458333,103.12753,146.26461)" />
|
||||
<path
|
||||
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.26399338;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
d="m 108.07728,148.64122 c 0,1.2393 -1.00465,2.24394 -2.24395,2.24394 -1.23929,0 -2.24716,-1.00465 -2.25221,-2.24394 l -0.009,-2.24458 2.26136,6.4e-4 c 1.2393,3.4e-4 2.24395,1.00464 2.24395,2.24394 z"
|
||||
id="path7523-7"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ssscss" />
|
||||
<circle
|
||||
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#50dbb5;fill-opacity:1;stroke:none;stroke-width:0.36885914;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
|
||||
id="path7482-1"
|
||||
cx="105.83707"
|
||||
cy="148.64352"
|
||||
r="1.844296" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
@ -1,21 +1,15 @@
|
||||
/* App Grid */
|
||||
|
||||
$app_icon_size: 96px;
|
||||
$app_icon_padding: 24px;
|
||||
|
||||
// app icons
|
||||
.icon-grid {
|
||||
-shell-grid-horizontal-item-size: $app_icon_size + $app_icon_padding * 2;
|
||||
-shell-grid-vertical-item-size: $app_icon_size + $app_icon_padding * 2;
|
||||
spacing: $base_spacing * 6;
|
||||
|
||||
.overview-icon {
|
||||
icon-size: $app_icon_size;
|
||||
}
|
||||
row-spacing: $base_spacing * 6;
|
||||
column-spacing: $base_spacing * 6;
|
||||
max-row-spacing: $base_spacing * 12;
|
||||
max-column-spacing: $base_spacing * 12;
|
||||
}
|
||||
|
||||
//.app-display { spacing: 20px; }
|
||||
|
||||
/* App Icons */
|
||||
|
||||
$app_grid_fg_color: #fff;
|
||||
@ -44,8 +38,8 @@ $app_grid_fg_color: #fff;
|
||||
.app-folder-dialog {
|
||||
border-radius: $modal_radius * 1.5;
|
||||
border: 1px solid $osd_outer_borders_color;
|
||||
spacing: 12px;
|
||||
background-color: transparentize(darken($osd_bg_color,10%), 0.05);
|
||||
padding: 12px;
|
||||
|
||||
& .folder-name-container {
|
||||
padding: 24px 36px 0;
|
||||
@ -54,7 +48,7 @@ $app_grid_fg_color: #fff;
|
||||
& .folder-name-label,
|
||||
& .folder-name-entry {
|
||||
font-size: 18pt;
|
||||
font-weight: bold;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
& .folder-name-entry { width: 300px }
|
||||
@ -73,11 +67,24 @@ $app_grid_fg_color: #fff;
|
||||
& > StIcon { icon-size: 16px }
|
||||
}
|
||||
}
|
||||
|
||||
& .icon-grid {
|
||||
row-spacing: $base_spacing * 2;
|
||||
column-spacing: $base_spacing * 5;
|
||||
}
|
||||
|
||||
& .page-indicators {
|
||||
margin-bottom: 18px;
|
||||
|
||||
.page-indicator {
|
||||
padding: 15px 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.app-folder-dialog-container {
|
||||
padding: 12px;
|
||||
width: 800px;
|
||||
height: 600px;
|
||||
width: 620px;
|
||||
height: 620px;
|
||||
}
|
||||
|
||||
.app-folder-icon {
|
||||
@ -123,15 +130,11 @@ $app_grid_fg_color: #fff;
|
||||
}
|
||||
|
||||
// Some hacks I don't even know
|
||||
.all-apps,
|
||||
.frequent-apps > StBoxLayout {
|
||||
.all-apps {
|
||||
// horizontal padding to make sure scrollbars or dash don't overlap content
|
||||
padding: 0px 88px 10px 88px;
|
||||
}
|
||||
|
||||
// Label when no frequent apps
|
||||
.no-frequent-applications-label { @extend %status_text; }
|
||||
|
||||
// shutdown and other actions in the grid
|
||||
.system-action-icon {
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
@ -139,44 +142,3 @@ $app_grid_fg_color: #fff;
|
||||
border-radius: 99px;
|
||||
icon-size: $app_icon_size * 0.5;
|
||||
}
|
||||
|
||||
/* Frequent | All toggle */
|
||||
|
||||
// container
|
||||
.app-view-controls {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
// buttons
|
||||
.app-view-control {
|
||||
padding: 4px 32px;
|
||||
margin: 0 4px;
|
||||
|
||||
&, &:hover, &:checked {
|
||||
@include button(undecorated);
|
||||
color: darken($osd_fg_color, 25%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $osd_fg_color;
|
||||
box-shadow: inset 0 -2px darken($osd_fg_color, 25%);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: inset 0 -2px $osd_fg_color;
|
||||
}
|
||||
|
||||
&:checked {
|
||||
color: $osd_fg_color;
|
||||
box-shadow: inset 0 -2px $selected_bg_color;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-right-width: 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
@ -153,9 +153,11 @@
|
||||
}
|
||||
|
||||
.calendar-day-with-events {
|
||||
color: lighten($fg_color,10%);
|
||||
font-weight: bold;
|
||||
background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
|
||||
&.calendar-work-day {
|
||||
color: lighten($fg_color,10%);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-other-month-day {
|
||||
@ -175,6 +177,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Events */
|
||||
.events-button {
|
||||
@include notification_bubble;
|
||||
padding: $base_padding * 2;
|
||||
|
||||
.events-box {
|
||||
spacing: $base_spacing;
|
||||
}
|
||||
|
||||
.events-list {
|
||||
spacing: 2 * $base_spacing;
|
||||
}
|
||||
|
||||
.events-title {
|
||||
color: desaturate(darken($fg_color,40%), 10%);
|
||||
font-weight: bold;
|
||||
margin-bottom: $base_margin;
|
||||
}
|
||||
|
||||
.event-time {
|
||||
color: darken($fg_color,20%);
|
||||
font-feature-settings: "tnum";
|
||||
@include fontsize($base_font_size - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* World clocks */
|
||||
.world-clocks-button {
|
||||
@include notification_bubble;
|
||||
@ -202,7 +230,7 @@
|
||||
.world-clocks-time {
|
||||
font-weight: bold;
|
||||
color: $fg_color;
|
||||
font-feature-settings: "lnum";
|
||||
font-feature-settings: "tnum";
|
||||
@include fontsize($base_font_size);
|
||||
text-align: right;
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* Looking Glass */
|
||||
|
||||
$text_fg_color: #ccc;
|
||||
|
||||
// Dialog
|
||||
#LookingGlassDialog {
|
||||
background-color: $osd_bg_color;
|
||||
@ -52,6 +54,11 @@
|
||||
&:hover { color: lighten($link_color, 10%); }
|
||||
&:active { color: darken($link_color, 10%); }
|
||||
}
|
||||
.actor-link {
|
||||
color: $text_fg_color;
|
||||
&:hover { color: lighten($text_fg_color, 20%); }
|
||||
&:active { color: darken($text_fg_color, 20%); }
|
||||
}
|
||||
}
|
||||
|
||||
.lg-completions-text {
|
||||
|
@ -54,6 +54,10 @@
|
||||
@extend %status_text;
|
||||
}
|
||||
|
||||
.grid-search-results {
|
||||
spacing: $base_spacing * 6;
|
||||
}
|
||||
|
||||
// Search results with icons
|
||||
.grid-search-result {
|
||||
@extend %app-well-app;
|
||||
|
@ -8,6 +8,7 @@ $window_thumbnail_border_color:transparentize($selected_fg_color, 0.65);
|
||||
$window_close_button_size: 24px;
|
||||
$window_close_button_padding: 3px;
|
||||
|
||||
$window_clone_border_size: 6px;
|
||||
|
||||
// Window picker
|
||||
.window-picker {
|
||||
@ -22,7 +23,7 @@ $window_close_button_padding: 3px;
|
||||
|
||||
// Borders on window thumbnails
|
||||
.window-clone-border {
|
||||
border-width: 6px;
|
||||
border-width: $window_clone_border_size;
|
||||
border-style: solid;
|
||||
border-color: $window_thumbnail_border_color;
|
||||
border-radius: $base_border_radius + 2;
|
||||
@ -54,8 +55,6 @@ $window_close_button_padding: 3px;
|
||||
width: $window_close_button_size;
|
||||
box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.5);
|
||||
|
||||
-shell-close-overlap: $window_close_button_size * 0.5;
|
||||
|
||||
&:hover {
|
||||
background-color: lighten($selected_bg_color, 5%);
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ const { ServiceImplementation } = imports.dbusService;
|
||||
const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
|
||||
const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface);
|
||||
|
||||
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
|
||||
|
||||
var NotificationDaemon = class extends ServiceImplementation {
|
||||
constructor() {
|
||||
super(NotificationsIface, '/org/freedesktop/Notifications');
|
||||
@ -42,7 +44,15 @@ var NotificationDaemon = class extends ServiceImplementation {
|
||||
null, null);
|
||||
}
|
||||
|
||||
NotifyAsync(params, invocation) {
|
||||
async NotifyAsync(params, invocation) {
|
||||
const pid = await this._getSenderPid(invocation.get_sender());
|
||||
const hints = params[6];
|
||||
|
||||
params[6] = {
|
||||
...hints,
|
||||
'sender-pid': new GLib.Variant('u', pid),
|
||||
};
|
||||
|
||||
this._proxy.NotifyRemote(...params, (res, error) => {
|
||||
if (this._handleError(invocation, error))
|
||||
return;
|
||||
@ -77,4 +87,19 @@ var NotificationDaemon = class extends ServiceImplementation {
|
||||
invocation.return_value(new GLib.Variant('(ssss)', res));
|
||||
});
|
||||
}
|
||||
|
||||
async _getSenderPid(sender) {
|
||||
const res = await Gio.DBus.session.call(
|
||||
'org.freedesktop.DBus',
|
||||
'/',
|
||||
'org.freedesktop.DBus',
|
||||
'GetConnectionUnixProcessID',
|
||||
new GLib.Variant('(s)', [sender]),
|
||||
new GLib.VariantType('(u)'),
|
||||
Gio.DBusCallFlags.NONE,
|
||||
-1,
|
||||
null);
|
||||
const [pid] = res.deepUnpack();
|
||||
return pid;
|
||||
}
|
||||
};
|
||||
|
@ -184,7 +184,7 @@ var AuthPrompt = GObject.registerClass({
|
||||
});
|
||||
this._defaultButtonWell.add_constraint(new Clutter.BindConstraint({
|
||||
source: this.cancelButton,
|
||||
coordinate: Clutter.BindCoordinate.SIZE,
|
||||
coordinate: Clutter.BindCoordinate.WIDTH,
|
||||
}));
|
||||
this._mainBox.add_child(this._defaultButtonWell);
|
||||
|
||||
@ -424,7 +424,13 @@ var AuthPrompt = GObject.registerClass({
|
||||
}
|
||||
|
||||
updateSensitivity(sensitive) {
|
||||
if (this._entry.reactive === sensitive)
|
||||
return;
|
||||
|
||||
this._entry.reactive = sensitive;
|
||||
|
||||
if (sensitive)
|
||||
this._entry.grab_key_focus();
|
||||
}
|
||||
|
||||
vfunc_hide() {
|
||||
|
@ -589,8 +589,8 @@ var LoginDialog = GObject.registerClass({
|
||||
return actorBox;
|
||||
}
|
||||
|
||||
vfunc_allocate(dialogBox, flags) {
|
||||
this.set_allocation(dialogBox, flags);
|
||||
vfunc_allocate(dialogBox) {
|
||||
this.set_allocation(dialogBox);
|
||||
|
||||
let themeNode = this.get_theme_node();
|
||||
dialogBox = themeNode.get_content_box(dialogBox);
|
||||
@ -719,19 +719,19 @@ var LoginDialog = GObject.registerClass({
|
||||
|
||||
// Finally hand out the allocations
|
||||
if (bannerAllocation)
|
||||
this._bannerView.allocate(bannerAllocation, flags);
|
||||
this._bannerView.allocate(bannerAllocation);
|
||||
|
||||
if (authPromptAllocation)
|
||||
this._authPrompt.allocate(authPromptAllocation, flags);
|
||||
this._authPrompt.allocate(authPromptAllocation);
|
||||
|
||||
if (userSelectionAllocation)
|
||||
this._userSelectionBox.allocate(userSelectionAllocation, flags);
|
||||
this._userSelectionBox.allocate(userSelectionAllocation);
|
||||
|
||||
if (logoAllocation)
|
||||
this._logoBin.allocate(logoAllocation, flags);
|
||||
this._logoBin.allocate(logoAllocation);
|
||||
|
||||
if (sessionMenuButtonAllocation)
|
||||
this._sessionMenuButton.allocate(sessionMenuButtonAllocation, flags);
|
||||
this._sessionMenuButton.allocate(sessionMenuButtonAllocation);
|
||||
}
|
||||
|
||||
_ensureUserListLoaded() {
|
||||
@ -810,12 +810,13 @@ var LoginDialog = GObject.registerClass({
|
||||
return;
|
||||
|
||||
this._logoBin.destroy_all_children();
|
||||
if (this._logoFile && this._logoBin.resource_scale > 0) {
|
||||
const [valid, resourceScale] = this._logoBin.get_resource_scale();
|
||||
if (this._logoFile && valid) {
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
|
||||
-1, -1,
|
||||
scaleFactor,
|
||||
this._logoBin.resource_scale));
|
||||
resourceScale));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@
|
||||
<file>misc/modemManager.js</file>
|
||||
<file>misc/objectManager.js</file>
|
||||
<file>misc/params.js</file>
|
||||
<file>misc/parentalControlsManager.js</file>
|
||||
<file>misc/permissionStore.js</file>
|
||||
<file>misc/smartcardManager.js</file>
|
||||
<file>misc/systemActions.js</file>
|
||||
@ -101,13 +102,13 @@
|
||||
<file>ui/swipeTracker.js</file>
|
||||
<file>ui/switcherPopup.js</file>
|
||||
<file>ui/switchMonitor.js</file>
|
||||
<file>ui/tweener.js</file>
|
||||
<file>ui/unlockDialog.js</file>
|
||||
<file>ui/userWidget.js</file>
|
||||
<file>ui/viewSelector.js</file>
|
||||
<file>ui/windowAttentionHandler.js</file>
|
||||
<file>ui/windowMenu.js</file>
|
||||
<file>ui/windowManager.js</file>
|
||||
<file>ui/windowPreview.js</file>
|
||||
<file>ui/workspace.js</file>
|
||||
<file>ui/workspaceSwitcherPopup.js</file>
|
||||
<file>ui/workspaceThumbnail.js</file>
|
||||
|
@ -171,13 +171,13 @@ var IBusManager = class {
|
||||
this._panelService.connect('set-content-type', this._setContentType.bind(this));
|
||||
} catch (e) {
|
||||
}
|
||||
this._updateReadiness();
|
||||
|
||||
try {
|
||||
// If an engine is already active we need to get its properties
|
||||
const engine =
|
||||
await this._ibus.get_global_engine_async(-1, this._cancellable);
|
||||
this._engineChanged(this._ibus, engine.get_name());
|
||||
this._updateReadiness();
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
|
||||
[expr_, base, attrHead] = matches;
|
||||
|
||||
methods = getPropertyNamesFromExpression(base, commandHeader).filter(
|
||||
attr => attr.slice(0, attrHead.length) == attrHead
|
||||
);
|
||||
attr => attr.slice(0, attrHead.length) === attrHead);
|
||||
}
|
||||
|
||||
// Look for the empty expression or partially entered words
|
||||
@ -34,8 +33,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
|
||||
if (text == '' || matches) {
|
||||
[expr_, attrHead] = matches;
|
||||
methods = globalCompletionList.filter(
|
||||
attr => attr.slice(0, attrHead.length) == attrHead
|
||||
);
|
||||
attr => attr.slice(0, attrHead.length) === attrHead);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
|
||||
|
||||
const { GLib, GnomeDesktop, Meta } = imports.gi;
|
||||
const { GLib, GnomeDesktop } = imports.gi;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
@ -62,11 +62,11 @@ var KeyboardManager = class {
|
||||
return;
|
||||
|
||||
this._currentKeymap = { layouts, variants, options };
|
||||
Meta.get_backend().set_keymap(layouts, variants, options);
|
||||
global.backend.set_keymap(layouts, variants, options);
|
||||
}
|
||||
|
||||
_applyLayoutGroupIndex(idx) {
|
||||
Meta.get_backend().lock_layout_group(idx);
|
||||
global.backend.lock_layout_group(idx);
|
||||
}
|
||||
|
||||
apply(id) {
|
||||
|
146
js/misc/parentalControlsManager.js
Normal file
146
js/misc/parentalControlsManager.js
Normal file
@ -0,0 +1,146 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
//
|
||||
// Copyright (C) 2018, 2019, 2020 Endless Mobile, Inc.
|
||||
//
|
||||
// This is a GNOME Shell component to wrap the interactions over
|
||||
// D-Bus with the malcontent library.
|
||||
//
|
||||
// Licensed under the GNU General Public License Version 2
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 2
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
/* exported getDefault */
|
||||
|
||||
const { Gio, GObject, Shell } = imports.gi;
|
||||
|
||||
// We require libmalcontent ≥ 0.6.0
|
||||
const HAVE_MALCONTENT = imports.package.checkSymbol(
|
||||
'Malcontent', '0', 'ManagerGetValueFlags');
|
||||
|
||||
var Malcontent = null;
|
||||
if (HAVE_MALCONTENT) {
|
||||
Malcontent = imports.gi.Malcontent;
|
||||
Gio._promisify(Malcontent.Manager.prototype, 'get_app_filter_async', 'get_app_filter_finish');
|
||||
}
|
||||
|
||||
let _singleton = null;
|
||||
|
||||
function getDefault() {
|
||||
if (_singleton === null)
|
||||
_singleton = new ParentalControlsManager();
|
||||
|
||||
return _singleton;
|
||||
}
|
||||
|
||||
// A manager class which provides cached access to the constructing user’s
|
||||
// parental controls settings. It’s possible for the user’s parental controls
|
||||
// to change at runtime if the Parental Controls application is used by an
|
||||
// administrator from within the user’s session.
|
||||
var ParentalControlsManager = GObject.registerClass({
|
||||
Signals: {
|
||||
'app-filter-changed': {},
|
||||
},
|
||||
}, class ParentalControlsManager extends GObject.Object {
|
||||
_init() {
|
||||
super._init();
|
||||
|
||||
this._initialized = false;
|
||||
this._disabled = false;
|
||||
this._appFilter = null;
|
||||
|
||||
this._initializeManager();
|
||||
}
|
||||
|
||||
async _initializeManager() {
|
||||
if (!HAVE_MALCONTENT) {
|
||||
log('Skipping parental controls support as it’s disabled');
|
||||
this._initialized = true;
|
||||
this.emit('app-filter-changed');
|
||||
return;
|
||||
}
|
||||
|
||||
log(`Getting parental controls for user ${Shell.util_get_uid()}`);
|
||||
try {
|
||||
const connection = await Gio.DBus.get(Gio.BusType.SYSTEM, null);
|
||||
this._manager = new Malcontent.Manager({ connection });
|
||||
this._appFilter = await this._manager.get_app_filter_async(
|
||||
Shell.util_get_uid(),
|
||||
Malcontent.ManagerGetValueFlags.NONE,
|
||||
null);
|
||||
} catch (e) {
|
||||
if (e.matches(Malcontent.ManagerError, Malcontent.ManagerError.DISABLED)) {
|
||||
log('Parental controls globally disabled');
|
||||
this._disabled = true;
|
||||
} else {
|
||||
logError(e, 'Failed to get parental controls settings');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._manager.connect('app-filter-changed', this._onAppFilterChanged.bind(this));
|
||||
|
||||
// Signal initialisation is complete.
|
||||
this._initialized = true;
|
||||
this.emit('app-filter-changed');
|
||||
}
|
||||
|
||||
async _onAppFilterChanged(manager, uid) {
|
||||
// Emit 'changed' signal only if app-filter is changed for currently logged-in user.
|
||||
let currentUid = Shell.util_get_uid();
|
||||
if (currentUid !== uid)
|
||||
return;
|
||||
|
||||
try {
|
||||
this._appFilter = await this._manager.get_app_filter_async(
|
||||
currentUid,
|
||||
Malcontent.ManagerGetValueFlags.NONE,
|
||||
null);
|
||||
this.emit('app-filter-changed');
|
||||
} catch (e) {
|
||||
// Log an error and keep the old app filter.
|
||||
logError(e, `Failed to get new MctAppFilter for uid ${Shell.util_get_uid()} on app-filter-changed`);
|
||||
}
|
||||
}
|
||||
|
||||
get initialized() {
|
||||
return this._initialized;
|
||||
}
|
||||
|
||||
// Calculate whether the given app (a Gio.DesktopAppInfo) should be shown
|
||||
// on the desktop, in search results, etc. The app should be shown if:
|
||||
// - The .desktop file doesn’t say it should be hidden.
|
||||
// - The executable from the .desktop file’s Exec line isn’t blacklisted in
|
||||
// the user’s parental controls.
|
||||
// - None of the flatpak app IDs from the X-Flatpak and the
|
||||
// X-Flatpak-RenamedFrom lines are blacklisted in the user’s parental
|
||||
// controls.
|
||||
shouldShowApp(appInfo) {
|
||||
// Quick decision?
|
||||
if (!appInfo.should_show())
|
||||
return false;
|
||||
|
||||
// Are parental controls enabled (at configure time or runtime)?
|
||||
if (!HAVE_MALCONTENT || this._disabled)
|
||||
return true;
|
||||
|
||||
// Have we finished initialising yet?
|
||||
if (!this.initialized) {
|
||||
log(`Warning: Hiding app because parental controls not yet initialised: ${appInfo.get_id()}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._appFilter.is_appinfo_allowed(appInfo);
|
||||
}
|
||||
});
|
@ -83,13 +83,17 @@ const SystemActions = GObject.registerClass({
|
||||
this._canHavePowerOff = true;
|
||||
this._canHaveSuspend = true;
|
||||
|
||||
function tokenizeKeywords(keywords) {
|
||||
return keywords.split(';').map(keyword => GLib.str_tokenize_and_fold(keyword, null)).flat(2);
|
||||
}
|
||||
|
||||
this._actions = new Map();
|
||||
this._actions.set(POWER_OFF_ACTION_ID, {
|
||||
// Translators: The name of the power-off action in search
|
||||
name: C_("search-result", "Power Off"),
|
||||
iconName: 'system-shutdown-symbolic',
|
||||
// Translators: A list of keywords that match the power-off action, separated by semicolons
|
||||
keywords: _('power off;shutdown;reboot;restart;halt;stop').split(/[; ]/),
|
||||
keywords: tokenizeKeywords(_('power off;shutdown;reboot;restart;halt;stop')),
|
||||
available: false,
|
||||
});
|
||||
this._actions.set(LOCK_SCREEN_ACTION_ID, {
|
||||
@ -97,15 +101,15 @@ const SystemActions = GObject.registerClass({
|
||||
name: C_("search-result", "Lock Screen"),
|
||||
iconName: 'system-lock-screen-symbolic',
|
||||
// Translators: A list of keywords that match the lock screen action, separated by semicolons
|
||||
keywords: _("lock screen").split(/[; ]/),
|
||||
keywords: tokenizeKeywords(_('lock screen')),
|
||||
available: false,
|
||||
});
|
||||
this._actions.set(LOGOUT_ACTION_ID, {
|
||||
// Translators: The name of the logout action in search
|
||||
name: C_("search-result", "Log Out"),
|
||||
iconName: 'application-exit-symbolic',
|
||||
iconName: 'system-log-out-symbolic',
|
||||
// Translators: A list of keywords that match the logout action, separated by semicolons
|
||||
keywords: _("logout;log out;sign off").split(/[; ]/),
|
||||
keywords: tokenizeKeywords(_('logout;log out;sign off')),
|
||||
available: false,
|
||||
});
|
||||
this._actions.set(SUSPEND_ACTION_ID, {
|
||||
@ -113,7 +117,7 @@ const SystemActions = GObject.registerClass({
|
||||
name: C_("search-result", "Suspend"),
|
||||
iconName: 'media-playback-pause-symbolic',
|
||||
// Translators: A list of keywords that match the suspend action, separated by semicolons
|
||||
keywords: _("suspend;sleep").split(/[; ]/),
|
||||
keywords: tokenizeKeywords(_('suspend;sleep')),
|
||||
available: false,
|
||||
});
|
||||
this._actions.set(SWITCH_USER_ACTION_ID, {
|
||||
@ -121,14 +125,14 @@ const SystemActions = GObject.registerClass({
|
||||
name: C_("search-result", "Switch User"),
|
||||
iconName: 'system-switch-user-symbolic',
|
||||
// Translators: A list of keywords that match the switch user action, separated by semicolons
|
||||
keywords: _("switch user").split(/[; ]/),
|
||||
keywords: tokenizeKeywords(_('switch user')),
|
||||
available: false,
|
||||
});
|
||||
this._actions.set(LOCK_ORIENTATION_ACTION_ID, {
|
||||
name: '',
|
||||
iconName: '',
|
||||
// Translators: A list of keywords that match the lock orientation action, separated by semicolons
|
||||
keywords: _("lock orientation;unlock orientation;screen;rotation").split(/[; ]/),
|
||||
keywords: tokenizeKeywords(_('lock orientation;unlock orientation;screen;rotation')),
|
||||
available: false,
|
||||
});
|
||||
|
||||
@ -277,7 +281,7 @@ const SystemActions = GObject.registerClass({
|
||||
|
||||
getMatchingActions(terms) {
|
||||
// terms is a list of strings
|
||||
terms = terms.map(term => term.toLowerCase());
|
||||
terms = terms.map(term => GLib.str_tokenize_and_fold(term, null)[0]);
|
||||
|
||||
let results = [];
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
|
||||
formatTime, formatTimeSpan, createTimeLabel, insertSorted,
|
||||
makeCloseButton, ensureActorVisibleInScrollView, wiggle */
|
||||
ensureActorVisibleInScrollView, wiggle */
|
||||
|
||||
const { Clutter, Gio, GLib, GObject, Shell, St, GnomeDesktop } = imports.gi;
|
||||
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
|
||||
const Gettext = imports.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
@ -363,51 +363,6 @@ function insertSorted(array, val, cmp) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
var CloseButton = GObject.registerClass(
|
||||
class CloseButton extends St.Button {
|
||||
_init(boxpointer) {
|
||||
super._init({
|
||||
style_class: 'notification-close',
|
||||
x_expand: true,
|
||||
y_expand: true,
|
||||
x_align: Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.START,
|
||||
});
|
||||
|
||||
this._boxPointer = boxpointer;
|
||||
if (boxpointer)
|
||||
this._boxPointer.connect('arrow-side-changed', this._sync.bind(this));
|
||||
}
|
||||
|
||||
_computeBoxPointerOffset() {
|
||||
if (!this._boxPointer || !this._boxPointer.get_stage())
|
||||
return 0;
|
||||
|
||||
let side = this._boxPointer.arrowSide;
|
||||
if (side == St.Side.TOP)
|
||||
return this._boxPointer.getArrowHeight();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
_sync() {
|
||||
let themeNode = this.get_theme_node();
|
||||
|
||||
let offY = this._computeBoxPointerOffset();
|
||||
this.translation_x = themeNode.get_length('-shell-close-overlap-x');
|
||||
this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY;
|
||||
}
|
||||
|
||||
vfunc_style_changed() {
|
||||
this._sync();
|
||||
super.vfunc_style_changed();
|
||||
}
|
||||
});
|
||||
|
||||
function makeCloseButton(boxpointer) {
|
||||
return new CloseButton(boxpointer);
|
||||
}
|
||||
|
||||
function ensureActorVisibleInScrollView(scrollView, actor) {
|
||||
let adjustment = scrollView.vscroll.adjustment;
|
||||
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
|
||||
|
@ -68,8 +68,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
this._items = this._switcherList.icons;
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
super.vfunc_allocate(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
super.vfunc_allocate(box);
|
||||
|
||||
// Allocate the thumbnails
|
||||
// We try to avoid overflowing the screen so we base the resulting size on
|
||||
@ -102,7 +102,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
||||
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
|
||||
let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
|
||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||
this._thumbnails.allocate(childBox, flags);
|
||||
this._thumbnails.allocate(childBox);
|
||||
}
|
||||
}
|
||||
|
||||
@ -681,8 +681,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
// Cache the window list now; we don't handle dynamic changes here,
|
||||
// and we don't want to be continually retrieving it
|
||||
appIcon.cachedWindows = allWindows.filter(
|
||||
w => windowTracker.get_window_app(w) == appIcon.app
|
||||
);
|
||||
w => windowTracker.get_window_app(w) === appIcon.app);
|
||||
if (appIcon.cachedWindows.length > 0)
|
||||
this._addIcon(appIcon);
|
||||
}
|
||||
@ -750,9 +749,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
return super.vfunc_get_preferred_height(forWidth);
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
vfunc_allocate(box) {
|
||||
// Allocate the main list items
|
||||
super.vfunc_allocate(box, flags);
|
||||
super.vfunc_allocate(box);
|
||||
|
||||
let contentBox = this.get_theme_node().get_content_box(box);
|
||||
|
||||
@ -767,7 +766,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
||||
childBox.x2 = childBox.x1 + arrowWidth;
|
||||
childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight;
|
||||
childBox.y2 = childBox.y1 + arrowHeight;
|
||||
this._arrows[i].allocate(childBox, flags);
|
||||
this._arrows[i].allocate(childBox);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1057,28 +1056,28 @@ class WindowSwitcher extends SwitcherPopup.SwitcherList {
|
||||
return [minHeight, natHeight];
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
vfunc_allocate(box) {
|
||||
let themeNode = this.get_theme_node();
|
||||
let contentBox = themeNode.get_content_box(box);
|
||||
const labelHeight = this._label.height;
|
||||
const totalLabelHeight =
|
||||
labelHeight + themeNode.get_padding(St.Side.BOTTOM);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = contentBox.x1;
|
||||
childBox.x2 = contentBox.x2;
|
||||
childBox.y2 = contentBox.y2;
|
||||
childBox.y1 = childBox.y2 - this._label.height;
|
||||
this._label.allocate(childBox, flags);
|
||||
|
||||
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM);
|
||||
childBox.x1 = box.x1;
|
||||
childBox.x2 = box.x2;
|
||||
childBox.y1 = box.y1;
|
||||
childBox.y2 = box.y2 - totalLabelHeight;
|
||||
super.vfunc_allocate(childBox, flags);
|
||||
box.y2 -= totalLabelHeight;
|
||||
super.vfunc_allocate(box);
|
||||
|
||||
// Hooking up the parent vfunc will call this.set_allocation() with
|
||||
// the height without the label height, so call it again with the
|
||||
// correct size here.
|
||||
this.set_allocation(box, flags);
|
||||
box.y2 += totalLabelHeight;
|
||||
this.set_allocation(box);
|
||||
|
||||
const childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = contentBox.x1;
|
||||
childBox.x2 = contentBox.x2;
|
||||
childBox.y2 = contentBox.y2;
|
||||
childBox.y1 = childBox.y2 - labelHeight;
|
||||
this._label.allocate(childBox);
|
||||
}
|
||||
|
||||
highlight(index, justOutline) {
|
||||
|
@ -15,8 +15,7 @@ class Animation extends St.Bin {
|
||||
const themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||
|
||||
super._init({
|
||||
width: width * themeContext.scale_factor,
|
||||
height: height * themeContext.scale_factor,
|
||||
style: `width: ${width}px; height: ${height}px;`,
|
||||
});
|
||||
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
|
1216
js/ui/appDisplay.js
1216
js/ui/appDisplay.js
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
||||
/* exported getAppFavorites */
|
||||
|
||||
const Shell = imports.gi.Shell;
|
||||
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
@ -12,6 +13,7 @@ const RENAMED_DESKTOP_IDS = {
|
||||
'cheese.desktop': 'org.gnome.Cheese.desktop',
|
||||
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
|
||||
'empathy.desktop': 'org.gnome.Empathy.desktop',
|
||||
'eog.desktop': 'org.gnome.eog.desktop',
|
||||
'epiphany.desktop': 'org.gnome.Epiphany.desktop',
|
||||
'evolution.desktop': 'org.gnome.Evolution.desktop',
|
||||
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
|
||||
@ -64,6 +66,13 @@ const RENAMED_DESKTOP_IDS = {
|
||||
|
||||
class AppFavorites {
|
||||
constructor() {
|
||||
// Filter the apps through the user’s parental controls.
|
||||
this._parentalControlsManager = ParentalControlsManager.getDefault();
|
||||
this._parentalControlsManager.connect('app-filter-changed', () => {
|
||||
this.reload();
|
||||
this.emit('changed');
|
||||
});
|
||||
|
||||
this.FAVORITE_APPS_KEY = 'favorite-apps';
|
||||
this._favorites = {};
|
||||
global.settings.connect('changed::%s'.format(this.FAVORITE_APPS_KEY), this._onFavsChanged.bind(this));
|
||||
@ -95,7 +104,7 @@ class AppFavorites {
|
||||
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
||||
|
||||
let apps = ids.map(id => appSys.lookup_app(id))
|
||||
.filter(app => app != null);
|
||||
.filter(app => app !== null && this._parentalControlsManager.shouldShowApp(app.app_info));
|
||||
this._favorites = {};
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app = apps[i];
|
||||
@ -134,6 +143,9 @@ class AppFavorites {
|
||||
if (!app)
|
||||
return false;
|
||||
|
||||
if (!this._parentalControlsManager.shouldShowApp(app.app_info))
|
||||
return false;
|
||||
|
||||
let ids = this._getIds();
|
||||
if (pos == -1)
|
||||
ids.push(appId);
|
||||
|
@ -147,9 +147,8 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
|
||||
_onDeviceSelected(dialog, device) {
|
||||
let connection = this._dbusImpl.get_connection();
|
||||
let info = this._dbusImpl.get_info();
|
||||
let deviceName = Object.keys(AudioDevice).filter(
|
||||
dev => AudioDevice[dev] == device
|
||||
)[0].toLowerCase();
|
||||
const deviceName = Object.keys(AudioDevice)
|
||||
.filter(dev => AudioDevice[dev] === device)[0].toLowerCase();
|
||||
connection.emit_signal(this._audioSelectionDialog._sender,
|
||||
this._dbusImpl.get_object_path(),
|
||||
info ? info.name : null,
|
||||
|
@ -512,8 +512,8 @@ var SystemBackground = GObject.registerClass({
|
||||
super._init({
|
||||
meta_display: global.display,
|
||||
monitor: 0,
|
||||
background: _systemBackground,
|
||||
});
|
||||
this.content.background = _systemBackground;
|
||||
|
||||
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
this.emit('loaded');
|
||||
@ -738,6 +738,8 @@ var BackgroundManager = class BackgroundManager {
|
||||
let backgroundActor = new Meta.BackgroundActor({
|
||||
meta_display: global.display,
|
||||
monitor: this._monitorIndex,
|
||||
});
|
||||
backgroundActor.content.set({
|
||||
background,
|
||||
vignette: this._vignette,
|
||||
vignette_sharpness: 0.5,
|
||||
|
@ -30,8 +30,8 @@ var BarLevel = GObject.registerClass({
|
||||
accessible_role: Atk.Role.LEVEL_BAR,
|
||||
};
|
||||
super._init(Object.assign(defaultParams, params));
|
||||
this.connect('allocation-changed', (actor, box) => {
|
||||
this._barLevelWidth = box.get_width();
|
||||
this.connect('notify::allocation', () => {
|
||||
this._barLevelWidth = this.allocation.get_width();
|
||||
});
|
||||
|
||||
this._customAccessible = St.GenericAccessible.new_for_actor(this);
|
||||
|
@ -196,8 +196,13 @@ var BoxPointer = GObject.registerClass({
|
||||
return themeNode.adjust_preferred_height(...height);
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
if (this._sourceActor && this._sourceActor.mapped) {
|
||||
this._reposition(box);
|
||||
this._updateFlip(box);
|
||||
}
|
||||
|
||||
this.set_allocation(box);
|
||||
|
||||
let themeNode = this.get_theme_node();
|
||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||
@ -209,7 +214,7 @@ var BoxPointer = GObject.registerClass({
|
||||
childBox.y1 = 0;
|
||||
childBox.x2 = availWidth;
|
||||
childBox.y2 = availHeight;
|
||||
this._border.allocate(childBox, flags);
|
||||
this._border.allocate(childBox);
|
||||
|
||||
childBox.x1 = borderWidth;
|
||||
childBox.y1 = borderWidth;
|
||||
@ -229,13 +234,7 @@ var BoxPointer = GObject.registerClass({
|
||||
childBox.x2 -= rise;
|
||||
break;
|
||||
}
|
||||
this.bin.allocate(childBox, flags);
|
||||
|
||||
if (this._sourceActor && this._sourceActor.mapped) {
|
||||
this._reposition(box);
|
||||
this._updateFlip(box);
|
||||
this.set_allocation(box, flags);
|
||||
}
|
||||
this.bin.allocate(childBox);
|
||||
}
|
||||
|
||||
_drawBorder(area) {
|
||||
|
@ -14,7 +14,6 @@ const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
var MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
var SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||
var ELLIPSIS_CHAR = '\u2026';
|
||||
|
||||
var MESSAGE_ICON_SIZE = -1; // pick up from CSS
|
||||
|
||||
@ -32,10 +31,6 @@ function sameDay(dateA, dateB) {
|
||||
return sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
|
||||
}
|
||||
|
||||
function isToday(date) {
|
||||
return sameDay(new Date(), date);
|
||||
}
|
||||
|
||||
function _isWorkDay(date) {
|
||||
/* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
|
||||
let days = C_('calendar-no-work', "06");
|
||||
@ -222,7 +217,12 @@ class DBusEventSource extends EventSourceBase {
|
||||
}
|
||||
}
|
||||
|
||||
this._dbusProxy.connectSignal('Changed', this._onChanged.bind(this));
|
||||
this._dbusProxy.connectSignal('EventsAddedOrUpdated',
|
||||
this._onEventsAddedOrUpdated.bind(this));
|
||||
this._dbusProxy.connectSignal('EventsRemoved',
|
||||
this._onEventsRemoved.bind(this));
|
||||
this._dbusProxy.connectSignal('ClientDisappeared',
|
||||
this._onClientDisappeared.bind(this));
|
||||
|
||||
this._dbusProxy.connect('notify::g-name-owner', () => {
|
||||
if (this._dbusProxy.g_name_owner)
|
||||
@ -258,7 +258,7 @@ class DBusEventSource extends EventSourceBase {
|
||||
}
|
||||
|
||||
_resetCache() {
|
||||
this._events = [];
|
||||
this._events = new Map();
|
||||
this._lastRequestBegin = null;
|
||||
this._lastRequestEnd = null;
|
||||
}
|
||||
@ -274,28 +274,47 @@ class DBusEventSource extends EventSourceBase {
|
||||
this.emit('changed');
|
||||
}
|
||||
|
||||
_onChanged() {
|
||||
this._loadEvents(false);
|
||||
_onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) {
|
||||
const [appointments = []] = argArray;
|
||||
let changed = false;
|
||||
|
||||
for (let n = 0; n < appointments.length; n++) {
|
||||
const [id, summary, allDay, startTime, endTime] = appointments[n];
|
||||
const date = new Date(startTime * 1000);
|
||||
const end = new Date(endTime * 1000);
|
||||
let event = new CalendarEvent(id, date, end, summary, allDay);
|
||||
this._events.set(event.id, event);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
this.emit('changed');
|
||||
}
|
||||
|
||||
_onEventsReceived(results, _error) {
|
||||
let newEvents = [];
|
||||
let appointments = results[0] || [];
|
||||
for (let n = 0; n < appointments.length; n++) {
|
||||
let a = appointments[n];
|
||||
let date = new Date(a[4] * 1000);
|
||||
let end = new Date(a[5] * 1000);
|
||||
let id = a[0];
|
||||
let summary = a[1];
|
||||
let allDay = a[3];
|
||||
let event = new CalendarEvent(id, date, end, summary, allDay);
|
||||
newEvents.push(event);
|
||||
}
|
||||
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
|
||||
_onEventsRemoved(dbusProxy, nameOwner, argArray) {
|
||||
const [ids = []] = argArray;
|
||||
|
||||
this._events = newEvents;
|
||||
this._isLoading = false;
|
||||
this.emit('changed');
|
||||
let changed = false;
|
||||
for (const id of ids)
|
||||
changed |= this._events.delete(id);
|
||||
|
||||
if (changed)
|
||||
this.emit('changed');
|
||||
}
|
||||
|
||||
_onClientDisappeared(dbusProxy, nameOwner, argArray) {
|
||||
let [sourceUid = ''] = argArray;
|
||||
sourceUid += '\n';
|
||||
|
||||
let changed = false;
|
||||
for (const id of this._events.keys()) {
|
||||
if (id.startsWith(sourceUid))
|
||||
changed |= this._events.delete(id);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
this.emit('changed');
|
||||
}
|
||||
|
||||
_loadEvents(forceReload) {
|
||||
@ -304,33 +323,38 @@ class DBusEventSource extends EventSourceBase {
|
||||
return;
|
||||
|
||||
if (this._curRequestBegin && this._curRequestEnd) {
|
||||
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
||||
this._curRequestEnd.getTime() / 1000,
|
||||
forceReload,
|
||||
this._onEventsReceived.bind(this),
|
||||
Gio.DBusCallFlags.NONE);
|
||||
if (forceReload) {
|
||||
this._events.clear();
|
||||
this.emit('changed');
|
||||
}
|
||||
this._dbusProxy.SetTimeRangeRemote(
|
||||
this._curRequestBegin.getTime() / 1000,
|
||||
this._curRequestEnd.getTime() / 1000,
|
||||
forceReload,
|
||||
Gio.DBusCallFlags.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
requestRange(begin, end) {
|
||||
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
||||
this._isLoading = true;
|
||||
this._lastRequestBegin = begin;
|
||||
this._lastRequestEnd = end;
|
||||
this._curRequestBegin = begin;
|
||||
this._curRequestEnd = end;
|
||||
this._loadEvents(false);
|
||||
this._loadEvents(true);
|
||||
}
|
||||
}
|
||||
|
||||
*_getFilteredEvents(begin, end) {
|
||||
for (const event of this._events.values()) {
|
||||
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
|
||||
yield event;
|
||||
}
|
||||
}
|
||||
|
||||
getEvents(begin, end) {
|
||||
let result = [];
|
||||
for (let n = 0; n < this._events.length; n++) {
|
||||
let event = this._events[n];
|
||||
let result = [...this._getFilteredEvents(begin, end)];
|
||||
|
||||
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
|
||||
result.push(event);
|
||||
}
|
||||
result.sort((event1, event2) => {
|
||||
// sort events by end time on ending day
|
||||
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
|
||||
@ -344,12 +368,8 @@ class DBusEventSource extends EventSourceBase {
|
||||
let dayBegin = _getBeginningOfDay(day);
|
||||
let dayEnd = _getEndOfDay(day);
|
||||
|
||||
let events = this.getEvents(dayBegin, dayEnd);
|
||||
|
||||
if (events.length == 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
const { done } = this._getFilteredEvents(dayBegin, dayEnd).next();
|
||||
return !done;
|
||||
}
|
||||
});
|
||||
|
||||
@ -698,61 +718,6 @@ var Calendar = GObject.registerClass({
|
||||
}
|
||||
});
|
||||
|
||||
var EventMessage = GObject.registerClass(
|
||||
class EventMessage extends MessageList.Message {
|
||||
_init(event, date) {
|
||||
super._init('', event.summary);
|
||||
|
||||
this._event = event;
|
||||
this._date = date;
|
||||
|
||||
this.setTitle(this._formatEventTime());
|
||||
|
||||
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
|
||||
this.setIcon(this._icon);
|
||||
}
|
||||
|
||||
vfunc_style_changed() {
|
||||
let iconVisible = this.get_parent().has_style_pseudo_class('first-child');
|
||||
this._icon.opacity = iconVisible ? 255 : 0;
|
||||
super.vfunc_style_changed();
|
||||
}
|
||||
|
||||
_formatEventTime() {
|
||||
let periodBegin = _getBeginningOfDay(this._date);
|
||||
let periodEnd = _getEndOfDay(this._date);
|
||||
let allDay = this._event.allDay || (this._event.date <= periodBegin &&
|
||||
this._event.end >= periodEnd);
|
||||
let title;
|
||||
if (allDay) {
|
||||
/* Translators: Shown in calendar event list for all day events
|
||||
* Keep it short, best if you can use less then 10 characters
|
||||
*/
|
||||
title = C_("event list time", "All Day");
|
||||
} else {
|
||||
let date = this._event.date >= periodBegin
|
||||
? this._event.date
|
||||
: this._event.end;
|
||||
title = Util.formatTime(date, { timeOnly: true });
|
||||
}
|
||||
|
||||
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
|
||||
if (this._event.date < periodBegin && !this._event.allDay) {
|
||||
if (rtl)
|
||||
title = '%s%s'.format(title, ELLIPSIS_CHAR);
|
||||
else
|
||||
title = '%s%s'.format(ELLIPSIS_CHAR, title);
|
||||
}
|
||||
if (this._event.end > periodEnd && !this._event.allDay) {
|
||||
if (rtl)
|
||||
title = '%s%s'.format(ELLIPSIS_CHAR, title);
|
||||
else
|
||||
title = '%s%s'.format(title, ELLIPSIS_CHAR);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
});
|
||||
|
||||
var NotificationMessage = GObject.registerClass(
|
||||
class NotificationMessage extends MessageList.Message {
|
||||
_init(notification) {
|
||||
@ -818,148 +783,6 @@ class NotificationMessage extends MessageList.Message {
|
||||
}
|
||||
});
|
||||
|
||||
var EventsSection = GObject.registerClass(
|
||||
class EventsSection extends MessageList.MessageListSection {
|
||||
_init() {
|
||||
super._init();
|
||||
|
||||
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
|
||||
this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
|
||||
this._eventSource = new EmptyEventSource();
|
||||
|
||||
this._messageById = new Map();
|
||||
|
||||
this._title = new St.Button({ style_class: 'events-section-title',
|
||||
label: '',
|
||||
can_focus: true });
|
||||
this._title.child.x_align = Clutter.ActorAlign.START;
|
||||
this.insert_child_below(this._title, null);
|
||||
|
||||
this._title.connect('clicked', this._onTitleClicked.bind(this));
|
||||
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
|
||||
|
||||
this._appSys = Shell.AppSystem.get_default();
|
||||
this._appSys.connect('installed-changed',
|
||||
this._appInstalledChanged.bind(this));
|
||||
this._appInstalledChanged();
|
||||
}
|
||||
|
||||
setEventSource(eventSource) {
|
||||
if (!(eventSource instanceof EventSourceBase))
|
||||
throw new Error('Event source is not valid type');
|
||||
|
||||
this._eventSource = eventSource;
|
||||
this._eventSource.connect('changed', this._reloadEvents.bind(this));
|
||||
}
|
||||
|
||||
get allowed() {
|
||||
return Main.sessionMode.showCalendarEvents;
|
||||
}
|
||||
|
||||
_updateTitle() {
|
||||
this._title.visible = !isToday(this._date);
|
||||
|
||||
if (!this._title.visible)
|
||||
return;
|
||||
|
||||
let dayFormat;
|
||||
let now = new Date();
|
||||
if (sameYear(this._date, now)) {
|
||||
/* Translators: Shown on calendar heading when selected day occurs on current year */
|
||||
dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d"));
|
||||
} else {
|
||||
/* Translators: Shown on calendar heading when selected day occurs on different year */
|
||||
dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d, %Y"));
|
||||
}
|
||||
this._title.label = this._date.toLocaleFormat(dayFormat);
|
||||
}
|
||||
|
||||
_reloadEvents() {
|
||||
if (this._eventSource.isLoading)
|
||||
return;
|
||||
|
||||
this._reloading = true;
|
||||
|
||||
let periodBegin = _getBeginningOfDay(this._date);
|
||||
let periodEnd = _getEndOfDay(this._date);
|
||||
let events = this._eventSource.getEvents(periodBegin, periodEnd);
|
||||
|
||||
let ids = events.map(e => e.id);
|
||||
this._messageById.forEach((message, id) => {
|
||||
if (ids.includes(id))
|
||||
return;
|
||||
this._messageById.delete(id);
|
||||
this.removeMessage(message);
|
||||
});
|
||||
|
||||
for (let i = 0; i < events.length; i++) {
|
||||
let event = events[i];
|
||||
|
||||
let message = this._messageById.get(event.id);
|
||||
if (!message) {
|
||||
message = new EventMessage(event, this._date);
|
||||
this._messageById.set(event.id, message);
|
||||
this.addMessage(message, false);
|
||||
} else {
|
||||
this.moveMessage(message, i, false);
|
||||
}
|
||||
}
|
||||
|
||||
this._reloading = false;
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_appInstalledChanged() {
|
||||
this._calendarApp = undefined;
|
||||
this._title.reactive = this._getCalendarApp() != null;
|
||||
}
|
||||
|
||||
_getCalendarApp() {
|
||||
if (this._calendarApp !== undefined)
|
||||
return this._calendarApp;
|
||||
|
||||
let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
|
||||
if (apps && (apps.length > 0)) {
|
||||
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
|
||||
let defaultInRecommended = apps.some(a => a.equal(app));
|
||||
this._calendarApp = defaultInRecommended ? app : apps[0];
|
||||
} else {
|
||||
this._calendarApp = null;
|
||||
}
|
||||
return this._calendarApp;
|
||||
}
|
||||
|
||||
_onTitleClicked() {
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
|
||||
let appInfo = this._getCalendarApp();
|
||||
if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
|
||||
let app = this._appSys.lookup_app('evolution-calendar.desktop');
|
||||
if (app)
|
||||
appInfo = app.app_info;
|
||||
}
|
||||
appInfo.launch([], global.create_app_launch_context(0, -1));
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
super.setDate(date);
|
||||
this._updateTitle();
|
||||
this._reloadEvents();
|
||||
}
|
||||
|
||||
_shouldShow() {
|
||||
return !this.empty || !isToday(this._date);
|
||||
}
|
||||
|
||||
_sync() {
|
||||
if (this._reloading)
|
||||
return;
|
||||
|
||||
super._sync();
|
||||
}
|
||||
});
|
||||
|
||||
var TimeLabel = GObject.registerClass(
|
||||
class NotificationTimeLabel extends St.Label {
|
||||
_init(datetime) {
|
||||
@ -1056,10 +879,6 @@ class NotificationSection extends MessageList.MessageListSection {
|
||||
});
|
||||
super.vfunc_map();
|
||||
}
|
||||
|
||||
_shouldShow() {
|
||||
return !this.empty && isToday(this._date);
|
||||
}
|
||||
});
|
||||
|
||||
var Placeholder = GObject.registerClass(
|
||||
@ -1068,41 +887,13 @@ class Placeholder extends St.BoxLayout {
|
||||
super._init({ style_class: 'message-list-placeholder', vertical: true });
|
||||
this._date = new Date();
|
||||
|
||||
let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
|
||||
let otherFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-events.svg');
|
||||
this._todayIcon = new Gio.FileIcon({ file: todayFile });
|
||||
this._otherIcon = new Gio.FileIcon({ file: otherFile });
|
||||
|
||||
this._icon = new St.Icon();
|
||||
const file = Gio.File.new_for_uri(
|
||||
'resource:///org/gnome/shell/theme/no-notifications.svg');
|
||||
this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file }) });
|
||||
this.add_actor(this._icon);
|
||||
|
||||
this._label = new St.Label();
|
||||
this._label = new St.Label({ text: _('No Notifications') });
|
||||
this.add_actor(this._label);
|
||||
|
||||
this._sync();
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
if (sameDay(this._date, date))
|
||||
return;
|
||||
this._date = date;
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_sync() {
|
||||
let today = isToday(this._date);
|
||||
if (today && this._icon.gicon == this._todayIcon)
|
||||
return;
|
||||
if (!today && this._icon.gicon == this._otherIcon)
|
||||
return;
|
||||
|
||||
if (today) {
|
||||
this._icon.gicon = this._todayIcon;
|
||||
this._label.text = _("No Notifications");
|
||||
} else {
|
||||
this._icon.gicon = this._otherIcon;
|
||||
this._label.text = _("No Events");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -1167,8 +958,8 @@ class CalendarMessageList extends St.Widget {
|
||||
child: this._dndSwitch,
|
||||
label_actor: dndLabel,
|
||||
});
|
||||
this._dndButton.bind_property('checked',
|
||||
this._dndSwitch, 'state',
|
||||
this._dndSwitch.bind_property('state',
|
||||
this._dndButton, 'checked',
|
||||
GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE);
|
||||
hbox.add_child(this._dndButton);
|
||||
|
||||
@ -1203,9 +994,6 @@ class CalendarMessageList extends St.Widget {
|
||||
this._notificationSection = new NotificationSection();
|
||||
this._addSection(this._notificationSection);
|
||||
|
||||
this._eventsSection = new EventsSection();
|
||||
this._addSection(this._eventsSection);
|
||||
|
||||
Main.sessionMode.connect('updated', this._sync.bind(this));
|
||||
}
|
||||
|
||||
@ -1241,13 +1029,4 @@ class CalendarMessageList extends St.Widget {
|
||||
let canClear = sections.some(s => s.canClear && s.visible);
|
||||
this._clearButton.reactive = canClear;
|
||||
}
|
||||
|
||||
setEventSource(eventSource) {
|
||||
this._eventsSection.setEventSource(eventSource);
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
this._sectionList.get_children().forEach(s => s.setDate(date));
|
||||
this._placeholder.setDate(date);
|
||||
}
|
||||
});
|
||||
|
@ -13,17 +13,13 @@ var ComponentManager = class {
|
||||
_sessionUpdated() {
|
||||
let newEnabledComponents = Main.sessionMode.components;
|
||||
|
||||
newEnabledComponents.filter(
|
||||
name => !this._enabledComponents.includes(name)
|
||||
).forEach(name => {
|
||||
this._enableComponent(name);
|
||||
});
|
||||
newEnabledComponents
|
||||
.filter(name => !this._enabledComponents.includes(name))
|
||||
.forEach(name => this._enableComponent(name));
|
||||
|
||||
this._enabledComponents.filter(
|
||||
name => !newEnabledComponents.includes(name)
|
||||
).forEach(name => {
|
||||
this._disableComponent(name);
|
||||
});
|
||||
this._enabledComponents
|
||||
.filter(name => !newEnabledComponents.includes(name))
|
||||
.forEach(name => this._disableComponent(name));
|
||||
|
||||
this._enabledComponents = newEnabledComponents;
|
||||
}
|
||||
|
@ -125,8 +125,7 @@ var ContentTypeDiscoverer = class {
|
||||
_emitCallback(mount, contentTypes = []) {
|
||||
// we're not interested in win32 software content types here
|
||||
contentTypes = contentTypes.filter(
|
||||
type => type != 'x-content/win32-software'
|
||||
);
|
||||
type => type !== 'x-content/win32-software');
|
||||
|
||||
let apps = [];
|
||||
contentTypes.forEach(type => {
|
||||
|
@ -327,12 +327,16 @@ var AuthenticationDialog = GObject.registerClass({
|
||||
}
|
||||
|
||||
let resetDialog = () => {
|
||||
this._sessionRequestTimeoutId = 0;
|
||||
|
||||
if (this.state != ModalDialog.State.OPENED)
|
||||
return;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
|
||||
this._passwordEntry.hide();
|
||||
this._cancelButton.grab_key_focus();
|
||||
this._okButton.reactive = false;
|
||||
|
||||
return GLib.SOURCE_REMOVE;
|
||||
};
|
||||
|
||||
if (delay) {
|
||||
|
@ -292,11 +292,11 @@ class DashActor extends St.Widget {
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
vfunc_allocate(box) {
|
||||
let contentBox = this.get_theme_node().get_content_box(box);
|
||||
let availWidth = contentBox.x2 - contentBox.x1;
|
||||
|
||||
this.set_allocation(box, flags);
|
||||
this.set_allocation(box);
|
||||
|
||||
let [appIcons, showAppsButton] = this.get_children();
|
||||
let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
|
||||
@ -306,11 +306,11 @@ class DashActor extends St.Widget {
|
||||
childBox.y1 = contentBox.y1;
|
||||
childBox.x2 = contentBox.x2;
|
||||
childBox.y2 = contentBox.y2 - showAppsNatHeight;
|
||||
appIcons.allocate(childBox, flags);
|
||||
appIcons.allocate(childBox);
|
||||
|
||||
childBox.y1 = contentBox.y2 - showAppsNatHeight;
|
||||
childBox.y2 = contentBox.y2;
|
||||
showAppsButton.allocate(childBox, flags);
|
||||
showAppsButton.allocate(childBox);
|
||||
}
|
||||
|
||||
vfunc_get_preferred_height(forWidth) {
|
||||
@ -815,7 +815,12 @@ var Dash = GObject.registerClass({
|
||||
else
|
||||
pos = 0; // always insert at the top when dash is empty
|
||||
|
||||
if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
|
||||
// Put the placeholder after the last favorite if we are not
|
||||
// in the favorites zone
|
||||
if (pos > numFavorites)
|
||||
pos = numFavorites;
|
||||
|
||||
if (pos !== this._dragPlaceholderPos && this._animatingPlaceholdersCount === 0) {
|
||||
this._dragPlaceholderPos = pos;
|
||||
|
||||
// Don't allow positioning before or after self
|
||||
@ -843,11 +848,6 @@ var Dash = GObject.registerClass({
|
||||
this._dragPlaceholder.show(fadeIn);
|
||||
}
|
||||
|
||||
// Remove the drag placeholder if we are not in the
|
||||
// "favorites zone"
|
||||
if (pos > numFavorites)
|
||||
this._clearDragPlaceholder();
|
||||
|
||||
if (!this._dragPlaceholder)
|
||||
return DND.DragMotionResult.NO_DROP;
|
||||
|
||||
|
@ -13,7 +13,11 @@ const System = imports.system;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
const NC_ = (context, str) => '%s\u0004%s'.format(context, str);
|
||||
const T_ = Shell.util_translate_time_string;
|
||||
|
||||
const MAX_FORECASTS = 5;
|
||||
const ELLIPSIS_CHAR = '\u2026';
|
||||
|
||||
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
|
||||
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
|
||||
@ -84,6 +88,188 @@ class TodayButton extends St.Button {
|
||||
}
|
||||
});
|
||||
|
||||
var EventsSection = GObject.registerClass(
|
||||
class EventsSection extends St.Button {
|
||||
_init() {
|
||||
super._init({
|
||||
style_class: 'events-button',
|
||||
can_focus: true,
|
||||
x_expand: true,
|
||||
child: new St.BoxLayout({
|
||||
style_class: 'events-box',
|
||||
vertical: true,
|
||||
x_expand: true,
|
||||
}),
|
||||
});
|
||||
|
||||
this._startDate = null;
|
||||
this._endDate = null;
|
||||
|
||||
this._eventSource = null;
|
||||
this._calendarApp = null;
|
||||
|
||||
this._title = new St.Label({
|
||||
style_class: 'events-title',
|
||||
});
|
||||
this.child.add_child(this._title);
|
||||
|
||||
this._eventsList = new St.BoxLayout({
|
||||
style_class: 'events-list',
|
||||
vertical: true,
|
||||
x_expand: true,
|
||||
});
|
||||
this.child.add_child(this._eventsList);
|
||||
|
||||
this._appSys = Shell.AppSystem.get_default();
|
||||
this._appSys.connect('installed-changed',
|
||||
this._appInstalledChanged.bind(this));
|
||||
this._appInstalledChanged();
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
const day = [date.getFullYear(), date.getMonth(), date.getDate()];
|
||||
this._startDate = new Date(...day);
|
||||
this._endDate = new Date(...day, 23, 59, 59, 999);
|
||||
|
||||
this._updateTitle();
|
||||
this._reloadEvents();
|
||||
}
|
||||
|
||||
setEventSource(eventSource) {
|
||||
if (!(eventSource instanceof Calendar.EventSourceBase))
|
||||
throw new Error('Event source is not valid type');
|
||||
|
||||
this._eventSource = eventSource;
|
||||
this._eventSource.connect('changed', this._reloadEvents.bind(this));
|
||||
this._eventSource.connect('notify::has-calendars',
|
||||
this._sync.bind(this));
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_updateTitle() {
|
||||
/* Translators: Shown on calendar heading when selected day occurs on current year */
|
||||
const sameYearFormat = T_(NC_('calendar heading', '%B %-d'));
|
||||
|
||||
/* Translators: Shown on calendar heading when selected day occurs on different year */
|
||||
const otherYearFormat = T_(NC_('calendar heading', '%B %-d %Y'));
|
||||
|
||||
const timeSpanDay = GLib.TIME_SPAN_DAY / 1000;
|
||||
const now = new Date();
|
||||
|
||||
if (this._startDate <= now && now <= this._endDate)
|
||||
this._title.text = _('Today');
|
||||
else if (this._endDate < now && now - this._endDate < timeSpanDay)
|
||||
this._title.text = _('Yesterday');
|
||||
else if (this._startDate > now && this._startDate - now < timeSpanDay)
|
||||
this._title.text = _('Tomorrow');
|
||||
else if (this._startDate.getFullYear() === now.getFullYear())
|
||||
this._title.text = this._startDate.toLocaleFormat(sameYearFormat);
|
||||
else
|
||||
this._title.text = this._startDate.toLocaleFormat(otherYearFormat);
|
||||
}
|
||||
|
||||
_formatEventTime(event) {
|
||||
const allDay = event.allDay ||
|
||||
(event.date <= this._startDate && event.end >= this._endDate);
|
||||
|
||||
let title;
|
||||
if (allDay) {
|
||||
/* Translators: Shown in calendar event list for all day events
|
||||
* Keep it short, best if you can use less then 10 characters
|
||||
*/
|
||||
title = C_('event list time', 'All Day');
|
||||
} else {
|
||||
let date = event.date >= this._startDate ? event.date : event.end;
|
||||
title = Util.formatTime(date, { timeOnly: true });
|
||||
}
|
||||
|
||||
const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
|
||||
if (event.date < this._startDate && !event.allDay) {
|
||||
if (rtl)
|
||||
title = '%s%s'.format(title, ELLIPSIS_CHAR);
|
||||
else
|
||||
title = '%s%s'.format(ELLIPSIS_CHAR, title);
|
||||
}
|
||||
if (event.end > this._endDate && !event.allDay) {
|
||||
if (rtl)
|
||||
title = '%s%s'.format(ELLIPSIS_CHAR, title);
|
||||
else
|
||||
title = '%s%s'.format(title, ELLIPSIS_CHAR);
|
||||
}
|
||||
return title;
|
||||
}
|
||||
|
||||
_reloadEvents() {
|
||||
if (this._eventSource.isLoading || this._reloading)
|
||||
return;
|
||||
|
||||
this._reloading = true;
|
||||
|
||||
[...this._eventsList].forEach(c => c.destroy());
|
||||
|
||||
const events =
|
||||
this._eventSource.getEvents(this._startDate, this._endDate);
|
||||
|
||||
for (let event of events) {
|
||||
const box = new St.BoxLayout({
|
||||
style_class: 'event-box',
|
||||
vertical: true,
|
||||
});
|
||||
box.add(new St.Label({
|
||||
text: event.summary,
|
||||
style_class: 'event-summary',
|
||||
}));
|
||||
box.add(new St.Label({
|
||||
text: this._formatEventTime(event),
|
||||
style_class: 'event-time',
|
||||
}));
|
||||
this._eventsList.add_child(box);
|
||||
}
|
||||
|
||||
if (this._eventsList.get_n_children() === 0) {
|
||||
const placeholder = new St.Label({
|
||||
text: _('No Events'),
|
||||
style_class: 'event-placeholder',
|
||||
});
|
||||
this._eventsList.add_child(placeholder);
|
||||
}
|
||||
|
||||
this._reloading = false;
|
||||
this._sync();
|
||||
}
|
||||
|
||||
vfunc_clicked() {
|
||||
Main.overview.hide();
|
||||
Main.panel.closeCalendar();
|
||||
|
||||
let appInfo = this._calendarApp;
|
||||
if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
|
||||
const app = this._appSys.lookup_app('evolution-calendar.desktop');
|
||||
if (app)
|
||||
appInfo = app.app_info;
|
||||
}
|
||||
appInfo.launch([], global.create_app_launch_context(0, -1));
|
||||
}
|
||||
|
||||
_appInstalledChanged() {
|
||||
const apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
|
||||
if (apps && (apps.length > 0)) {
|
||||
const app = Gio.AppInfo.get_default_for_type('text/calendar', false);
|
||||
const defaultInRecommended = apps.some(a => a.equal(app));
|
||||
this._calendarApp = defaultInRecommended ? app : apps[0];
|
||||
} else {
|
||||
this._calendarApp = null;
|
||||
}
|
||||
|
||||
return this._sync();
|
||||
}
|
||||
|
||||
_sync() {
|
||||
this.visible = this._eventSource && this._eventSource.hasCalendars;
|
||||
this.reactive = this._calendarApp !== null;
|
||||
}
|
||||
});
|
||||
|
||||
var WorldClocksSection = GObject.registerClass(
|
||||
class WorldClocksSection extends St.Button {
|
||||
_init() {
|
||||
@ -94,6 +280,7 @@ class WorldClocksSection extends St.Button {
|
||||
});
|
||||
this._clock = new GnomeDesktop.WallClock();
|
||||
this._clockNotifyId = 0;
|
||||
this._tzNotifyId = 0;
|
||||
|
||||
this._locations = [];
|
||||
|
||||
@ -166,8 +353,6 @@ class WorldClocksSection extends St.Button {
|
||||
layout.attach(header, 0, 0, 2, 1);
|
||||
this.label_actor = header;
|
||||
|
||||
let localOffset = GLib.DateTime.new_now_local().get_utc_offset();
|
||||
|
||||
for (let i = 0; i < this._locations.length; i++) {
|
||||
let l = this._locations[i].location;
|
||||
|
||||
@ -180,21 +365,8 @@ class WorldClocksSection extends St.Button {
|
||||
|
||||
let time = new St.Label({ style_class: 'world-clocks-time' });
|
||||
|
||||
const utcOffset = this._getTimeAtLocation(l).get_utc_offset();
|
||||
const offsetCurrentTz = utcOffset - localOffset;
|
||||
const offsetHours = Math.abs(offsetCurrentTz) / GLib.TIME_SPAN_HOUR;
|
||||
const offsetMinutes =
|
||||
(Math.abs(offsetCurrentTz) % GLib.TIME_SPAN_HOUR) /
|
||||
GLib.TIME_SPAN_MINUTE;
|
||||
|
||||
const prefix = offsetCurrentTz >= 0 ? '+' : '-';
|
||||
const text = offsetMinutes === 0
|
||||
? '%s%d'.format(prefix, offsetHours)
|
||||
: '%s%d\u2236%d'.format(prefix, offsetHours, offsetMinutes);
|
||||
|
||||
const tz = new St.Label({
|
||||
style_class: 'world-clocks-timezone',
|
||||
text,
|
||||
x_align: Clutter.ActorAlign.END,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
});
|
||||
@ -212,32 +384,65 @@ class WorldClocksSection extends St.Button {
|
||||
layout.attach(tz, 2, i + 1, 1, 1);
|
||||
}
|
||||
|
||||
this._locations[i].actor = time;
|
||||
this._locations[i].timeLabel = time;
|
||||
this._locations[i].tzLabel = tz;
|
||||
}
|
||||
|
||||
if (this._grid.get_n_children() > 1) {
|
||||
if (!this._clockNotifyId) {
|
||||
this._clockNotifyId =
|
||||
this._clock.connect('notify::clock', this._updateLabels.bind(this));
|
||||
this._clock.connect('notify::clock', this._updateTimeLabels.bind(this));
|
||||
}
|
||||
this._updateLabels();
|
||||
if (!this._tzNotifyId) {
|
||||
this._tzNotifyId =
|
||||
this._clock.connect('notify::timezone', this._updateTimezoneLabels.bind(this));
|
||||
}
|
||||
this._updateTimeLabels();
|
||||
this._updateTimezoneLabels();
|
||||
} else {
|
||||
if (this._clockNotifyId)
|
||||
this._clock.disconnect(this._clockNotifyId);
|
||||
this._clockNotifyId = 0;
|
||||
|
||||
if (this._tzNotifyId)
|
||||
this._clock.disconnect(this._tzNotifyId);
|
||||
this._tzNotifyId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_getTimezoneOffsetAtLocation(location) {
|
||||
const localOffset = GLib.DateTime.new_now_local().get_utc_offset();
|
||||
const utcOffset = this._getTimeAtLocation(location).get_utc_offset();
|
||||
const offsetCurrentTz = utcOffset - localOffset;
|
||||
const offsetHours = Math.abs(offsetCurrentTz) / GLib.TIME_SPAN_HOUR;
|
||||
const offsetMinutes =
|
||||
(Math.abs(offsetCurrentTz) % GLib.TIME_SPAN_HOUR) /
|
||||
GLib.TIME_SPAN_MINUTE;
|
||||
|
||||
const prefix = offsetCurrentTz >= 0 ? '+' : '-';
|
||||
const text = offsetMinutes === 0
|
||||
? '%s%d'.format(prefix, offsetHours)
|
||||
: '%s%d\u2236%d'.format(prefix, offsetHours, offsetMinutes);
|
||||
return text;
|
||||
}
|
||||
|
||||
_getTimeAtLocation(location) {
|
||||
let tz = GLib.TimeZone.new(location.get_timezone().get_tzid());
|
||||
return GLib.DateTime.new_now(tz);
|
||||
}
|
||||
|
||||
_updateLabels() {
|
||||
_updateTimeLabels() {
|
||||
for (let i = 0; i < this._locations.length; i++) {
|
||||
let l = this._locations[i];
|
||||
let now = this._getTimeAtLocation(l.location);
|
||||
l.actor.text = Util.formatTime(now, { timeOnly: true });
|
||||
l.timeLabel.text = Util.formatTime(now, { timeOnly: true });
|
||||
}
|
||||
}
|
||||
|
||||
_updateTimezoneLabels() {
|
||||
for (let i = 0; i < this._locations.length; i++) {
|
||||
let l = this._locations[i];
|
||||
l.tzLabel.text = this._getTimezoneOffsetAtLocation(l.location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -281,13 +486,13 @@ class WeatherSection extends St.Button {
|
||||
this.child = box;
|
||||
|
||||
let titleBox = new St.BoxLayout({ style_class: 'weather-header-box' });
|
||||
titleBox.add_child(new St.Label({
|
||||
this._titleLabel = new St.Label({
|
||||
style_class: 'weather-header',
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
x_expand: true,
|
||||
y_align: Clutter.ActorAlign.END,
|
||||
text: _('Weather'),
|
||||
}));
|
||||
});
|
||||
titleBox.add_child(this._titleLabel);
|
||||
box.add_child(titleBox);
|
||||
|
||||
this._titleLocation = new St.Label({
|
||||
@ -414,10 +619,8 @@ class WeatherSection extends St.Button {
|
||||
_updateForecasts() {
|
||||
this._forecastGrid.destroy_all_children();
|
||||
|
||||
if (!this._weatherClient.hasLocation) {
|
||||
this._setStatusLabel(_("Select a location…"));
|
||||
if (!this._weatherClient.hasLocation)
|
||||
return;
|
||||
}
|
||||
|
||||
const { info } = this._weatherClient;
|
||||
this._titleLocation.text = this._findBestLocationName(info.location);
|
||||
@ -444,6 +647,12 @@ class WeatherSection extends St.Button {
|
||||
if (!this.visible)
|
||||
return;
|
||||
|
||||
if (this._weatherClient.hasLocation)
|
||||
this._titleLabel.text = _('Weather');
|
||||
else
|
||||
this._titleLabel.text = _('Select weather location…');
|
||||
|
||||
this._forecastGrid.visible = this._weatherClient.hasLocation;
|
||||
this._titleLocation.visible = this._weatherClient.hasLocation;
|
||||
|
||||
this._updateForecasts();
|
||||
@ -462,7 +671,6 @@ class MessagesIndicator extends St.Icon {
|
||||
|
||||
this._sources = [];
|
||||
this._count = 0;
|
||||
this._doNotDisturb = false;
|
||||
|
||||
this._settings = new Gio.Settings({
|
||||
schema_id: 'org.gnome.desktop.notifications',
|
||||
@ -543,8 +751,8 @@ class FreezableBinLayout extends Clutter.BinLayout {
|
||||
return this._savedHeight;
|
||||
}
|
||||
|
||||
vfunc_allocate(container, allocation, flags) {
|
||||
super.vfunc_allocate(container, allocation, flags);
|
||||
vfunc_allocate(container, allocation) {
|
||||
super.vfunc_allocate(container, allocation);
|
||||
|
||||
let [width, height] = allocation.get_size();
|
||||
this._savedWidth = [width, width];
|
||||
@ -610,7 +818,7 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
|
||||
let date = _gDateTimeToDate(datetime);
|
||||
layout.frozen = !_isToday(date);
|
||||
this._messageList.setDate(date);
|
||||
this._eventsItem.setDate(date);
|
||||
});
|
||||
|
||||
this.menu.connect('open-state-changed', (menu, isOpen) => {
|
||||
@ -619,7 +827,7 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
let now = new Date();
|
||||
this._calendar.setDate(now);
|
||||
this._date.setDate(now);
|
||||
this._messageList.setDate(now);
|
||||
this._eventsItem.setDate(now);
|
||||
}
|
||||
});
|
||||
|
||||
@ -650,6 +858,9 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
style_class: 'datemenu-displays-box' });
|
||||
this._displaysSection.add_actor(displaysBox);
|
||||
|
||||
this._eventsItem = new EventsSection();
|
||||
displaysBox.add_child(this._eventsItem);
|
||||
|
||||
this._clocksItem = new WorldClocksSection();
|
||||
displaysBox.add_child(this._clocksItem);
|
||||
|
||||
@ -675,7 +886,7 @@ class DateMenuButton extends PanelMenu.Button {
|
||||
this._eventSource.destroy();
|
||||
|
||||
this._calendar.setEventSource(eventSource);
|
||||
this._messageList.setEventSource(eventSource);
|
||||
this._eventsItem.setEventSource(eventSource);
|
||||
|
||||
this._eventSource = eventSource;
|
||||
}
|
||||
|
44
js/ui/dnd.js
44
js/ui/dnd.js
@ -375,19 +375,30 @@ var _Draggable = class _Draggable {
|
||||
|
||||
this._dragActorSource = undefined;
|
||||
this._dragOrigParent = this.actor.get_parent();
|
||||
this._dragOrigX = this._dragActor.x;
|
||||
this._dragOrigY = this._dragActor.y;
|
||||
this._dragActorHadFixedPos = this._dragActor.fixed_position_set;
|
||||
this._dragOrigX = this._dragActor.allocation.x1;
|
||||
this._dragOrigY = this._dragActor.allocation.y1;
|
||||
this._dragOrigWidth = this._dragActor.allocation.get_width();
|
||||
this._dragOrigHeight = this._dragActor.allocation.get_height();
|
||||
this._dragOrigScale = this._dragActor.scale_x;
|
||||
|
||||
// When the actor gets reparented to the uiGroup, it will be
|
||||
// allocated its preferred size, so use that size instead of the
|
||||
// current allocation size.
|
||||
const [, newAllocatedWidth] = this._dragActor.get_preferred_width(-1);
|
||||
const [, newAllocatedHeight] = this._dragActor.get_preferred_height(-1);
|
||||
|
||||
const transformedAllocation =
|
||||
Shell.util_get_transformed_allocation(this._dragActor);
|
||||
|
||||
// Set the actor's scale such that it will keep the same
|
||||
// transformed size when it's reparented to the uiGroup
|
||||
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
|
||||
this._dragActor.set_scale(scaledWidth / this.actor.width,
|
||||
scaledHeight / this.actor.height);
|
||||
this._dragActor.set_scale(
|
||||
transformedAllocation.get_width() / newAllocatedWidth,
|
||||
transformedAllocation.get_height() / newAllocatedHeight);
|
||||
|
||||
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
|
||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||
this._dragOffsetX = transformedAllocation.x1 - this._dragStartX;
|
||||
this._dragOffsetY = transformedAllocation.y1 - this._dragStartY;
|
||||
|
||||
this._dragOrigParent.remove_actor(this._dragActor);
|
||||
Main.uiGroup.add_child(this._dragActor);
|
||||
@ -417,6 +428,10 @@ var _Draggable = class _Draggable {
|
||||
this._dragOffsetX -= transX;
|
||||
this._dragOffsetY -= transY;
|
||||
|
||||
this._dragActor.set_position(
|
||||
this._dragX + this._dragOffsetX,
|
||||
this._dragY + this._dragOffsetY);
|
||||
|
||||
if (this._dragActorMaxSize != undefined) {
|
||||
let [scaledWidth, scaledHeight] = this._dragActor.get_transformed_size();
|
||||
let currentSize = Math.max(scaledWidth, scaledHeight);
|
||||
@ -635,9 +650,15 @@ var _Draggable = class _Draggable {
|
||||
if (parentWidth != 0)
|
||||
parentScale = parentScaledWidth / parentWidth;
|
||||
|
||||
// Also adjust for the difference in the original actor width
|
||||
// and the width it is now (children of uiGroup always get
|
||||
// allocated their preferred size)
|
||||
const childScaleX =
|
||||
this._dragOrigWidth / this._dragActor.allocation.get_width();
|
||||
|
||||
x = parentX + parentScale * this._dragOrigX;
|
||||
y = parentY + parentScale * this._dragOrigY;
|
||||
scale = this._dragOrigScale * parentScale;
|
||||
scale = this._dragOrigScale * parentScale * childScaleX;
|
||||
} else {
|
||||
// Snap back actor to its original stage position
|
||||
x = this._snapBackX;
|
||||
@ -718,7 +739,10 @@ var _Draggable = class _Draggable {
|
||||
Main.uiGroup.remove_child(this._dragActor);
|
||||
this._dragOrigParent.add_actor(this._dragActor);
|
||||
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
|
||||
dragActor.set_position(this._dragOrigX, this._dragOrigY);
|
||||
if (this._dragActorHadFixedPos)
|
||||
dragActor.set_position(this._dragOrigX, this._dragOrigY);
|
||||
else
|
||||
dragActor.fixed_position_set = false;
|
||||
} else {
|
||||
dragActor.destroy();
|
||||
}
|
||||
|
@ -245,16 +245,15 @@ function _loggingFunc(...args) {
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Add some bindings to the global JS namespace; (gjs keeps the web
|
||||
// browser convention of having that namespace be called 'window'.)
|
||||
window.global = Shell.Global.get();
|
||||
// Add some bindings to the global JS namespace
|
||||
globalThis.global = Shell.Global.get();
|
||||
|
||||
window.log = _loggingFunc;
|
||||
globalThis.log = _loggingFunc;
|
||||
|
||||
window._ = Gettext.gettext;
|
||||
window.C_ = Gettext.pgettext;
|
||||
window.ngettext = Gettext.ngettext;
|
||||
window.N_ = s => s;
|
||||
globalThis._ = Gettext.gettext;
|
||||
globalThis.C_ = Gettext.pgettext;
|
||||
globalThis.ngettext = Gettext.ngettext;
|
||||
globalThis.N_ = s => s;
|
||||
|
||||
GObject.gtypeNameBasedOnJSPath = true;
|
||||
|
||||
@ -286,6 +285,11 @@ function init() {
|
||||
_easeActorProperty(this, 'value', target, params);
|
||||
};
|
||||
|
||||
Clutter.Actor.prototype[Symbol.iterator] = function* () {
|
||||
for (let c = this.get_first_child(); c; c = c.get_next_sibling())
|
||||
yield c;
|
||||
};
|
||||
|
||||
Clutter.Actor.prototype.toString = function () {
|
||||
return St.describe_actor(this);
|
||||
};
|
||||
@ -356,10 +360,12 @@ function init() {
|
||||
|
||||
// OK, now things are initialized enough that we can import shell JS
|
||||
const Format = imports.format;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
Tweener.init();
|
||||
String.prototype.format = Format.format;
|
||||
|
||||
Math.clamp = function (x, lower, upper) {
|
||||
return Math.min(Math.max(x, lower), upper);
|
||||
};
|
||||
}
|
||||
|
||||
// adjustAnimationTime:
|
||||
|
@ -238,7 +238,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
|
||||
});
|
||||
|
||||
function init() {
|
||||
_httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });
|
||||
_httpSession = new Soup.Session({ ssl_use_system_ca_file: true });
|
||||
|
||||
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
|
||||
// _httpSession.add_feature(new Soup.ProxyResolverDefault());
|
||||
|
@ -26,6 +26,7 @@ var ExtensionManager = class {
|
||||
this._updateNotified = false;
|
||||
|
||||
this._extensions = new Map();
|
||||
this._unloadedExtensions = new Map();
|
||||
this._enabledExtensions = [];
|
||||
this._extensionOrder = [];
|
||||
|
||||
@ -102,18 +103,18 @@ var ExtensionManager = class {
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.stylesheet) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
}
|
||||
|
||||
try {
|
||||
extension.stateObj.disable();
|
||||
} catch (e) {
|
||||
this.logExtensionError(uuid, e);
|
||||
}
|
||||
|
||||
if (extension.stylesheet) {
|
||||
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
|
||||
theme.unload_stylesheet(extension.stylesheet);
|
||||
delete extension.stylesheet;
|
||||
}
|
||||
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let otherUuid = order[i];
|
||||
try {
|
||||
@ -259,7 +260,8 @@ var ExtensionManager = class {
|
||||
if (!extension)
|
||||
return;
|
||||
|
||||
let message = error.toString();
|
||||
const message = error instanceof Error
|
||||
? error.message : error.toString();
|
||||
|
||||
extension.error = message;
|
||||
extension.state = ExtensionState.ERROR;
|
||||
@ -268,6 +270,7 @@ var ExtensionManager = class {
|
||||
extension.errors.push(message);
|
||||
|
||||
logError(error, 'Extension %s'.format(uuid));
|
||||
this._updateCanChange(extension);
|
||||
this.emit('extension-state-changed', extension);
|
||||
}
|
||||
|
||||
@ -317,6 +320,14 @@ var ExtensionManager = class {
|
||||
return extension;
|
||||
}
|
||||
|
||||
_canLoad(extension) {
|
||||
if (!this._unloadedExtensions.has(extension.uuid))
|
||||
return true;
|
||||
|
||||
const version = this._unloadedExtensions.get(extension.uuid);
|
||||
return extension.metadata.version === version;
|
||||
}
|
||||
|
||||
loadExtension(extension) {
|
||||
// Default to error, we set success as the last step
|
||||
extension.state = ExtensionState.ERROR;
|
||||
@ -325,6 +336,9 @@ var ExtensionManager = class {
|
||||
|
||||
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
|
||||
extension.state = ExtensionState.OUT_OF_DATE;
|
||||
} else if (!this._canLoad(extension)) {
|
||||
this.logExtensionError(extension.uuid, new Error(
|
||||
'A different version was loaded previously. You need to log out for changes to take effect.'));
|
||||
} else {
|
||||
let enabled = this._enabledExtensions.includes(extension.uuid);
|
||||
if (enabled) {
|
||||
@ -335,6 +349,8 @@ var ExtensionManager = class {
|
||||
} else {
|
||||
extension.state = ExtensionState.INITIALIZED;
|
||||
}
|
||||
|
||||
this._unloadedExtensions.delete(extension.uuid);
|
||||
}
|
||||
|
||||
this._updateCanChange(extension);
|
||||
@ -342,15 +358,22 @@ var ExtensionManager = class {
|
||||
}
|
||||
|
||||
unloadExtension(extension) {
|
||||
const { uuid, type } = extension;
|
||||
|
||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||
// but it will be removed on next reboot, and hopefully nothing
|
||||
// broke too much.
|
||||
this._callExtensionDisable(extension.uuid);
|
||||
this._callExtensionDisable(uuid);
|
||||
|
||||
extension.state = ExtensionState.UNINSTALLED;
|
||||
this.emit('extension-state-changed', extension);
|
||||
|
||||
this._extensions.delete(extension.uuid);
|
||||
// If we did install an importer, it is now cached and it's
|
||||
// impossible to load a different version
|
||||
if (type === ExtensionType.PER_USER && extension.imports)
|
||||
this._unloadedExtensions.set(uuid, extension.metadata.version);
|
||||
|
||||
this._extensions.delete(uuid);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -463,19 +486,15 @@ var ExtensionManager = class {
|
||||
|
||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||
// new setting, but not in the old one.
|
||||
newEnabledExtensions.filter(
|
||||
uuid => !this._enabledExtensions.includes(uuid)
|
||||
).forEach(uuid => {
|
||||
this._callExtensionEnable(uuid);
|
||||
});
|
||||
newEnabledExtensions
|
||||
.filter(uuid => !this._enabledExtensions.includes(uuid))
|
||||
.forEach(uuid => this._callExtensionEnable(uuid));
|
||||
|
||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||
// old setting, but not in the new one.
|
||||
this._extensionOrder.filter(
|
||||
uuid => !newEnabledExtensions.includes(uuid)
|
||||
).reverse().forEach(uuid => {
|
||||
this._callExtensionDisable(uuid);
|
||||
});
|
||||
this._extensionOrder
|
||||
.filter(uuid => !newEnabledExtensions.includes(uuid))
|
||||
.reverse().forEach(uuid => this._callExtensionDisable(uuid));
|
||||
|
||||
this._enabledExtensions = newEnabledExtensions;
|
||||
}
|
||||
|
1795
js/ui/iconGrid.js
1795
js/ui/iconGrid.js
File diff suppressed because it is too large
Load Diff
@ -61,7 +61,7 @@ class AspectContainer extends St.Widget {
|
||||
this.queue_relayout();
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
vfunc_allocate(box) {
|
||||
if (box.get_width() > 0 && box.get_height() > 0) {
|
||||
let sizeRatio = box.get_width() / box.get_height();
|
||||
|
||||
@ -79,7 +79,7 @@ class AspectContainer extends St.Widget {
|
||||
}
|
||||
}
|
||||
|
||||
super.vfunc_allocate(box, flags);
|
||||
super.vfunc_allocate(box);
|
||||
}
|
||||
});
|
||||
|
||||
@ -722,7 +722,7 @@ var EmojiPager = GObject.registerClass({
|
||||
|
||||
_onPan(action) {
|
||||
let [dist_, dx, dy_] = action.get_motion_delta(0);
|
||||
this.delta = this.delta + dx;
|
||||
this.delta += dx;
|
||||
|
||||
if (this._currentKey != null) {
|
||||
this._currentKey.cancel();
|
||||
@ -935,8 +935,7 @@ var EmojiSelection = GObject.registerClass({
|
||||
this.add_child(this._emojiPager);
|
||||
|
||||
this._pageIndicator = new PageIndicators.PageIndicators(
|
||||
Clutter.Orientation.HORIZONTAL
|
||||
);
|
||||
Clutter.Orientation.HORIZONTAL);
|
||||
this.add_child(this._pageIndicator);
|
||||
this._pageIndicator.setReactive(false);
|
||||
|
||||
@ -1119,7 +1118,7 @@ var KeyboardManager = class KeyBoardManager {
|
||||
this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this));
|
||||
|
||||
this._lastDevice = null;
|
||||
Meta.get_backend().connect('last-device-changed', (backend, device) => {
|
||||
global.backend.connect('last-device-changed', (backend, device) => {
|
||||
if (device.device_type === Clutter.InputDeviceType.KEYBOARD_DEVICE)
|
||||
return;
|
||||
|
||||
@ -1257,6 +1256,10 @@ class Keyboard extends St.BoxLayout {
|
||||
return this._keyboardVisible && super.visible;
|
||||
}
|
||||
|
||||
set visible(visible) {
|
||||
super.visible = visible;
|
||||
}
|
||||
|
||||
_onFocusPositionChanged(focusTracker) {
|
||||
let rect = focusTracker.getCurrentRect();
|
||||
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
|
||||
|
@ -246,7 +246,7 @@ var LayoutManager = GObject.registerClass({
|
||||
vertical: true });
|
||||
this.addChrome(this.panelBox, { affectsStruts: true,
|
||||
trackFullscreen: true });
|
||||
this.panelBox.connect('allocation-changed',
|
||||
this.panelBox.connect('notify::allocation',
|
||||
this._panelBoxChanged.bind(this));
|
||||
|
||||
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
|
||||
|
@ -27,13 +27,11 @@ var RadialShaderEffect = GObject.registerClass({
|
||||
'brightness': GObject.ParamSpec.float(
|
||||
'brightness', 'brightness', 'brightness',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 1, 1
|
||||
),
|
||||
0, 1, 1),
|
||||
'sharpness': GObject.ParamSpec.float(
|
||||
'sharpness', 'sharpness', 'sharpness',
|
||||
GObject.ParamFlags.READWRITE,
|
||||
0, 1, 0
|
||||
),
|
||||
0, 1, 0),
|
||||
},
|
||||
}, class RadialShaderEffect extends Shell.GLSLEffect {
|
||||
_init(params) {
|
||||
|
@ -37,10 +37,9 @@ const LG_ANIMATION_TIME = 500;
|
||||
|
||||
function _getAutoCompleteGlobalKeywords() {
|
||||
const keywords = ['true', 'false', 'null', 'new'];
|
||||
// Don't add the private properties of window (i.e., ones starting with '_')
|
||||
const windowProperties = Object.getOwnPropertyNames(window).filter(
|
||||
a => a.charAt(0) != '_'
|
||||
);
|
||||
// Don't add the private properties of globalThis (i.e., ones starting with '_')
|
||||
const windowProperties = Object.getOwnPropertyNames(globalThis).filter(
|
||||
a => a.charAt(0) !== '_');
|
||||
const headerProperties = JsParse.getDeclaredConstants(commandHeader);
|
||||
|
||||
return keywords.concat(windowProperties).concat(headerProperties);
|
||||
@ -555,8 +554,8 @@ var Inspector = GObject.registerClass({
|
||||
this._lookingGlass = lookingGlass;
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
if (!this._eventHandler)
|
||||
return;
|
||||
@ -571,7 +570,7 @@ var Inspector = GObject.registerClass({
|
||||
childBox.x2 = childBox.x1 + natWidth;
|
||||
childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + natHeight;
|
||||
this._eventHandler.allocate(childBox, flags);
|
||||
this._eventHandler.allocate(childBox);
|
||||
}
|
||||
|
||||
_close() {
|
||||
@ -803,6 +802,191 @@ var Extensions = GObject.registerClass({
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
var ActorLink = GObject.registerClass({
|
||||
Signals: {
|
||||
'inspect-actor': {},
|
||||
},
|
||||
}, class ActorLink extends St.Button {
|
||||
_init(actor) {
|
||||
this._arrow = new St.Icon({
|
||||
icon_name: 'pan-end-symbolic',
|
||||
icon_size: 8,
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
|
||||
});
|
||||
|
||||
const label = new St.Label({
|
||||
text: actor.toString(),
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
});
|
||||
|
||||
const inspectButton = new St.Button({
|
||||
child: new St.Icon({
|
||||
icon_name: 'insert-object-symbolic',
|
||||
icon_size: 12,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
}),
|
||||
reactive: true,
|
||||
x_expand: true,
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
});
|
||||
inspectButton.connect('clicked', () => this.emit('inspect-actor'));
|
||||
|
||||
const box = new St.BoxLayout();
|
||||
box.add_child(this._arrow);
|
||||
box.add_child(label);
|
||||
box.add_child(inspectButton);
|
||||
|
||||
super._init({
|
||||
reactive: true,
|
||||
track_hover: true,
|
||||
toggle_mode: true,
|
||||
style_class: 'actor-link',
|
||||
child: box,
|
||||
x_align: Clutter.ActorAlign.START,
|
||||
});
|
||||
|
||||
this._actor = actor;
|
||||
}
|
||||
|
||||
vfunc_clicked() {
|
||||
this._arrow.ease({
|
||||
rotation_angle_z: this.checked ? 90 : 0,
|
||||
duration: 250,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var ActorTreeViewer = GObject.registerClass(
|
||||
class ActorTreeViewer extends St.BoxLayout {
|
||||
_init(lookingGlass) {
|
||||
super._init();
|
||||
|
||||
this._lookingGlass = lookingGlass;
|
||||
this._actorData = new Map();
|
||||
}
|
||||
|
||||
_showActorChildren(actor) {
|
||||
const data = this._actorData.get(actor);
|
||||
if (!data || data.visible)
|
||||
return;
|
||||
|
||||
data.visible = true;
|
||||
data.actorAddedId = actor.connect('actor-added', (container, child) => {
|
||||
this._addActor(data.children, child);
|
||||
});
|
||||
data.actorRemovedId = actor.connect('actor-removed', (container, child) => {
|
||||
this._removeActor(child);
|
||||
});
|
||||
|
||||
for (let child of actor)
|
||||
this._addActor(data.children, child);
|
||||
}
|
||||
|
||||
_hideActorChildren(actor) {
|
||||
const data = this._actorData.get(actor);
|
||||
if (!data || !data.visible)
|
||||
return;
|
||||
|
||||
for (let child of actor)
|
||||
this._removeActor(child);
|
||||
|
||||
data.visible = false;
|
||||
if (data.actorAddedId > 0) {
|
||||
actor.disconnect(data.actorAddedId);
|
||||
data.actorAddedId = 0;
|
||||
}
|
||||
if (data.actorRemovedId > 0) {
|
||||
actor.disconnect(data.actorRemovedId);
|
||||
data.actorRemovedId = 0;
|
||||
}
|
||||
data.children.remove_all_children();
|
||||
}
|
||||
|
||||
_addActor(container, actor) {
|
||||
if (this._actorData.has(actor))
|
||||
return;
|
||||
|
||||
if (actor === this._lookingGlass)
|
||||
return;
|
||||
|
||||
const button = new ActorLink(actor);
|
||||
button.connect('notify::checked', () => {
|
||||
this._lookingGlass.setBorderPaintTarget(actor);
|
||||
if (button.checked)
|
||||
this._showActorChildren(actor);
|
||||
else
|
||||
this._hideActorChildren(actor);
|
||||
});
|
||||
button.connect('inspect-actor', () => {
|
||||
this._lookingGlass.inspectObject(actor, button);
|
||||
});
|
||||
|
||||
const mainContainer = new St.BoxLayout({ vertical: true });
|
||||
const childrenContainer = new St.BoxLayout({
|
||||
vertical: true,
|
||||
style: 'padding: 0 0 0 18px',
|
||||
});
|
||||
|
||||
mainContainer.add_child(button);
|
||||
mainContainer.add_child(childrenContainer);
|
||||
|
||||
this._actorData.set(actor, {
|
||||
button,
|
||||
container: mainContainer,
|
||||
children: childrenContainer,
|
||||
visible: false,
|
||||
actorAddedId: 0,
|
||||
actorRemovedId: 0,
|
||||
actorDestroyedId: actor.connect('destroy', () => this._removeActor(actor)),
|
||||
});
|
||||
|
||||
let belowChild = null;
|
||||
const nextSibling = actor.get_next_sibling();
|
||||
if (nextSibling && this._actorData.has(nextSibling))
|
||||
belowChild = this._actorData.get(nextSibling).container;
|
||||
|
||||
container.insert_child_above(mainContainer, belowChild);
|
||||
}
|
||||
|
||||
_removeActor(actor) {
|
||||
const data = this._actorData.get(actor);
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
for (let child of actor)
|
||||
this._removeActor(child);
|
||||
|
||||
if (data.actorAddedId > 0) {
|
||||
actor.disconnect(data.actorAddedId);
|
||||
data.actorAddedId = 0;
|
||||
}
|
||||
if (data.actorRemovedId > 0) {
|
||||
actor.disconnect(data.actorRemovedId);
|
||||
data.actorRemovedId = 0;
|
||||
}
|
||||
if (data.actorDestroyedId > 0) {
|
||||
actor.disconnect(data.actorDestroyedId);
|
||||
data.actorDestroyedId = 0;
|
||||
}
|
||||
data.container.destroy();
|
||||
this._actorData.delete(actor);
|
||||
}
|
||||
|
||||
vfunc_map() {
|
||||
super.vfunc_map();
|
||||
this._addActor(this, global.stage);
|
||||
}
|
||||
|
||||
vfunc_unmap() {
|
||||
super.vfunc_unmap();
|
||||
this._removeActor(global.stage);
|
||||
}
|
||||
});
|
||||
|
||||
var LookingGlass = GObject.registerClass(
|
||||
class LookingGlass extends St.BoxLayout {
|
||||
_init() {
|
||||
@ -834,9 +1018,9 @@ class LookingGlass extends St.BoxLayout {
|
||||
Main.uiGroup.add_actor(this);
|
||||
Main.uiGroup.set_child_below_sibling(this,
|
||||
Main.layoutManager.panelBox);
|
||||
Main.layoutManager.panelBox.connect('allocation-changed',
|
||||
Main.layoutManager.panelBox.connect('notify::allocation',
|
||||
this._queueResize.bind(this));
|
||||
Main.layoutManager.keyboardBox.connect('allocation-changed',
|
||||
Main.layoutManager.keyboardBox.connect('notify::allocation',
|
||||
this._queueResize.bind(this));
|
||||
|
||||
this._objInspector = new ObjInspector(this);
|
||||
@ -918,6 +1102,9 @@ class LookingGlass extends St.BoxLayout {
|
||||
this._extensions = new Extensions(this);
|
||||
notebook.appendPage('Extensions', this._extensions);
|
||||
|
||||
this._actorTreeViewer = new ActorTreeViewer(this);
|
||||
notebook.appendPage('Actors', this._actorTreeViewer);
|
||||
|
||||
this._entry.clutter_text.connect('activate', (o, _e) => {
|
||||
// Hide any completions we are currently showing
|
||||
this._hideCompletions();
|
||||
|
@ -643,8 +643,7 @@ var Magnifier = class Magnifier {
|
||||
// Applies only to the first zoom region.
|
||||
if (this._zoomRegions.length) {
|
||||
this._zoomRegions[0].setClampScrollingAtEdges(
|
||||
!this._settings.get_boolean(CLAMP_MODE_KEY)
|
||||
);
|
||||
!this._settings.get_boolean(CLAMP_MODE_KEY));
|
||||
}
|
||||
}
|
||||
|
||||
@ -652,8 +651,7 @@ var Magnifier = class Magnifier {
|
||||
// Applies only to the first zoom region.
|
||||
if (this._zoomRegions.length) {
|
||||
this._zoomRegions[0].setMouseTrackingMode(
|
||||
this._settings.get_enum(MOUSE_TRACKING_KEY)
|
||||
);
|
||||
this._settings.get_enum(MOUSE_TRACKING_KEY));
|
||||
}
|
||||
}
|
||||
|
||||
@ -661,8 +659,7 @@ var Magnifier = class Magnifier {
|
||||
// Applies only to the first zoom region.
|
||||
if (this._zoomRegions.length) {
|
||||
this._zoomRegions[0].setFocusTrackingMode(
|
||||
this._settings.get_enum(FOCUS_TRACKING_KEY)
|
||||
);
|
||||
this._settings.get_enum(FOCUS_TRACKING_KEY));
|
||||
}
|
||||
}
|
||||
|
||||
@ -670,8 +667,7 @@ var Magnifier = class Magnifier {
|
||||
// Applies only to the first zoom region.
|
||||
if (this._zoomRegions.length) {
|
||||
this._zoomRegions[0].setCaretTrackingMode(
|
||||
this._settings.get_enum(CARET_TRACKING_KEY)
|
||||
);
|
||||
this._settings.get_enum(CARET_TRACKING_KEY));
|
||||
}
|
||||
}
|
||||
|
||||
@ -679,8 +675,7 @@ var Magnifier = class Magnifier {
|
||||
// Applies only to the first zoom region.
|
||||
if (this._zoomRegions.length) {
|
||||
this._zoomRegions[0].setInvertLightness(
|
||||
this._settings.get_boolean(INVERT_LIGHTNESS_KEY)
|
||||
);
|
||||
this._settings.get_boolean(INVERT_LIGHTNESS_KEY));
|
||||
}
|
||||
}
|
||||
|
||||
@ -688,8 +683,7 @@ var Magnifier = class Magnifier {
|
||||
// Applies only to the first zoom region.
|
||||
if (this._zoomRegions.length) {
|
||||
this._zoomRegions[0].setColorSaturation(
|
||||
this._settings.get_double(COLOR_SATURATION_KEY)
|
||||
);
|
||||
this._settings.get_double(COLOR_SATURATION_KEY));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1941,9 +1935,8 @@ var MagShaderEffects = class MagShaderEffects {
|
||||
// it modifies the brightness and/or contrast.
|
||||
let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
|
||||
this._brightnessContrast.set_enabled(
|
||||
bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE ||
|
||||
cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE
|
||||
);
|
||||
bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE ||
|
||||
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1970,8 +1963,7 @@ var MagShaderEffects = class MagShaderEffects {
|
||||
// a null first argument.
|
||||
let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
|
||||
this._brightnessContrast.set_enabled(
|
||||
cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE ||
|
||||
bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE
|
||||
);
|
||||
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE ||
|
||||
bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE);
|
||||
}
|
||||
};
|
||||
|
@ -46,6 +46,7 @@ const XdndHandler = imports.ui.xdndHandler;
|
||||
const KbdA11yDialog = imports.ui.kbdA11yDialog;
|
||||
const LocatePointer = imports.ui.locatePointer;
|
||||
const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
|
||||
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
||||
|
||||
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
|
||||
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
|
||||
@ -96,6 +97,8 @@ let _oskResource = null;
|
||||
Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish');
|
||||
Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish');
|
||||
|
||||
let _remoteAccessInhibited = false;
|
||||
|
||||
function _sessionUpdated() {
|
||||
if (sessionMode.isPrimary)
|
||||
_loadDefaultStylesheet();
|
||||
@ -120,12 +123,23 @@ function _sessionUpdated() {
|
||||
if (lookingGlass)
|
||||
lookingGlass.close();
|
||||
}
|
||||
|
||||
let remoteAccessController = global.backend.get_remote_access_controller();
|
||||
if (remoteAccessController) {
|
||||
if (sessionMode.allowScreencast && _remoteAccessInhibited) {
|
||||
remoteAccessController.uninhibit_remote_access();
|
||||
_remoteAccessInhibited = false;
|
||||
} else if (!sessionMode.allowScreencast && !_remoteAccessInhibited) {
|
||||
remoteAccessController.inhibit_remote_access();
|
||||
_remoteAccessInhibited = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function start() {
|
||||
// These are here so we don't break compatibility.
|
||||
global.logError = window.log;
|
||||
global.log = window.log;
|
||||
global.logError = globalThis.log;
|
||||
global.log = globalThis.log;
|
||||
|
||||
// Chain up async errors reported from C
|
||||
global.connect('notify-error', (global, msg, detail) => {
|
||||
@ -140,6 +154,10 @@ function start() {
|
||||
sessionMode.connect('updated', _sessionUpdated);
|
||||
|
||||
St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet);
|
||||
|
||||
// Initialize ParentalControlsManager before the UI
|
||||
ParentalControlsManager.getDefault();
|
||||
|
||||
_initializeUI();
|
||||
|
||||
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
|
||||
@ -521,7 +539,9 @@ function pushModal(actor, params) {
|
||||
let prevFocusDestroyId;
|
||||
if (prevFocus != null) {
|
||||
prevFocusDestroyId = prevFocus.connect('destroy', () => {
|
||||
let index = _findModal(actor);
|
||||
const index = modalActorFocusStack.findIndex(
|
||||
record => record.prevFocus === prevFocus);
|
||||
|
||||
if (index >= 0)
|
||||
modalActorFocusStack[index].prevFocus = null;
|
||||
});
|
||||
@ -797,7 +817,7 @@ function showRestartMessage(message) {
|
||||
|
||||
var AnimationsSettings = class {
|
||||
constructor() {
|
||||
let backend = Meta.get_backend();
|
||||
let backend = global.backend;
|
||||
if (!backend.is_rendering_hardware_accelerated()) {
|
||||
St.Settings.get().inhibit_animations();
|
||||
return;
|
||||
|
@ -4,7 +4,6 @@ const { Atk, Clutter, Gio, GLib,
|
||||
const Main = imports.ui.main;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
|
||||
const Calendar = imports.ui.calendar;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
var MESSAGE_ANIMATION_TIME = 100;
|
||||
@ -285,12 +284,12 @@ var LabelExpanderLayout = GObject.registerClass({
|
||||
return [min, nat];
|
||||
}
|
||||
|
||||
vfunc_allocate(container, box, flags) {
|
||||
vfunc_allocate(container, box) {
|
||||
for (let i = 0; i < container.get_n_children(); i++) {
|
||||
let child = container.get_child_at_index(i);
|
||||
|
||||
if (child.visible)
|
||||
child.allocate(box, flags);
|
||||
child.allocate(box);
|
||||
}
|
||||
|
||||
}
|
||||
@ -572,7 +571,6 @@ var MessageListSection = GObject.registerClass({
|
||||
Main.sessionMode.disconnect(id);
|
||||
});
|
||||
|
||||
this._date = new Date();
|
||||
this._empty = true;
|
||||
this._canClear = false;
|
||||
this._sync();
|
||||
@ -598,13 +596,6 @@ var MessageListSection = GObject.registerClass({
|
||||
return true;
|
||||
}
|
||||
|
||||
setDate(date) {
|
||||
if (Calendar.sameDay(date, this._date))
|
||||
return;
|
||||
this._date = date;
|
||||
this._sync();
|
||||
}
|
||||
|
||||
addMessage(message, animate) {
|
||||
this.addMessageAtIndex(message, -1, animate);
|
||||
}
|
||||
|
@ -136,29 +136,22 @@ var FocusGrabber = class FocusGrabber {
|
||||
var NotificationPolicy = GObject.registerClass({
|
||||
Properties: {
|
||||
'enable': GObject.ParamSpec.boolean(
|
||||
'enable', 'enable', 'enable',
|
||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||
true),
|
||||
'enable', 'enable', 'enable', GObject.ParamFlags.READABLE, true),
|
||||
'enable-sound': GObject.ParamSpec.boolean(
|
||||
'enable-sound', 'enable-sound', 'enable-sound',
|
||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||
true),
|
||||
GObject.ParamFlags.READABLE, true),
|
||||
'show-banners': GObject.ParamSpec.boolean(
|
||||
'show-banners', 'show-banners', 'show-banners',
|
||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||
true),
|
||||
GObject.ParamFlags.READABLE, true),
|
||||
'force-expanded': GObject.ParamSpec.boolean(
|
||||
'force-expanded', 'force-expanded', 'force-expanded',
|
||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||
false),
|
||||
GObject.ParamFlags.READABLE, false),
|
||||
'show-in-lock-screen': GObject.ParamSpec.boolean(
|
||||
'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen',
|
||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||
false),
|
||||
GObject.ParamFlags.READABLE, false),
|
||||
'details-in-lock-screen': GObject.ParamSpec.boolean(
|
||||
'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen',
|
||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
||||
false),
|
||||
GObject.ParamFlags.READABLE, false),
|
||||
},
|
||||
}, class NotificationPolicy extends GObject.Object {
|
||||
// Do nothing for the default policy. These methods are only useful for the
|
||||
@ -169,24 +162,28 @@ var NotificationPolicy = GObject.registerClass({
|
||||
this.run_dispose();
|
||||
}
|
||||
|
||||
get enable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
get enableSound() {
|
||||
return this.enable_sound;
|
||||
return true;
|
||||
}
|
||||
|
||||
get showBanners() {
|
||||
return this.show_banners;
|
||||
return true;
|
||||
}
|
||||
|
||||
get forceExpanded() {
|
||||
return this.force_expanded;
|
||||
return false;
|
||||
}
|
||||
|
||||
get showInLockScreen() {
|
||||
return this.show_in_lock_screen;
|
||||
return false;
|
||||
}
|
||||
|
||||
get detailsInLockScreen() {
|
||||
return this.details_in_lock_screen;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -689,8 +686,8 @@ class SourceActorWithLabel extends SourceActor {
|
||||
});
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
super.vfunc_allocate(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
super.vfunc_allocate(box);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
@ -710,7 +707,7 @@ class SourceActorWithLabel extends SourceActor {
|
||||
childBox.y1 = box.y2 - naturalHeight;
|
||||
childBox.y2 = box.y2;
|
||||
|
||||
this._counterBin.allocate(childBox, flags);
|
||||
this._counterBin.allocate(childBox);
|
||||
}
|
||||
|
||||
_updateCount() {
|
||||
@ -1167,8 +1164,7 @@ var MessageTray = GObject.registerClass({
|
||||
this._onNotificationDestroy.bind(this));
|
||||
this._notificationQueue.push(notification);
|
||||
this._notificationQueue.sort(
|
||||
(n1, n2) => n2.urgency - n1.urgency
|
||||
);
|
||||
(n1, n2) => n2.urgency - n1.urgency);
|
||||
this.emit('queue-changed');
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@
|
||||
const { Gio, GObject, Shell, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Calendar = imports.ui.calendar;
|
||||
const Main = imports.ui.main;
|
||||
const MessageList = imports.ui.messageList;
|
||||
|
||||
@ -173,6 +172,11 @@ var MprisPlayer = class MprisPlayer {
|
||||
if (!this._mprisProxy.g_name_owner)
|
||||
this._close();
|
||||
});
|
||||
// It is possible for the bus to disappear before the previous signal
|
||||
// is connected, so we must ensure that the bus still exists at this
|
||||
// point.
|
||||
if (!this._mprisProxy.g_name_owner)
|
||||
this._close();
|
||||
}
|
||||
|
||||
_onPlayerProxyReady() {
|
||||
@ -247,10 +251,6 @@ class MediaSection extends MessageList.MessageListSection {
|
||||
this._onProxyReady.bind(this));
|
||||
}
|
||||
|
||||
_shouldShow() {
|
||||
return !this.empty && Calendar.isToday(this._date);
|
||||
}
|
||||
|
||||
get allowed() {
|
||||
return !Main.sessionMode.isGreeter;
|
||||
}
|
||||
|
@ -10,13 +10,6 @@ const Params = imports.misc.params;
|
||||
|
||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||
|
||||
// Should really be defined in Gio.js
|
||||
const BusIface = loadInterfaceXML('org.freedesktop.DBus');
|
||||
var BusProxy = Gio.DBusProxy.makeProxyWrapper(BusIface);
|
||||
function Bus() {
|
||||
return new BusProxy(Gio.DBus.session, 'org.freedesktop.DBus', '/org/freedesktop/DBus');
|
||||
}
|
||||
|
||||
const FdoNotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
|
||||
|
||||
var NotificationClosedReason = {
|
||||
@ -49,9 +42,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
|
||||
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
||||
|
||||
this._sources = [];
|
||||
this._senderToPid = {};
|
||||
this._notifications = {};
|
||||
this._busProxy = new Bus();
|
||||
|
||||
this._nextNotificationId = 1;
|
||||
|
||||
@ -116,12 +107,9 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
|
||||
//
|
||||
// If no existing source is found, a new source is created as long as
|
||||
// pid is provided.
|
||||
//
|
||||
// Either a pid or ndata.notification is needed to retrieve or
|
||||
// create a source.
|
||||
_getSource(title, pid, ndata, sender) {
|
||||
if (!pid && !(ndata && ndata.notification))
|
||||
return null;
|
||||
throw new Error('Either a pid or ndata.notification is needed');
|
||||
|
||||
// We use notification's source for the notifications we still have
|
||||
// around that are getting replaced because we don't keep sources
|
||||
@ -218,42 +206,10 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
|
||||
this._notifications[id] = ndata;
|
||||
|
||||
let sender = invocation.get_sender();
|
||||
let pid = this._senderToPid[sender];
|
||||
let pid = hints['sender-pid'];
|
||||
|
||||
let source = this._getSource(appName, pid, ndata, sender, null);
|
||||
|
||||
if (source) {
|
||||
this._notifyForSource(source, ndata);
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
}
|
||||
|
||||
if (replacesId) {
|
||||
// There's already a pending call to GetConnectionUnixProcessID,
|
||||
// which will see the new notification data when it finishes,
|
||||
// so we don't have to do anything.
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
}
|
||||
|
||||
this._busProxy.GetConnectionUnixProcessIDRemote(sender, (result, excp) => {
|
||||
// The app may have updated or removed the notification
|
||||
ndata = this._notifications[id];
|
||||
if (!ndata)
|
||||
return;
|
||||
|
||||
if (excp) {
|
||||
logError(excp, 'Call to GetConnectionUnixProcessID failed');
|
||||
return;
|
||||
}
|
||||
|
||||
[pid] = result;
|
||||
source = this._getSource(appName, pid, ndata, sender, null);
|
||||
|
||||
this._senderToPid[sender] = pid;
|
||||
source.connect('destroy', () => {
|
||||
delete this._senderToPid[sender];
|
||||
});
|
||||
this._notifyForSource(source, ndata);
|
||||
});
|
||||
this._notifyForSource(source, ndata);
|
||||
|
||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||
}
|
||||
@ -417,12 +373,11 @@ var FdoNotificationDaemonSource = GObject.registerClass(
|
||||
class FdoNotificationDaemonSource extends MessageTray.Source {
|
||||
_init(title, pid, sender, appId) {
|
||||
this.pid = pid;
|
||||
this.initialTitle = title;
|
||||
this.app = this._getApp(appId);
|
||||
|
||||
super._init(title);
|
||||
|
||||
this.initialTitle = title;
|
||||
|
||||
if (this.app)
|
||||
this.title = this.app.get_name();
|
||||
else
|
||||
@ -470,19 +425,20 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
|
||||
}
|
||||
|
||||
_getApp(appId) {
|
||||
const appSys = Shell.AppSystem.get_default();
|
||||
let app;
|
||||
|
||||
app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
|
||||
if (app != null)
|
||||
return app;
|
||||
|
||||
if (appId) {
|
||||
app = Shell.AppSystem.get_default().lookup_app('%s.desktop'.format(appId));
|
||||
if (app != null)
|
||||
return app;
|
||||
}
|
||||
if (appId)
|
||||
app = appSys.lookup_app('%s.desktop'.format(appId));
|
||||
|
||||
return null;
|
||||
if (!app)
|
||||
app = appSys.lookup_app('%s.desktop'.format(this.initialTitle));
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
setTitle(title) {
|
||||
|
@ -244,11 +244,11 @@ var Overview = class {
|
||||
_unshadeBackgrounds() {
|
||||
let backgrounds = this._backgroundGroup.get_children();
|
||||
for (let i = 0; i < backgrounds.length; i++) {
|
||||
backgrounds[i].ease_property('brightness', 1.0, {
|
||||
backgrounds[i].ease_property('@content.brightness', 1.0, {
|
||||
duration: SHADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
});
|
||||
backgrounds[i].ease_property('vignette-sharpness', 0.0, {
|
||||
backgrounds[i].ease_property('@content.vignette-sharpness', 0.0, {
|
||||
duration: SHADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
});
|
||||
@ -258,14 +258,16 @@ var Overview = class {
|
||||
_shadeBackgrounds() {
|
||||
let backgrounds = this._backgroundGroup.get_children();
|
||||
for (let i = 0; i < backgrounds.length; i++) {
|
||||
backgrounds[i].ease_property('brightness', Lightbox.VIGNETTE_BRIGHTNESS, {
|
||||
duration: SHADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
});
|
||||
backgrounds[i].ease_property('vignette-sharpness', Lightbox.VIGNETTE_SHARPNESS, {
|
||||
duration: SHADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
});
|
||||
backgrounds[i].ease_property('@content.brightness',
|
||||
Lightbox.VIGNETTE_BRIGHTNESS, {
|
||||
duration: SHADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
});
|
||||
backgrounds[i].ease_property('@content.vignette-sharpness',
|
||||
Lightbox.VIGNETTE_SHARPNESS, {
|
||||
duration: SHADE_ANIMATION_TIME,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,8 +402,7 @@ var Overview = class {
|
||||
|
||||
_getDesktopClone() {
|
||||
let windows = global.get_window_actors().filter(
|
||||
w => w.meta_window.get_window_type() == Meta.WindowType.DESKTOP
|
||||
);
|
||||
w => w.meta_window.get_window_type() === Meta.WindowType.DESKTOP);
|
||||
if (windows.length == 0)
|
||||
return null;
|
||||
|
||||
@ -576,7 +577,7 @@ var Overview = class {
|
||||
this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC;
|
||||
|
||||
Meta.disable_unredirect_for_display(global.display);
|
||||
this.viewSelector.show();
|
||||
this.viewSelector.animateToOverview();
|
||||
|
||||
this._overview.opacity = 0;
|
||||
this._overview.ease({
|
||||
|
@ -51,7 +51,7 @@ var SlideLayout = GObject.registerClass({
|
||||
return [minWidth, natWidth];
|
||||
}
|
||||
|
||||
vfunc_allocate(container, box, flags) {
|
||||
vfunc_allocate(container, box) {
|
||||
let child = container.get_first_child();
|
||||
|
||||
let availWidth = Math.round(box.x2 - box.x1);
|
||||
@ -72,7 +72,7 @@ var SlideLayout = GObject.registerClass({
|
||||
actorBox.y1 = box.y1;
|
||||
actorBox.y2 = actorBox.y1 + availHeight;
|
||||
|
||||
child.allocate(actorBox, flags);
|
||||
child.allocate(actorBox);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
@ -394,10 +394,10 @@ class DashSpacer extends St.Widget {
|
||||
});
|
||||
|
||||
var ControlsLayout = GObject.registerClass({
|
||||
Signals: { 'allocation-changed': { flags: GObject.SignalFlags.RUN_LAST } },
|
||||
Signals: { 'allocation-changed': {} },
|
||||
}, class ControlsLayout extends Clutter.BinLayout {
|
||||
vfunc_allocate(container, box, flags) {
|
||||
super.vfunc_allocate(container, box, flags);
|
||||
vfunc_allocate(container, box) {
|
||||
super.vfunc_allocate(container, box);
|
||||
this.emit('allocation-changed');
|
||||
}
|
||||
});
|
||||
@ -473,6 +473,7 @@ class ControlsManager extends St.Widget {
|
||||
|
||||
// A workspace might have been inserted or removed before the active
|
||||
// one, causing the adjustment to go out of sync, so update the value
|
||||
this._workspaceAdjustment.remove_transition('value');
|
||||
this._workspaceAdjustment.value = activeIndex;
|
||||
}
|
||||
|
||||
|
161
js/ui/padOsd.js
161
js/ui/padOsd.js
@ -2,7 +2,7 @@
|
||||
/* exported PadOsd, PadOsdService */
|
||||
|
||||
const { Atk, Clutter, GDesktopEnums, Gio,
|
||||
GLib, GObject, Gtk, Meta, Rsvg, St } = imports.gi;
|
||||
GLib, GObject, Gtk, Meta, Pango, Rsvg, St } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
@ -329,6 +329,7 @@ var PadDiagram = GObject.registerClass({
|
||||
|
||||
this._imagePath = imagePath;
|
||||
this._handle = this._composeStyledDiagram();
|
||||
this._initLabels();
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
@ -343,6 +344,26 @@ var PadDiagram = GObject.registerClass({
|
||||
this.add_actor(actor);
|
||||
}
|
||||
|
||||
_initLabels() {
|
||||
let i = 0;
|
||||
for (i = 0; ; i++) {
|
||||
if (!this._addLabel(Meta.PadActionType.BUTTON, i))
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
if (!this._addLabel(Meta.PadActionType.RING, i, CW) ||
|
||||
!this._addLabel(Meta.PadActionType.RING, i, CCW))
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
if (!this._addLabel(Meta.PadActionType.STRIP, i, UP) ||
|
||||
!this._addLabel(Meta.PadActionType.STRIP, i, DOWN))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_wrappingSvgHeader() {
|
||||
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
|
||||
'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
|
||||
@ -362,10 +383,8 @@ var PadDiagram = GObject.registerClass({
|
||||
|
||||
for (let i = 0; i < this._activeButtons.length; i++) {
|
||||
let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]);
|
||||
css += '.%s {'.format(ch);
|
||||
css += ' stroke: %s !important;'.format(ACTIVE_COLOR);
|
||||
css += ' fill: %s !important;'.format(ACTIVE_COLOR);
|
||||
css += '}';
|
||||
css += '.%s.Leader { stroke: %s !important; }'.format(ch, ACTIVE_COLOR);
|
||||
css += '.%s.Button { stroke: %s !important; fill: %s !important; }'.format(ch, ACTIVE_COLOR, ACTIVE_COLOR);
|
||||
}
|
||||
|
||||
return css;
|
||||
@ -390,9 +409,6 @@ var PadDiagram = GObject.registerClass({
|
||||
}
|
||||
|
||||
_updateDiagramScale() {
|
||||
if (this._handle == null)
|
||||
return;
|
||||
|
||||
[this._actorWidth, this._actorHeight] = this.get_size();
|
||||
let dimensions = this._handle.get_dimensions();
|
||||
let scaleX = this._actorWidth / dimensions.width;
|
||||
@ -405,6 +421,11 @@ var PadDiagram = GObject.registerClass({
|
||||
let [, natWidth] = child.get_preferred_width(natHeight);
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
// I miss Cairo.Matrix
|
||||
let dimensions = this._handle.get_dimensions();
|
||||
x = x * this._scale + this._actorWidth / 2 - dimensions.width / 2 * this._scale;
|
||||
y = y * this._scale + this._actorHeight / 2 - dimensions.height / 2 * this._scale;
|
||||
|
||||
if (direction == LTR) {
|
||||
childBox.x1 = x;
|
||||
childBox.x2 = x + natWidth;
|
||||
@ -415,22 +436,23 @@ var PadDiagram = GObject.registerClass({
|
||||
|
||||
childBox.y1 = y - natHeight / 2;
|
||||
childBox.y2 = y + natHeight / 2;
|
||||
child.allocate(childBox, 0);
|
||||
child.allocate(childBox);
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
super.vfunc_allocate(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
super.vfunc_allocate(box);
|
||||
if (this._handle === null)
|
||||
return;
|
||||
|
||||
this._updateDiagramScale();
|
||||
|
||||
for (let i = 0; i < this._labels.length; i++) {
|
||||
let [label, action, idx, dir] = this._labels[i];
|
||||
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
||||
const { label, x, y, arrangement } = this._labels[i];
|
||||
this._allocateChild(label, x, y, arrangement);
|
||||
}
|
||||
|
||||
if (this._editorActor && this._curEdited) {
|
||||
let [label_, action, idx, dir] = this._curEdited;
|
||||
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
||||
const { x, y, arrangement } = this._curEdited;
|
||||
this._allocateChild(this._editorActor, x, y, arrangement);
|
||||
}
|
||||
}
|
||||
@ -457,17 +479,6 @@ var PadDiagram = GObject.registerClass({
|
||||
cr.$dispose();
|
||||
}
|
||||
|
||||
_transformPoint(x, y) {
|
||||
if (this._handle == null || this._scale == null)
|
||||
return [x, y];
|
||||
|
||||
// I miss Cairo.Matrix
|
||||
let dimensions = this._handle.get_dimensions();
|
||||
x = x * this._scale + this._actorWidth / 2 - dimensions.width / 2 * this._scale;
|
||||
y = y * this._scale + this._actorHeight / 2 - dimensions.height / 2 * this._scale;
|
||||
return [Math.round(x), Math.round(y)];
|
||||
}
|
||||
|
||||
_getItemLabelCoords(labelName, leaderName) {
|
||||
if (this._handle == null)
|
||||
return [false];
|
||||
@ -495,44 +506,39 @@ var PadDiagram = GObject.registerClass({
|
||||
pos.y = this._imageHeight - pos.y;
|
||||
}
|
||||
|
||||
let [x, y] = this._transformPoint(pos.x, pos.y);
|
||||
|
||||
return [true, x, y, direction];
|
||||
return [true, pos.x, pos.y, direction];
|
||||
}
|
||||
|
||||
getButtonLabelCoords(button) {
|
||||
_getButtonLabels(button) {
|
||||
let ch = String.fromCharCode('A'.charCodeAt() + button);
|
||||
let labelName = 'Label%s'.format(ch);
|
||||
let leaderName = 'Leader%s'.format(ch);
|
||||
|
||||
return this._getItemLabelCoords(labelName, leaderName);
|
||||
return [labelName, leaderName];
|
||||
}
|
||||
|
||||
getRingLabelCoords(number, dir) {
|
||||
_getRingLabels(number, dir) {
|
||||
let numStr = number > 0 ? (number + 1).toString() : '';
|
||||
let dirStr = dir == CW ? 'CW' : 'CCW';
|
||||
let labelName = 'LabelRing%s%s'.format(numStr, dirStr);
|
||||
let leaderName = 'LeaderRing%s%s'.format(numStr, dirStr);
|
||||
|
||||
return this._getItemLabelCoords(labelName, leaderName);
|
||||
return [labelName, leaderName];
|
||||
}
|
||||
|
||||
getStripLabelCoords(number, dir) {
|
||||
_getStripLabels(number, dir) {
|
||||
let numStr = number > 0 ? (number + 1).toString() : '';
|
||||
let dirStr = dir == UP ? 'Up' : 'Down';
|
||||
let labelName = 'LabelStrip%s%s'.format(numStr, dirStr);
|
||||
let leaderName = 'LeaderStrip%s%s'.format(numStr, dirStr);
|
||||
|
||||
return this._getItemLabelCoords(labelName, leaderName);
|
||||
return [labelName, leaderName];
|
||||
}
|
||||
|
||||
getLabelCoords(action, idx, dir) {
|
||||
_getLabelCoords(action, idx, dir) {
|
||||
if (action == Meta.PadActionType.BUTTON)
|
||||
return this.getButtonLabelCoords(idx);
|
||||
return this._getItemLabelCoords(...this._getButtonLabels(idx));
|
||||
else if (action == Meta.PadActionType.RING)
|
||||
return this.getRingLabelCoords(idx, dir);
|
||||
return this._getItemLabelCoords(...this._getRingLabels(idx, dir));
|
||||
else if (action == Meta.PadActionType.STRIP)
|
||||
return this.getStripLabelCoords(idx, dir);
|
||||
return this._getItemLabelCoords(...this._getStripLabels(idx, dir));
|
||||
|
||||
return [false];
|
||||
}
|
||||
@ -557,26 +563,30 @@ var PadDiagram = GObject.registerClass({
|
||||
this._invalidateSvg();
|
||||
}
|
||||
|
||||
addLabel(label, type, idx, dir) {
|
||||
this._labels.push([label, type, idx, dir]);
|
||||
_addLabel(action, idx, dir) {
|
||||
let [found, x, y, arrangement] = this._getLabelCoords(action, idx, dir);
|
||||
if (!found)
|
||||
return false;
|
||||
|
||||
let label = new St.Label();
|
||||
this._labels.push({ label, action, idx, dir, x, y, arrangement });
|
||||
this.add_actor(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
updateLabels(getText) {
|
||||
for (let i = 0; i < this._labels.length; i++) {
|
||||
let [label, action, idx, dir] = this._labels[i];
|
||||
const { label, action, idx, dir } = this._labels[i];
|
||||
let str = getText(action, idx, dir);
|
||||
label.set_text(str);
|
||||
}
|
||||
|
||||
this.queue_relayout();
|
||||
}
|
||||
|
||||
_applyLabel(label, action, idx, dir, str) {
|
||||
if (str != null) {
|
||||
if (str !== null)
|
||||
label.set_text(str);
|
||||
|
||||
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
||||
this._allocateChild(label, x, y, arrangement);
|
||||
}
|
||||
label.show();
|
||||
}
|
||||
|
||||
@ -584,18 +594,20 @@ var PadDiagram = GObject.registerClass({
|
||||
this._editorActor.hide();
|
||||
|
||||
if (this._prevEdited) {
|
||||
let [label, action, idx, dir] = this._prevEdited;
|
||||
const { label, action, idx, dir } = this._prevEdited;
|
||||
this._applyLabel(label, action, idx, dir, str);
|
||||
this._prevEdited = null;
|
||||
}
|
||||
|
||||
if (this._curEdited) {
|
||||
let [label, action, idx, dir] = this._curEdited;
|
||||
const { label, action, idx, dir } = this._curEdited;
|
||||
this._applyLabel(label, action, idx, dir, str);
|
||||
if (continues)
|
||||
this._prevEdited = this._curEdited;
|
||||
this._curEdited = null;
|
||||
}
|
||||
|
||||
this.queue_relayout();
|
||||
}
|
||||
|
||||
startEdition(action, idx, dir) {
|
||||
@ -605,21 +617,19 @@ var PadDiagram = GObject.registerClass({
|
||||
return;
|
||||
|
||||
for (let i = 0; i < this._labels.length; i++) {
|
||||
let [label, itemAction, itemIdx, itemDir] = this._labels[i];
|
||||
if (action == itemAction && idx == itemIdx && dir == itemDir) {
|
||||
if (action == this._labels[i].action &&
|
||||
idx == this._labels[i].idx && dir == this._labels[i].dir) {
|
||||
this._curEdited = this._labels[i];
|
||||
editedLabel = label;
|
||||
editedLabel = this._curEdited.label;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._curEdited == null)
|
||||
return;
|
||||
let [found] = this.getLabelCoords(action, idx, dir);
|
||||
if (!found)
|
||||
return;
|
||||
this._editorActor.show();
|
||||
editedLabel.hide();
|
||||
this.queue_relayout();
|
||||
}
|
||||
});
|
||||
|
||||
@ -693,6 +703,7 @@ var PadOsd = GObject.registerClass({
|
||||
|
||||
this._titleLabel = new St.Label({ style: 'font-side: larger; font-weight: bold;',
|
||||
x_align: Clutter.ActorAlign.CENTER });
|
||||
this._titleLabel.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
|
||||
this._titleLabel.clutter_text.set_text(padDevice.get_device_name());
|
||||
labelBox.add_actor(this._titleLabel);
|
||||
|
||||
@ -710,31 +721,7 @@ var PadOsd = GObject.registerClass({
|
||||
x_expand: true,
|
||||
y_expand: true });
|
||||
this.add_actor(this._padDiagram);
|
||||
|
||||
// FIXME: Fix num buttons.
|
||||
let i = 0;
|
||||
for (i = 0; i < 50; i++) {
|
||||
let [found] = this._padDiagram.getButtonLabelCoords(i);
|
||||
if (!found)
|
||||
break;
|
||||
this._createLabel(Meta.PadActionType.BUTTON, i);
|
||||
}
|
||||
|
||||
for (i = 0; i < padDevice.get_n_rings(); i++) {
|
||||
let [found] = this._padDiagram.getRingLabelCoords(i, CW);
|
||||
if (!found)
|
||||
break;
|
||||
this._createLabel(Meta.PadActionType.RING, i, CW);
|
||||
this._createLabel(Meta.PadActionType.RING, i, CCW);
|
||||
}
|
||||
|
||||
for (i = 0; i < padDevice.get_n_strips(); i++) {
|
||||
let [found] = this._padDiagram.getStripLabelCoords(i, UP);
|
||||
if (!found)
|
||||
break;
|
||||
this._createLabel(Meta.PadActionType.STRIP, i, UP);
|
||||
this._createLabel(Meta.PadActionType.STRIP, i, DOWN);
|
||||
}
|
||||
this._updateActionLabels();
|
||||
|
||||
let buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||
x_expand: true,
|
||||
@ -787,11 +774,6 @@ var PadOsd = GObject.registerClass({
|
||||
return str ? str : _("None");
|
||||
}
|
||||
|
||||
_createLabel(type, number, dir) {
|
||||
let label = new St.Label({ text: this._getActionText(type, number) });
|
||||
this._padDiagram.addLabel(label, type, number, dir);
|
||||
}
|
||||
|
||||
_updateActionLabels() {
|
||||
this._padDiagram.updateLabels(this._getActionText.bind(this));
|
||||
}
|
||||
@ -867,8 +849,7 @@ var PadOsd = GObject.registerClass({
|
||||
this._tipLabel.set_text(_("Press any key to exit"));
|
||||
}
|
||||
|
||||
this._titleLabel.clutter_text.set_markup(
|
||||
'<span size="larger"><b>%s</b></span>'.format(title));
|
||||
this._titleLabel.set_text(title);
|
||||
}
|
||||
|
||||
_isEditedAction(type, number, dir) {
|
||||
|
@ -120,6 +120,10 @@ var PageIndicators = GObject.registerClass({
|
||||
for (let i = 0; i < children.length; i++)
|
||||
this._updateIndicator(children[i], i);
|
||||
}
|
||||
|
||||
get nPages() {
|
||||
return this._nPages;
|
||||
}
|
||||
});
|
||||
|
||||
var AnimatedPageIndicators = GObject.registerClass(
|
||||
|
105
js/ui/panel.js
105
js/ui/panel.js
@ -5,6 +5,7 @@ const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
const Cairo = imports.cairo;
|
||||
|
||||
const Animation = imports.ui.animation;
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const Config = imports.misc.config;
|
||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||
const DND = imports.ui.dnd;
|
||||
@ -60,69 +61,20 @@ function _unpremultiply(color) {
|
||||
return new Clutter.Color({ red, green, blue, alpha: color.alpha });
|
||||
}
|
||||
|
||||
class AppMenu extends PopupMenu.PopupMenu {
|
||||
class AppMenu extends AppDisplay.BaseAppMenu {
|
||||
constructor(sourceActor) {
|
||||
super(sourceActor, 0.5, St.Side.TOP);
|
||||
super(sourceActor, St.Side.TOP);
|
||||
|
||||
this.actor.add_style_class_name('app-menu');
|
||||
|
||||
this._app = null;
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
|
||||
this._windowsChangedId = 0;
|
||||
|
||||
/* Translators: This is the heading of a list of open windows */
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem(_("Open Windows")));
|
||||
|
||||
this._windowSection = new PopupMenu.PopupMenuSection();
|
||||
this.addMenuItem(this._windowSection);
|
||||
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._newWindowItem = this.addAction(_("New Window"), () => {
|
||||
this._app.open_new_window(-1);
|
||||
});
|
||||
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._actionSection = new PopupMenu.PopupMenuSection();
|
||||
this.addMenuItem(this._actionSection);
|
||||
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this._detailsItem = this.addAction(_('Show Details'), async () => {
|
||||
let id = this._app.get_id();
|
||||
let args = GLib.Variant.new('(ss)', [id, '']);
|
||||
const bus = await Gio.DBus.get(Gio.BusType.SESSION, null);
|
||||
bus.call(
|
||||
'org.gnome.Software',
|
||||
'/org/gnome/Software',
|
||||
'org.gtk.Actions', 'Activate',
|
||||
new GLib.Variant('(sava{sv})', ['details', [args], null]),
|
||||
null, 0, -1, null);
|
||||
});
|
||||
|
||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
|
||||
this.addAction(_("Quit"), () => {
|
||||
this._app.request_quit();
|
||||
});
|
||||
|
||||
this._appSystem.connect('installed-changed', () => {
|
||||
this._updateDetailsVisibility();
|
||||
});
|
||||
this._updateDetailsVisibility();
|
||||
}
|
||||
|
||||
_updateDetailsVisibility() {
|
||||
let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
|
||||
this._detailsItem.visible = sw != null;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
if (!this._app)
|
||||
return true;
|
||||
return super.isEmpty();
|
||||
get app() {
|
||||
return this._app;
|
||||
}
|
||||
|
||||
setApp(app) {
|
||||
@ -157,25 +109,6 @@ class AppMenu extends PopupMenu.PopupMenu {
|
||||
this._newWindowItem.visible =
|
||||
app && app.can_open_new_window() && !actions.includes('new-window');
|
||||
}
|
||||
|
||||
_updateWindowsSection() {
|
||||
this._windowSection.removeAll();
|
||||
|
||||
if (!this._app)
|
||||
return;
|
||||
|
||||
let windows = this._app.get_windows();
|
||||
windows.forEach(window => {
|
||||
let title = window.title || this._app.get_name();
|
||||
let item = this._windowSection.addAction(title, event => {
|
||||
Main.activateWindow(window, event.get_time());
|
||||
});
|
||||
let id = window.connect('notify::title', () => {
|
||||
item.label.text = window.title || this._app.get_name();
|
||||
});
|
||||
item.connect('destroy', () => window.disconnect(id));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -214,7 +147,10 @@ var AppMenuButton = GObject.registerClass({
|
||||
this._onIconThemeChanged.bind(this));
|
||||
|
||||
let iconEffect = new Clutter.DesaturateEffect();
|
||||
this._iconBox = new St.Bin({ style_class: 'app-menu-icon' });
|
||||
this._iconBox = new St.Bin({
|
||||
style_class: 'app-menu-icon',
|
||||
y_align: Clutter.ActorAlign.CENTER,
|
||||
});
|
||||
this._iconBox.add_effect(iconEffect);
|
||||
this._container.add_actor(this._iconBox);
|
||||
|
||||
@ -281,7 +217,7 @@ var AppMenuButton = GObject.registerClass({
|
||||
this.remove_all_transitions();
|
||||
this.ease({
|
||||
opacity: 0,
|
||||
mode: Clutter.Animation.EASE_OUT_QUAD,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
duration: Overview.ANIMATION_TIME,
|
||||
onComplete: () => this.hide(),
|
||||
});
|
||||
@ -839,8 +775,8 @@ class Panel extends St.Widget {
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
let allocWidth = box.x2 - box.x1;
|
||||
let allocHeight = box.y2 - box.y1;
|
||||
@ -876,13 +812,13 @@ class Panel extends St.Widget {
|
||||
childBox.x2 = Math.min(Math.floor(sideWidth),
|
||||
leftNaturalWidth);
|
||||
}
|
||||
this._leftBox.allocate(childBox, flags);
|
||||
this._leftBox.allocate(childBox);
|
||||
|
||||
childBox.x1 = Math.ceil(sideWidth);
|
||||
childBox.y1 = 0;
|
||||
childBox.x2 = childBox.x1 + centerWidth;
|
||||
childBox.y2 = allocHeight;
|
||||
this._centerBox.allocate(childBox, flags);
|
||||
this._centerBox.allocate(childBox);
|
||||
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = allocHeight;
|
||||
@ -896,7 +832,7 @@ class Panel extends St.Widget {
|
||||
0);
|
||||
childBox.x2 = allocWidth;
|
||||
}
|
||||
this._rightBox.allocate(childBox, flags);
|
||||
this._rightBox.allocate(childBox);
|
||||
|
||||
let cornerWidth, cornerHeight;
|
||||
|
||||
@ -906,7 +842,7 @@ class Panel extends St.Widget {
|
||||
childBox.x2 = cornerWidth;
|
||||
childBox.y1 = allocHeight;
|
||||
childBox.y2 = allocHeight + cornerHeight;
|
||||
this._leftCorner.allocate(childBox, flags);
|
||||
this._leftCorner.allocate(childBox);
|
||||
|
||||
[, cornerWidth] = this._rightCorner.get_preferred_width(-1);
|
||||
[, cornerHeight] = this._rightCorner.get_preferred_height(-1);
|
||||
@ -914,7 +850,7 @@ class Panel extends St.Widget {
|
||||
childBox.x2 = allocWidth;
|
||||
childBox.y1 = allocHeight;
|
||||
childBox.y2 = allocHeight + cornerHeight;
|
||||
this._rightCorner.allocate(childBox, flags);
|
||||
this._rightCorner.allocate(childBox);
|
||||
}
|
||||
|
||||
_tryDragWindow(event) {
|
||||
@ -1153,10 +1089,9 @@ class Panel extends St.Widget {
|
||||
|
||||
_getDraggableWindowForPosition(stageX) {
|
||||
let workspaceManager = global.workspace_manager;
|
||||
let workspace = workspaceManager.get_active_workspace();
|
||||
let allWindowsByStacking = global.display.sort_windows_by_stacking(
|
||||
workspace.list_windows()
|
||||
).reverse();
|
||||
const windows = workspaceManager.get_active_workspace().list_windows();
|
||||
const allWindowsByStacking =
|
||||
global.display.sort_windows_by_stacking(windows).reverse();
|
||||
|
||||
return allWindowsByStacking.find(metaWindow => {
|
||||
let rect = metaWindow.get_frame_rect();
|
||||
|
@ -59,8 +59,8 @@ class ButtonBox extends St.Widget {
|
||||
return [0, 0];
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
let child = this.get_first_child();
|
||||
if (!child)
|
||||
@ -83,7 +83,7 @@ class ButtonBox extends St.Widget {
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = availHeight;
|
||||
|
||||
child.allocate(childBox, flags);
|
||||
child.allocate(childBox);
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
|
@ -198,7 +198,7 @@ var ScreenShield = class {
|
||||
let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
|
||||
let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
|
||||
let inhibit = this._loginSession && this._loginSession.Active &&
|
||||
!this._isActive && lockEnabled && !lockLocked;
|
||||
!this._isActive && lockEnabled && !lockLocked && Main.sessionMode.unlockDialog;
|
||||
if (inhibit) {
|
||||
this._loginManager.inhibit(_("GNOME needs to lock the screen"),
|
||||
inhibitor => {
|
||||
@ -345,7 +345,7 @@ var ScreenShield = class {
|
||||
this._lockDialogGroup.remove_all_transitions();
|
||||
|
||||
if (animate) {
|
||||
// Tween the lock screen out of screen
|
||||
// Animate the lock screen out of screen
|
||||
// if velocity is not specified (i.e. we come here from pressing ESC),
|
||||
// use the same speed regardless of original position
|
||||
// if velocity is specified, it's in pixels per milliseconds
|
||||
@ -561,7 +561,8 @@ var ScreenShield = class {
|
||||
if (this._activationTime == 0)
|
||||
this._activationTime = GLib.get_monotonic_time();
|
||||
|
||||
this._ensureUnlockDialog(true);
|
||||
if (!this._ensureUnlockDialog(true))
|
||||
return;
|
||||
|
||||
this.actor.show();
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported ScreenshotService */
|
||||
|
||||
const { Clutter, Graphene, Gio, GObject, GLib, Meta, Shell, St } = imports.gi;
|
||||
const { Clutter, Gio, GObject, GLib, Meta, Shell, St } = imports.gi;
|
||||
|
||||
const GrabHelper = imports.ui.grabHelper;
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
@ -37,7 +37,9 @@ var ScreenshotService = class {
|
||||
|
||||
let sender = invocation.get_sender();
|
||||
if (this._screenShooter.has(sender) || lockedDown) {
|
||||
invocation.return_value(GLib.Variant.new('(bs)', [false, '']));
|
||||
invocation.return_error_literal(
|
||||
Gio.IOErrorEnum, Gio.IOErrorEnum.BUSY,
|
||||
'There is an ongoing operation for this sender');
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -259,15 +261,13 @@ var ScreenshotService = class {
|
||||
}
|
||||
|
||||
async PickColorAsync(params, invocation) {
|
||||
let pickPixel = new PickPixel();
|
||||
const screenshot = this._createScreenshot(invocation, false);
|
||||
if (!screenshot)
|
||||
return;
|
||||
|
||||
const pickPixel = new PickPixel(screenshot);
|
||||
try {
|
||||
const coords = await pickPixel.pickAsync();
|
||||
|
||||
let screenshot = this._createScreenshot(invocation, false);
|
||||
if (!screenshot)
|
||||
return;
|
||||
|
||||
const [color] = await screenshot.pick_color(coords.x, coords.y);
|
||||
const color = await pickPixel.pickAsync();
|
||||
const { red, green, blue } = color;
|
||||
const retval = GLib.Variant.new('(a{sv})', [{
|
||||
color: GLib.Variant.new('(ddd)', [
|
||||
@ -276,12 +276,13 @@ var ScreenshotService = class {
|
||||
blue / 255.0,
|
||||
]),
|
||||
}]);
|
||||
this._removeShooterForSender(invocation.get_sender());
|
||||
invocation.return_value(retval);
|
||||
} catch (e) {
|
||||
invocation.return_error_literal(
|
||||
Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
|
||||
'Operation was cancelled');
|
||||
} finally {
|
||||
this._removeShooterForSender(invocation.get_sender());
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -379,12 +380,145 @@ class SelectArea extends St.Widget {
|
||||
}
|
||||
});
|
||||
|
||||
var RecolorEffect = GObject.registerClass({
|
||||
Properties: {
|
||||
color: GObject.ParamSpec.boxed(
|
||||
'color', 'color', 'replacement color',
|
||||
GObject.ParamFlags.WRITABLE,
|
||||
Clutter.Color.$gtype),
|
||||
chroma: GObject.ParamSpec.boxed(
|
||||
'chroma', 'chroma', 'color to replace',
|
||||
GObject.ParamFlags.WRITABLE,
|
||||
Clutter.Color.$gtype),
|
||||
threshold: GObject.ParamSpec.float(
|
||||
'threshold', 'threshold', 'threshold',
|
||||
GObject.ParamFlags.WRITABLE,
|
||||
0.0, 1.0, 0.0),
|
||||
smoothing: GObject.ParamSpec.float(
|
||||
'smoothing', 'smoothing', 'smoothing',
|
||||
GObject.ParamFlags.WRITABLE,
|
||||
0.0, 1.0, 0.0),
|
||||
},
|
||||
}, class RecolorEffect extends Shell.GLSLEffect {
|
||||
_init(params) {
|
||||
this._color = new Clutter.Color();
|
||||
this._chroma = new Clutter.Color();
|
||||
this._threshold = 0;
|
||||
this._smoothing = 0;
|
||||
|
||||
this._colorLocation = null;
|
||||
this._chromaLocation = null;
|
||||
this._thresholdLocation = null;
|
||||
this._smoothingLocation = null;
|
||||
|
||||
super._init(params);
|
||||
|
||||
this._colorLocation = this.get_uniform_location('recolor_color');
|
||||
this._chromaLocation = this.get_uniform_location('chroma_color');
|
||||
this._thresholdLocation = this.get_uniform_location('threshold');
|
||||
this._smoothingLocation = this.get_uniform_location('smoothing');
|
||||
|
||||
this._updateColorUniform(this._colorLocation, this._color);
|
||||
this._updateColorUniform(this._chromaLocation, this._chroma);
|
||||
this._updateFloatUniform(this._thresholdLocation, this._threshold);
|
||||
this._updateFloatUniform(this._smoothingLocation, this._smoothing);
|
||||
}
|
||||
|
||||
_updateColorUniform(location, color) {
|
||||
if (!location)
|
||||
return;
|
||||
|
||||
this.set_uniform_float(location,
|
||||
3, [color.red / 255, color.green / 255, color.blue / 255]);
|
||||
this.queue_repaint();
|
||||
}
|
||||
|
||||
_updateFloatUniform(location, value) {
|
||||
if (!location)
|
||||
return;
|
||||
|
||||
this.set_uniform_float(location, 1, [value]);
|
||||
this.queue_repaint();
|
||||
}
|
||||
|
||||
set color(c) {
|
||||
if (this._color.equal(c))
|
||||
return;
|
||||
|
||||
this._color = c;
|
||||
this.notify('color');
|
||||
|
||||
this._updateColorUniform(this._colorLocation, this._color);
|
||||
}
|
||||
|
||||
set chroma(c) {
|
||||
if (this._chroma.equal(c))
|
||||
return;
|
||||
|
||||
this._chroma = c;
|
||||
this.notify('chroma');
|
||||
|
||||
this._updateColorUniform(this._chromaLocation, this._chroma);
|
||||
}
|
||||
|
||||
set threshold(value) {
|
||||
if (this._threshold === value)
|
||||
return;
|
||||
|
||||
this._threshold = value;
|
||||
this.notify('threshold');
|
||||
|
||||
this._updateFloatUniform(this._thresholdLocation, this._threshold);
|
||||
}
|
||||
|
||||
set smoothing(value) {
|
||||
if (this._smoothing === value)
|
||||
return;
|
||||
|
||||
this._smoothing = value;
|
||||
this.notify('smoothing');
|
||||
|
||||
this._updateFloatUniform(this._smoothingLocation, this._smoothing);
|
||||
}
|
||||
|
||||
vfunc_build_pipeline() {
|
||||
// Conversion parameters from https://en.wikipedia.org/wiki/YCbCr
|
||||
const decl = `
|
||||
vec3 rgb2yCrCb(vec3 c) { \n
|
||||
float y = 0.299 * c.r + 0.587 * c.g + 0.114 * c.b; \n
|
||||
float cr = 0.7133 * (c.r - y); \n
|
||||
float cb = 0.5643 * (c.b - y); \n
|
||||
return vec3(y, cr, cb); \n
|
||||
} \n
|
||||
\n
|
||||
uniform vec3 chroma_color; \n
|
||||
uniform vec3 recolor_color; \n
|
||||
uniform float threshold; \n
|
||||
uniform float smoothing; \n`;
|
||||
const src = `
|
||||
vec3 mask = rgb2yCrCb(chroma_color.rgb); \n
|
||||
vec3 yCrCb = rgb2yCrCb(cogl_color_out.rgb); \n
|
||||
float blend = \n
|
||||
smoothstep(threshold, \n
|
||||
threshold + smoothing, \n
|
||||
distance(yCrCb.gb, mask.gb)); \n
|
||||
cogl_color_out.rgb = \n
|
||||
mix(recolor_color, cogl_color_out.rgb, blend); \n`;
|
||||
|
||||
this.add_glsl_snippet(Shell.SnippetHook.FRAGMENT, decl, src, false);
|
||||
}
|
||||
});
|
||||
|
||||
var PickPixel = GObject.registerClass(
|
||||
class PickPixel extends St.Widget {
|
||||
_init() {
|
||||
_init(screenshot) {
|
||||
super._init({ visible: false, reactive: true });
|
||||
|
||||
this._screenshot = screenshot;
|
||||
|
||||
this._result = null;
|
||||
this._color = null;
|
||||
this._inPick = false;
|
||||
|
||||
Main.uiGroup.add_actor(this);
|
||||
|
||||
@ -393,16 +527,44 @@ class PickPixel extends St.Widget {
|
||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||
coordinate: Clutter.BindCoordinate.ALL });
|
||||
this.add_constraint(constraint);
|
||||
|
||||
const action = new Clutter.ClickAction();
|
||||
action.connect('clicked', async () => {
|
||||
await this._pickColor(...action.get_coords());
|
||||
this._result = this._color;
|
||||
this._grabHelper.ungrab();
|
||||
});
|
||||
this.add_action(action);
|
||||
|
||||
this._recolorEffect = new RecolorEffect({
|
||||
chroma: new Clutter.Color({
|
||||
red: 80,
|
||||
green: 219,
|
||||
blue: 181,
|
||||
}),
|
||||
threshold: 0.04,
|
||||
smoothing: 0.07,
|
||||
});
|
||||
this._previewCursor = new St.Icon({
|
||||
icon_name: 'color-pick',
|
||||
icon_size: Meta.prefs_get_cursor_size(),
|
||||
effect: this._recolorEffect,
|
||||
visible: false,
|
||||
});
|
||||
Main.uiGroup.add_actor(this._previewCursor);
|
||||
}
|
||||
|
||||
async pickAsync() {
|
||||
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
|
||||
global.display.set_cursor(Meta.Cursor.BLANK);
|
||||
Main.uiGroup.set_child_above_sibling(this, null);
|
||||
this.show();
|
||||
|
||||
this._pickColor(...global.get_pointer());
|
||||
|
||||
await this._grabHelper.grabAsync({ actor: this });
|
||||
|
||||
global.display.set_cursor(Meta.Cursor.DEFAULT);
|
||||
this._previewCursor.destroy();
|
||||
|
||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
this.destroy();
|
||||
@ -412,10 +574,25 @@ class PickPixel extends St.Widget {
|
||||
return this._result;
|
||||
}
|
||||
|
||||
vfunc_button_release_event(buttonEvent) {
|
||||
let { x, y } = buttonEvent;
|
||||
this._result = new Graphene.Point({ x, y });
|
||||
this._grabHelper.ungrab();
|
||||
async _pickColor(x, y) {
|
||||
if (this._inPick)
|
||||
return;
|
||||
|
||||
this._inPick = true;
|
||||
this._previewCursor.set_position(x, y);
|
||||
[this._color] = await this._screenshot.pick_color(x, y);
|
||||
this._inPick = false;
|
||||
|
||||
if (!this._color)
|
||||
return;
|
||||
|
||||
this._recolorEffect.color = this._color;
|
||||
this._previewCursor.show();
|
||||
}
|
||||
|
||||
vfunc_motion_event(motionEvent) {
|
||||
const { x, y } = motionEvent;
|
||||
this._pickColor(x, y);
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
});
|
||||
|
165
js/ui/search.js
165
js/ui/search.js
@ -6,17 +6,17 @@ const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
const Main = imports.ui.main;
|
||||
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
||||
const RemoteSearch = imports.ui.remoteSearch;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
|
||||
|
||||
var MAX_LIST_SEARCH_RESULTS_ROWS = 5;
|
||||
var MAX_GRID_SEARCH_RESULTS_ROWS = 1;
|
||||
|
||||
var MaxWidthBox = GObject.registerClass(
|
||||
class MaxWidthBox extends St.BoxLayout {
|
||||
vfunc_allocate(box, flags) {
|
||||
vfunc_allocate(box) {
|
||||
let themeNode = this.get_theme_node();
|
||||
let maxWidth = themeNode.get_max_width();
|
||||
let availWidth = box.x2 - box.x1;
|
||||
@ -28,7 +28,7 @@ class MaxWidthBox extends St.BoxLayout {
|
||||
adjustedBox.x2 -= Math.floor(excessWidth / 2);
|
||||
}
|
||||
|
||||
super.vfunc_allocate(adjustedBox, flags);
|
||||
super.vfunc_allocate(adjustedBox);
|
||||
}
|
||||
});
|
||||
|
||||
@ -219,8 +219,7 @@ var SearchResultsBase = GObject.registerClass({
|
||||
|
||||
_ensureResultActors(results, callback) {
|
||||
let metasNeeded = results.filter(
|
||||
resultId => this._resultDisplays[resultId] === undefined
|
||||
);
|
||||
resultId => this._resultDisplays[resultId] === undefined);
|
||||
|
||||
if (metasNeeded.length === 0) {
|
||||
callback(true);
|
||||
@ -349,18 +348,140 @@ class ListSearchResults extends SearchResultsBase {
|
||||
}
|
||||
});
|
||||
|
||||
var GridSearchResultsLayout = GObject.registerClass({
|
||||
Properties: {
|
||||
'spacing': GObject.ParamSpec.int('spacing', 'Spacing', 'Spacing',
|
||||
GObject.ParamFlags.READWRITE, 0, GLib.MAXINT32, 0),
|
||||
},
|
||||
}, class GridSearchResultsLayout extends Clutter.LayoutManager {
|
||||
_init() {
|
||||
super._init();
|
||||
this._spacing = 0;
|
||||
}
|
||||
|
||||
vfunc_set_container(container) {
|
||||
this._container = container;
|
||||
}
|
||||
|
||||
vfunc_get_preferred_width(container, forHeight) {
|
||||
let minWidth = 0;
|
||||
let natWidth = 0;
|
||||
let first = true;
|
||||
|
||||
for (let child of container) {
|
||||
if (!child.visible)
|
||||
continue;
|
||||
|
||||
const [childMinWidth, childNatWidth] = child.get_preferred_width(forHeight);
|
||||
|
||||
minWidth = Math.max(minWidth, childMinWidth);
|
||||
natWidth += childNatWidth;
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
natWidth += this._spacing;
|
||||
}
|
||||
|
||||
return [minWidth, natWidth];
|
||||
}
|
||||
|
||||
vfunc_get_preferred_height(container, forWidth) {
|
||||
let minHeight = 0;
|
||||
let natHeight = 0;
|
||||
|
||||
for (let child of container) {
|
||||
if (!child.visible)
|
||||
continue;
|
||||
|
||||
const [childMinHeight, childNatHeight] = child.get_preferred_height(forWidth);
|
||||
|
||||
minHeight = Math.max(minHeight, childMinHeight);
|
||||
natHeight = Math.max(natHeight, childNatHeight);
|
||||
}
|
||||
|
||||
return [minHeight, natHeight];
|
||||
}
|
||||
|
||||
vfunc_allocate(container, box) {
|
||||
const width = box.get_width();
|
||||
|
||||
const childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = 0;
|
||||
childBox.y1 = 0;
|
||||
|
||||
let first = true;
|
||||
for (let child of container) {
|
||||
if (!child.visible)
|
||||
continue;
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
childBox.x1 += this._spacing;
|
||||
|
||||
const [childWidth] = child.get_preferred_width(-1);
|
||||
const [childHeight] = child.get_preferred_height(-1);
|
||||
childBox.set_size(childWidth, childHeight);
|
||||
|
||||
if (childBox.x1 + childWidth > width)
|
||||
return;
|
||||
|
||||
child.allocate(childBox);
|
||||
|
||||
childBox.x1 += childWidth;
|
||||
}
|
||||
}
|
||||
|
||||
columnsForWidth(width) {
|
||||
if (!this._container)
|
||||
return -1;
|
||||
|
||||
const [minWidth] = this.get_preferred_width(this._container, -1);
|
||||
|
||||
if (minWidth === 0)
|
||||
return -1;
|
||||
|
||||
let nCols = 0;
|
||||
while (width > minWidth) {
|
||||
width -= minWidth;
|
||||
if (nCols > 0)
|
||||
width -= this._spacing;
|
||||
nCols++;
|
||||
}
|
||||
|
||||
return nCols;
|
||||
}
|
||||
|
||||
get spacing() {
|
||||
return this._spacing;
|
||||
}
|
||||
|
||||
set spacing(v) {
|
||||
if (this._spacing === v)
|
||||
return;
|
||||
this._spacing = v;
|
||||
this.layout_changed();
|
||||
}
|
||||
});
|
||||
|
||||
var GridSearchResults = GObject.registerClass(
|
||||
class GridSearchResults extends SearchResultsBase {
|
||||
_init(provider, resultsView) {
|
||||
super._init(provider, resultsView);
|
||||
|
||||
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
|
||||
xAlign: St.Align.START });
|
||||
this._grid = new St.Widget({ style_class: 'grid-search-results' });
|
||||
this._grid.layout_manager = new GridSearchResultsLayout();
|
||||
|
||||
this._bin = new St.Bin({ x_align: Clutter.ActorAlign.CENTER });
|
||||
this._bin.set_child(this._grid);
|
||||
this._grid.connect('style-changed', () => {
|
||||
const node = this._grid.get_theme_node();
|
||||
this._grid.layout_manager.spacing = node.get_length('spacing');
|
||||
});
|
||||
|
||||
this._resultDisplayBin.set_child(this._bin);
|
||||
this._resultDisplayBin.set_child(new St.Bin({
|
||||
child: this._grid,
|
||||
x_align: Clutter.ActorAlign.CENTER,
|
||||
}));
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
@ -400,12 +521,11 @@ class GridSearchResults extends SearchResultsBase {
|
||||
if (width == 0)
|
||||
return -1;
|
||||
|
||||
let nCols = this._grid.columnsForWidth(width);
|
||||
return nCols * this._grid.getRowLimit();
|
||||
return this._grid.layout_manager.columnsForWidth(width);
|
||||
}
|
||||
|
||||
_clearResultDisplay() {
|
||||
this._grid.removeAll();
|
||||
this._grid.remove_all_children();
|
||||
}
|
||||
|
||||
_createResultDisplay(meta) {
|
||||
@ -414,14 +534,15 @@ class GridSearchResults extends SearchResultsBase {
|
||||
}
|
||||
|
||||
_addItem(display) {
|
||||
this._grid.addItem(display);
|
||||
this._grid.add_child(display);
|
||||
}
|
||||
|
||||
getFirstResult() {
|
||||
if (this._grid.visibleItemsCount() > 0)
|
||||
return this._grid.getItemAtIndex(0);
|
||||
else
|
||||
return null;
|
||||
for (let child of this._grid) {
|
||||
if (child.visible)
|
||||
return child;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
@ -431,6 +552,9 @@ var SearchResultsView = GObject.registerClass({
|
||||
_init() {
|
||||
super._init({ name: 'searchResults', vertical: true });
|
||||
|
||||
this._parentalControlsManager = ParentalControlsManager.getDefault();
|
||||
this._parentalControlsManager.connect('app-filter-changed', this._reloadRemoteProviders.bind(this));
|
||||
|
||||
this._content = new MaxWidthBox({
|
||||
name: 'searchResultsContent',
|
||||
vertical: true,
|
||||
@ -505,6 +629,11 @@ var SearchResultsView = GObject.registerClass({
|
||||
|
||||
_registerProvider(provider) {
|
||||
provider.searchInProgress = false;
|
||||
|
||||
// Filter out unwanted providers.
|
||||
if (provider.appInfo && !this._parentalControlsManager.shouldShowApp(provider.appInfo))
|
||||
return;
|
||||
|
||||
this._providers.push(provider);
|
||||
this._ensureProviderDisplay(provider);
|
||||
}
|
||||
|
@ -295,8 +295,8 @@ var ShellMountPasswordDialog = GObject.registerClass({
|
||||
this._keyfilesLabel = new St.Label({ visible: false });
|
||||
this._keyfilesLabel.clutter_text.set_markup(
|
||||
/* Translators: %s is the Disks application */
|
||||
_("To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead.").format(disksApp.get_name())
|
||||
);
|
||||
_('To unlock a volume that uses keyfiles, use the <i>%s</i> utility instead.')
|
||||
.format(disksApp.get_name()));
|
||||
this._keyfilesLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||
this._keyfilesLabel.clutter_text.line_wrap = true;
|
||||
content.add_child(this._keyfilesLabel);
|
||||
@ -464,8 +464,7 @@ var ShellMountPasswordDialog = GObject.registerClass({
|
||||
/* Translators: %s is the Disks application */
|
||||
_("Unable to start %s").format(app.get_name()),
|
||||
/* Translators: %s is the Disks application */
|
||||
_("Couldn’t find the %s application").format(app.get_name())
|
||||
);
|
||||
_('Couldn’t find the %s application').format(app.get_name()));
|
||||
}
|
||||
this._onCancelButton();
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported Indicator */
|
||||
|
||||
const { Gio, GnomeBluetooth, GObject } = imports.gi;
|
||||
const { Gio, GLib, GnomeBluetooth, GObject } = imports.gi;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
@ -35,7 +35,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
|
||||
this._sync();
|
||||
});
|
||||
this._proxy.connect('g-properties-changed', this._sync.bind(this));
|
||||
this._proxy.connect('g-properties-changed', this._queueSync.bind(this));
|
||||
|
||||
this._item = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
|
||||
this._item.icon.icon_name = 'bluetooth-active-symbolic';
|
||||
@ -49,15 +49,27 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
this._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
|
||||
this.menu.addMenuItem(this._item);
|
||||
|
||||
this._syncId = 0;
|
||||
this._adapter = null;
|
||||
|
||||
this._client = new GnomeBluetooth.Client();
|
||||
this._model = this._client.get_model();
|
||||
this._model.connect('row-changed', this._sync.bind(this));
|
||||
this._model.connect('row-deleted', this._sync.bind(this));
|
||||
this._model.connect('row-deleted', this._queueSync.bind(this));
|
||||
this._model.connect('row-changed', this._queueSync.bind(this));
|
||||
this._model.connect('row-inserted', this._sync.bind(this));
|
||||
Main.sessionMode.connect('updated', this._sync.bind(this));
|
||||
this._sync();
|
||||
}
|
||||
|
||||
_setHadSetupDevices(value) {
|
||||
if (this._hadSetupDevices === value)
|
||||
return;
|
||||
|
||||
this._hadSetupDevices = value;
|
||||
global.settings.set_boolean(
|
||||
HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
|
||||
}
|
||||
|
||||
_getDefaultAdapter() {
|
||||
let [ret, iter] = this._model.get_iter_first();
|
||||
while (ret) {
|
||||
@ -96,20 +108,28 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
ret = this._model.iter_next(iter);
|
||||
}
|
||||
|
||||
if (this._hadSetupDevices !== (deviceInfos.length > 0)) {
|
||||
this._hadSetupDevices = !this._hadSetupDevices;
|
||||
global.settings.set_boolean(HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
|
||||
}
|
||||
|
||||
return deviceInfos;
|
||||
}
|
||||
|
||||
_queueSync() {
|
||||
if (this._syncId)
|
||||
return;
|
||||
this._syncId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||
this._syncId = 0;
|
||||
this._sync();
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
}
|
||||
|
||||
_sync() {
|
||||
let adapter = this._getDefaultAdapter();
|
||||
let devices = this._getDeviceInfos(adapter);
|
||||
const connectedDevices = devices.filter(dev => dev.connected);
|
||||
const nConnectedDevices = connectedDevices.length;
|
||||
const nDevices = devices.length;
|
||||
|
||||
if (adapter && this._adapter)
|
||||
this._setHadSetupDevices(devices.length > 0);
|
||||
this._adapter = adapter;
|
||||
|
||||
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||
|
||||
@ -118,7 +138,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
|
||||
// Remember if there were setup devices and show the menu
|
||||
// if we've seen setup devices and we're not hard blocked
|
||||
if (nDevices > 0)
|
||||
if (this._hadSetupDevices)
|
||||
this._item.visible = !this._proxy.BluetoothHardwareAirplaneMode;
|
||||
else
|
||||
this._item.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
|
||||
|
@ -48,7 +48,9 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
this._item.connect('key-press-event', (actor, event) => {
|
||||
return this._slider.emit('key-press-event', event);
|
||||
});
|
||||
|
||||
this._item.connect('scroll-event', (actor, event) => {
|
||||
return this._slider.emit('scroll-event', event);
|
||||
});
|
||||
}
|
||||
|
||||
_sliderChanged() {
|
||||
|
@ -805,8 +805,8 @@ class InputSourceIndicatorContainer extends St.Widget {
|
||||
}, [0, 0]);
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
// translate box to (0, 0)
|
||||
box.x2 -= box.x1;
|
||||
@ -815,7 +815,7 @@ class InputSourceIndicatorContainer extends St.Widget {
|
||||
box.y1 = 0;
|
||||
|
||||
this.get_children().forEach(c => {
|
||||
c.allocate_align_fill(box, 0.5, 0.5, false, false, flags);
|
||||
c.allocate_align_fill(box, 0.5, 0.5, false, false);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -225,10 +225,6 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
}
|
||||
});
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
|
||||
var AppAuthorizer = class {
|
||||
constructor(desktopId, reqAccuracyLevel, permStoreProxy, maxAccuracyLevel) {
|
||||
this.desktopId = desktopId;
|
||||
@ -313,9 +309,8 @@ var AppAuthorizer = class {
|
||||
|
||||
_completeAuth() {
|
||||
if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
|
||||
this._accuracyLevel = clamp(this._accuracyLevel,
|
||||
0,
|
||||
this._maxAccuracyLevel);
|
||||
this._accuracyLevel = Math.clamp(this._accuracyLevel,
|
||||
0, this._maxAccuracyLevel);
|
||||
}
|
||||
this._saveToPermissionStore();
|
||||
|
||||
|
@ -716,8 +716,7 @@ class NMWirelessDialog extends ModalDialog.ModalDialog {
|
||||
|
||||
let connections = client.get_connections();
|
||||
this._connections = connections.filter(
|
||||
connection => device.connection_valid(connection)
|
||||
);
|
||||
connection => device.connection_valid(connection));
|
||||
|
||||
this._apAddedId = device.connect('access-point-added', this._accessPointAdded.bind(this));
|
||||
this._apRemovedId = device.connect('access-point-removed', this._accessPointRemoved.bind(this));
|
||||
@ -1863,8 +1862,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
_syncVpnConnections() {
|
||||
let activeConnections = this._client.get_active_connections() || [];
|
||||
let vpnConnections = activeConnections.filter(
|
||||
a => a instanceof NM.VpnConnection
|
||||
);
|
||||
a => a instanceof NM.VpnConnection);
|
||||
vpnConnections.forEach(a => {
|
||||
ensureActiveConnectionProps(a);
|
||||
});
|
||||
|
@ -112,12 +112,12 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
let chargingState = this._proxy.State == UPower.DeviceState.CHARGING
|
||||
? '-charging' : '';
|
||||
let fillLevel = 10 * Math.floor(this._proxy.Percentage / 10);
|
||||
let icon;
|
||||
if (this._proxy.State == UPower.DeviceState.FULLY_CHARGED ||
|
||||
fillLevel === 100)
|
||||
icon = 'battery-level-100-charged-symbolic';
|
||||
else
|
||||
icon = 'battery-level-%d%s-symbolic'.format(fillLevel, chargingState);
|
||||
const charged =
|
||||
this._proxy.State === UPower.DeviceState.FULLY_CHARGED ||
|
||||
(this._proxy.State === UPower.DeviceState.CHARGING && fillLevel === 100);
|
||||
const icon = charged
|
||||
? 'battery-level-100-charged-symbolic'
|
||||
: 'battery-level-%d%s-symbolic'.format(fillLevel, chargingState);
|
||||
|
||||
// Make sure we fall back to fallback-icon-name and not GThemedIcon's
|
||||
// default fallbacks
|
||||
@ -139,7 +139,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
label = _("%d\u2009%%").format(100);
|
||||
else
|
||||
label = _("%d\u2009%%").format(this._proxy.Percentage);
|
||||
this._percentageLabel.clutter_text.set_markup('<span size="smaller">' + label + '</span>');
|
||||
this._percentageLabel.text = label;
|
||||
|
||||
// The status label
|
||||
this._item.label.text = this._getStatus();
|
||||
|
@ -11,8 +11,7 @@ class RemoteAccessApplet extends PanelMenu.SystemIndicator {
|
||||
_init() {
|
||||
super._init();
|
||||
|
||||
let backend = Meta.get_backend();
|
||||
let controller = backend.get_remote_access_controller();
|
||||
let controller = global.backend.get_remote_access_controller();
|
||||
|
||||
if (!controller)
|
||||
return;
|
||||
|
@ -82,8 +82,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
||||
});
|
||||
|
||||
let app = this._settingsApp = Shell.AppSystem.get_default().lookup_app(
|
||||
'gnome-control-center.desktop'
|
||||
);
|
||||
'gnome-control-center.desktop');
|
||||
if (app) {
|
||||
let [icon, name] = [app.app_info.get_icon().names[0],
|
||||
app.get_name()];
|
||||
|
@ -56,6 +56,9 @@ var StreamSlider = class {
|
||||
this.item.connect('key-press-event', (actor, event) => {
|
||||
return this._slider.emit('key-press-event', event);
|
||||
});
|
||||
this.item.connect('scroll-event', (actor, event) => {
|
||||
return this._slider.emit('scroll-event', event);
|
||||
});
|
||||
|
||||
this._stream = null;
|
||||
this._volumeCancellable = null;
|
||||
|
@ -28,10 +28,6 @@ const State = {
|
||||
SCROLLING: 1,
|
||||
};
|
||||
|
||||
function clamp(value, min, max) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
|
||||
const TouchpadSwipeGesture = GObject.registerClass({
|
||||
Properties: {
|
||||
'enabled': GObject.ParamSpec.boolean(
|
||||
@ -558,8 +554,8 @@ var SwipeTracker = GObject.registerClass({
|
||||
|
||||
let firstPoint = this._snapPoints[0];
|
||||
let lastPoint = this._snapPoints[this._snapPoints.length - 1];
|
||||
this._progress = clamp(this._progress, firstPoint, lastPoint);
|
||||
this._progress = clamp(this._progress,
|
||||
this._progress = Math.clamp(this._progress, firstPoint, lastPoint);
|
||||
this._progress = Math.clamp(this._progress,
|
||||
this._initialProgress - 1, this._initialProgress + 1);
|
||||
|
||||
this.emit('update', this._progress);
|
||||
@ -606,7 +602,7 @@ var SwipeTracker = GObject.registerClass({
|
||||
|
||||
let duration = Math.abs((this._progress - endProgress) / velocity * DURATION_MULTIPLIER);
|
||||
if (duration > 0) {
|
||||
duration = clamp(duration,
|
||||
duration = Math.clamp(duration,
|
||||
MIN_ANIMATION_DURATION, MAX_ANIMATION_DURATION);
|
||||
}
|
||||
|
||||
|
@ -66,8 +66,8 @@ var SwitcherPopup = GObject.registerClass({
|
||||
this._disableHover();
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let primary = Main.layoutManager.primaryMonitor;
|
||||
@ -84,7 +84,7 @@ var SwitcherPopup = GObject.registerClass({
|
||||
childBox.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
|
||||
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
|
||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||
this._switcherList.allocate(childBox, flags);
|
||||
this._switcherList.allocate(childBox);
|
||||
}
|
||||
|
||||
_initialSelection(backward, _binding) {
|
||||
@ -317,7 +317,7 @@ var SwitcherPopup = GObject.registerClass({
|
||||
this.ease({
|
||||
opacity: 0,
|
||||
duration: POPUP_FADE_OUT_TIME,
|
||||
mode: Clutter.Animation.EASE_OUT_QUAD,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => this.destroy(),
|
||||
});
|
||||
} else {
|
||||
@ -591,8 +591,8 @@ var SwitcherList = GObject.registerClass({
|
||||
return themeNode.adjust_preferred_height(maxChildMin, maxChildNat);
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
let contentBox = this.get_theme_node().get_content_box(box);
|
||||
let width = contentBox.x2 - contentBox.x1;
|
||||
@ -606,7 +606,7 @@ var SwitcherList = GObject.registerClass({
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let scrollable = minListWidth > width;
|
||||
|
||||
this._scrollView.allocate(contentBox, flags);
|
||||
this._scrollView.allocate(contentBox);
|
||||
|
||||
let arrowWidth = Math.floor(leftPadding / 3);
|
||||
let arrowHeight = arrowWidth * 2;
|
||||
@ -614,7 +614,7 @@ var SwitcherList = GObject.registerClass({
|
||||
childBox.y1 = this.height / 2 - arrowWidth;
|
||||
childBox.x2 = childBox.x1 + arrowWidth;
|
||||
childBox.y2 = childBox.y1 + arrowHeight;
|
||||
this._leftArrow.allocate(childBox, flags);
|
||||
this._leftArrow.allocate(childBox);
|
||||
this._leftArrow.opacity = this._scrollableLeft && scrollable ? 255 : 0;
|
||||
|
||||
arrowWidth = Math.floor(rightPadding / 3);
|
||||
@ -623,7 +623,7 @@ var SwitcherList = GObject.registerClass({
|
||||
childBox.y1 = this.height / 2 - arrowWidth;
|
||||
childBox.x2 = childBox.x1 + arrowWidth;
|
||||
childBox.y2 = childBox.y1 + arrowHeight;
|
||||
this._rightArrow.allocate(childBox, flags);
|
||||
this._rightArrow.allocate(childBox);
|
||||
this._rightArrow.opacity = this._scrollableRight && scrollable ? 255 : 0;
|
||||
}
|
||||
});
|
||||
|
228
js/ui/tweener.js
228
js/ui/tweener.js
@ -1,228 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported init, addCaller, addTween, getTweenCount, removeTweens,
|
||||
pauseTweens, resumeTweens, registerSpecialProperty,
|
||||
registerSpecialPropertyModifier, registerSpecialPropertySplitter */
|
||||
|
||||
const { Clutter, GLib, Shell } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
const Tweener = imports.tweener.tweener;
|
||||
|
||||
const { adjustAnimationTime } = imports.ui.environment;
|
||||
|
||||
// This is a wrapper around imports.tweener.tweener that adds a bit of
|
||||
// Clutter integration. If the tweening target is a Clutter.Actor, then
|
||||
// the tweenings will automatically be removed if the actor is destroyed.
|
||||
|
||||
// ActionScript Tweener methods that imports.tweener.tweener doesn't
|
||||
// currently implement: getTweens, getVersion, registerTransition,
|
||||
// setTimeScale, updateTime.
|
||||
|
||||
// imports.tweener.tweener methods that we don't re-export:
|
||||
// pauseAllTweens, removeAllTweens, resumeAllTweens. (It would be hard
|
||||
// to clean up properly after removeAllTweens, and also, any code that
|
||||
// calls any of these is almost certainly wrong anyway, because they
|
||||
// affect the entire application.)
|
||||
|
||||
// Called from Main.start
|
||||
function init() {
|
||||
Tweener.setFrameTicker(new ClutterFrameTicker());
|
||||
}
|
||||
|
||||
|
||||
function addCaller(target, tweeningParameters) {
|
||||
_wrapTweening(target, tweeningParameters);
|
||||
Tweener.addCaller(target, tweeningParameters);
|
||||
}
|
||||
|
||||
function addTween(target, tweeningParameters) {
|
||||
_wrapTweening(target, tweeningParameters);
|
||||
Tweener.addTween(target, tweeningParameters);
|
||||
}
|
||||
|
||||
function _wrapTweening(target, tweeningParameters) {
|
||||
let state = _getTweenState(target);
|
||||
|
||||
if (!state.destroyedId) {
|
||||
if (target instanceof Clutter.Actor) {
|
||||
state.actor = target;
|
||||
state.destroyedId = target.connect('destroy', _actorDestroyed);
|
||||
} else if (target.actor && target.actor instanceof Clutter.Actor) {
|
||||
state.actor = target.actor;
|
||||
state.destroyedId = target.actor.connect('destroy', () => _actorDestroyed(target));
|
||||
}
|
||||
}
|
||||
|
||||
let { time, delay } = tweeningParameters;
|
||||
if (!isNaN(time))
|
||||
tweeningParameters['time'] = adjustAnimationTime(1000 * time) / 1000;
|
||||
if (!isNaN(delay))
|
||||
tweeningParameters['delay'] = adjustAnimationTime(1000 * delay) / 1000;
|
||||
|
||||
_addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted);
|
||||
}
|
||||
|
||||
function _getTweenState(target) {
|
||||
// If we were paranoid, we could keep a plist mapping targets to
|
||||
// states... but we're not that paranoid.
|
||||
if (!target.__ShellTweenerState)
|
||||
target.__ShellTweenerState = {};
|
||||
return target.__ShellTweenerState;
|
||||
}
|
||||
|
||||
function _resetTweenState(target) {
|
||||
let state = target.__ShellTweenerState;
|
||||
|
||||
if (state) {
|
||||
if (state.destroyedId)
|
||||
state.actor.disconnect(state.destroyedId);
|
||||
}
|
||||
|
||||
target.__ShellTweenerState = {};
|
||||
}
|
||||
|
||||
function _addHandler(target, params, name, handler) {
|
||||
if (params[name]) {
|
||||
let oldHandler = params[name];
|
||||
let oldScope = params[`${name}Scope`];
|
||||
let oldParams = params[`${name}Params`];
|
||||
let eventScope = oldScope ? oldScope : target;
|
||||
|
||||
params[name] = () => {
|
||||
oldHandler.apply(eventScope, oldParams);
|
||||
handler(target);
|
||||
};
|
||||
} else {
|
||||
params[name] = () => handler(target);
|
||||
}
|
||||
}
|
||||
|
||||
function _actorDestroyed(target) {
|
||||
_resetTweenState(target);
|
||||
Tweener.removeTweens(target);
|
||||
}
|
||||
|
||||
function _tweenCompleted(target) {
|
||||
if (!isTweening(target))
|
||||
_resetTweenState(target);
|
||||
}
|
||||
|
||||
function getTweenCount(scope) {
|
||||
return Tweener.getTweenCount(scope);
|
||||
}
|
||||
|
||||
// imports.tweener.tweener doesn't provide this method (which exists
|
||||
// in the ActionScript version) but it's easy to implement.
|
||||
function isTweening(scope) {
|
||||
return Tweener.getTweenCount(scope) != 0;
|
||||
}
|
||||
|
||||
function removeTweens(...args) {
|
||||
if (Tweener.removeTweens(args)) {
|
||||
let [scope] = args;
|
||||
// If we just removed the last active tween, clean up
|
||||
if (Tweener.getTweenCount(scope) == 0)
|
||||
_tweenCompleted(scope);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function pauseTweens(...args) {
|
||||
return Tweener.pauseTweens(...args);
|
||||
}
|
||||
|
||||
function resumeTweens(...args) {
|
||||
return Tweener.resumeTweens(...args);
|
||||
}
|
||||
|
||||
|
||||
function registerSpecialProperty(...args) {
|
||||
Tweener.registerSpecialProperty(...args);
|
||||
}
|
||||
|
||||
function registerSpecialPropertyModifier(name, modifyFunction, getFunction) {
|
||||
Tweener.registerSpecialPropertyModifier(name, modifyFunction, getFunction);
|
||||
}
|
||||
|
||||
function registerSpecialPropertySplitter(name, splitFunction, parameters) {
|
||||
Tweener.registerSpecialPropertySplitter(name, splitFunction, parameters);
|
||||
}
|
||||
|
||||
|
||||
// The 'FrameTicker' object is an object used to feed new frames to
|
||||
// Tweener so it can update values and redraw. The default frame
|
||||
// ticker for Tweener just uses a simple timeout at a fixed frame rate
|
||||
// and has no idea of "catching up" by dropping frames.
|
||||
//
|
||||
// We substitute it with custom frame ticker here that connects
|
||||
// Tweener to a Clutter.TimeLine. Now, Clutter.Timeline itself isn't a
|
||||
// whole lot more sophisticated than a simple timeout at a fixed frame
|
||||
// rate, but at least it knows how to drop frames. (See
|
||||
// HippoAnimationManager for a more sophisticated view of continuous
|
||||
// time updates; even better is to pay attention to the vertical
|
||||
// vblank and sync to that when possible.)
|
||||
//
|
||||
var ClutterFrameTicker = class {
|
||||
constructor() {
|
||||
// We don't have a finite duration; tweener will tell us to stop
|
||||
// when we need to stop, so use 1000 seconds as "infinity", and
|
||||
// set the timeline to loop. Doing this means we have to track
|
||||
// time ourselves, since clutter timeline's time will cycle
|
||||
// instead of strictly increase.
|
||||
this._timeline = new Clutter.Timeline({ duration: 1000 * 1000 });
|
||||
this._timeline.set_loop(true);
|
||||
this._startTime = -1;
|
||||
this._currentTime = -1;
|
||||
|
||||
this._timeline.connect('new-frame', () => {
|
||||
this._onNewFrame();
|
||||
});
|
||||
|
||||
let perfLog = Shell.PerfLog.get_default();
|
||||
perfLog.define_event("tweener.framePrepareStart",
|
||||
"Start of a new animation frame",
|
||||
"");
|
||||
perfLog.define_event("tweener.framePrepareDone",
|
||||
"Finished preparing frame",
|
||||
"");
|
||||
}
|
||||
|
||||
get FRAME_RATE() {
|
||||
return 60;
|
||||
}
|
||||
|
||||
_onNewFrame() {
|
||||
// If there is a lot of setup to start the animation, then
|
||||
// first frame number we get from clutter might be a long ways
|
||||
// into the animation (or the animation might even be done).
|
||||
// That looks bad, so we always start at the first frame of the
|
||||
// animation then only do frame dropping from there.
|
||||
if (this._startTime < 0)
|
||||
this._startTime = GLib.get_monotonic_time() / 1000.0;
|
||||
|
||||
// currentTime is in milliseconds
|
||||
let perfLog = Shell.PerfLog.get_default();
|
||||
this._currentTime = GLib.get_monotonic_time() / 1000.0 - this._startTime;
|
||||
perfLog.event("tweener.framePrepareStart");
|
||||
this.emit('prepare-frame');
|
||||
perfLog.event("tweener.framePrepareDone");
|
||||
}
|
||||
|
||||
getTime() {
|
||||
return this._currentTime;
|
||||
}
|
||||
|
||||
start() {
|
||||
this._timeline.start();
|
||||
global.begin_work();
|
||||
}
|
||||
|
||||
stop() {
|
||||
this._timeline.stop();
|
||||
this._startTime = -1;
|
||||
this._currentTime = -1;
|
||||
global.end_work();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(ClutterFrameTicker.prototype);
|
@ -405,7 +405,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
|
||||
return this._stack.get_preferred_height(forWidth);
|
||||
}
|
||||
|
||||
vfunc_allocate(container, box, flags) {
|
||||
vfunc_allocate(container, box) {
|
||||
let [width, height] = box.get_size();
|
||||
|
||||
let tenthOfHeight = height / 10.0;
|
||||
@ -432,7 +432,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
|
||||
actorBox.x2 = columnX1 + columnWidth;
|
||||
actorBox.y2 = actorBox.y1 + maxNotificationsHeight;
|
||||
|
||||
this._notifications.allocate(actorBox, flags);
|
||||
this._notifications.allocate(actorBox);
|
||||
|
||||
// Authentication Box
|
||||
let stackY = Math.min(
|
||||
@ -444,7 +444,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
|
||||
actorBox.x2 = columnX1 + columnWidth;
|
||||
actorBox.y2 = stackY + stackHeight;
|
||||
|
||||
this._stack.allocate(actorBox, flags);
|
||||
this._stack.allocate(actorBox);
|
||||
|
||||
// Switch User button
|
||||
if (this._switchUserButton.visible) {
|
||||
@ -461,7 +461,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
|
||||
actorBox.x2 = actorBox.x1 + natWidth;
|
||||
actorBox.y2 = actorBox.y1 + natHeight;
|
||||
|
||||
this._switchUserButton.allocate(actorBox, flags);
|
||||
this._switchUserButton.allocate(actorBox);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -566,9 +566,17 @@ var UnlockDialog = GObject.registerClass({
|
||||
this._otherUserButton.set_pivot_point(0.5, 0.5);
|
||||
this._otherUserButton.connect('clicked', this._otherUserClicked.bind(this));
|
||||
|
||||
let screenSaverSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.screensaver' });
|
||||
screenSaverSettings.bind('user-switch-enabled',
|
||||
this._otherUserButton, 'visible', Gio.SettingsBindFlags.GET);
|
||||
this._screenSaverSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.screensaver' });
|
||||
|
||||
this._userSwitchEnabledId = 0;
|
||||
this._userSwitchEnabledId = this._screenSaverSettings.connect('changed::user-switch-enabled',
|
||||
this._updateUserSwitchVisibility.bind(this));
|
||||
|
||||
this._userLoadedId = 0;
|
||||
this._userLoadedId = this._user.connect('notify::is-loaded',
|
||||
this._updateUserSwitchVisibility.bind(this));
|
||||
|
||||
this._updateUserSwitchVisibility();
|
||||
|
||||
// Main Box
|
||||
let mainBox = new St.Widget();
|
||||
@ -605,7 +613,7 @@ var UnlockDialog = GObject.registerClass({
|
||||
this._showPrompt();
|
||||
|
||||
if (GLib.unichar_isgraph(unichar))
|
||||
this.addCharacter(unichar);
|
||||
this._authPrompt.addCharacter(unichar);
|
||||
|
||||
return Clutter.EVENT_PROPAGATE;
|
||||
}
|
||||
@ -828,6 +836,21 @@ var UnlockDialog = GObject.registerClass({
|
||||
this._gdmClient = null;
|
||||
delete this._gdmClient;
|
||||
}
|
||||
|
||||
if (this._userLoadedId) {
|
||||
this._user.disconnect(this._userLoadedId);
|
||||
this._userLoadedId = 0;
|
||||
}
|
||||
|
||||
if (this._userSwitchEnabledId) {
|
||||
this._screenSaverSettings.disconnect(this._userSwitchEnabledId);
|
||||
this._userSwitchEnabledId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
_updateUserSwitchVisibility() {
|
||||
this._otherUserButton.visible = this._userManager.can_switch() &&
|
||||
this._screenSaverSettings.get_boolean('user-switch-enabled');
|
||||
}
|
||||
|
||||
cancel() {
|
||||
@ -835,11 +858,6 @@ var UnlockDialog = GObject.registerClass({
|
||||
this._authPrompt.cancel();
|
||||
}
|
||||
|
||||
addCharacter(unichar) {
|
||||
this._showPrompt();
|
||||
this._authPrompt.addCharacter(unichar);
|
||||
}
|
||||
|
||||
finish(onComplete) {
|
||||
this._ensureAuthPrompt();
|
||||
this._authPrompt.finish(onComplete);
|
||||
|
@ -144,8 +144,8 @@ class UserWidgetLabel extends St.Widget {
|
||||
}
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
@ -164,7 +164,7 @@ class UserWidgetLabel extends St.Widget {
|
||||
childBox.x2 = availWidth;
|
||||
childBox.y2 = availHeight;
|
||||
|
||||
this._currentLabel.allocate(childBox, flags);
|
||||
this._currentLabel.allocate(childBox);
|
||||
}
|
||||
|
||||
vfunc_paint(paintContext) {
|
||||
|
@ -132,6 +132,7 @@ var ViewSelector = GObject.registerClass({
|
||||
super._init({
|
||||
name: 'viewSelector',
|
||||
x_expand: true,
|
||||
visible: false,
|
||||
});
|
||||
|
||||
this._showAppsButton = showAppsButton;
|
||||
@ -271,9 +272,10 @@ var ViewSelector = GObject.registerClass({
|
||||
Main.overview.show();
|
||||
}
|
||||
|
||||
show() {
|
||||
animateToOverview() {
|
||||
this.show();
|
||||
this.reset();
|
||||
this._workspacesDisplay.show(this._showAppsButton.checked);
|
||||
this._workspacesDisplay.animateToOverview(this._showAppsButton.checked);
|
||||
this._activePage = null;
|
||||
if (this._showAppsButton.checked)
|
||||
this._showPage(this._appsPage);
|
||||
@ -301,9 +303,11 @@ var ViewSelector = GObject.registerClass({
|
||||
this._workspacesDisplay.setWorkspacesFullGeometry(geom);
|
||||
}
|
||||
|
||||
hide() {
|
||||
vfunc_hide() {
|
||||
this.reset();
|
||||
this._workspacesDisplay.hide();
|
||||
|
||||
super.vfunc_hide();
|
||||
}
|
||||
|
||||
_addPage(actor, name, a11yIcon, params) {
|
||||
|
@ -82,8 +82,10 @@ class DisplayChangeDialog extends ModalDialog.ModalDialog {
|
||||
}
|
||||
|
||||
_formatCountDown() {
|
||||
let fmt = ngettext("Settings changes will revert in %d second",
|
||||
"Settings changes will revert in %d seconds");
|
||||
const fmt = ngettext(
|
||||
'Settings changes will revert in %d second',
|
||||
'Settings changes will revert in %d seconds',
|
||||
this._countDown);
|
||||
return fmt.format(this._countDown);
|
||||
}
|
||||
|
||||
@ -898,35 +900,47 @@ var WindowManager = class {
|
||||
|
||||
global.display.connect('init-xserver', (display, task) => {
|
||||
IBusManager.getIBusManager().restartDaemon(['--xim']);
|
||||
Shell.util_start_systemd_unit('gsd-xsettings.target', 'fail');
|
||||
|
||||
/* Leave this watchdog timeout so don't block indefinitely here */
|
||||
let timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, () => {
|
||||
Gio.DBus.session.unwatch_name(watchId);
|
||||
log('Warning: Failed to start gsd-xsettings');
|
||||
task.return_boolean(true);
|
||||
timeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
try {
|
||||
if (!Shell.util_start_systemd_unit('gsd-xsettings.target', 'fail'))
|
||||
log('Not starting gsd-xsettings; waiting for gnome-session to do so');
|
||||
|
||||
/* When gsd-xsettings daemon is started, we are good to resume */
|
||||
let watchId = Gio.DBus.session.watch_name(
|
||||
'org.gnome.SettingsDaemon.XSettings',
|
||||
Gio.BusNameWatcherFlags.NONE,
|
||||
() => {
|
||||
/* Leave this watchdog timeout so don't block indefinitely here */
|
||||
let timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, () => {
|
||||
Gio.DBus.session.unwatch_name(watchId);
|
||||
if (timeoutId > 0) {
|
||||
task.return_boolean(true);
|
||||
GLib.source_remove(timeoutId);
|
||||
}
|
||||
},
|
||||
null);
|
||||
log('Warning: Failed to start gsd-xsettings');
|
||||
task.return_boolean(true);
|
||||
timeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
|
||||
/* When gsd-xsettings daemon is started, we are good to resume */
|
||||
let watchId = Gio.DBus.session.watch_name(
|
||||
'org.gnome.SettingsDaemon.XSettings',
|
||||
Gio.BusNameWatcherFlags.NONE,
|
||||
() => {
|
||||
Gio.DBus.session.unwatch_name(watchId);
|
||||
if (timeoutId > 0) {
|
||||
task.return_boolean(true);
|
||||
GLib.source_remove(timeoutId);
|
||||
}
|
||||
},
|
||||
null);
|
||||
} catch (e) {
|
||||
log('Error starting gsd-xsettings: %s'.format(e.message));
|
||||
task.return_boolean(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
global.display.connect('x11-display-closing', () => {
|
||||
if (!Meta.is_wayland_compositor())
|
||||
return;
|
||||
Shell.util_stop_systemd_unit('gsd-xsettings.target', 'fail');
|
||||
try {
|
||||
Shell.util_stop_systemd_unit('gsd-xsettings.target', 'fail');
|
||||
} catch (e) {
|
||||
log('Error stopping gsd-xsettings: %s'.format(e.message));
|
||||
}
|
||||
IBusManager.getIBusManager().restartDaemon();
|
||||
});
|
||||
|
||||
@ -1264,13 +1278,13 @@ var WindowManager = class {
|
||||
}
|
||||
|
||||
_sizeChangeWindow(shellwm, actor, whichChange, oldFrameRect, _oldBufferRect) {
|
||||
let types = [Meta.WindowType.NORMAL];
|
||||
if (!this._shouldAnimateActor(actor, types)) {
|
||||
shellwm.completed_size_change(actor);
|
||||
return;
|
||||
}
|
||||
const types = [Meta.WindowType.NORMAL];
|
||||
const shouldAnimate =
|
||||
this._shouldAnimateActor(actor, types) &&
|
||||
oldFrameRect.width > 0 &&
|
||||
oldFrameRect.height > 0;
|
||||
|
||||
if (oldFrameRect.width > 0 && oldFrameRect.height > 0)
|
||||
if (shouldAnimate)
|
||||
this._prepareAnimationInfo(shellwm, actor, oldFrameRect, whichChange);
|
||||
else
|
||||
shellwm.completed_size_change(actor);
|
||||
@ -1285,17 +1299,24 @@ var WindowManager = class {
|
||||
actorClone.set_position(oldFrameRect.x, oldFrameRect.y);
|
||||
actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
|
||||
|
||||
if (this._clearAnimationInfo(actor))
|
||||
actor.freeze();
|
||||
|
||||
if (this._clearAnimationInfo(actor)) {
|
||||
log('Old animationInfo removed from actor %s'.format(actor));
|
||||
this._shellwm.completed_size_change(actor);
|
||||
}
|
||||
|
||||
let destroyId = actor.connect('destroy', () => {
|
||||
this._clearAnimationInfo(actor);
|
||||
});
|
||||
|
||||
this._resizePending.add(actor);
|
||||
actor.__animationInfo = { clone: actorClone,
|
||||
oldRect: oldFrameRect,
|
||||
destroyId };
|
||||
actor.__animationInfo = {
|
||||
clone: actorClone,
|
||||
oldRect: oldFrameRect,
|
||||
frozen: true,
|
||||
destroyId,
|
||||
};
|
||||
}
|
||||
|
||||
_sizeChangedWindow(shellwm, actor) {
|
||||
@ -1348,13 +1369,17 @@ var WindowManager = class {
|
||||
// Now unfreeze actor updates, to get it to the new size.
|
||||
// It's important that we don't wait until the animation is completed to
|
||||
// do this, otherwise our scale will be applied to the old texture size.
|
||||
shellwm.completed_size_change(actor);
|
||||
actor.thaw();
|
||||
actor.__animationInfo.frozen = false;
|
||||
}
|
||||
|
||||
_clearAnimationInfo(actor) {
|
||||
if (actor.__animationInfo) {
|
||||
actor.__animationInfo.clone.destroy();
|
||||
actor.disconnect(actor.__animationInfo.destroyId);
|
||||
if (actor.__animationInfo.frozen)
|
||||
actor.thaw();
|
||||
|
||||
delete actor.__animationInfo;
|
||||
return true;
|
||||
}
|
||||
@ -1369,10 +1394,13 @@ var WindowManager = class {
|
||||
actor.translation_x = 0;
|
||||
actor.translation_y = 0;
|
||||
this._clearAnimationInfo(actor);
|
||||
this._shellwm.completed_size_change(actor);
|
||||
}
|
||||
|
||||
if (this._resizePending.delete(actor))
|
||||
if (this._resizePending.delete(actor)) {
|
||||
this._clearAnimationInfo(actor);
|
||||
this._shellwm.completed_size_change(actor);
|
||||
}
|
||||
}
|
||||
|
||||
_hasAttachedDialogs(window, ignoreWindow) {
|
||||
@ -2087,8 +2115,16 @@ var WindowManager = class {
|
||||
newWs = workspaceManager.get_workspace_by_index(workspaceManager.n_workspaces - 1);
|
||||
} else if (isNaN(target)) {
|
||||
// Prepend a new workspace dynamically
|
||||
if (workspaceManager.get_active_workspace_index() == 0 &&
|
||||
action == 'move' && target == 'up' && this._isWorkspacePrepended == false) {
|
||||
let prependTarget;
|
||||
if (vertical)
|
||||
prependTarget = 'up';
|
||||
else if (rtl)
|
||||
prependTarget = 'right';
|
||||
else
|
||||
prependTarget = 'left';
|
||||
if (workspaceManager.get_active_workspace_index() === 0 &&
|
||||
action === 'move' && target === prependTarget &&
|
||||
this._isWorkspacePrepended === false) {
|
||||
this.insertWorkspace(0);
|
||||
this._isWorkspacePrepended = true;
|
||||
}
|
||||
|
736
js/ui/windowPreview.js
Normal file
736
js/ui/windowPreview.js
Normal file
@ -0,0 +1,736 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
/* exported WindowPreview */
|
||||
|
||||
const { Atk, Clutter, GLib, GObject,
|
||||
Graphene, Meta, Pango, Shell, St } = imports.gi;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
|
||||
var WINDOW_DND_SIZE = 256;
|
||||
|
||||
var WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 750;
|
||||
var WINDOW_OVERLAY_FADE_TIME = 200;
|
||||
|
||||
var DRAGGING_WINDOW_OPACITY = 100;
|
||||
|
||||
var WindowPreviewLayout = GObject.registerClass({
|
||||
Properties: {
|
||||
'bounding-box': GObject.ParamSpec.boxed(
|
||||
'bounding-box', 'Bounding box', 'Bounding box',
|
||||
GObject.ParamFlags.READABLE,
|
||||
Clutter.ActorBox.$gtype),
|
||||
},
|
||||
}, class WindowPreviewLayout extends Clutter.LayoutManager {
|
||||
_init() {
|
||||
super._init();
|
||||
|
||||
this._container = null;
|
||||
this._boundingBox = new Clutter.ActorBox();
|
||||
this._windows = new Map();
|
||||
}
|
||||
|
||||
_layoutChanged() {
|
||||
let frameRect;
|
||||
|
||||
for (const windowInfo of this._windows.values()) {
|
||||
const frame = windowInfo.metaWindow.get_frame_rect();
|
||||
frameRect = frameRect ? frameRect.union(frame) : frame;
|
||||
}
|
||||
|
||||
if (!frameRect)
|
||||
frameRect = new Meta.Rectangle();
|
||||
|
||||
const oldBox = this._boundingBox.copy();
|
||||
this._boundingBox.set_origin(frameRect.x, frameRect.y);
|
||||
this._boundingBox.set_size(frameRect.width, frameRect.height);
|
||||
|
||||
if (!this._boundingBox.equal(oldBox))
|
||||
this.notify('bounding-box');
|
||||
|
||||
// Always call layout_changed(), a size or position change of an
|
||||
// attached dialog might not affect the boundingBox
|
||||
this.layout_changed();
|
||||
}
|
||||
|
||||
vfunc_set_container(container) {
|
||||
this._container = container;
|
||||
}
|
||||
|
||||
vfunc_get_preferred_height(_container, _forWidth) {
|
||||
return [0, this._boundingBox.get_height()];
|
||||
}
|
||||
|
||||
vfunc_get_preferred_width(_container, _forHeight) {
|
||||
return [0, this._boundingBox.get_width()];
|
||||
}
|
||||
|
||||
vfunc_allocate(container, box) {
|
||||
// If the scale isn't 1, we weren't allocated our preferred size
|
||||
// and have to scale the children allocations accordingly.
|
||||
const scaleX = box.get_width() / this._boundingBox.get_width();
|
||||
const scaleY = box.get_height() / this._boundingBox.get_height();
|
||||
|
||||
const childBox = new Clutter.ActorBox();
|
||||
|
||||
for (const child of container) {
|
||||
if (!child.visible)
|
||||
continue;
|
||||
|
||||
const windowInfo = this._windows.get(child);
|
||||
if (windowInfo) {
|
||||
const bufferRect = windowInfo.metaWindow.get_buffer_rect();
|
||||
childBox.set_origin(
|
||||
bufferRect.x - this._boundingBox.x1,
|
||||
bufferRect.y - this._boundingBox.y1);
|
||||
|
||||
const [, , natWidth, natHeight] = child.get_preferred_size();
|
||||
childBox.set_size(natWidth, natHeight);
|
||||
|
||||
childBox.x1 *= scaleX;
|
||||
childBox.x2 *= scaleX;
|
||||
childBox.y1 *= scaleY;
|
||||
childBox.y2 *= scaleY;
|
||||
|
||||
child.allocate(childBox);
|
||||
} else {
|
||||
child.allocate_preferred_size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* addWindow:
|
||||
* @param {Meta.Window} window: the MetaWindow instance
|
||||
*
|
||||
* Creates a ClutterActor drawing the texture of @window and adds it
|
||||
* to the container. If @window is already part of the preview, this
|
||||
* function will do nothing.
|
||||
*
|
||||
* @returns {Clutter.Actor} The newly created actor drawing @window
|
||||
*/
|
||||
addWindow(window) {
|
||||
const index = [...this._windows.values()].findIndex(info =>
|
||||
info.metaWindow === window);
|
||||
|
||||
if (index !== -1)
|
||||
return null;
|
||||
|
||||
const windowActor = window.get_compositor_private();
|
||||
const actor = new Clutter.Clone({ source: windowActor });
|
||||
|
||||
this._windows.set(actor, {
|
||||
metaWindow: window,
|
||||
windowActor,
|
||||
sizeChangedId: window.connect('size-changed', () =>
|
||||
this._layoutChanged()),
|
||||
positionChangedId: window.connect('position-changed', () =>
|
||||
this._layoutChanged()),
|
||||
windowActorDestroyId: windowActor.connect('destroy', () =>
|
||||
actor.destroy()),
|
||||
destroyId: actor.connect('destroy', () =>
|
||||
this.removeWindow(window)),
|
||||
});
|
||||
|
||||
this._container.add_child(actor);
|
||||
|
||||
this._layoutChanged();
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
/**
|
||||
* removeWindow:
|
||||
* @param {Meta.Window} window: the window to remove from the preview
|
||||
*
|
||||
* Removes a MetaWindow @window from the preview which has been added
|
||||
* previously using addWindow(). If @window is not part of preview,
|
||||
* this function will do nothing.
|
||||
*/
|
||||
removeWindow(window) {
|
||||
const entry = [...this._windows].find(
|
||||
([, i]) => i.metaWindow === window);
|
||||
|
||||
if (!entry)
|
||||
return;
|
||||
|
||||
const [actor, windowInfo] = entry;
|
||||
|
||||
windowInfo.metaWindow.disconnect(windowInfo.sizeChangedId);
|
||||
windowInfo.metaWindow.disconnect(windowInfo.positionChangedId);
|
||||
windowInfo.windowActor.disconnect(windowInfo.windowActorDestroyId);
|
||||
actor.disconnect(windowInfo.destroyId);
|
||||
|
||||
this._windows.delete(actor);
|
||||
this._container.remove_child(actor);
|
||||
|
||||
this._layoutChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* getWindows:
|
||||
*
|
||||
* Gets an array of all MetaWindows that were added to the layout
|
||||
* using addWindow(), ordered by the insertion order.
|
||||
*
|
||||
* @returns {Array} An array including all windows
|
||||
*/
|
||||
getWindows() {
|
||||
return [...this._windows.values()].map(i => i.metaWindow);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
get bounding_box() {
|
||||
return this._boundingBox;
|
||||
}
|
||||
});
|
||||
|
||||
var WindowPreview = GObject.registerClass({
|
||||
Signals: {
|
||||
'drag-begin': {},
|
||||
'drag-cancelled': {},
|
||||
'drag-end': {},
|
||||
'selected': { param_types: [GObject.TYPE_UINT] },
|
||||
'show-chrome': {},
|
||||
'size-changed': {},
|
||||
},
|
||||
}, class WindowPreview extends St.Widget {
|
||||
_init(metaWindow, workspace) {
|
||||
this.metaWindow = metaWindow;
|
||||
this.metaWindow._delegate = this;
|
||||
this._windowActor = metaWindow.get_compositor_private();
|
||||
this._workspace = workspace;
|
||||
|
||||
super._init({
|
||||
reactive: true,
|
||||
can_focus: true,
|
||||
accessible_role: Atk.Role.PUSH_BUTTON,
|
||||
offscreen_redirect: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY,
|
||||
});
|
||||
|
||||
this._windowContainer = new Clutter.Actor();
|
||||
// gjs currently can't handle setting an actors layout manager during
|
||||
// the initialization of the actor if that layout manager keeps track
|
||||
// of its container, so set the layout manager after creating the
|
||||
// container
|
||||
this._windowContainer.layout_manager = new WindowPreviewLayout();
|
||||
this.add_child(this._windowContainer);
|
||||
|
||||
this._addWindow(metaWindow);
|
||||
|
||||
this._delegate = this;
|
||||
|
||||
this.slotId = 0;
|
||||
this._stackAbove = null;
|
||||
|
||||
this._windowContainer.layout_manager.connect(
|
||||
'notify::bounding-box', layout => {
|
||||
// A bounding box of 0x0 means all windows were removed
|
||||
if (layout.bounding_box.get_area() > 0)
|
||||
this.emit('size-changed');
|
||||
});
|
||||
|
||||
this._windowDestroyId =
|
||||
this._windowActor.connect('destroy', () => this.destroy());
|
||||
|
||||
this._updateAttachedDialogs();
|
||||
this.x = this.boundingBox.x;
|
||||
this.y = this.boundingBox.y;
|
||||
|
||||
let clickAction = new Clutter.ClickAction();
|
||||
clickAction.connect('clicked', () => this._activate());
|
||||
clickAction.connect('long-press', this._onLongPress.bind(this));
|
||||
this.add_action(clickAction);
|
||||
this.connect('destroy', this._onDestroy.bind(this));
|
||||
|
||||
this._draggable = DND.makeDraggable(this,
|
||||
{ restoreOnSuccess: true,
|
||||
manualMode: true,
|
||||
dragActorMaxSize: WINDOW_DND_SIZE,
|
||||
dragActorOpacity: DRAGGING_WINDOW_OPACITY });
|
||||
this._draggable.connect('drag-begin', this._onDragBegin.bind(this));
|
||||
this._draggable.connect('drag-cancelled', this._onDragCancelled.bind(this));
|
||||
this._draggable.connect('drag-end', this._onDragEnd.bind(this));
|
||||
this.inDrag = false;
|
||||
|
||||
this._selected = false;
|
||||
this._closeRequested = false;
|
||||
this._idleHideOverlayId = 0;
|
||||
|
||||
this._border = new St.Widget({
|
||||
visible: false,
|
||||
style_class: 'window-clone-border',
|
||||
});
|
||||
this._borderConstraint = new Clutter.BindConstraint({
|
||||
source: this._windowContainer,
|
||||
coordinate: Clutter.BindCoordinate.SIZE,
|
||||
});
|
||||
this._border.add_constraint(this._borderConstraint);
|
||||
this._border.add_constraint(new Clutter.AlignConstraint({
|
||||
source: this._windowContainer,
|
||||
align_axis: Clutter.AlignAxis.BOTH,
|
||||
factor: 0.5,
|
||||
}));
|
||||
this._borderCenter = new Clutter.Actor();
|
||||
this._border.bind_property('visible', this._borderCenter, 'visible',
|
||||
GObject.BindingFlags.SYNC_CREATE);
|
||||
this._borderCenterConstraint = new Clutter.BindConstraint({
|
||||
source: this._windowContainer,
|
||||
coordinate: Clutter.BindCoordinate.SIZE,
|
||||
});
|
||||
this._borderCenter.add_constraint(this._borderCenterConstraint);
|
||||
this._borderCenter.add_constraint(new Clutter.AlignConstraint({
|
||||
source: this._windowContainer,
|
||||
align_axis: Clutter.AlignAxis.BOTH,
|
||||
factor: 0.5,
|
||||
}));
|
||||
this._border.connect('style-changed',
|
||||
this._onBorderStyleChanged.bind(this));
|
||||
|
||||
this._title = new St.Label({
|
||||
visible: false,
|
||||
style_class: 'window-caption',
|
||||
text: this._getCaption(),
|
||||
reactive: true,
|
||||
});
|
||||
this._title.add_constraint(new Clutter.BindConstraint({
|
||||
source: this._borderCenter,
|
||||
coordinate: Clutter.BindCoordinate.POSITION,
|
||||
}));
|
||||
this._title.add_constraint(new Clutter.AlignConstraint({
|
||||
source: this._borderCenter,
|
||||
align_axis: Clutter.AlignAxis.X_AXIS,
|
||||
factor: 0.5,
|
||||
}));
|
||||
this._title.add_constraint(new Clutter.AlignConstraint({
|
||||
source: this._borderCenter,
|
||||
align_axis: Clutter.AlignAxis.Y_AXIS,
|
||||
pivot_point: new Graphene.Point({ x: -1, y: 0.5 }),
|
||||
factor: 1,
|
||||
}));
|
||||
this._title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
||||
this.label_actor = this._title;
|
||||
this._updateCaptionId = this.metaWindow.connect('notify::title', () => {
|
||||
this._title.text = this._getCaption();
|
||||
});
|
||||
|
||||
const layout = Meta.prefs_get_button_layout();
|
||||
this._closeButtonSide =
|
||||
layout.left_buttons.includes(Meta.ButtonFunction.CLOSE)
|
||||
? St.Side.LEFT : St.Side.RIGHT;
|
||||
|
||||
this._closeButton = new St.Button({
|
||||
visible: false,
|
||||
style_class: 'window-close',
|
||||
child: new St.Icon({ icon_name: 'window-close-symbolic' }),
|
||||
});
|
||||
this._closeButton.add_constraint(new Clutter.BindConstraint({
|
||||
source: this._borderCenter,
|
||||
coordinate: Clutter.BindCoordinate.POSITION,
|
||||
}));
|
||||
this._closeButton.add_constraint(new Clutter.AlignConstraint({
|
||||
source: this._borderCenter,
|
||||
align_axis: Clutter.AlignAxis.X_AXIS,
|
||||
pivot_point: new Graphene.Point({ x: 0.5, y: -1 }),
|
||||
factor: this._closeButtonSide === St.Side.LEFT ? 0 : 1,
|
||||
}));
|
||||
this._closeButton.add_constraint(new Clutter.AlignConstraint({
|
||||
source: this._borderCenter,
|
||||
align_axis: Clutter.AlignAxis.Y_AXIS,
|
||||
pivot_point: new Graphene.Point({ x: -1, y: 0.5 }),
|
||||
factor: 0,
|
||||
}));
|
||||
this._closeButton.connect('clicked', () => this._deleteAll());
|
||||
|
||||
this.add_child(this._borderCenter);
|
||||
this.add_child(this._border);
|
||||
this.add_child(this._title);
|
||||
this.add_child(this._closeButton);
|
||||
}
|
||||
|
||||
vfunc_get_preferred_width(forHeight) {
|
||||
const themeNode = this.get_theme_node();
|
||||
|
||||
// Only include window previews in size request, not chrome
|
||||
const [minWidth, natWidth] =
|
||||
this._windowContainer.get_preferred_width(
|
||||
themeNode.adjust_for_height(forHeight));
|
||||
|
||||
return themeNode.adjust_preferred_width(minWidth, natWidth);
|
||||
}
|
||||
|
||||
vfunc_get_preferred_height(forWidth) {
|
||||
const themeNode = this.get_theme_node();
|
||||
const [minHeight, natHeight] =
|
||||
this._windowContainer.get_preferred_height(
|
||||
themeNode.adjust_for_width(forWidth));
|
||||
|
||||
return themeNode.adjust_preferred_height(minHeight, natHeight);
|
||||
}
|
||||
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
for (const child of this)
|
||||
child.allocate_available_size(0, 0, box.get_width(), box.get_height());
|
||||
}
|
||||
|
||||
_onBorderStyleChanged() {
|
||||
let borderNode = this._border.get_theme_node();
|
||||
this._borderSize = borderNode.get_border_width(St.Side.TOP);
|
||||
|
||||
// Increase the size of the border actor so the border outlines
|
||||
// the bounding box
|
||||
this._borderConstraint.offset = this._borderSize * 2;
|
||||
this._borderCenterConstraint.offset = this._borderSize;
|
||||
}
|
||||
|
||||
_windowCanClose() {
|
||||
return this.metaWindow.can_close() &&
|
||||
!this._hasAttachedDialogs();
|
||||
}
|
||||
|
||||
_getCaption() {
|
||||
if (this.metaWindow.title)
|
||||
return this.metaWindow.title;
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let app = tracker.get_window_app(this.metaWindow);
|
||||
return app.get_name();
|
||||
}
|
||||
|
||||
chromeHeights() {
|
||||
this._border.ensure_style();
|
||||
this._title.ensure_style();
|
||||
const [, closeButtonHeight] = this._closeButton.get_preferred_height(-1);
|
||||
const [, titleHeight] = this._title.get_preferred_height(-1);
|
||||
|
||||
const topOversize = (this._borderSize / 2) + (closeButtonHeight / 2);
|
||||
const bottomOversize = Math.max(
|
||||
this._borderSize,
|
||||
(titleHeight / 2) + (this._borderSize / 2));
|
||||
|
||||
return [topOversize, bottomOversize];
|
||||
}
|
||||
|
||||
chromeWidths() {
|
||||
this._border.ensure_style();
|
||||
const [, closeButtonWidth] = this._closeButton.get_preferred_width(-1);
|
||||
|
||||
const leftOversize = this._closeButtonSide === St.Side.LEFT
|
||||
? (this._borderSize / 2) + (closeButtonWidth / 2)
|
||||
: this._borderSize;
|
||||
const rightOversize = this._closeButtonSide === St.Side.LEFT
|
||||
? this._borderSize
|
||||
: (this._borderSize / 2) + (closeButtonWidth / 2);
|
||||
|
||||
return [leftOversize, rightOversize];
|
||||
}
|
||||
|
||||
showOverlay(animate) {
|
||||
const ongoingTransition = this._border.get_transition('opacity');
|
||||
|
||||
// Don't do anything if we're fully visible already
|
||||
if (this._border.visible && !ongoingTransition)
|
||||
return;
|
||||
|
||||
// If we're supposed to animate and an animation in our direction
|
||||
// is already happening, let that one continue
|
||||
if (animate &&
|
||||
ongoingTransition &&
|
||||
ongoingTransition.get_interval().peek_final_value() === 255)
|
||||
return;
|
||||
|
||||
const toShow = this._windowCanClose()
|
||||
? [this._border, this._title, this._closeButton]
|
||||
: [this._border, this._title];
|
||||
|
||||
toShow.forEach(a => {
|
||||
a.opacity = 0;
|
||||
a.show();
|
||||
a.ease({
|
||||
opacity: 255,
|
||||
duration: animate ? WINDOW_OVERLAY_FADE_TIME : 0,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
});
|
||||
});
|
||||
|
||||
this.emit('show-chrome');
|
||||
}
|
||||
|
||||
hideOverlay(animate) {
|
||||
const ongoingTransition = this._border.get_transition('opacity');
|
||||
|
||||
// Don't do anything if we're fully hidden already
|
||||
if (!this._border.visible && !ongoingTransition)
|
||||
return;
|
||||
|
||||
// If we're supposed to animate and an animation in our direction
|
||||
// is already happening, let that one continue
|
||||
if (animate &&
|
||||
ongoingTransition &&
|
||||
ongoingTransition.get_interval().peek_final_value() === 0)
|
||||
return;
|
||||
|
||||
[this._border, this._title, this._closeButton].forEach(a => {
|
||||
a.opacity = 255;
|
||||
a.ease({
|
||||
opacity: 0,
|
||||
duration: animate ? WINDOW_OVERLAY_FADE_TIME : 0,
|
||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||
onComplete: () => a.hide(),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
_addWindow(metaWindow) {
|
||||
const clone = this._windowContainer.layout_manager.addWindow(metaWindow);
|
||||
|
||||
// We expect this to be used for all interaction rather than
|
||||
// the ClutterClone; as the former is reactive and the latter
|
||||
// is not, this just works for most cases. However, for DND all
|
||||
// actors are picked, so DND operations would operate on the clone.
|
||||
// To avoid this, we hide it from pick.
|
||||
Shell.util_set_hidden_from_pick(clone, true);
|
||||
}
|
||||
|
||||
vfunc_has_overlaps() {
|
||||
return this._hasAttachedDialogs();
|
||||
}
|
||||
|
||||
_deleteAll() {
|
||||
const windows = this._windowContainer.layout_manager.getWindows();
|
||||
|
||||
// Delete all windows, starting from the bottom-most (most-modal) one
|
||||
for (const window of windows.reverse())
|
||||
window.delete(global.get_current_time());
|
||||
|
||||
this._closeRequested = true;
|
||||
}
|
||||
|
||||
addDialog(win) {
|
||||
let parent = win.get_transient_for();
|
||||
while (parent.is_attached_dialog())
|
||||
parent = parent.get_transient_for();
|
||||
|
||||
// Display dialog if it is attached to our metaWindow
|
||||
if (win.is_attached_dialog() && parent == this.metaWindow)
|
||||
this._addWindow(win);
|
||||
|
||||
// The dialog popped up after the user tried to close the window,
|
||||
// assume it's a close confirmation and leave the overview
|
||||
if (this._closeRequested)
|
||||
this._activate();
|
||||
}
|
||||
|
||||
_hasAttachedDialogs() {
|
||||
return this._windowContainer.layout_manager.getWindows().length > 1;
|
||||
}
|
||||
|
||||
_updateAttachedDialogs() {
|
||||
let iter = win => {
|
||||
let actor = win.get_compositor_private();
|
||||
|
||||
if (!actor)
|
||||
return false;
|
||||
if (!win.is_attached_dialog())
|
||||
return false;
|
||||
|
||||
this._addWindow(win);
|
||||
win.foreach_transient(iter);
|
||||
return true;
|
||||
};
|
||||
this.metaWindow.foreach_transient(iter);
|
||||
}
|
||||
|
||||
get boundingBox() {
|
||||
const box = this._windowContainer.layout_manager.bounding_box;
|
||||
|
||||
return {
|
||||
x: box.x1,
|
||||
y: box.y1,
|
||||
width: box.get_width(),
|
||||
height: box.get_height(),
|
||||
};
|
||||
}
|
||||
|
||||
get windowCenter() {
|
||||
const box = this._windowContainer.layout_manager.bounding_box;
|
||||
|
||||
return new Graphene.Point({
|
||||
x: box.get_x() + box.get_width() / 2,
|
||||
y: box.get_y() + box.get_height() / 2,
|
||||
});
|
||||
}
|
||||
|
||||
// Find the actor just below us, respecting reparenting done by DND code
|
||||
_getActualStackAbove() {
|
||||
if (this._stackAbove == null)
|
||||
return null;
|
||||
|
||||
if (this.inDrag) {
|
||||
if (this._stackAbove._delegate)
|
||||
return this._stackAbove._delegate._getActualStackAbove();
|
||||
else
|
||||
return null;
|
||||
} else {
|
||||
return this._stackAbove;
|
||||
}
|
||||
}
|
||||
|
||||
setStackAbove(actor) {
|
||||
this._stackAbove = actor;
|
||||
if (this.inDrag)
|
||||
// We'll fix up the stack after the drag
|
||||
return;
|
||||
|
||||
let parent = this.get_parent();
|
||||
let actualAbove = this._getActualStackAbove();
|
||||
if (actualAbove == null)
|
||||
parent.set_child_below_sibling(this, null);
|
||||
else
|
||||
parent.set_child_above_sibling(this, actualAbove);
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
this._windowActor.disconnect(this._windowDestroyId);
|
||||
|
||||
this.metaWindow._delegate = null;
|
||||
this._delegate = null;
|
||||
|
||||
this.metaWindow.disconnect(this._updateCaptionId);
|
||||
|
||||
if (this._longPressLater) {
|
||||
Meta.later_remove(this._longPressLater);
|
||||
delete this._longPressLater;
|
||||
}
|
||||
|
||||
if (this._idleHideOverlayId > 0) {
|
||||
GLib.source_remove(this._idleHideOverlayId);
|
||||
this._idleHideOverlayId = 0;
|
||||
}
|
||||
|
||||
if (this.inDrag) {
|
||||
this.emit('drag-end');
|
||||
this.inDrag = false;
|
||||
}
|
||||
}
|
||||
|
||||
_activate() {
|
||||
this._selected = true;
|
||||
this.emit('selected', global.get_current_time());
|
||||
}
|
||||
|
||||
vfunc_enter_event(crossingEvent) {
|
||||
this.showOverlay(true);
|
||||
return super.vfunc_enter_event(crossingEvent);
|
||||
}
|
||||
|
||||
vfunc_leave_event(crossingEvent) {
|
||||
if (this._idleHideOverlayId > 0)
|
||||
GLib.source_remove(this._idleHideOverlayId);
|
||||
|
||||
this._idleHideOverlayId = GLib.timeout_add(
|
||||
GLib.PRIORITY_DEFAULT,
|
||||
WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT, () => {
|
||||
if (this._closeButton['has-pointer'] ||
|
||||
this._title['has-pointer'])
|
||||
return GLib.SOURCE_CONTINUE;
|
||||
|
||||
if (!this['has-pointer'])
|
||||
this.hideOverlay(true);
|
||||
|
||||
this._idleHideOverlayId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
});
|
||||
|
||||
GLib.Source.set_name_by_id(this._idleHideOverlayId, '[gnome-shell] this._idleHideOverlayId');
|
||||
|
||||
return super.vfunc_leave_event(crossingEvent);
|
||||
}
|
||||
|
||||
vfunc_key_focus_in() {
|
||||
super.vfunc_key_focus_in();
|
||||
this.showOverlay(true);
|
||||
}
|
||||
|
||||
vfunc_key_focus_out() {
|
||||
super.vfunc_key_focus_out();
|
||||
this.hideOverlay(true);
|
||||
}
|
||||
|
||||
vfunc_key_press_event(keyEvent) {
|
||||
let symbol = keyEvent.keyval;
|
||||
let isEnter = symbol == Clutter.KEY_Return || symbol == Clutter.KEY_KP_Enter;
|
||||
if (isEnter) {
|
||||
this._activate();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.vfunc_key_press_event(keyEvent);
|
||||
}
|
||||
|
||||
_onLongPress(action, actor, state) {
|
||||
// Take advantage of the Clutter policy to consider
|
||||
// a long-press canceled when the pointer movement
|
||||
// exceeds dnd-drag-threshold to manually start the drag
|
||||
if (state == Clutter.LongPressState.CANCEL) {
|
||||
let event = Clutter.get_current_event();
|
||||
this._dragTouchSequence = event.get_event_sequence();
|
||||
|
||||
if (this._longPressLater)
|
||||
return true;
|
||||
|
||||
// A click cancels a long-press before any click handler is
|
||||
// run - make sure to not start a drag in that case
|
||||
this._longPressLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
delete this._longPressLater;
|
||||
if (this._selected)
|
||||
return;
|
||||
let [x, y] = action.get_coords();
|
||||
action.release();
|
||||
this._draggable.startDrag(x, y, global.get_current_time(), this._dragTouchSequence, event.get_device());
|
||||
});
|
||||
} else {
|
||||
this.showOverlay(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_onDragBegin(_draggable, _time) {
|
||||
this.inDrag = true;
|
||||
this.hideOverlay(false);
|
||||
this.emit('drag-begin');
|
||||
}
|
||||
|
||||
handleDragOver(source, actor, x, y, time) {
|
||||
return this._workspace.handleDragOver(source, actor, x, y, time);
|
||||
}
|
||||
|
||||
acceptDrop(source, actor, x, y, time) {
|
||||
return this._workspace.acceptDrop(source, actor, x, y, time);
|
||||
}
|
||||
|
||||
_onDragCancelled(_draggable, _time) {
|
||||
this.emit('drag-cancelled');
|
||||
}
|
||||
|
||||
_onDragEnd(_draggable, _time, _snapback) {
|
||||
this.inDrag = false;
|
||||
|
||||
// We may not have a parent if DnD completed successfully, in
|
||||
// which case our clone will shortly be destroyed and replaced
|
||||
// with a new one on the target workspace.
|
||||
let parent = this.get_parent();
|
||||
if (parent !== null) {
|
||||
if (this._stackAbove == null)
|
||||
parent.set_child_below_sibling(this, null);
|
||||
else
|
||||
parent.set_child_above_sibling(this, this._stackAbove);
|
||||
}
|
||||
|
||||
if (this['has-pointer'])
|
||||
this.showOverlay(true);
|
||||
|
||||
this.emit('drag-end');
|
||||
}
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@ -86,8 +86,8 @@ class WorkspaceSwitcherPopupList extends St.Widget {
|
||||
return this._getSizeForOppositeOrientation();
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
let themeNode = this.get_theme_node();
|
||||
box = themeNode.get_content_box(box);
|
||||
@ -111,7 +111,7 @@ class WorkspaceSwitcherPopupList extends St.Widget {
|
||||
} else {
|
||||
y += this._childHeight + this._itemSpacing;
|
||||
}
|
||||
child.allocate(childBox, flags);
|
||||
child.allocate(childBox);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -567,7 +567,8 @@ var WorkspaceThumbnail = GObject.registerClass({
|
||||
if (this.state > ThumbnailState.NORMAL)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
if (source.realWindow && !this._isMyWindow(source.realWindow))
|
||||
if (source.metaWindow &&
|
||||
!this._isMyWindow(source.metaWindow.get_compositor_private()))
|
||||
return DND.DragMotionResult.MOVE_DROP;
|
||||
if (source.app && source.app.can_open_new_window())
|
||||
return DND.DragMotionResult.COPY_DROP;
|
||||
@ -581,8 +582,8 @@ var WorkspaceThumbnail = GObject.registerClass({
|
||||
if (this.state > ThumbnailState.NORMAL)
|
||||
return false;
|
||||
|
||||
if (source.realWindow) {
|
||||
let win = source.realWindow;
|
||||
if (source.metaWindow) {
|
||||
let win = source.metaWindow.get_compositor_private();
|
||||
if (this._isMyWindow(win))
|
||||
return false;
|
||||
|
||||
@ -795,7 +796,7 @@ var ThumbnailsBox = GObject.registerClass({
|
||||
|
||||
// Draggable target interface
|
||||
handleDragOver(source, actor, x, y, time) {
|
||||
if (!source.realWindow &&
|
||||
if (!source.metaWindow &&
|
||||
(!source.app || !source.app.can_open_new_window()) &&
|
||||
(source.app || !source.shellWorkspaceLaunch) &&
|
||||
source != Main.xdndHandler)
|
||||
@ -846,7 +847,7 @@ var ThumbnailsBox = GObject.registerClass({
|
||||
if (this._dropWorkspace != -1)
|
||||
return this._thumbnails[this._dropWorkspace].handleDragOverInternal(source, actor, time);
|
||||
else if (this._dropPlaceholderPos != -1)
|
||||
return source.realWindow ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.COPY_DROP;
|
||||
return source.metaWindow ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.COPY_DROP;
|
||||
else
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
}
|
||||
@ -855,12 +856,12 @@ var ThumbnailsBox = GObject.registerClass({
|
||||
if (this._dropWorkspace != -1) {
|
||||
return this._thumbnails[this._dropWorkspace].acceptDropInternal(source, actor, time);
|
||||
} else if (this._dropPlaceholderPos != -1) {
|
||||
if (!source.realWindow &&
|
||||
if (!source.metaWindow &&
|
||||
(!source.app || !source.app.can_open_new_window()) &&
|
||||
(source.app || !source.shellWorkspaceLaunch))
|
||||
return false;
|
||||
|
||||
let isWindow = !!source.realWindow;
|
||||
let isWindow = !!source.metaWindow;
|
||||
|
||||
let newWorkspaceIndex;
|
||||
[newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1];
|
||||
@ -1204,8 +1205,8 @@ var ThumbnailsBox = GObject.registerClass({
|
||||
this.queue_relayout();
|
||||
}
|
||||
|
||||
vfunc_allocate(box, flags) {
|
||||
this.set_allocation(box, flags);
|
||||
vfunc_allocate(box) {
|
||||
this.set_allocation(box);
|
||||
|
||||
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
|
||||
|
||||
@ -1299,7 +1300,7 @@ var ThumbnailsBox = GObject.registerClass({
|
||||
childBox.x2 = x2;
|
||||
childBox.y1 = Math.round(y);
|
||||
childBox.y2 = Math.round(y + placeholderHeight);
|
||||
this._dropPlaceholder.allocate(childBox, flags);
|
||||
this._dropPlaceholder.allocate(childBox);
|
||||
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
|
||||
this._dropPlaceholder.show();
|
||||
});
|
||||
@ -1331,7 +1332,7 @@ var ThumbnailsBox = GObject.registerClass({
|
||||
childBox.y2 = y1 + portholeHeight;
|
||||
|
||||
thumbnail.set_scale(roundedHScale, roundedVScale);
|
||||
thumbnail.allocate(childBox, flags);
|
||||
thumbnail.allocate(childBox);
|
||||
|
||||
// We round the collapsing portion so that we don't get thumbnails resizing
|
||||
// during an animation due to differences in rounded, but leave the uncollapsed
|
||||
@ -1355,6 +1356,6 @@ var ThumbnailsBox = GObject.registerClass({
|
||||
childBox.x2 += indicatorRightFullBorder;
|
||||
childBox.y1 = indicatorY1 - indicatorTopFullBorder;
|
||||
childBox.y2 = indicatorY2 + indicatorBottomFullBorder;
|
||||
this._indicator.allocate(childBox, flags);
|
||||
this._indicator.allocate(childBox);
|
||||
}
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ const SwipeTracker = imports.ui.swipeTracker;
|
||||
const Workspace = imports.ui.workspace;
|
||||
|
||||
var WORKSPACE_SWITCH_TIME = 250;
|
||||
var SCROLL_TIMEOUT_TIME = 150;
|
||||
|
||||
var AnimationType = {
|
||||
ZOOM: 0,
|
||||
@ -392,7 +393,10 @@ class ExtraWorkspaceView extends WorkspacesViewBase {
|
||||
var WorkspacesDisplay = GObject.registerClass(
|
||||
class WorkspacesDisplay extends St.Widget {
|
||||
_init(scrollAdjustment) {
|
||||
super._init({ clip_to_allocation: true });
|
||||
super._init({
|
||||
visible: false,
|
||||
clip_to_allocation: true,
|
||||
});
|
||||
this.connect('notify::allocation', this._updateWorkspacesActualGeometry.bind(this));
|
||||
|
||||
let workspaceManager = global.workspace_manager;
|
||||
@ -449,6 +453,7 @@ class WorkspacesDisplay extends St.Widget {
|
||||
this._keyPressEventId = 0;
|
||||
this._scrollTimeoutId = 0;
|
||||
|
||||
this._actualGeometry = null;
|
||||
this._fullGeometry = null;
|
||||
this._inWindowDrag = false;
|
||||
|
||||
@ -607,15 +612,19 @@ class WorkspacesDisplay extends St.Widget {
|
||||
return this._getPrimaryView().navigate_focus(from, direction, false);
|
||||
}
|
||||
|
||||
show(fadeOnPrimary) {
|
||||
animateToOverview(fadeOnPrimary) {
|
||||
this.show();
|
||||
this._updateWorkspacesViews();
|
||||
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);
|
||||
|
||||
if (this._actualGeometry && this._fullGeometry) {
|
||||
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 =
|
||||
@ -639,7 +648,7 @@ class WorkspacesDisplay extends St.Widget {
|
||||
}
|
||||
}
|
||||
|
||||
hide() {
|
||||
vfunc_hide() {
|
||||
if (this._restackedNotifyId > 0) {
|
||||
Main.overview.disconnect(this._restackedNotifyId);
|
||||
this._restackedNotifyId = 0;
|
||||
@ -655,6 +664,8 @@ class WorkspacesDisplay extends St.Widget {
|
||||
for (let i = 0; i < this._workspacesViews.length; i++)
|
||||
this._workspacesViews[i].destroy();
|
||||
this._workspacesViews = [];
|
||||
|
||||
super.vfunc_hide();
|
||||
}
|
||||
|
||||
_workspacesOnlyOnPrimaryChanged() {
|
||||
@ -689,8 +700,10 @@ class WorkspacesDisplay extends St.Widget {
|
||||
|
||||
this._workspacesViews.forEach(v => v.show());
|
||||
|
||||
this._updateWorkspacesFullGeometry();
|
||||
this._updateWorkspacesActualGeometry();
|
||||
if (this._fullGeometry)
|
||||
this._syncWorkspacesFullGeometry();
|
||||
if (this._actualGeometry)
|
||||
this._syncWorkspacesActualGeometry();
|
||||
}
|
||||
|
||||
_getMonitorIndexForEvent(event) {
|
||||
@ -742,10 +755,10 @@ class WorkspacesDisplay extends St.Widget {
|
||||
// the sliding controls were never slid in at all.
|
||||
setWorkspacesFullGeometry(geom) {
|
||||
this._fullGeometry = geom;
|
||||
this._updateWorkspacesFullGeometry();
|
||||
this._syncWorkspacesFullGeometry();
|
||||
}
|
||||
|
||||
_updateWorkspacesFullGeometry() {
|
||||
_syncWorkspacesFullGeometry() {
|
||||
if (!this._workspacesViews.length)
|
||||
return;
|
||||
|
||||
@ -757,18 +770,21 @@ class WorkspacesDisplay extends St.Widget {
|
||||
}
|
||||
|
||||
_updateWorkspacesActualGeometry() {
|
||||
const [x, y] = this.get_transformed_position();
|
||||
const width = this.allocation.get_width();
|
||||
const height = this.allocation.get_height();
|
||||
|
||||
this._actualGeometry = { x, y, width, height };
|
||||
this._syncWorkspacesActualGeometry();
|
||||
}
|
||||
|
||||
_syncWorkspacesActualGeometry() {
|
||||
if (!this._workspacesViews.length)
|
||||
return;
|
||||
|
||||
let [x, y] = this.get_transformed_position();
|
||||
let allocation = this.allocation;
|
||||
let width = allocation.x2 - allocation.x1;
|
||||
let height = allocation.y2 - allocation.y1;
|
||||
let primaryGeometry = { x, y, width, height };
|
||||
|
||||
let monitors = Main.layoutManager.monitors;
|
||||
for (let i = 0; i < monitors.length; i++) {
|
||||
let geometry = i == this._primaryIndex ? primaryGeometry : monitors[i];
|
||||
let geometry = i === this._primaryIndex ? this._actualGeometry : monitors[i];
|
||||
this._workspacesViews[i].setActualGeometry(geometry);
|
||||
}
|
||||
}
|
||||
@ -815,12 +831,11 @@ class WorkspacesDisplay extends St.Widget {
|
||||
|
||||
this._canScroll = false;
|
||||
this._scrollTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
|
||||
WORKSPACE_SWITCH_TIME, () => {
|
||||
SCROLL_TIMEOUT_TIME, () => {
|
||||
this._canScroll = true;
|
||||
this._scrollTimeoutId = 0;
|
||||
return GLib.SOURCE_REMOVE;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const { Clutter, Meta } = imports.gi;
|
||||
const { Clutter } = imports.gi;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
@ -17,7 +17,7 @@ var XdndHandler = class {
|
||||
Main.uiGroup.add_actor(this._dummy);
|
||||
this._dummy.hide();
|
||||
|
||||
var dnd = Meta.get_backend().get_dnd();
|
||||
var dnd = global.backend.get_dnd();
|
||||
dnd.connect('dnd-enter', this._onEnter.bind(this));
|
||||
dnd.connect('dnd-position-change', this._onPositionChanged.bind(this));
|
||||
dnd.connect('dnd-leave', this._onLeave.bind(this));
|
||||
|
@ -218,12 +218,12 @@ globals:
|
||||
ARGV: readonly
|
||||
Debugger: readonly
|
||||
GIRepositoryGType: readonly
|
||||
globalThis: readonly
|
||||
imports: readonly
|
||||
Intl: readonly
|
||||
log: readonly
|
||||
logError: readonly
|
||||
print: readonly
|
||||
printerr: readonly
|
||||
window: readonly
|
||||
parserOptions:
|
||||
ecmaVersion: 2019
|
||||
|
32
meson.build
32
meson.build
@ -1,6 +1,6 @@
|
||||
project('gnome-shell', 'c',
|
||||
version: '3.37.0',
|
||||
meson_version: '>= 0.47.0',
|
||||
version: '3.37.2',
|
||||
meson_version: '>= 0.53.0',
|
||||
license: 'GPLv2+'
|
||||
)
|
||||
|
||||
@ -19,13 +19,13 @@ cogl_pango_pc = 'mutter-cogl-pango-' + mutter_api_version
|
||||
libmutter_pc = 'libmutter-' + mutter_api_version
|
||||
|
||||
ecal_req = '>= 3.33.1'
|
||||
eds_req = '>= 3.17.2'
|
||||
eds_req = '>= 3.33.1'
|
||||
gcr_req = '>= 3.7.5'
|
||||
gio_req = '>= 2.56.0'
|
||||
gi_req = '>= 1.49.1'
|
||||
gjs_req = '>= 1.63.2'
|
||||
gjs_req = '>= 1.65.1'
|
||||
gtk_req = '>= 3.15.0'
|
||||
mutter_req = '>= 3.36.0'
|
||||
mutter_req = '>= 3.37.2'
|
||||
polkit_req = '>= 0.100'
|
||||
schemas_req = '>= 3.33.1'
|
||||
startup_req = '>= 0.11'
|
||||
@ -63,16 +63,9 @@ portaldir = join_paths(datadir, 'xdg-desktop-portal', 'portals')
|
||||
schemadir = join_paths(datadir, 'glib-2.0', 'schemas')
|
||||
servicedir = join_paths(datadir, 'dbus-1', 'services')
|
||||
|
||||
# XXX: Once https://github.com/systemd/systemd/issues/9595 is fixed and we can
|
||||
# depend on this version, replace with something like:
|
||||
# systemduserunitdir = systemd_dep.get_pkgconfig_variable('systemduserunitdir',
|
||||
# define_variable: ['prefix', prefix])
|
||||
# and uncomment systemd_dep below
|
||||
systemduserunitdir = join_paths(prefix, 'lib', 'systemd', 'user')
|
||||
|
||||
keybindings_dep = dependency('gnome-keybindings', required: false)
|
||||
if keybindings_dep.found()
|
||||
keysdir = keybindings_dep.get_pkgconfig_variable('keysdir')
|
||||
keysdir = keybindings_dep.get_pkgconfig_variable('keysdir', define_variable: ['datadir', datadir])
|
||||
else
|
||||
keysdir = join_paths(datadir, 'gnome-control-center', 'keybindings')
|
||||
endif
|
||||
@ -122,8 +115,9 @@ endif
|
||||
|
||||
if get_option('systemd')
|
||||
libsystemd_dep = dependency('libsystemd')
|
||||
# XXX: see systemduserunitdir
|
||||
# systemd_dep = dependency('systemd')
|
||||
systemd_dep = dependency('systemd')
|
||||
systemduserunitdir = systemd_dep.get_pkgconfig_variable('systemduserunitdir',
|
||||
define_variable: ['prefix', prefix])
|
||||
have_systemd = true
|
||||
else
|
||||
libsystemd_dep = []
|
||||
@ -321,8 +315,6 @@ if get_option('man')
|
||||
summary_dirs += { 'mandir': get_option('mandir') }
|
||||
endif
|
||||
|
||||
if meson.version().version_compare('>= 0.53.0')
|
||||
summary(summary_dirs, section: 'Directories')
|
||||
summary(summary_build, section: 'Build Configuration')
|
||||
summary(summary_options, section: 'Build Options')
|
||||
endif
|
||||
summary(summary_dirs, section: 'Directories')
|
||||
summary(summary_build, section: 'Build Configuration')
|
||||
summary(summary_options, section: 'Build Options')
|
||||
|
1
mutter
Submodule
1
mutter
Submodule
Submodule mutter added at 1551b6d386
@ -56,6 +56,7 @@ nl
|
||||
nn
|
||||
oc
|
||||
or
|
||||
os
|
||||
pa
|
||||
pl
|
||||
pt
|
||||
|
@ -94,5 +94,7 @@ subprojects/extensions-tool/src/command-prefs.c
|
||||
subprojects/extensions-tool/src/command-reset.c
|
||||
subprojects/extensions-tool/src/command-uninstall.c
|
||||
subprojects/extensions-tool/src/main.c
|
||||
subprojects/extensions-tool/src/templates/00-plain.desktop.in
|
||||
subprojects/extensions-tool/src/templates/indicator.desktop.in
|
||||
# Please do not remove this file from POTFILES.in. Run "git submodule init && git submodule update" to get it.
|
||||
subprojects/gvc/gvc-mixer-control.c
|
||||
|
1
po/POTFILES.skip
Normal file
1
po/POTFILES.skip
Normal file
@ -0,0 +1 @@
|
||||
subprojects/extensions-tool/src/templates/indicator/extension.js
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user