Compare commits
350 Commits
3.36.3
...
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 | |||
402fd8ec29 | |||
fbe2e30f38 | |||
fb6ead2881 | |||
7ff7fb5d3b | |||
8030d9ad32 | |||
45bc850715 | |||
51a913730e | |||
0a4974ac8c | |||
1666fa195d | |||
a9df4e7516 | |||
343b3351f1 | |||
407b12c3cb | |||
455a8f3076 | |||
5067bda61a | |||
e138b6e3af | |||
9bc9d5165f | |||
26c2cb9f65 | |||
da44649e6f | |||
a0def23940 | |||
f49b58cf97 | |||
cadd9a99c0 | |||
7061889a29 | |||
764527c8c9 | |||
18742fcc32 |
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/calendar-server/org.gnome.Shell.CalendarServer.service
|
||||||
src/gnome-shell
|
src/gnome-shell
|
||||||
src/gnome-shell-calendar-server
|
src/gnome-shell-calendar-server
|
||||||
src/gnome-shell-extension-prefs
|
|
||||||
src/gnome-shell-extension-tool
|
src/gnome-shell-extension-tool
|
||||||
src/gnome-shell-hotplug-sniffer
|
src/gnome-shell-hotplug-sniffer
|
||||||
src/gnome-shell-perf-helper
|
src/gnome-shell-perf-helper
|
||||||
|
@ -18,7 +18,7 @@ variables:
|
|||||||
- merge_requests
|
- merge_requests
|
||||||
|
|
||||||
check_commit_log:
|
check_commit_log:
|
||||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||||
stage: review
|
stage: review
|
||||||
variables:
|
variables:
|
||||||
GIT_DEPTH: "100"
|
GIT_DEPTH: "100"
|
||||||
@ -28,10 +28,10 @@ check_commit_log:
|
|||||||
- merge_requests
|
- merge_requests
|
||||||
|
|
||||||
js_check:
|
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
|
stage: review
|
||||||
script:
|
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)
|
- (! grep -q . $JS_LOG)
|
||||||
<<: *only_default
|
<<: *only_default
|
||||||
artifacts:
|
artifacts:
|
||||||
@ -40,7 +40,7 @@ js_check:
|
|||||||
when: on_failure
|
when: on_failure
|
||||||
|
|
||||||
eslint:
|
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
|
stage: review
|
||||||
script:
|
script:
|
||||||
- ./.gitlab-ci/run-eslint.sh
|
- ./.gitlab-ci/run-eslint.sh
|
||||||
@ -51,21 +51,21 @@ eslint:
|
|||||||
when: always
|
when: always
|
||||||
|
|
||||||
potfile_check:
|
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
|
stage: review
|
||||||
script:
|
script:
|
||||||
- ./.gitlab-ci/check-potfiles.sh
|
- ./.gitlab-ci/check-potfiles.sh
|
||||||
<<: *only_default
|
<<: *only_default
|
||||||
|
|
||||||
no_template_check:
|
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
|
stage: review
|
||||||
script:
|
script:
|
||||||
- ./.gitlab-ci/check-template-strings.sh
|
- ./.gitlab-ci/check-template-strings.sh
|
||||||
<<: *only_default
|
<<: *only_default
|
||||||
|
|
||||||
build:
|
build:
|
||||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||||
stage: build
|
stage: build
|
||||||
before_script:
|
before_script:
|
||||||
- .gitlab-ci/checkout-mutter.sh
|
- .gitlab-ci/checkout-mutter.sh
|
||||||
@ -83,7 +83,7 @@ build:
|
|||||||
- build
|
- build
|
||||||
|
|
||||||
test:
|
test:
|
||||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||||
stage: test
|
stage: test
|
||||||
variables:
|
variables:
|
||||||
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
|
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
|
||||||
@ -100,7 +100,7 @@ test:
|
|||||||
when: on_failure
|
when: on_failure
|
||||||
|
|
||||||
test-pot:
|
test-pot:
|
||||||
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
|
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
|
||||||
stage: test
|
stage: test
|
||||||
before_script:
|
before_script:
|
||||||
- ninja -C mutter/build install
|
- ninja -C mutter/build install
|
||||||
@ -124,11 +124,7 @@ flatpak:
|
|||||||
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
|
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
|
||||||
FLATPAK_MODULE: "gnome-extensions-app"
|
FLATPAK_MODULE: "gnome-extensions-app"
|
||||||
APP_ID: "org.gnome.Extensions"
|
APP_ID: "org.gnome.Extensions"
|
||||||
MESON_ARGS: "$SUBPROJECT"
|
|
||||||
extends: .flatpak
|
extends: .flatpak
|
||||||
before_script:
|
|
||||||
- flatpak run --command=$SUBPROJECT/generate-translations.sh
|
|
||||||
--filesystem=host org.gnome.Sdk//master
|
|
||||||
<<: *only_default
|
<<: *only_default
|
||||||
|
|
||||||
nightly:
|
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
|
# find source files that contain gettext keywords
|
||||||
files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs)
|
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
|
# find those that aren't listed in POTFILES.in
|
||||||
missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done)
|
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 extra_args=ARGS_$1
|
||||||
local output_var=OUTPUT_$1
|
local output_var=OUTPUT_$1
|
||||||
local output=${!output_var}
|
local output=${!output_var}
|
||||||
|
local cache=.eslintcache-${1,,}
|
||||||
|
|
||||||
# ensure output exists even if eslint doesn't report any errors
|
# ensure output exists even if eslint doesn't report any errors
|
||||||
mkdir -p $(dirname $output)
|
mkdir -p $(dirname $output)
|
||||||
touch $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() {
|
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
|
3.36.0
|
||||||
======
|
======
|
||||||
* Fix off-by-1900 error in date conversions [Florian; !1061]
|
* Fix off-by-1900 error in date conversions [Florian; !1061]
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
<node>
|
<node>
|
||||||
<interface name="org.gnome.Shell.CalendarServer">
|
<interface name="org.gnome.Shell.CalendarServer">
|
||||||
<method name="GetEvents">
|
<method name="SetTimeRange">
|
||||||
<arg type="x" direction="in" />
|
<arg type="x" name="since" direction="in"/>
|
||||||
<arg type="x" direction="in" />
|
<arg type="x" name="until" direction="in"/>
|
||||||
<arg type="b" direction="in" />
|
<arg type="b" name="force_reload" direction="in"/>
|
||||||
<arg type="a(sssbxxa{sv})" direction="out" />
|
|
||||||
</method>
|
</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" />
|
<property name="HasCalendars" type="b" access="read" />
|
||||||
<signal name="Changed" />
|
|
||||||
</interface>
|
</interface>
|
||||||
</node>
|
</node>
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
<gresources>
|
<gresources>
|
||||||
<gresource prefix="/org/gnome/shell/dbus-interfaces">
|
<gresource prefix="/org/gnome/shell/dbus-interfaces">
|
||||||
<file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file>
|
<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.Application.xml</file>
|
||||||
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Device.xml</file>
|
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Device.xml</file>
|
||||||
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Manager.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-focused.svg</file>
|
||||||
<file>checkbox-off.svg</file>
|
<file>checkbox-off.svg</file>
|
||||||
<file>checkbox.svg</file>
|
<file>checkbox.svg</file>
|
||||||
|
<file alias="icons/color-pick.svg">color-pick.svg</file>
|
||||||
<file>dash-placeholder.svg</file>
|
<file>dash-placeholder.svg</file>
|
||||||
<file>gnome-shell.css</file>
|
<file>gnome-shell.css</file>
|
||||||
<file>gnome-shell-high-contrast.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 = [
|
desktop_files = [
|
||||||
'org.gnome.Shell.desktop',
|
'org.gnome.Shell.desktop',
|
||||||
|
'org.gnome.Shell.Extensions.desktop',
|
||||||
]
|
]
|
||||||
service_files = []
|
service_files = []
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ endforeach
|
|||||||
|
|
||||||
|
|
||||||
subdir('dbus-interfaces')
|
subdir('dbus-interfaces')
|
||||||
|
subdir('icons')
|
||||||
subdir('theme')
|
subdir('theme')
|
||||||
|
|
||||||
data_resources = [
|
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 Grid */
|
||||||
|
|
||||||
$app_icon_size: 96px;
|
$app_icon_size: 96px;
|
||||||
$app_icon_padding: 24px;
|
|
||||||
|
|
||||||
// app icons
|
// app icons
|
||||||
.icon-grid {
|
.icon-grid {
|
||||||
-shell-grid-horizontal-item-size: $app_icon_size + $app_icon_padding * 2;
|
row-spacing: $base_spacing * 6;
|
||||||
-shell-grid-vertical-item-size: $app_icon_size + $app_icon_padding * 2;
|
column-spacing: $base_spacing * 6;
|
||||||
spacing: $base_spacing * 6;
|
max-row-spacing: $base_spacing * 12;
|
||||||
|
max-column-spacing: $base_spacing * 12;
|
||||||
.overview-icon {
|
|
||||||
icon-size: $app_icon_size;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//.app-display { spacing: 20px; }
|
|
||||||
|
|
||||||
/* App Icons */
|
/* App Icons */
|
||||||
|
|
||||||
$app_grid_fg_color: #fff;
|
$app_grid_fg_color: #fff;
|
||||||
@ -44,8 +38,8 @@ $app_grid_fg_color: #fff;
|
|||||||
.app-folder-dialog {
|
.app-folder-dialog {
|
||||||
border-radius: $modal_radius * 1.5;
|
border-radius: $modal_radius * 1.5;
|
||||||
border: 1px solid $osd_outer_borders_color;
|
border: 1px solid $osd_outer_borders_color;
|
||||||
spacing: 12px;
|
|
||||||
background-color: transparentize(darken($osd_bg_color,10%), 0.05);
|
background-color: transparentize(darken($osd_bg_color,10%), 0.05);
|
||||||
|
padding: 12px;
|
||||||
|
|
||||||
& .folder-name-container {
|
& .folder-name-container {
|
||||||
padding: 24px 36px 0;
|
padding: 24px 36px 0;
|
||||||
@ -54,7 +48,7 @@ $app_grid_fg_color: #fff;
|
|||||||
& .folder-name-label,
|
& .folder-name-label,
|
||||||
& .folder-name-entry {
|
& .folder-name-entry {
|
||||||
font-size: 18pt;
|
font-size: 18pt;
|
||||||
font-weight: bold;
|
font-weight: 800;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .folder-name-entry { width: 300px }
|
& .folder-name-entry { width: 300px }
|
||||||
@ -73,11 +67,24 @@ $app_grid_fg_color: #fff;
|
|||||||
& > StIcon { icon-size: 16px }
|
& > 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 {
|
.app-folder-dialog-container {
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
width: 800px;
|
width: 620px;
|
||||||
height: 600px;
|
height: 620px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.app-folder-icon {
|
.app-folder-icon {
|
||||||
@ -123,15 +130,11 @@ $app_grid_fg_color: #fff;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Some hacks I don't even know
|
// Some hacks I don't even know
|
||||||
.all-apps,
|
.all-apps {
|
||||||
.frequent-apps > StBoxLayout {
|
|
||||||
// horizontal padding to make sure scrollbars or dash don't overlap content
|
// horizontal padding to make sure scrollbars or dash don't overlap content
|
||||||
padding: 0px 88px 10px 88px;
|
padding: 0px 88px 10px 88px;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Label when no frequent apps
|
|
||||||
.no-frequent-applications-label { @extend %status_text; }
|
|
||||||
|
|
||||||
// shutdown and other actions in the grid
|
// shutdown and other actions in the grid
|
||||||
.system-action-icon {
|
.system-action-icon {
|
||||||
background-color: rgba(0,0,0,0.8);
|
background-color: rgba(0,0,0,0.8);
|
||||||
@ -139,44 +142,3 @@ $app_grid_fg_color: #fff;
|
|||||||
border-radius: 99px;
|
border-radius: 99px;
|
||||||
icon-size: $app_icon_size * 0.5;
|
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 {
|
.calendar-day-with-events {
|
||||||
color: lighten($fg_color,10%);
|
|
||||||
font-weight: bold;
|
|
||||||
background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
|
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 {
|
.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 */
|
||||||
.world-clocks-button {
|
.world-clocks-button {
|
||||||
@include notification_bubble;
|
@include notification_bubble;
|
||||||
@ -202,7 +230,7 @@
|
|||||||
.world-clocks-time {
|
.world-clocks-time {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
color: $fg_color;
|
color: $fg_color;
|
||||||
font-feature-settings: "lnum";
|
font-feature-settings: "tnum";
|
||||||
@include fontsize($base_font_size);
|
@include fontsize($base_font_size);
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
/* Looking Glass */
|
/* Looking Glass */
|
||||||
|
|
||||||
|
$text_fg_color: #ccc;
|
||||||
|
|
||||||
// Dialog
|
// Dialog
|
||||||
#LookingGlassDialog {
|
#LookingGlassDialog {
|
||||||
background-color: $osd_bg_color;
|
background-color: $osd_bg_color;
|
||||||
@ -52,6 +54,11 @@
|
|||||||
&:hover { color: lighten($link_color, 10%); }
|
&:hover { color: lighten($link_color, 10%); }
|
||||||
&:active { color: darken($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 {
|
.lg-completions-text {
|
||||||
|
@ -54,6 +54,10 @@
|
|||||||
@extend %status_text;
|
@extend %status_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid-search-results {
|
||||||
|
spacing: $base_spacing * 6;
|
||||||
|
}
|
||||||
|
|
||||||
// Search results with icons
|
// Search results with icons
|
||||||
.grid-search-result {
|
.grid-search-result {
|
||||||
@extend %app-well-app;
|
@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_size: 24px;
|
||||||
$window_close_button_padding: 3px;
|
$window_close_button_padding: 3px;
|
||||||
|
|
||||||
|
$window_clone_border_size: 6px;
|
||||||
|
|
||||||
// Window picker
|
// Window picker
|
||||||
.window-picker {
|
.window-picker {
|
||||||
@ -22,7 +23,7 @@ $window_close_button_padding: 3px;
|
|||||||
|
|
||||||
// Borders on window thumbnails
|
// Borders on window thumbnails
|
||||||
.window-clone-border {
|
.window-clone-border {
|
||||||
border-width: 6px;
|
border-width: $window_clone_border_size;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-color: $window_thumbnail_border_color;
|
border-color: $window_thumbnail_border_color;
|
||||||
border-radius: $base_border_radius + 2;
|
border-radius: $base_border_radius + 2;
|
||||||
@ -54,8 +55,6 @@ $window_close_button_padding: 3px;
|
|||||||
width: $window_close_button_size;
|
width: $window_close_button_size;
|
||||||
box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.5);
|
box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.5);
|
||||||
|
|
||||||
-shell-close-overlap: $window_close_button_size * 0.5;
|
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: lighten($selected_bg_color, 5%);
|
background-color: lighten($selected_bg_color, 5%);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ const { ServiceImplementation } = imports.dbusService;
|
|||||||
const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
|
const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
|
||||||
const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface);
|
const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface);
|
||||||
|
|
||||||
|
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
|
||||||
|
|
||||||
var NotificationDaemon = class extends ServiceImplementation {
|
var NotificationDaemon = class extends ServiceImplementation {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(NotificationsIface, '/org/freedesktop/Notifications');
|
super(NotificationsIface, '/org/freedesktop/Notifications');
|
||||||
@ -42,7 +44,15 @@ var NotificationDaemon = class extends ServiceImplementation {
|
|||||||
null, null);
|
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) => {
|
this._proxy.NotifyRemote(...params, (res, error) => {
|
||||||
if (this._handleError(invocation, error))
|
if (this._handleError(invocation, error))
|
||||||
return;
|
return;
|
||||||
@ -77,4 +87,19 @@ var NotificationDaemon = class extends ServiceImplementation {
|
|||||||
invocation.return_value(new GLib.Variant('(ssss)', res));
|
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({
|
this._defaultButtonWell.add_constraint(new Clutter.BindConstraint({
|
||||||
source: this.cancelButton,
|
source: this.cancelButton,
|
||||||
coordinate: Clutter.BindCoordinate.SIZE,
|
coordinate: Clutter.BindCoordinate.WIDTH,
|
||||||
}));
|
}));
|
||||||
this._mainBox.add_child(this._defaultButtonWell);
|
this._mainBox.add_child(this._defaultButtonWell);
|
||||||
|
|
||||||
@ -424,7 +424,13 @@ var AuthPrompt = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateSensitivity(sensitive) {
|
updateSensitivity(sensitive) {
|
||||||
|
if (this._entry.reactive === sensitive)
|
||||||
|
return;
|
||||||
|
|
||||||
this._entry.reactive = sensitive;
|
this._entry.reactive = sensitive;
|
||||||
|
|
||||||
|
if (sensitive)
|
||||||
|
this._entry.grab_key_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_hide() {
|
vfunc_hide() {
|
||||||
|
@ -589,8 +589,8 @@ var LoginDialog = GObject.registerClass({
|
|||||||
return actorBox;
|
return actorBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(dialogBox, flags) {
|
vfunc_allocate(dialogBox) {
|
||||||
this.set_allocation(dialogBox, flags);
|
this.set_allocation(dialogBox);
|
||||||
|
|
||||||
let themeNode = this.get_theme_node();
|
let themeNode = this.get_theme_node();
|
||||||
dialogBox = themeNode.get_content_box(dialogBox);
|
dialogBox = themeNode.get_content_box(dialogBox);
|
||||||
@ -719,19 +719,19 @@ var LoginDialog = GObject.registerClass({
|
|||||||
|
|
||||||
// Finally hand out the allocations
|
// Finally hand out the allocations
|
||||||
if (bannerAllocation)
|
if (bannerAllocation)
|
||||||
this._bannerView.allocate(bannerAllocation, flags);
|
this._bannerView.allocate(bannerAllocation);
|
||||||
|
|
||||||
if (authPromptAllocation)
|
if (authPromptAllocation)
|
||||||
this._authPrompt.allocate(authPromptAllocation, flags);
|
this._authPrompt.allocate(authPromptAllocation);
|
||||||
|
|
||||||
if (userSelectionAllocation)
|
if (userSelectionAllocation)
|
||||||
this._userSelectionBox.allocate(userSelectionAllocation, flags);
|
this._userSelectionBox.allocate(userSelectionAllocation);
|
||||||
|
|
||||||
if (logoAllocation)
|
if (logoAllocation)
|
||||||
this._logoBin.allocate(logoAllocation, flags);
|
this._logoBin.allocate(logoAllocation);
|
||||||
|
|
||||||
if (sessionMenuButtonAllocation)
|
if (sessionMenuButtonAllocation)
|
||||||
this._sessionMenuButton.allocate(sessionMenuButtonAllocation, flags);
|
this._sessionMenuButton.allocate(sessionMenuButtonAllocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ensureUserListLoaded() {
|
_ensureUserListLoaded() {
|
||||||
@ -810,12 +810,13 @@ var LoginDialog = GObject.registerClass({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this._logoBin.destroy_all_children();
|
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;
|
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||||
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
|
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
|
||||||
-1, -1,
|
-1, -1,
|
||||||
scaleFactor,
|
scaleFactor,
|
||||||
this._logoBin.resource_scale));
|
resourceScale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
|
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
|
||||||
DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */
|
DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */
|
||||||
|
|
||||||
const { Clutter, Gio, GLib } = imports.gi;
|
const { Clutter, Gdm, Gio, GLib } = imports.gi;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Batch = imports.gdm.batch;
|
const Batch = imports.gdm.batch;
|
||||||
@ -12,6 +12,15 @@ const Main = imports.ui.main;
|
|||||||
const Params = imports.misc.params;
|
const Params = imports.misc.params;
|
||||||
const SmartcardManager = imports.misc.smartcardManager;
|
const SmartcardManager = imports.misc.smartcardManager;
|
||||||
|
|
||||||
|
Gio._promisify(Gdm.Client.prototype,
|
||||||
|
'open_reauthentication_channel', 'open_reauthentication_channel_finish');
|
||||||
|
Gio._promisify(Gdm.Client.prototype,
|
||||||
|
'get_user_verifier', 'get_user_verifier_finish');
|
||||||
|
Gio._promisify(Gdm.UserVerifierProxy.prototype,
|
||||||
|
'call_begin_verification_for_user', 'call_begin_verification_for_user_finish');
|
||||||
|
Gio._promisify(Gdm.UserVerifierProxy.prototype,
|
||||||
|
'call_begin_verification', 'call_begin_verification_finish');
|
||||||
|
|
||||||
var PASSWORD_SERVICE_NAME = 'gdm-password';
|
var PASSWORD_SERVICE_NAME = 'gdm-password';
|
||||||
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
|
||||||
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
|
||||||
@ -168,14 +177,12 @@ var ShellUserVerifier = class {
|
|||||||
|
|
||||||
this._checkForFingerprintReader();
|
this._checkForFingerprintReader();
|
||||||
|
|
||||||
if (userName) {
|
// If possible, reauthenticate an already running session,
|
||||||
// If possible, reauthenticate an already running session,
|
// so any session specific credentials get updated appropriately
|
||||||
// so any session specific credentials get updated appropriately
|
if (userName)
|
||||||
this._client.open_reauthentication_channel(userName, this._cancellable,
|
this._openReauthenticationChannel(userName);
|
||||||
this._reauthenticationChannelOpened.bind(this));
|
else
|
||||||
} else {
|
this._getUserVerifier();
|
||||||
this._client.get_user_verifier(this._cancellable, this._userVerifierGot.bind(this));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
@ -339,10 +346,11 @@ var ShellUserVerifier = class {
|
|||||||
this._verificationFailed(false);
|
this._verificationFailed(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_reauthenticationChannelOpened(client, result) {
|
async _openReauthenticationChannel(userName) {
|
||||||
try {
|
try {
|
||||||
this._clearUserVerifier();
|
this._clearUserVerifier();
|
||||||
this._userVerifier = client.open_reauthentication_channel_finish(result);
|
this._userVerifier = await this._client.open_reauthentication_channel(
|
||||||
|
userName, this._cancellable);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||||
return;
|
return;
|
||||||
@ -351,8 +359,7 @@ var ShellUserVerifier = class {
|
|||||||
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there
|
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there
|
||||||
// is no session to reauthenticate. Fall back to performing
|
// is no session to reauthenticate. Fall back to performing
|
||||||
// verification from this login session
|
// verification from this login session
|
||||||
client.get_user_verifier(this._cancellable,
|
this._getUserVerifier();
|
||||||
this._userVerifierGot.bind(this));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -366,10 +373,11 @@ var ShellUserVerifier = class {
|
|||||||
this._hold.release();
|
this._hold.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
_userVerifierGot(client, result) {
|
async _getUserVerifier() {
|
||||||
try {
|
try {
|
||||||
this._clearUserVerifier();
|
this._clearUserVerifier();
|
||||||
this._userVerifier = client.get_user_verifier_finish(result);
|
this._userVerifier =
|
||||||
|
await this._client.get_user_verifier(this._cancellable);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||||
return;
|
return;
|
||||||
@ -421,35 +429,25 @@ var ShellUserVerifier = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_startService(serviceName) {
|
async _startService(serviceName) {
|
||||||
this._hold.acquire();
|
this._hold.acquire();
|
||||||
if (this._userName) {
|
try {
|
||||||
this._userVerifier.call_begin_verification_for_user(serviceName, this._userName, this._cancellable, (obj, result) => {
|
if (this._userName) {
|
||||||
try {
|
await this._userVerifier.call_begin_verification_for_user(
|
||||||
obj.call_begin_verification_for_user_finish(result);
|
serviceName, this._userName, this._cancellable);
|
||||||
} catch (e) {
|
} else {
|
||||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
await this._userVerifier.call_begin_verification(
|
||||||
return;
|
serviceName, this._cancellable);
|
||||||
this._reportInitError('Failed to start verification for user', e);
|
}
|
||||||
return;
|
} catch (e) {
|
||||||
}
|
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||||
|
return;
|
||||||
this._hold.release();
|
this._reportInitError(this._userName
|
||||||
});
|
? 'Failed to start verification for user'
|
||||||
} else {
|
: 'Failed to start verification', e);
|
||||||
this._userVerifier.call_begin_verification(serviceName, this._cancellable, (obj, result) => {
|
return;
|
||||||
try {
|
|
||||||
obj.call_begin_verification_finish(result);
|
|
||||||
} catch (e) {
|
|
||||||
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
|
||||||
return;
|
|
||||||
this._reportInitError('Failed to start verification', e);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._hold.release();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
this._hold.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
_beginVerification() {
|
_beginVerification() {
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
<file>misc/modemManager.js</file>
|
<file>misc/modemManager.js</file>
|
||||||
<file>misc/objectManager.js</file>
|
<file>misc/objectManager.js</file>
|
||||||
<file>misc/params.js</file>
|
<file>misc/params.js</file>
|
||||||
|
<file>misc/parentalControlsManager.js</file>
|
||||||
<file>misc/permissionStore.js</file>
|
<file>misc/permissionStore.js</file>
|
||||||
<file>misc/smartcardManager.js</file>
|
<file>misc/smartcardManager.js</file>
|
||||||
<file>misc/systemActions.js</file>
|
<file>misc/systemActions.js</file>
|
||||||
@ -101,13 +102,13 @@
|
|||||||
<file>ui/swipeTracker.js</file>
|
<file>ui/swipeTracker.js</file>
|
||||||
<file>ui/switcherPopup.js</file>
|
<file>ui/switcherPopup.js</file>
|
||||||
<file>ui/switchMonitor.js</file>
|
<file>ui/switchMonitor.js</file>
|
||||||
<file>ui/tweener.js</file>
|
|
||||||
<file>ui/unlockDialog.js</file>
|
<file>ui/unlockDialog.js</file>
|
||||||
<file>ui/userWidget.js</file>
|
<file>ui/userWidget.js</file>
|
||||||
<file>ui/viewSelector.js</file>
|
<file>ui/viewSelector.js</file>
|
||||||
<file>ui/windowAttentionHandler.js</file>
|
<file>ui/windowAttentionHandler.js</file>
|
||||||
<file>ui/windowMenu.js</file>
|
<file>ui/windowMenu.js</file>
|
||||||
<file>ui/windowManager.js</file>
|
<file>ui/windowManager.js</file>
|
||||||
|
<file>ui/windowPreview.js</file>
|
||||||
<file>ui/workspace.js</file>
|
<file>ui/workspace.js</file>
|
||||||
<file>ui/workspaceSwitcherPopup.js</file>
|
<file>ui/workspaceSwitcherPopup.js</file>
|
||||||
<file>ui/workspaceThumbnail.js</file>
|
<file>ui/workspaceThumbnail.js</file>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported ExtensionState, ExtensionType, getCurrentExtension,
|
/* exported ExtensionState, ExtensionType, getCurrentExtension,
|
||||||
getSettings, initTranslations, isOutOfDate, installImporter,
|
getSettings, initTranslations, openPrefs, isOutOfDate,
|
||||||
serializeExtension, deserializeExtension */
|
installImporter, serializeExtension, deserializeExtension */
|
||||||
|
|
||||||
// Common utils for the extension system and the extension
|
// Common utils for the extension system and the extension
|
||||||
// preferences tool
|
// preferences tool
|
||||||
@ -153,6 +153,27 @@ function getSettings(schema) {
|
|||||||
return new Gio.Settings({ settings_schema: schemaObj });
|
return new Gio.Settings({ settings_schema: schemaObj });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* openPrefs:
|
||||||
|
*
|
||||||
|
* Open the preference dialog of the current extension
|
||||||
|
*/
|
||||||
|
function openPrefs() {
|
||||||
|
const extension = getCurrentExtension();
|
||||||
|
|
||||||
|
if (!extension)
|
||||||
|
throw new Error('openPrefs() can only be called from extensions');
|
||||||
|
|
||||||
|
try {
|
||||||
|
const extensionManager = imports.ui.main.extensionManager;
|
||||||
|
extensionManager.openExtensionPrefs(extension.uuid, '', {});
|
||||||
|
} catch (e) {
|
||||||
|
if (e.name === 'ImportError')
|
||||||
|
throw new Error('openPrefs() cannot be called from preferences');
|
||||||
|
logError(e, 'Failed to open extension preferences');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* versionCheck:
|
* versionCheck:
|
||||||
* @param {string[]} required - an array of versions we're compatible with
|
* @param {string[]} required - an array of versions we're compatible with
|
||||||
|
@ -6,6 +6,15 @@ const Signals = imports.signals;
|
|||||||
|
|
||||||
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
|
||||||
|
|
||||||
|
Gio._promisify(IBus.Bus.prototype,
|
||||||
|
'list_engines_async', 'list_engines_async_finish');
|
||||||
|
Gio._promisify(IBus.Bus.prototype,
|
||||||
|
'request_name_async', 'request_name_async_finish');
|
||||||
|
Gio._promisify(IBus.Bus.prototype,
|
||||||
|
'get_global_engine_async', 'get_global_engine_async_finish');
|
||||||
|
Gio._promisify(IBus.Bus.prototype,
|
||||||
|
'set_global_engine_async', 'set_global_engine_async_finish');
|
||||||
|
|
||||||
// Ensure runtime version matches
|
// Ensure runtime version matches
|
||||||
_checkIBusVersion(1, 5, 2);
|
_checkIBusVersion(1, 5, 2);
|
||||||
|
|
||||||
@ -102,16 +111,14 @@ var IBusManager = class {
|
|||||||
|
|
||||||
_onConnected() {
|
_onConnected() {
|
||||||
this._cancellable = new Gio.Cancellable();
|
this._cancellable = new Gio.Cancellable();
|
||||||
this._ibus.list_engines_async(-1, this._cancellable,
|
this._initEngines();
|
||||||
this._initEngines.bind(this));
|
this._initPanelService();
|
||||||
this._ibus.request_name_async(IBus.SERVICE_PANEL,
|
|
||||||
IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable,
|
|
||||||
this._initPanelService.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_initEngines(ibus, result) {
|
async _initEngines() {
|
||||||
try {
|
try {
|
||||||
let enginesList = this._ibus.list_engines_async_finish(result);
|
const enginesList =
|
||||||
|
await this._ibus.list_engines_async(-1, this._cancellable);
|
||||||
for (let i = 0; i < enginesList.length; ++i) {
|
for (let i = 0; i < enginesList.length; ++i) {
|
||||||
let name = enginesList[i].get_name();
|
let name = enginesList[i].get_name();
|
||||||
this._engines.set(name, enginesList[i]);
|
this._engines.set(name, enginesList[i]);
|
||||||
@ -126,9 +133,10 @@ var IBusManager = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_initPanelService(ibus, result) {
|
async _initPanelService() {
|
||||||
try {
|
try {
|
||||||
this._ibus.request_name_async_finish(result);
|
await this._ibus.request_name_async(IBus.SERVICE_PANEL,
|
||||||
|
IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||||
logError(e);
|
logError(e);
|
||||||
@ -163,19 +171,15 @@ var IBusManager = class {
|
|||||||
this._panelService.connect('set-content-type', this._setContentType.bind(this));
|
this._panelService.connect('set-content-type', this._setContentType.bind(this));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
// If an engine is already active we need to get its properties
|
|
||||||
this._ibus.get_global_engine_async(-1, this._cancellable, (_bus, res) => {
|
|
||||||
let engine;
|
|
||||||
try {
|
|
||||||
engine = this._ibus.get_global_engine_async_finish(res);
|
|
||||||
if (!engine)
|
|
||||||
return;
|
|
||||||
} catch (e) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this._engineChanged(this._ibus, engine.get_name());
|
|
||||||
});
|
|
||||||
this._updateReadiness();
|
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());
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateReadiness() {
|
_updateReadiness() {
|
||||||
@ -223,7 +227,7 @@ var IBusManager = class {
|
|||||||
return this._engines.get(id);
|
return this._engines.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
setEngine(id, callback) {
|
async setEngine(id, callback) {
|
||||||
// Send id even if id == this._currentEngineName
|
// Send id even if id == this._currentEngineName
|
||||||
// because 'properties-registered' signal can be emitted
|
// because 'properties-registered' signal can be emitted
|
||||||
// while this._ibusSources == null on a lock screen.
|
// while this._ibusSources == null on a lock screen.
|
||||||
@ -233,18 +237,16 @@ var IBusManager = class {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._ibus.set_global_engine_async(id,
|
try {
|
||||||
this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
|
await this._ibus.set_global_engine_async(id,
|
||||||
this._cancellable, (_bus, res) => {
|
this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
|
||||||
try {
|
this._cancellable);
|
||||||
this._ibus.set_global_engine_async_finish(res);
|
} catch (e) {
|
||||||
} catch (e) {
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
||||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
|
logError(e);
|
||||||
logError(e);
|
}
|
||||||
}
|
if (callback)
|
||||||
if (callback)
|
callback();
|
||||||
callback();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
preloadEngines(ids) {
|
preloadEngines(ids) {
|
||||||
|
@ -4,6 +4,9 @@ const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
|
|||||||
|
|
||||||
const Keyboard = imports.ui.status.keyboard;
|
const Keyboard = imports.ui.status.keyboard;
|
||||||
|
|
||||||
|
Gio._promisify(IBus.Bus.prototype,
|
||||||
|
'create_input_context_async', 'create_input_context_async_finish');
|
||||||
|
|
||||||
var HIDE_PANEL_TIME = 50;
|
var HIDE_PANEL_TIME = 50;
|
||||||
|
|
||||||
var InputMethod = GObject.registerClass(
|
var InputMethod = GObject.registerClass(
|
||||||
@ -46,15 +49,11 @@ class InputMethod extends Clutter.InputMethod {
|
|||||||
this._currentSource = this._inputSourceManager.currentSource;
|
this._currentSource = this._inputSourceManager.currentSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onConnected() {
|
async _onConnected() {
|
||||||
this._cancellable = new Gio.Cancellable();
|
this._cancellable = new Gio.Cancellable();
|
||||||
this._ibus.create_input_context_async('gnome-shell', -1,
|
|
||||||
this._cancellable, this._setContext.bind(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
_setContext(bus, res) {
|
|
||||||
try {
|
try {
|
||||||
this._context = this._ibus.create_input_context_async_finish(res);
|
this._context = await this._ibus.create_input_context_async(
|
||||||
|
'gnome-shell', -1, this._cancellable);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
|
||||||
logError(e);
|
logError(e);
|
||||||
|
@ -24,8 +24,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
|
|||||||
[expr_, base, attrHead] = matches;
|
[expr_, base, attrHead] = matches;
|
||||||
|
|
||||||
methods = getPropertyNamesFromExpression(base, commandHeader).filter(
|
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
|
// Look for the empty expression or partially entered words
|
||||||
@ -34,8 +33,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
|
|||||||
if (text == '' || matches) {
|
if (text == '' || matches) {
|
||||||
[expr_, attrHead] = matches;
|
[expr_, attrHead] = matches;
|
||||||
methods = globalCompletionList.filter(
|
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 -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
|
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
|
||||||
|
|
||||||
const { GLib, GnomeDesktop, Meta } = imports.gi;
|
const { GLib, GnomeDesktop } = imports.gi;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
@ -62,11 +62,11 @@ var KeyboardManager = class {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
this._currentKeymap = { layouts, variants, options };
|
this._currentKeymap = { layouts, variants, options };
|
||||||
Meta.get_backend().set_keymap(layouts, variants, options);
|
global.backend.set_keymap(layouts, variants, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyLayoutGroupIndex(idx) {
|
_applyLayoutGroupIndex(idx) {
|
||||||
Meta.get_backend().lock_layout_group(idx);
|
global.backend.lock_layout_group(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(id) {
|
apply(id) {
|
||||||
|
@ -50,25 +50,22 @@ function canLock() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function registerSessionWithGDM() {
|
async function registerSessionWithGDM() {
|
||||||
log("Registering session with GDM");
|
log("Registering session with GDM");
|
||||||
Gio.DBus.system.call('org.gnome.DisplayManager',
|
try {
|
||||||
'/org/gnome/DisplayManager/Manager',
|
await Gio.DBus.system.call(
|
||||||
'org.gnome.DisplayManager.Manager',
|
'org.gnome.DisplayManager',
|
||||||
'RegisterSession',
|
'/org/gnome/DisplayManager/Manager',
|
||||||
GLib.Variant.new('(a{sv})', [{}]), null,
|
'org.gnome.DisplayManager.Manager',
|
||||||
Gio.DBusCallFlags.NONE, -1, null,
|
'RegisterSession',
|
||||||
(source, result) => {
|
GLib.Variant.new('(a{sv})', [{}]), null,
|
||||||
try {
|
Gio.DBusCallFlags.NONE, -1, null);
|
||||||
source.call_finish(result);
|
} catch (e) {
|
||||||
} catch (e) {
|
if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
|
||||||
if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
|
log(`Error registering session with GDM: ${e.message}`);
|
||||||
log(`Error registering session with GDM: ${e.message}`);
|
else
|
||||||
else
|
log('Not calling RegisterSession(): method not exported, GDM too old?');
|
||||||
log("Not calling RegisterSession(): method not exported, GDM too old?");
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let _loginManager = null;
|
let _loginManager = null;
|
||||||
@ -174,24 +171,19 @@ var LoginManagerSystemd = class {
|
|||||||
this._proxy.SuspendRemote(true);
|
this._proxy.SuspendRemote(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
inhibit(reason, callback) {
|
async inhibit(reason, callback) {
|
||||||
let inVariant = GLib.Variant.new('(ssss)',
|
try {
|
||||||
['sleep',
|
const inVariant = new GLib.Variant('(ssss)',
|
||||||
'GNOME Shell',
|
['sleep', 'GNOME Shell', reason, 'delay']);
|
||||||
reason,
|
const [outVariant_, fdList] =
|
||||||
'delay']);
|
await this._proxy.call_with_unix_fd_list('Inhibit',
|
||||||
this._proxy.call_with_unix_fd_list('Inhibit', inVariant, 0, -1, null, null,
|
inVariant, 0, -1, null, null);
|
||||||
(proxy, result) => {
|
const [fd] = fdList.steal_fds();
|
||||||
let fd = -1;
|
callback(new Gio.UnixInputStream({ fd }));
|
||||||
try {
|
} catch (e) {
|
||||||
let [outVariant_, fdList] = proxy.call_with_unix_fd_list_finish(result);
|
logError(e, 'Error getting systemd inhibitor');
|
||||||
fd = fdList.steal_fds()[0];
|
callback(null);
|
||||||
callback(new Gio.UnixInputStream({ fd }));
|
}
|
||||||
} catch (e) {
|
|
||||||
logError(e, "Error getting systemd inhibitor");
|
|
||||||
callback(null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_prepareForSleep(proxy, sender, [aboutToSuspend]) {
|
_prepareForSleep(proxy, sender, [aboutToSuspend]) {
|
||||||
|
@ -57,9 +57,7 @@ var ObjectManager = class {
|
|||||||
// Start out inhibiting load until at least the proxy
|
// Start out inhibiting load until at least the proxy
|
||||||
// manager is loaded and the remote objects are fetched
|
// manager is loaded and the remote objects are fetched
|
||||||
this._numLoadInhibitors = 1;
|
this._numLoadInhibitors = 1;
|
||||||
this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
|
this._initManagerProxy();
|
||||||
this._cancellable,
|
|
||||||
this._onManagerProxyLoaded.bind(this));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_tryToCompleteLoad() {
|
_tryToCompleteLoad() {
|
||||||
@ -73,7 +71,7 @@ var ObjectManager = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_addInterface(objectPath, interfaceName, onFinished) {
|
async _addInterface(objectPath, interfaceName, onFinished) {
|
||||||
let info = this._interfaceInfos[interfaceName];
|
let info = this._interfaceInfos[interfaceName];
|
||||||
|
|
||||||
if (!info) {
|
if (!info) {
|
||||||
@ -89,40 +87,38 @@ var ObjectManager = class {
|
|||||||
g_interface_info: info,
|
g_interface_info: info,
|
||||||
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
|
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
|
||||||
|
|
||||||
proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => {
|
try {
|
||||||
try {
|
await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable);
|
||||||
initable.init_finish(result);
|
} catch (e) {
|
||||||
} catch (e) {
|
logError(e, `could not initialize proxy for interface ${interfaceName}`);
|
||||||
logError(e, `could not initialize proxy for interface ${interfaceName}`);
|
|
||||||
|
|
||||||
if (onFinished)
|
|
||||||
onFinished();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let isNewObject;
|
|
||||||
if (!this._objects[objectPath]) {
|
|
||||||
this._objects[objectPath] = {};
|
|
||||||
isNewObject = true;
|
|
||||||
} else {
|
|
||||||
isNewObject = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._objects[objectPath][interfaceName] = proxy;
|
|
||||||
|
|
||||||
if (!this._interfaces[interfaceName])
|
|
||||||
this._interfaces[interfaceName] = [];
|
|
||||||
|
|
||||||
this._interfaces[interfaceName].push(proxy);
|
|
||||||
|
|
||||||
if (isNewObject)
|
|
||||||
this.emit('object-added', objectPath);
|
|
||||||
|
|
||||||
this.emit('interface-added', interfaceName, proxy);
|
|
||||||
|
|
||||||
if (onFinished)
|
if (onFinished)
|
||||||
onFinished();
|
onFinished();
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isNewObject;
|
||||||
|
if (!this._objects[objectPath]) {
|
||||||
|
this._objects[objectPath] = {};
|
||||||
|
isNewObject = true;
|
||||||
|
} else {
|
||||||
|
isNewObject = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._objects[objectPath][interfaceName] = proxy;
|
||||||
|
|
||||||
|
if (!this._interfaces[interfaceName])
|
||||||
|
this._interfaces[interfaceName] = [];
|
||||||
|
|
||||||
|
this._interfaces[interfaceName].push(proxy);
|
||||||
|
|
||||||
|
if (isNewObject)
|
||||||
|
this.emit('object-added', objectPath);
|
||||||
|
|
||||||
|
this.emit('interface-added', interfaceName, proxy);
|
||||||
|
|
||||||
|
if (onFinished)
|
||||||
|
onFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
_removeInterface(objectPath, interfaceName) {
|
_removeInterface(objectPath, interfaceName) {
|
||||||
@ -151,9 +147,10 @@ var ObjectManager = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onManagerProxyLoaded(initable, result) {
|
async _initManagerProxy() {
|
||||||
try {
|
try {
|
||||||
initable.init_finish(result);
|
await this._managerProxy.init_async(
|
||||||
|
GLib.PRIORITY_DEFAULT, this._cancellable);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e, `could not initialize object manager for object ${this._serviceName}`);
|
logError(e, `could not initialize object manager for object ${this._serviceName}`);
|
||||||
|
|
||||||
|
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._canHavePowerOff = true;
|
||||||
this._canHaveSuspend = 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 = new Map();
|
||||||
this._actions.set(POWER_OFF_ACTION_ID, {
|
this._actions.set(POWER_OFF_ACTION_ID, {
|
||||||
// Translators: The name of the power-off action in search
|
// Translators: The name of the power-off action in search
|
||||||
name: C_("search-result", "Power Off"),
|
name: C_("search-result", "Power Off"),
|
||||||
iconName: 'system-shutdown-symbolic',
|
iconName: 'system-shutdown-symbolic',
|
||||||
// Translators: A list of keywords that match the power-off action, separated by semicolons
|
// 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,
|
available: false,
|
||||||
});
|
});
|
||||||
this._actions.set(LOCK_SCREEN_ACTION_ID, {
|
this._actions.set(LOCK_SCREEN_ACTION_ID, {
|
||||||
@ -97,15 +101,15 @@ const SystemActions = GObject.registerClass({
|
|||||||
name: C_("search-result", "Lock Screen"),
|
name: C_("search-result", "Lock Screen"),
|
||||||
iconName: 'system-lock-screen-symbolic',
|
iconName: 'system-lock-screen-symbolic',
|
||||||
// Translators: A list of keywords that match the lock screen action, separated by semicolons
|
// Translators: A list of keywords that match the lock screen action, separated by semicolons
|
||||||
keywords: _("lock screen").split(/[; ]/),
|
keywords: tokenizeKeywords(_('lock screen')),
|
||||||
available: false,
|
available: false,
|
||||||
});
|
});
|
||||||
this._actions.set(LOGOUT_ACTION_ID, {
|
this._actions.set(LOGOUT_ACTION_ID, {
|
||||||
// Translators: The name of the logout action in search
|
// Translators: The name of the logout action in search
|
||||||
name: C_("search-result", "Log Out"),
|
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
|
// 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,
|
available: false,
|
||||||
});
|
});
|
||||||
this._actions.set(SUSPEND_ACTION_ID, {
|
this._actions.set(SUSPEND_ACTION_ID, {
|
||||||
@ -113,7 +117,7 @@ const SystemActions = GObject.registerClass({
|
|||||||
name: C_("search-result", "Suspend"),
|
name: C_("search-result", "Suspend"),
|
||||||
iconName: 'media-playback-pause-symbolic',
|
iconName: 'media-playback-pause-symbolic',
|
||||||
// Translators: A list of keywords that match the suspend action, separated by semicolons
|
// Translators: A list of keywords that match the suspend action, separated by semicolons
|
||||||
keywords: _("suspend;sleep").split(/[; ]/),
|
keywords: tokenizeKeywords(_('suspend;sleep')),
|
||||||
available: false,
|
available: false,
|
||||||
});
|
});
|
||||||
this._actions.set(SWITCH_USER_ACTION_ID, {
|
this._actions.set(SWITCH_USER_ACTION_ID, {
|
||||||
@ -121,14 +125,14 @@ const SystemActions = GObject.registerClass({
|
|||||||
name: C_("search-result", "Switch User"),
|
name: C_("search-result", "Switch User"),
|
||||||
iconName: 'system-switch-user-symbolic',
|
iconName: 'system-switch-user-symbolic',
|
||||||
// Translators: A list of keywords that match the switch user action, separated by semicolons
|
// Translators: A list of keywords that match the switch user action, separated by semicolons
|
||||||
keywords: _("switch user").split(/[; ]/),
|
keywords: tokenizeKeywords(_('switch user')),
|
||||||
available: false,
|
available: false,
|
||||||
});
|
});
|
||||||
this._actions.set(LOCK_ORIENTATION_ACTION_ID, {
|
this._actions.set(LOCK_ORIENTATION_ACTION_ID, {
|
||||||
name: '',
|
name: '',
|
||||||
iconName: '',
|
iconName: '',
|
||||||
// Translators: A list of keywords that match the lock orientation action, separated by semicolons
|
// 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,
|
available: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -277,7 +281,7 @@ const SystemActions = GObject.registerClass({
|
|||||||
|
|
||||||
getMatchingActions(terms) {
|
getMatchingActions(terms) {
|
||||||
// terms is a list of strings
|
// 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 = [];
|
let results = [];
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
|
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
|
||||||
formatTime, formatTimeSpan, createTimeLabel, insertSorted,
|
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 Gettext = imports.gettext;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -363,51 +363,6 @@ function insertSorted(array, val, cmp) {
|
|||||||
return pos;
|
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) {
|
function ensureActorVisibleInScrollView(scrollView, actor) {
|
||||||
let adjustment = scrollView.vscroll.adjustment;
|
let adjustment = scrollView.vscroll.adjustment;
|
||||||
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
|
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
|
||||||
|
@ -7,6 +7,8 @@ const PermissionStore = imports.misc.permissionStore;
|
|||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||||
|
|
||||||
|
Gio._promisify(Geoclue.Simple, 'new', 'new_finish');
|
||||||
|
|
||||||
const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
|
const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
|
||||||
|
|
||||||
const WEATHER_BUS_NAME = 'org.gnome.Weather';
|
const WEATHER_BUS_NAME = 'org.gnome.Weather';
|
||||||
@ -79,16 +81,7 @@ var WeatherClient = class {
|
|||||||
this._weatherApp = null;
|
this._weatherApp = null;
|
||||||
this._weatherProxy = null;
|
this._weatherProxy = null;
|
||||||
|
|
||||||
let nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
|
this._createWeatherProxy();
|
||||||
Gio.DBusProxy.new(
|
|
||||||
Gio.DBus.session,
|
|
||||||
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
|
|
||||||
nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
|
|
||||||
WEATHER_BUS_NAME,
|
|
||||||
WEATHER_OBJECT_PATH,
|
|
||||||
WEATHER_INTEGRATION_IFACE,
|
|
||||||
null,
|
|
||||||
this._onWeatherProxyReady.bind(this));
|
|
||||||
|
|
||||||
this._settings = new Gio.Settings({
|
this._settings = new Gio.Settings({
|
||||||
schema_id: 'org.gnome.shell.weather',
|
schema_id: 'org.gnome.shell.weather',
|
||||||
@ -146,9 +139,17 @@ var WeatherClient = class {
|
|||||||
(!this._needsAuth || this._weatherAuthorized);
|
(!this._needsAuth || this._weatherAuthorized);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onWeatherProxyReady(o, res) {
|
async _createWeatherProxy() {
|
||||||
|
const nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
|
||||||
try {
|
try {
|
||||||
this._weatherProxy = Gio.DBusProxy.new_finish(res);
|
this._weatherProxy = await Gio.DBusProxy.new(
|
||||||
|
Gio.DBus.session,
|
||||||
|
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
|
||||||
|
nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
|
||||||
|
WEATHER_BUS_NAME,
|
||||||
|
WEATHER_OBJECT_PATH,
|
||||||
|
WEATHER_INTEGRATION_IFACE,
|
||||||
|
null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log(`Failed to create GNOME Weather proxy: ${e}`);
|
log(`Failed to create GNOME Weather proxy: ${e}`);
|
||||||
return;
|
return;
|
||||||
@ -239,25 +240,23 @@ var WeatherClient = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_startGClueService() {
|
async _startGClueService() {
|
||||||
if (this._gclueStarting)
|
if (this._gclueStarting)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this._gclueStarting = true;
|
this._gclueStarting = true;
|
||||||
|
|
||||||
Geoclue.Simple.new('org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null,
|
try {
|
||||||
(o, res) => {
|
this._gclueService = await Geoclue.Simple.new(
|
||||||
try {
|
'org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null);
|
||||||
this._gclueService = Geoclue.Simple.new_finish(res);
|
} catch (e) {
|
||||||
} catch (e) {
|
log(`Failed to connect to Geoclue2 service: ${e.message}`);
|
||||||
log(`Failed to connect to Geoclue2 service: ${e.message}`);
|
this._setLocation(this._mostRecentLocation);
|
||||||
this._setLocation(this._mostRecentLocation);
|
return;
|
||||||
return;
|
}
|
||||||
}
|
this._gclueStarted = true;
|
||||||
this._gclueStarted = true;
|
this._gclueService.get_client().distance_threshold = 100;
|
||||||
this._gclueService.get_client().distance_threshold = 100;
|
this._updateLocationMonitoring();
|
||||||
this._updateLocationMonitoring();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onGClueLocationChanged() {
|
_onGClueLocationChanged() {
|
||||||
|
@ -68,8 +68,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
|
|||||||
this._items = this._switcherList.icons;
|
this._items = this._switcherList.icons;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
super.vfunc_allocate(box, flags);
|
super.vfunc_allocate(box);
|
||||||
|
|
||||||
// Allocate the thumbnails
|
// Allocate the thumbnails
|
||||||
// We try to avoid overflowing the screen so we base the resulting size on
|
// 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);
|
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
|
||||||
let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
|
let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
|
||||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
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,
|
// Cache the window list now; we don't handle dynamic changes here,
|
||||||
// and we don't want to be continually retrieving it
|
// and we don't want to be continually retrieving it
|
||||||
appIcon.cachedWindows = allWindows.filter(
|
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)
|
if (appIcon.cachedWindows.length > 0)
|
||||||
this._addIcon(appIcon);
|
this._addIcon(appIcon);
|
||||||
}
|
}
|
||||||
@ -750,9 +749,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
|
|||||||
return super.vfunc_get_preferred_height(forWidth);
|
return super.vfunc_get_preferred_height(forWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
// Allocate the main list items
|
// Allocate the main list items
|
||||||
super.vfunc_allocate(box, flags);
|
super.vfunc_allocate(box);
|
||||||
|
|
||||||
let contentBox = this.get_theme_node().get_content_box(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.x2 = childBox.x1 + arrowWidth;
|
||||||
childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight;
|
childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight;
|
||||||
childBox.y2 = childBox.y1 + 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];
|
return [minHeight, natHeight];
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
let themeNode = this.get_theme_node();
|
let themeNode = this.get_theme_node();
|
||||||
let contentBox = themeNode.get_content_box(box);
|
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();
|
box.y2 -= totalLabelHeight;
|
||||||
childBox.x1 = contentBox.x1;
|
super.vfunc_allocate(box);
|
||||||
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);
|
|
||||||
|
|
||||||
// Hooking up the parent vfunc will call this.set_allocation() with
|
// Hooking up the parent vfunc will call this.set_allocation() with
|
||||||
// the height without the label height, so call it again with the
|
// the height without the label height, so call it again with the
|
||||||
// correct size here.
|
// 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) {
|
highlight(index, justOutline) {
|
||||||
|
@ -15,8 +15,7 @@ class Animation extends St.Bin {
|
|||||||
const themeContext = St.ThemeContext.get_for_stage(global.stage);
|
const themeContext = St.ThemeContext.get_for_stage(global.stage);
|
||||||
|
|
||||||
super._init({
|
super._init({
|
||||||
width: width * themeContext.scale_factor,
|
style: `width: ${width}px; height: ${height}px;`,
|
||||||
height: height * themeContext.scale_factor,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.connect('destroy', this._onDestroy.bind(this));
|
this.connect('destroy', this._onDestroy.bind(this));
|
||||||
|
1250
js/ui/appDisplay.js
1250
js/ui/appDisplay.js
File diff suppressed because it is too large
Load Diff
@ -2,6 +2,7 @@
|
|||||||
/* exported getAppFavorites */
|
/* exported getAppFavorites */
|
||||||
|
|
||||||
const Shell = imports.gi.Shell;
|
const Shell = imports.gi.Shell;
|
||||||
|
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -12,6 +13,7 @@ const RENAMED_DESKTOP_IDS = {
|
|||||||
'cheese.desktop': 'org.gnome.Cheese.desktop',
|
'cheese.desktop': 'org.gnome.Cheese.desktop',
|
||||||
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
|
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
|
||||||
'empathy.desktop': 'org.gnome.Empathy.desktop',
|
'empathy.desktop': 'org.gnome.Empathy.desktop',
|
||||||
|
'eog.desktop': 'org.gnome.eog.desktop',
|
||||||
'epiphany.desktop': 'org.gnome.Epiphany.desktop',
|
'epiphany.desktop': 'org.gnome.Epiphany.desktop',
|
||||||
'evolution.desktop': 'org.gnome.Evolution.desktop',
|
'evolution.desktop': 'org.gnome.Evolution.desktop',
|
||||||
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
|
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
|
||||||
@ -64,6 +66,13 @@ const RENAMED_DESKTOP_IDS = {
|
|||||||
|
|
||||||
class AppFavorites {
|
class AppFavorites {
|
||||||
constructor() {
|
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.FAVORITE_APPS_KEY = 'favorite-apps';
|
||||||
this._favorites = {};
|
this._favorites = {};
|
||||||
global.settings.connect('changed::%s'.format(this.FAVORITE_APPS_KEY), this._onFavsChanged.bind(this));
|
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);
|
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
|
||||||
|
|
||||||
let apps = ids.map(id => appSys.lookup_app(id))
|
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 = {};
|
this._favorites = {};
|
||||||
for (let i = 0; i < apps.length; i++) {
|
for (let i = 0; i < apps.length; i++) {
|
||||||
let app = apps[i];
|
let app = apps[i];
|
||||||
@ -134,6 +143,9 @@ class AppFavorites {
|
|||||||
if (!app)
|
if (!app)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (!this._parentalControlsManager.shouldShowApp(app.app_info))
|
||||||
|
return false;
|
||||||
|
|
||||||
let ids = this._getIds();
|
let ids = this._getIds();
|
||||||
if (pos == -1)
|
if (pos == -1)
|
||||||
ids.push(appId);
|
ids.push(appId);
|
||||||
|
@ -147,9 +147,8 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
|
|||||||
_onDeviceSelected(dialog, device) {
|
_onDeviceSelected(dialog, device) {
|
||||||
let connection = this._dbusImpl.get_connection();
|
let connection = this._dbusImpl.get_connection();
|
||||||
let info = this._dbusImpl.get_info();
|
let info = this._dbusImpl.get_info();
|
||||||
let deviceName = Object.keys(AudioDevice).filter(
|
const deviceName = Object.keys(AudioDevice)
|
||||||
dev => AudioDevice[dev] == device
|
.filter(dev => AudioDevice[dev] === device)[0].toLowerCase();
|
||||||
)[0].toLowerCase();
|
|
||||||
connection.emit_signal(this._audioSelectionDialog._sender,
|
connection.emit_signal(this._audioSelectionDialog._sender,
|
||||||
this._dbusImpl.get_object_path(),
|
this._dbusImpl.get_object_path(),
|
||||||
info ? info.name : null,
|
info ? info.name : null,
|
||||||
|
@ -512,8 +512,8 @@ var SystemBackground = GObject.registerClass({
|
|||||||
super._init({
|
super._init({
|
||||||
meta_display: global.display,
|
meta_display: global.display,
|
||||||
monitor: 0,
|
monitor: 0,
|
||||||
background: _systemBackground,
|
|
||||||
});
|
});
|
||||||
|
this.content.background = _systemBackground;
|
||||||
|
|
||||||
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||||
this.emit('loaded');
|
this.emit('loaded');
|
||||||
@ -738,6 +738,8 @@ var BackgroundManager = class BackgroundManager {
|
|||||||
let backgroundActor = new Meta.BackgroundActor({
|
let backgroundActor = new Meta.BackgroundActor({
|
||||||
meta_display: global.display,
|
meta_display: global.display,
|
||||||
monitor: this._monitorIndex,
|
monitor: this._monitorIndex,
|
||||||
|
});
|
||||||
|
backgroundActor.content.set({
|
||||||
background,
|
background,
|
||||||
vignette: this._vignette,
|
vignette: this._vignette,
|
||||||
vignette_sharpness: 0.5,
|
vignette_sharpness: 0.5,
|
||||||
|
@ -30,8 +30,8 @@ var BarLevel = GObject.registerClass({
|
|||||||
accessible_role: Atk.Role.LEVEL_BAR,
|
accessible_role: Atk.Role.LEVEL_BAR,
|
||||||
};
|
};
|
||||||
super._init(Object.assign(defaultParams, params));
|
super._init(Object.assign(defaultParams, params));
|
||||||
this.connect('allocation-changed', (actor, box) => {
|
this.connect('notify::allocation', () => {
|
||||||
this._barLevelWidth = box.get_width();
|
this._barLevelWidth = this.allocation.get_width();
|
||||||
});
|
});
|
||||||
|
|
||||||
this._customAccessible = St.GenericAccessible.new_for_actor(this);
|
this._customAccessible = St.GenericAccessible.new_for_actor(this);
|
||||||
|
@ -196,8 +196,13 @@ var BoxPointer = GObject.registerClass({
|
|||||||
return themeNode.adjust_preferred_height(...height);
|
return themeNode.adjust_preferred_height(...height);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
if (this._sourceActor && this._sourceActor.mapped) {
|
||||||
|
this._reposition(box);
|
||||||
|
this._updateFlip(box);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.set_allocation(box);
|
||||||
|
|
||||||
let themeNode = this.get_theme_node();
|
let themeNode = this.get_theme_node();
|
||||||
let borderWidth = themeNode.get_length('-arrow-border-width');
|
let borderWidth = themeNode.get_length('-arrow-border-width');
|
||||||
@ -209,7 +214,7 @@ var BoxPointer = GObject.registerClass({
|
|||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.x2 = availWidth;
|
childBox.x2 = availWidth;
|
||||||
childBox.y2 = availHeight;
|
childBox.y2 = availHeight;
|
||||||
this._border.allocate(childBox, flags);
|
this._border.allocate(childBox);
|
||||||
|
|
||||||
childBox.x1 = borderWidth;
|
childBox.x1 = borderWidth;
|
||||||
childBox.y1 = borderWidth;
|
childBox.y1 = borderWidth;
|
||||||
@ -229,13 +234,7 @@ var BoxPointer = GObject.registerClass({
|
|||||||
childBox.x2 -= rise;
|
childBox.x2 -= rise;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
this.bin.allocate(childBox, flags);
|
this.bin.allocate(childBox);
|
||||||
|
|
||||||
if (this._sourceActor && this._sourceActor.mapped) {
|
|
||||||
this._reposition(box);
|
|
||||||
this._updateFlip(box);
|
|
||||||
this.set_allocation(box, flags);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_drawBorder(area) {
|
_drawBorder(area) {
|
||||||
|
@ -14,7 +14,6 @@ const { loadInterfaceXML } = imports.misc.fileUtils;
|
|||||||
|
|
||||||
var MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
var MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||||
var SHOW_WEEKDATE_KEY = 'show-weekdate';
|
var SHOW_WEEKDATE_KEY = 'show-weekdate';
|
||||||
var ELLIPSIS_CHAR = '\u2026';
|
|
||||||
|
|
||||||
var MESSAGE_ICON_SIZE = -1; // pick up from CSS
|
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());
|
return sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
function isToday(date) {
|
|
||||||
return sameDay(new Date(), date);
|
|
||||||
}
|
|
||||||
|
|
||||||
function _isWorkDay(date) {
|
function _isWorkDay(date) {
|
||||||
/* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
|
/* 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");
|
let days = C_('calendar-no-work', "06");
|
||||||
@ -199,46 +194,52 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
|
|
||||||
this._initialized = false;
|
this._initialized = false;
|
||||||
this._dbusProxy = new CalendarServer();
|
this._dbusProxy = new CalendarServer();
|
||||||
this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, (object, result) => {
|
this._initProxy();
|
||||||
let loaded = false;
|
}
|
||||||
|
|
||||||
try {
|
async _initProxy() {
|
||||||
this._dbusProxy.init_finish(result);
|
let loaded = false;
|
||||||
loaded = true;
|
|
||||||
} catch (e) {
|
try {
|
||||||
if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
|
await this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null);
|
||||||
// Ignore timeouts and install signals as normal, because with high
|
loaded = true;
|
||||||
// probability the service will appear later on, and we will get a
|
} catch (e) {
|
||||||
// NameOwnerChanged which will finish loading
|
// Ignore timeouts and install signals as normal, because with high
|
||||||
//
|
// probability the service will appear later on, and we will get a
|
||||||
// (But still _initialized to false, because the proxy does not know
|
// NameOwnerChanged which will finish loading
|
||||||
// about the HasCalendars property and would cause an exception trying
|
//
|
||||||
// to read it)
|
// (But still _initialized to false, because the proxy does not know
|
||||||
} else {
|
// about the HasCalendars property and would cause an exception trying
|
||||||
log('Error loading calendars: %s'.format(e.message));
|
// to read it)
|
||||||
return;
|
if (!e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
|
||||||
}
|
log('Error loading calendars: %s'.format(e.message));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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', () => {
|
this._dbusProxy.connect('notify::g-name-owner', () => {
|
||||||
if (this._dbusProxy.g_name_owner)
|
if (this._dbusProxy.g_name_owner)
|
||||||
this._onNameAppeared();
|
|
||||||
else
|
|
||||||
this._onNameVanished();
|
|
||||||
});
|
|
||||||
|
|
||||||
this._dbusProxy.connect('g-properties-changed', () => {
|
|
||||||
this.notify('has-calendars');
|
|
||||||
});
|
|
||||||
|
|
||||||
this._initialized = loaded;
|
|
||||||
if (loaded) {
|
|
||||||
this.notify('has-calendars');
|
|
||||||
this._onNameAppeared();
|
this._onNameAppeared();
|
||||||
}
|
else
|
||||||
|
this._onNameVanished();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._dbusProxy.connect('g-properties-changed', () => {
|
||||||
|
this.notify('has-calendars');
|
||||||
|
});
|
||||||
|
|
||||||
|
this._initialized = loaded;
|
||||||
|
if (loaded) {
|
||||||
|
this.notify('has-calendars');
|
||||||
|
this._onNameAppeared();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
@ -257,7 +258,7 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_resetCache() {
|
_resetCache() {
|
||||||
this._events = [];
|
this._events = new Map();
|
||||||
this._lastRequestBegin = null;
|
this._lastRequestBegin = null;
|
||||||
this._lastRequestEnd = null;
|
this._lastRequestEnd = null;
|
||||||
}
|
}
|
||||||
@ -273,28 +274,47 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
this.emit('changed');
|
this.emit('changed');
|
||||||
}
|
}
|
||||||
|
|
||||||
_onChanged() {
|
_onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) {
|
||||||
this._loadEvents(false);
|
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) {
|
_onEventsRemoved(dbusProxy, nameOwner, argArray) {
|
||||||
let newEvents = [];
|
const [ids = []] = argArray;
|
||||||
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());
|
|
||||||
|
|
||||||
this._events = newEvents;
|
let changed = false;
|
||||||
this._isLoading = false;
|
for (const id of ids)
|
||||||
this.emit('changed');
|
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) {
|
_loadEvents(forceReload) {
|
||||||
@ -303,33 +323,38 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (this._curRequestBegin && this._curRequestEnd) {
|
if (this._curRequestBegin && this._curRequestEnd) {
|
||||||
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
|
if (forceReload) {
|
||||||
this._curRequestEnd.getTime() / 1000,
|
this._events.clear();
|
||||||
forceReload,
|
this.emit('changed');
|
||||||
this._onEventsReceived.bind(this),
|
}
|
||||||
Gio.DBusCallFlags.NONE);
|
this._dbusProxy.SetTimeRangeRemote(
|
||||||
|
this._curRequestBegin.getTime() / 1000,
|
||||||
|
this._curRequestEnd.getTime() / 1000,
|
||||||
|
forceReload,
|
||||||
|
Gio.DBusCallFlags.NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
requestRange(begin, end) {
|
requestRange(begin, end) {
|
||||||
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
|
||||||
this._isLoading = true;
|
|
||||||
this._lastRequestBegin = begin;
|
this._lastRequestBegin = begin;
|
||||||
this._lastRequestEnd = end;
|
this._lastRequestEnd = end;
|
||||||
this._curRequestBegin = begin;
|
this._curRequestBegin = begin;
|
||||||
this._curRequestEnd = end;
|
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) {
|
getEvents(begin, end) {
|
||||||
let result = [];
|
let result = [...this._getFilteredEvents(begin, end)];
|
||||||
for (let n = 0; n < this._events.length; n++) {
|
|
||||||
let event = this._events[n];
|
|
||||||
|
|
||||||
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
|
|
||||||
result.push(event);
|
|
||||||
}
|
|
||||||
result.sort((event1, event2) => {
|
result.sort((event1, event2) => {
|
||||||
// sort events by end time on ending day
|
// sort events by end time on ending day
|
||||||
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
|
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
|
||||||
@ -343,12 +368,8 @@ class DBusEventSource extends EventSourceBase {
|
|||||||
let dayBegin = _getBeginningOfDay(day);
|
let dayBegin = _getBeginningOfDay(day);
|
||||||
let dayEnd = _getEndOfDay(day);
|
let dayEnd = _getEndOfDay(day);
|
||||||
|
|
||||||
let events = this.getEvents(dayBegin, dayEnd);
|
const { done } = this._getFilteredEvents(dayBegin, dayEnd).next();
|
||||||
|
return !done;
|
||||||
if (events.length == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -697,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(
|
var NotificationMessage = GObject.registerClass(
|
||||||
class NotificationMessage extends MessageList.Message {
|
class NotificationMessage extends MessageList.Message {
|
||||||
_init(notification) {
|
_init(notification) {
|
||||||
@ -817,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(
|
var TimeLabel = GObject.registerClass(
|
||||||
class NotificationTimeLabel extends St.Label {
|
class NotificationTimeLabel extends St.Label {
|
||||||
_init(datetime) {
|
_init(datetime) {
|
||||||
@ -1055,10 +879,6 @@ class NotificationSection extends MessageList.MessageListSection {
|
|||||||
});
|
});
|
||||||
super.vfunc_map();
|
super.vfunc_map();
|
||||||
}
|
}
|
||||||
|
|
||||||
_shouldShow() {
|
|
||||||
return !this.empty && isToday(this._date);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var Placeholder = GObject.registerClass(
|
var Placeholder = GObject.registerClass(
|
||||||
@ -1067,41 +887,13 @@ class Placeholder extends St.BoxLayout {
|
|||||||
super._init({ style_class: 'message-list-placeholder', vertical: true });
|
super._init({ style_class: 'message-list-placeholder', vertical: true });
|
||||||
this._date = new Date();
|
this._date = new Date();
|
||||||
|
|
||||||
let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
|
const file = Gio.File.new_for_uri(
|
||||||
let otherFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-events.svg');
|
'resource:///org/gnome/shell/theme/no-notifications.svg');
|
||||||
this._todayIcon = new Gio.FileIcon({ file: todayFile });
|
this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file }) });
|
||||||
this._otherIcon = new Gio.FileIcon({ file: otherFile });
|
|
||||||
|
|
||||||
this._icon = new St.Icon();
|
|
||||||
this.add_actor(this._icon);
|
this.add_actor(this._icon);
|
||||||
|
|
||||||
this._label = new St.Label();
|
this._label = new St.Label({ text: _('No Notifications') });
|
||||||
this.add_actor(this._label);
|
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1166,8 +958,8 @@ class CalendarMessageList extends St.Widget {
|
|||||||
child: this._dndSwitch,
|
child: this._dndSwitch,
|
||||||
label_actor: dndLabel,
|
label_actor: dndLabel,
|
||||||
});
|
});
|
||||||
this._dndButton.bind_property('checked',
|
this._dndSwitch.bind_property('state',
|
||||||
this._dndSwitch, 'state',
|
this._dndButton, 'checked',
|
||||||
GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE);
|
GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE);
|
||||||
hbox.add_child(this._dndButton);
|
hbox.add_child(this._dndButton);
|
||||||
|
|
||||||
@ -1202,9 +994,6 @@ class CalendarMessageList extends St.Widget {
|
|||||||
this._notificationSection = new NotificationSection();
|
this._notificationSection = new NotificationSection();
|
||||||
this._addSection(this._notificationSection);
|
this._addSection(this._notificationSection);
|
||||||
|
|
||||||
this._eventsSection = new EventsSection();
|
|
||||||
this._addSection(this._eventsSection);
|
|
||||||
|
|
||||||
Main.sessionMode.connect('updated', this._sync.bind(this));
|
Main.sessionMode.connect('updated', this._sync.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1240,13 +1029,4 @@ class CalendarMessageList extends St.Widget {
|
|||||||
let canClear = sections.some(s => s.canClear && s.visible);
|
let canClear = sections.some(s => s.canClear && s.visible);
|
||||||
this._clearButton.reactive = canClear;
|
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() {
|
_sessionUpdated() {
|
||||||
let newEnabledComponents = Main.sessionMode.components;
|
let newEnabledComponents = Main.sessionMode.components;
|
||||||
|
|
||||||
newEnabledComponents.filter(
|
newEnabledComponents
|
||||||
name => !this._enabledComponents.includes(name)
|
.filter(name => !this._enabledComponents.includes(name))
|
||||||
).forEach(name => {
|
.forEach(name => this._enableComponent(name));
|
||||||
this._enableComponent(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._enabledComponents.filter(
|
this._enabledComponents
|
||||||
name => !newEnabledComponents.includes(name)
|
.filter(name => !newEnabledComponents.includes(name))
|
||||||
).forEach(name => {
|
.forEach(name => this._disableComponent(name));
|
||||||
this._disableComponent(name);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._enabledComponents = newEnabledComponents;
|
this._enabledComponents = newEnabledComponents;
|
||||||
}
|
}
|
||||||
|
@ -125,8 +125,7 @@ var ContentTypeDiscoverer = class {
|
|||||||
_emitCallback(mount, contentTypes = []) {
|
_emitCallback(mount, contentTypes = []) {
|
||||||
// we're not interested in win32 software content types here
|
// we're not interested in win32 software content types here
|
||||||
contentTypes = contentTypes.filter(
|
contentTypes = contentTypes.filter(
|
||||||
type => type != 'x-content/win32-software'
|
type => type !== 'x-content/win32-software');
|
||||||
);
|
|
||||||
|
|
||||||
let apps = [];
|
let apps = [];
|
||||||
contentTypes.forEach(type => {
|
contentTypes.forEach(type => {
|
||||||
|
@ -10,6 +10,7 @@ const MessageTray = imports.ui.messageTray;
|
|||||||
const ModalDialog = imports.ui.modalDialog;
|
const ModalDialog = imports.ui.modalDialog;
|
||||||
const ShellEntry = imports.ui.shellEntry;
|
const ShellEntry = imports.ui.shellEntry;
|
||||||
|
|
||||||
|
Gio._promisify(Shell.NetworkAgent.prototype, 'init_async', 'init_finish');
|
||||||
Gio._promisify(Shell.NetworkAgent.prototype,
|
Gio._promisify(Shell.NetworkAgent.prototype,
|
||||||
'search_vpn_plugin', 'search_vpn_plugin_finish');
|
'search_vpn_plugin', 'search_vpn_plugin_finish');
|
||||||
|
|
||||||
@ -482,39 +483,37 @@ var VPNRequestHandler = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_readStdoutOldStyle() {
|
async _readStdoutOldStyle() {
|
||||||
this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, (stream, result) => {
|
const [line, len_] =
|
||||||
let [line, len_] = this._dataStdout.read_line_finish_utf8(result);
|
await this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null);
|
||||||
|
|
||||||
if (line == null) {
|
if (line === null) {
|
||||||
// end of file
|
// end of file
|
||||||
this._stdout.close(null);
|
this._stdout.close(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._vpnChildProcessLineOldStyle(line);
|
this._vpnChildProcessLineOldStyle(line);
|
||||||
|
|
||||||
// try to read more!
|
// try to read more!
|
||||||
this._readStdoutOldStyle();
|
this._readStdoutOldStyle();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_readStdoutNewStyle() {
|
async _readStdoutNewStyle() {
|
||||||
this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null, (stream, result) => {
|
const cnt =
|
||||||
let cnt = this._dataStdout.fill_finish(result);
|
await this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null);
|
||||||
|
|
||||||
if (cnt == 0) {
|
if (cnt === 0) {
|
||||||
// end of file
|
// end of file
|
||||||
this._showNewStyleDialog();
|
this._showNewStyleDialog();
|
||||||
|
|
||||||
this._stdout.close(null);
|
this._stdout.close(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to read more
|
// Try to read more
|
||||||
this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
|
this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
|
||||||
this._readStdoutNewStyle();
|
this._readStdoutNewStyle();
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_showNewStyleDialog() {
|
_showNewStyleDialog() {
|
||||||
@ -621,15 +620,17 @@ var NetworkAgent = class {
|
|||||||
this._native.connect('cancel-request', this._cancelRequest.bind(this));
|
this._native.connect('cancel-request', this._cancelRequest.bind(this));
|
||||||
|
|
||||||
this._initialized = false;
|
this._initialized = false;
|
||||||
this._native.init_async(GLib.PRIORITY_DEFAULT, null, (o, res) => {
|
this._initNative();
|
||||||
try {
|
}
|
||||||
this._native.init_finish(res);
|
|
||||||
this._initialized = true;
|
async _initNative() {
|
||||||
} catch (e) {
|
try {
|
||||||
this._native = null;
|
await this._native.init_async(GLib.PRIORITY_DEFAULT, null);
|
||||||
logError(e, 'error initializing the NetworkManager Agent');
|
this._initialized = true;
|
||||||
}
|
} catch (e) {
|
||||||
});
|
this._native = null;
|
||||||
|
logError(e, 'error initializing the NetworkManager Agent');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enable() {
|
enable() {
|
||||||
|
@ -327,12 +327,16 @@ var AuthenticationDialog = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let resetDialog = () => {
|
let resetDialog = () => {
|
||||||
|
this._sessionRequestTimeoutId = 0;
|
||||||
|
|
||||||
if (this.state != ModalDialog.State.OPENED)
|
if (this.state != ModalDialog.State.OPENED)
|
||||||
return;
|
return GLib.SOURCE_REMOVE;
|
||||||
|
|
||||||
this._passwordEntry.hide();
|
this._passwordEntry.hide();
|
||||||
this._cancelButton.grab_key_focus();
|
this._cancelButton.grab_key_focus();
|
||||||
this._okButton.reactive = false;
|
this._okButton.reactive = false;
|
||||||
|
|
||||||
|
return GLib.SOURCE_REMOVE;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (delay) {
|
if (delay) {
|
||||||
|
@ -7,6 +7,14 @@ var Tpl = null;
|
|||||||
var Tp = null;
|
var Tp = null;
|
||||||
try {
|
try {
|
||||||
({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi);
|
({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi);
|
||||||
|
|
||||||
|
Gio._promisify(Tp.Channel.prototype, 'close_async', 'close_finish');
|
||||||
|
Gio._promisify(Tp.Channel.prototype,
|
||||||
|
'send_message_async', 'send_message_finish');
|
||||||
|
Gio._promisify(Tp.ChannelDispatchOperation.prototype,
|
||||||
|
'claim_with_async', 'claim_with_finish');
|
||||||
|
Gio._promisify(Tpl.LogManager.prototype,
|
||||||
|
'get_filtered_events_async', 'get_filtered_events_finish');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Telepathy is not available, chat integration will be disabled.');
|
log('Telepathy is not available, chat integration will be disabled.');
|
||||||
}
|
}
|
||||||
@ -215,7 +223,7 @@ class TelepathyClient extends Tp.BaseClient {
|
|||||||
|
|
||||||
// We can only handle text channel, so close any other channel
|
// We can only handle text channel, so close any other channel
|
||||||
if (!(channel instanceof Tp.TextChannel)) {
|
if (!(channel instanceof Tp.TextChannel)) {
|
||||||
channel.close_async(null);
|
channel.close_async();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,7 +269,7 @@ class TelepathyClient extends Tp.BaseClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_approveTextChannel(account, conn, channel, dispatchOp, context) {
|
async _approveTextChannel(account, conn, channel, dispatchOp, context) {
|
||||||
let [targetHandle_, targetHandleType] = channel.get_handle();
|
let [targetHandle_, targetHandleType] = channel.get_handle();
|
||||||
|
|
||||||
if (targetHandleType != Tp.HandleType.CONTACT) {
|
if (targetHandleType != Tp.HandleType.CONTACT) {
|
||||||
@ -270,17 +278,15 @@ class TelepathyClient extends Tp.BaseClient {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Approve private text channels right away as we are going to handle it
|
|
||||||
dispatchOp.claim_with_async(this, (o, result) => {
|
|
||||||
try {
|
|
||||||
dispatchOp.claim_with_finish(result);
|
|
||||||
this._handlingChannels(account, conn, [channel], false);
|
|
||||||
} catch (err) {
|
|
||||||
log('Failed to Claim channel: %s'.format(err.toString()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
context.accept();
|
context.accept();
|
||||||
|
|
||||||
|
// Approve private text channels right away as we are going to handle it
|
||||||
|
try {
|
||||||
|
await dispatchOp.claim_with_async(this);
|
||||||
|
this._handlingChannels(account, conn, [channel], false);
|
||||||
|
} catch (err) {
|
||||||
|
log('Failed to Claim channel: %s'.format(err.toString()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_delegatedChannelsCb(_client, _channels) {
|
_delegatedChannelsCb(_client, _channels) {
|
||||||
@ -441,17 +447,14 @@ class ChatSource extends MessageTray.Source {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_getLogMessages() {
|
async _getLogMessages() {
|
||||||
let logManager = Tpl.LogManager.dup_singleton();
|
let logManager = Tpl.LogManager.dup_singleton();
|
||||||
let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
|
let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
|
||||||
|
|
||||||
logManager.get_filtered_events_async(this._account, entity,
|
const [events] = await logManager.get_filtered_events_async(
|
||||||
Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
|
this._account, entity,
|
||||||
null, this._displayPendingMessages.bind(this));
|
Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
|
||||||
}
|
null);
|
||||||
|
|
||||||
_displayPendingMessages(logManager, result) {
|
|
||||||
let [success_, events] = logManager.get_filtered_events_finish(result);
|
|
||||||
|
|
||||||
let logMessages = events.map(e => ChatMessage.newFromTplTextEvent(e));
|
let logMessages = events.map(e => ChatMessage.newFromTplTextEvent(e));
|
||||||
this._ensureNotification();
|
this._ensureNotification();
|
||||||
@ -509,9 +512,7 @@ class ChatSource extends MessageTray.Source {
|
|||||||
this._ackMessages();
|
this._ackMessages();
|
||||||
// The chat box has been destroyed so it can't
|
// The chat box has been destroyed so it can't
|
||||||
// handle the channel any more.
|
// handle the channel any more.
|
||||||
this._channel.close_async((channel, result) => {
|
this._channel.close_async();
|
||||||
channel.close_finish(result);
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Don't indicate any unread messages when the notification
|
// Don't indicate any unread messages when the notification
|
||||||
// that represents them has been destroyed.
|
// that represents them has been destroyed.
|
||||||
@ -609,9 +610,7 @@ class ChatSource extends MessageTray.Source {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let msg = Tp.ClientMessage.new_text(type, text);
|
let msg = Tp.ClientMessage.new_text(type, text);
|
||||||
this._channel.send_message_async(msg, 0, (src, result) => {
|
this._channel.send_message_async(msg, 0);
|
||||||
this._channel.send_message_finish(result);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setChatState(state) {
|
setChatState(state) {
|
||||||
|
@ -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 contentBox = this.get_theme_node().get_content_box(box);
|
||||||
let availWidth = contentBox.x2 - contentBox.x1;
|
let availWidth = contentBox.x2 - contentBox.x1;
|
||||||
|
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
let [appIcons, showAppsButton] = this.get_children();
|
let [appIcons, showAppsButton] = this.get_children();
|
||||||
let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
|
let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
|
||||||
@ -306,11 +306,11 @@ class DashActor extends St.Widget {
|
|||||||
childBox.y1 = contentBox.y1;
|
childBox.y1 = contentBox.y1;
|
||||||
childBox.x2 = contentBox.x2;
|
childBox.x2 = contentBox.x2;
|
||||||
childBox.y2 = contentBox.y2 - showAppsNatHeight;
|
childBox.y2 = contentBox.y2 - showAppsNatHeight;
|
||||||
appIcons.allocate(childBox, flags);
|
appIcons.allocate(childBox);
|
||||||
|
|
||||||
childBox.y1 = contentBox.y2 - showAppsNatHeight;
|
childBox.y1 = contentBox.y2 - showAppsNatHeight;
|
||||||
childBox.y2 = contentBox.y2;
|
childBox.y2 = contentBox.y2;
|
||||||
showAppsButton.allocate(childBox, flags);
|
showAppsButton.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_get_preferred_height(forWidth) {
|
vfunc_get_preferred_height(forWidth) {
|
||||||
@ -815,7 +815,12 @@ var Dash = GObject.registerClass({
|
|||||||
else
|
else
|
||||||
pos = 0; // always insert at the top when dash is empty
|
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;
|
this._dragPlaceholderPos = pos;
|
||||||
|
|
||||||
// Don't allow positioning before or after self
|
// Don't allow positioning before or after self
|
||||||
@ -843,11 +848,6 @@ var Dash = GObject.registerClass({
|
|||||||
this._dragPlaceholder.show(fadeIn);
|
this._dragPlaceholder.show(fadeIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove the drag placeholder if we are not in the
|
|
||||||
// "favorites zone"
|
|
||||||
if (pos > numFavorites)
|
|
||||||
this._clearDragPlaceholder();
|
|
||||||
|
|
||||||
if (!this._dragPlaceholder)
|
if (!this._dragPlaceholder)
|
||||||
return DND.DragMotionResult.NO_DROP;
|
return DND.DragMotionResult.NO_DROP;
|
||||||
|
|
||||||
|
@ -13,7 +13,11 @@ const System = imports.system;
|
|||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
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 MAX_FORECASTS = 5;
|
||||||
|
const ELLIPSIS_CHAR = '\u2026';
|
||||||
|
|
||||||
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
|
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
|
||||||
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
|
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(
|
var WorldClocksSection = GObject.registerClass(
|
||||||
class WorldClocksSection extends St.Button {
|
class WorldClocksSection extends St.Button {
|
||||||
_init() {
|
_init() {
|
||||||
@ -94,6 +280,7 @@ class WorldClocksSection extends St.Button {
|
|||||||
});
|
});
|
||||||
this._clock = new GnomeDesktop.WallClock();
|
this._clock = new GnomeDesktop.WallClock();
|
||||||
this._clockNotifyId = 0;
|
this._clockNotifyId = 0;
|
||||||
|
this._tzNotifyId = 0;
|
||||||
|
|
||||||
this._locations = [];
|
this._locations = [];
|
||||||
|
|
||||||
@ -166,8 +353,6 @@ class WorldClocksSection extends St.Button {
|
|||||||
layout.attach(header, 0, 0, 2, 1);
|
layout.attach(header, 0, 0, 2, 1);
|
||||||
this.label_actor = header;
|
this.label_actor = header;
|
||||||
|
|
||||||
let localOffset = GLib.DateTime.new_now_local().get_utc_offset();
|
|
||||||
|
|
||||||
for (let i = 0; i < this._locations.length; i++) {
|
for (let i = 0; i < this._locations.length; i++) {
|
||||||
let l = this._locations[i].location;
|
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' });
|
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({
|
const tz = new St.Label({
|
||||||
style_class: 'world-clocks-timezone',
|
style_class: 'world-clocks-timezone',
|
||||||
text,
|
|
||||||
x_align: Clutter.ActorAlign.END,
|
x_align: Clutter.ActorAlign.END,
|
||||||
y_align: Clutter.ActorAlign.CENTER,
|
y_align: Clutter.ActorAlign.CENTER,
|
||||||
});
|
});
|
||||||
@ -212,32 +384,65 @@ class WorldClocksSection extends St.Button {
|
|||||||
layout.attach(tz, 2, i + 1, 1, 1);
|
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._grid.get_n_children() > 1) {
|
||||||
if (!this._clockNotifyId) {
|
if (!this._clockNotifyId) {
|
||||||
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 {
|
} else {
|
||||||
if (this._clockNotifyId)
|
if (this._clockNotifyId)
|
||||||
this._clock.disconnect(this._clockNotifyId);
|
this._clock.disconnect(this._clockNotifyId);
|
||||||
this._clockNotifyId = 0;
|
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) {
|
_getTimeAtLocation(location) {
|
||||||
let tz = GLib.TimeZone.new(location.get_timezone().get_tzid());
|
let tz = GLib.TimeZone.new(location.get_timezone().get_tzid());
|
||||||
return GLib.DateTime.new_now(tz);
|
return GLib.DateTime.new_now(tz);
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateLabels() {
|
_updateTimeLabels() {
|
||||||
for (let i = 0; i < this._locations.length; i++) {
|
for (let i = 0; i < this._locations.length; i++) {
|
||||||
let l = this._locations[i];
|
let l = this._locations[i];
|
||||||
let now = this._getTimeAtLocation(l.location);
|
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;
|
this.child = box;
|
||||||
|
|
||||||
let titleBox = new St.BoxLayout({ style_class: 'weather-header-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',
|
style_class: 'weather-header',
|
||||||
x_align: Clutter.ActorAlign.START,
|
x_align: Clutter.ActorAlign.START,
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
y_align: Clutter.ActorAlign.END,
|
y_align: Clutter.ActorAlign.END,
|
||||||
text: _('Weather'),
|
});
|
||||||
}));
|
titleBox.add_child(this._titleLabel);
|
||||||
box.add_child(titleBox);
|
box.add_child(titleBox);
|
||||||
|
|
||||||
this._titleLocation = new St.Label({
|
this._titleLocation = new St.Label({
|
||||||
@ -414,10 +619,8 @@ class WeatherSection extends St.Button {
|
|||||||
_updateForecasts() {
|
_updateForecasts() {
|
||||||
this._forecastGrid.destroy_all_children();
|
this._forecastGrid.destroy_all_children();
|
||||||
|
|
||||||
if (!this._weatherClient.hasLocation) {
|
if (!this._weatherClient.hasLocation)
|
||||||
this._setStatusLabel(_("Select a location…"));
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
const { info } = this._weatherClient;
|
const { info } = this._weatherClient;
|
||||||
this._titleLocation.text = this._findBestLocationName(info.location);
|
this._titleLocation.text = this._findBestLocationName(info.location);
|
||||||
@ -444,6 +647,12 @@ class WeatherSection extends St.Button {
|
|||||||
if (!this.visible)
|
if (!this.visible)
|
||||||
return;
|
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._titleLocation.visible = this._weatherClient.hasLocation;
|
||||||
|
|
||||||
this._updateForecasts();
|
this._updateForecasts();
|
||||||
@ -462,7 +671,6 @@ class MessagesIndicator extends St.Icon {
|
|||||||
|
|
||||||
this._sources = [];
|
this._sources = [];
|
||||||
this._count = 0;
|
this._count = 0;
|
||||||
this._doNotDisturb = false;
|
|
||||||
|
|
||||||
this._settings = new Gio.Settings({
|
this._settings = new Gio.Settings({
|
||||||
schema_id: 'org.gnome.desktop.notifications',
|
schema_id: 'org.gnome.desktop.notifications',
|
||||||
@ -543,8 +751,8 @@ class FreezableBinLayout extends Clutter.BinLayout {
|
|||||||
return this._savedHeight;
|
return this._savedHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(container, allocation, flags) {
|
vfunc_allocate(container, allocation) {
|
||||||
super.vfunc_allocate(container, allocation, flags);
|
super.vfunc_allocate(container, allocation);
|
||||||
|
|
||||||
let [width, height] = allocation.get_size();
|
let [width, height] = allocation.get_size();
|
||||||
this._savedWidth = [width, width];
|
this._savedWidth = [width, width];
|
||||||
@ -610,7 +818,7 @@ class DateMenuButton extends PanelMenu.Button {
|
|||||||
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
|
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
|
||||||
let date = _gDateTimeToDate(datetime);
|
let date = _gDateTimeToDate(datetime);
|
||||||
layout.frozen = !_isToday(date);
|
layout.frozen = !_isToday(date);
|
||||||
this._messageList.setDate(date);
|
this._eventsItem.setDate(date);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.menu.connect('open-state-changed', (menu, isOpen) => {
|
this.menu.connect('open-state-changed', (menu, isOpen) => {
|
||||||
@ -619,7 +827,7 @@ class DateMenuButton extends PanelMenu.Button {
|
|||||||
let now = new Date();
|
let now = new Date();
|
||||||
this._calendar.setDate(now);
|
this._calendar.setDate(now);
|
||||||
this._date.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' });
|
style_class: 'datemenu-displays-box' });
|
||||||
this._displaysSection.add_actor(displaysBox);
|
this._displaysSection.add_actor(displaysBox);
|
||||||
|
|
||||||
|
this._eventsItem = new EventsSection();
|
||||||
|
displaysBox.add_child(this._eventsItem);
|
||||||
|
|
||||||
this._clocksItem = new WorldClocksSection();
|
this._clocksItem = new WorldClocksSection();
|
||||||
displaysBox.add_child(this._clocksItem);
|
displaysBox.add_child(this._clocksItem);
|
||||||
|
|
||||||
@ -675,7 +886,7 @@ class DateMenuButton extends PanelMenu.Button {
|
|||||||
this._eventSource.destroy();
|
this._eventSource.destroy();
|
||||||
|
|
||||||
this._calendar.setEventSource(eventSource);
|
this._calendar.setEventSource(eventSource);
|
||||||
this._messageList.setEventSource(eventSource);
|
this._eventsItem.setEventSource(eventSource);
|
||||||
|
|
||||||
this._eventSource = 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._dragActorSource = undefined;
|
||||||
this._dragOrigParent = this.actor.get_parent();
|
this._dragOrigParent = this.actor.get_parent();
|
||||||
this._dragOrigX = this._dragActor.x;
|
this._dragActorHadFixedPos = this._dragActor.fixed_position_set;
|
||||||
this._dragOrigY = this._dragActor.y;
|
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;
|
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
|
// Set the actor's scale such that it will keep the same
|
||||||
// transformed size when it's reparented to the uiGroup
|
// transformed size when it's reparented to the uiGroup
|
||||||
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
|
this._dragActor.set_scale(
|
||||||
this._dragActor.set_scale(scaledWidth / this.actor.width,
|
transformedAllocation.get_width() / newAllocatedWidth,
|
||||||
scaledHeight / this.actor.height);
|
transformedAllocation.get_height() / newAllocatedHeight);
|
||||||
|
|
||||||
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
|
this._dragOffsetX = transformedAllocation.x1 - this._dragStartX;
|
||||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
this._dragOffsetY = transformedAllocation.y1 - this._dragStartY;
|
||||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
|
||||||
|
|
||||||
this._dragOrigParent.remove_actor(this._dragActor);
|
this._dragOrigParent.remove_actor(this._dragActor);
|
||||||
Main.uiGroup.add_child(this._dragActor);
|
Main.uiGroup.add_child(this._dragActor);
|
||||||
@ -417,6 +428,10 @@ var _Draggable = class _Draggable {
|
|||||||
this._dragOffsetX -= transX;
|
this._dragOffsetX -= transX;
|
||||||
this._dragOffsetY -= transY;
|
this._dragOffsetY -= transY;
|
||||||
|
|
||||||
|
this._dragActor.set_position(
|
||||||
|
this._dragX + this._dragOffsetX,
|
||||||
|
this._dragY + this._dragOffsetY);
|
||||||
|
|
||||||
if (this._dragActorMaxSize != undefined) {
|
if (this._dragActorMaxSize != undefined) {
|
||||||
let [scaledWidth, scaledHeight] = this._dragActor.get_transformed_size();
|
let [scaledWidth, scaledHeight] = this._dragActor.get_transformed_size();
|
||||||
let currentSize = Math.max(scaledWidth, scaledHeight);
|
let currentSize = Math.max(scaledWidth, scaledHeight);
|
||||||
@ -635,9 +650,15 @@ var _Draggable = class _Draggable {
|
|||||||
if (parentWidth != 0)
|
if (parentWidth != 0)
|
||||||
parentScale = parentScaledWidth / parentWidth;
|
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;
|
x = parentX + parentScale * this._dragOrigX;
|
||||||
y = parentY + parentScale * this._dragOrigY;
|
y = parentY + parentScale * this._dragOrigY;
|
||||||
scale = this._dragOrigScale * parentScale;
|
scale = this._dragOrigScale * parentScale * childScaleX;
|
||||||
} else {
|
} else {
|
||||||
// Snap back actor to its original stage position
|
// Snap back actor to its original stage position
|
||||||
x = this._snapBackX;
|
x = this._snapBackX;
|
||||||
@ -718,7 +739,10 @@ var _Draggable = class _Draggable {
|
|||||||
Main.uiGroup.remove_child(this._dragActor);
|
Main.uiGroup.remove_child(this._dragActor);
|
||||||
this._dragOrigParent.add_actor(this._dragActor);
|
this._dragOrigParent.add_actor(this._dragActor);
|
||||||
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
|
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 {
|
} else {
|
||||||
dragActor.destroy();
|
dragActor.destroy();
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,6 @@ const UserWidget = imports.ui.userWidget;
|
|||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||||
|
|
||||||
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
|
|
||||||
|
|
||||||
const _ITEM_ICON_SIZE = 64;
|
const _ITEM_ICON_SIZE = 64;
|
||||||
|
|
||||||
const EndSessionDialogIface = loadInterfaceXML('org.gnome.SessionManager.EndSessionDialog');
|
const EndSessionDialogIface = loadInterfaceXML('org.gnome.SessionManager.EndSessionDialog');
|
||||||
@ -280,7 +278,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
|||||||
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
|
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPkOfflineProxyCreated(proxy, error) {
|
async _onPkOfflineProxyCreated(proxy, error) {
|
||||||
if (error) {
|
if (error) {
|
||||||
log(error.message);
|
log(error.message);
|
||||||
return;
|
return;
|
||||||
@ -295,15 +293,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// It only makes sense to check for this permission if PackageKit is available.
|
// It only makes sense to check for this permission if PackageKit is available.
|
||||||
Polkit.Permission.new(
|
try {
|
||||||
'org.freedesktop.packagekit.trigger-offline-update', null, null,
|
this._updatesPermission = await Polkit.Permission.new(
|
||||||
(source, res) => {
|
'org.freedesktop.packagekit.trigger-offline-update', null, null);
|
||||||
try {
|
} catch (e) {
|
||||||
this._updatesPermission = Polkit.Permission.new_finish(res);
|
log('No permission to trigger offline updates: %s'.format(e.toString()));
|
||||||
} catch (e) {
|
}
|
||||||
log('No permission to trigger offline updates: %s'.format(e.toString()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
|
@ -10,10 +10,21 @@ imports.gi.versions.Gtk = '3.0';
|
|||||||
imports.gi.versions.TelepathyGLib = '0.12';
|
imports.gi.versions.TelepathyGLib = '0.12';
|
||||||
imports.gi.versions.TelepathyLogger = '0.2';
|
imports.gi.versions.TelepathyLogger = '0.2';
|
||||||
|
|
||||||
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
const { Clutter, Gio, GLib, GObject, Meta, Polkit, Shell, St } = imports.gi;
|
||||||
const Gettext = imports.gettext;
|
const Gettext = imports.gettext;
|
||||||
const System = imports.system;
|
const System = imports.system;
|
||||||
|
|
||||||
|
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async', 'fill_finish');
|
||||||
|
Gio._promisify(Gio.DataInputStream.prototype,
|
||||||
|
'read_line_async', 'read_line_finish');
|
||||||
|
Gio._promisify(Gio.DBus, 'get', 'get_finish');
|
||||||
|
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
|
||||||
|
Gio._promisify(Gio.DBusProxy, 'new', 'new_finish');
|
||||||
|
Gio._promisify(Gio.DBusProxy.prototype, 'init_async', 'init_finish');
|
||||||
|
Gio._promisify(Gio.DBusProxy.prototype,
|
||||||
|
'call_with_unix_fd_list', 'call_with_unix_fd_list_finish');
|
||||||
|
Gio._promisify(Polkit.Permission, 'new', 'new_finish');
|
||||||
|
|
||||||
let _localTimeZone = null;
|
let _localTimeZone = null;
|
||||||
|
|
||||||
// We can't import shell JS modules yet, because they may have
|
// We can't import shell JS modules yet, because they may have
|
||||||
@ -234,16 +245,15 @@ function _loggingFunc(...args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
// Add some bindings to the global JS namespace; (gjs keeps the web
|
// Add some bindings to the global JS namespace
|
||||||
// browser convention of having that namespace be called 'window'.)
|
globalThis.global = Shell.Global.get();
|
||||||
window.global = Shell.Global.get();
|
|
||||||
|
|
||||||
window.log = _loggingFunc;
|
globalThis.log = _loggingFunc;
|
||||||
|
|
||||||
window._ = Gettext.gettext;
|
globalThis._ = Gettext.gettext;
|
||||||
window.C_ = Gettext.pgettext;
|
globalThis.C_ = Gettext.pgettext;
|
||||||
window.ngettext = Gettext.ngettext;
|
globalThis.ngettext = Gettext.ngettext;
|
||||||
window.N_ = s => s;
|
globalThis.N_ = s => s;
|
||||||
|
|
||||||
GObject.gtypeNameBasedOnJSPath = true;
|
GObject.gtypeNameBasedOnJSPath = true;
|
||||||
|
|
||||||
@ -275,6 +285,11 @@ function init() {
|
|||||||
_easeActorProperty(this, 'value', target, params);
|
_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 () {
|
Clutter.Actor.prototype.toString = function () {
|
||||||
return St.describe_actor(this);
|
return St.describe_actor(this);
|
||||||
};
|
};
|
||||||
@ -345,10 +360,12 @@ function init() {
|
|||||||
|
|
||||||
// OK, now things are initialized enough that we can import shell JS
|
// OK, now things are initialized enough that we can import shell JS
|
||||||
const Format = imports.format;
|
const Format = imports.format;
|
||||||
const Tweener = imports.ui.tweener;
|
|
||||||
|
|
||||||
Tweener.init();
|
|
||||||
String.prototype.format = Format.format;
|
String.prototype.format = Format.format;
|
||||||
|
|
||||||
|
Math.clamp = function (x, lower, upper) {
|
||||||
|
return Math.min(Math.max(x, lower), upper);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// adjustAnimationTime:
|
// adjustAnimationTime:
|
||||||
|
@ -238,7 +238,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function init() {
|
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.
|
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
|
||||||
// _httpSession.add_feature(new Soup.ProxyResolverDefault());
|
// _httpSession.add_feature(new Soup.ProxyResolverDefault());
|
||||||
|
@ -26,6 +26,7 @@ var ExtensionManager = class {
|
|||||||
this._updateNotified = false;
|
this._updateNotified = false;
|
||||||
|
|
||||||
this._extensions = new Map();
|
this._extensions = new Map();
|
||||||
|
this._unloadedExtensions = new Map();
|
||||||
this._enabledExtensions = [];
|
this._enabledExtensions = [];
|
||||||
this._extensionOrder = [];
|
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 {
|
try {
|
||||||
extension.stateObj.disable();
|
extension.stateObj.disable();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logExtensionError(uuid, 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++) {
|
for (let i = 0; i < order.length; i++) {
|
||||||
let otherUuid = order[i];
|
let otherUuid = order[i];
|
||||||
try {
|
try {
|
||||||
@ -215,6 +216,24 @@ var ExtensionManager = class {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openExtensionPrefs(uuid, parentWindow, options) {
|
||||||
|
const extension = this.lookup(uuid);
|
||||||
|
if (!extension || !extension.hasPrefs)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Gio.DBus.session.call(
|
||||||
|
'org.gnome.Shell.Extensions',
|
||||||
|
'/org/gnome/Shell/Extensions',
|
||||||
|
'org.gnome.Shell.Extensions',
|
||||||
|
'OpenExtensionPrefs',
|
||||||
|
new GLib.Variant('(ssa{sv})', [uuid, parentWindow, options]),
|
||||||
|
null,
|
||||||
|
Gio.DBusCallFlags.NONE,
|
||||||
|
-1,
|
||||||
|
null);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
notifyExtensionUpdate(uuid) {
|
notifyExtensionUpdate(uuid) {
|
||||||
let extension = this.lookup(uuid);
|
let extension = this.lookup(uuid);
|
||||||
if (!extension)
|
if (!extension)
|
||||||
@ -241,7 +260,8 @@ var ExtensionManager = class {
|
|||||||
if (!extension)
|
if (!extension)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
let message = error.toString();
|
const message = error instanceof Error
|
||||||
|
? error.message : error.toString();
|
||||||
|
|
||||||
extension.error = message;
|
extension.error = message;
|
||||||
extension.state = ExtensionState.ERROR;
|
extension.state = ExtensionState.ERROR;
|
||||||
@ -250,6 +270,7 @@ var ExtensionManager = class {
|
|||||||
extension.errors.push(message);
|
extension.errors.push(message);
|
||||||
|
|
||||||
logError(error, 'Extension %s'.format(uuid));
|
logError(error, 'Extension %s'.format(uuid));
|
||||||
|
this._updateCanChange(extension);
|
||||||
this.emit('extension-state-changed', extension);
|
this.emit('extension-state-changed', extension);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,6 +320,14 @@ var ExtensionManager = class {
|
|||||||
return extension;
|
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) {
|
loadExtension(extension) {
|
||||||
// Default to error, we set success as the last step
|
// Default to error, we set success as the last step
|
||||||
extension.state = ExtensionState.ERROR;
|
extension.state = ExtensionState.ERROR;
|
||||||
@ -307,6 +336,9 @@ var ExtensionManager = class {
|
|||||||
|
|
||||||
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
|
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
|
||||||
extension.state = ExtensionState.OUT_OF_DATE;
|
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 {
|
} else {
|
||||||
let enabled = this._enabledExtensions.includes(extension.uuid);
|
let enabled = this._enabledExtensions.includes(extension.uuid);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@ -317,6 +349,8 @@ var ExtensionManager = class {
|
|||||||
} else {
|
} else {
|
||||||
extension.state = ExtensionState.INITIALIZED;
|
extension.state = ExtensionState.INITIALIZED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._unloadedExtensions.delete(extension.uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateCanChange(extension);
|
this._updateCanChange(extension);
|
||||||
@ -324,15 +358,22 @@ var ExtensionManager = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
unloadExtension(extension) {
|
unloadExtension(extension) {
|
||||||
|
const { uuid, type } = extension;
|
||||||
|
|
||||||
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
|
||||||
// but it will be removed on next reboot, and hopefully nothing
|
// but it will be removed on next reboot, and hopefully nothing
|
||||||
// broke too much.
|
// broke too much.
|
||||||
this._callExtensionDisable(extension.uuid);
|
this._callExtensionDisable(uuid);
|
||||||
|
|
||||||
extension.state = ExtensionState.UNINSTALLED;
|
extension.state = ExtensionState.UNINSTALLED;
|
||||||
this.emit('extension-state-changed', extension);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,19 +486,15 @@ var ExtensionManager = class {
|
|||||||
|
|
||||||
// Find and enable all the newly enabled extensions: UUIDs found in the
|
// Find and enable all the newly enabled extensions: UUIDs found in the
|
||||||
// new setting, but not in the old one.
|
// new setting, but not in the old one.
|
||||||
newEnabledExtensions.filter(
|
newEnabledExtensions
|
||||||
uuid => !this._enabledExtensions.includes(uuid)
|
.filter(uuid => !this._enabledExtensions.includes(uuid))
|
||||||
).forEach(uuid => {
|
.forEach(uuid => this._callExtensionEnable(uuid));
|
||||||
this._callExtensionEnable(uuid);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Find and disable all the newly disabled extensions: UUIDs found in the
|
// Find and disable all the newly disabled extensions: UUIDs found in the
|
||||||
// old setting, but not in the new one.
|
// old setting, but not in the new one.
|
||||||
this._extensionOrder.filter(
|
this._extensionOrder
|
||||||
uuid => !newEnabledExtensions.includes(uuid)
|
.filter(uuid => !newEnabledExtensions.includes(uuid))
|
||||||
).reverse().forEach(uuid => {
|
.reverse().forEach(uuid => this._callExtensionDisable(uuid));
|
||||||
this._callExtensionDisable(uuid);
|
|
||||||
});
|
|
||||||
|
|
||||||
this._enabledExtensions = newEnabledExtensions;
|
this._enabledExtensions = newEnabledExtensions;
|
||||||
}
|
}
|
||||||
|
1800
js/ui/iconGrid.js
1800
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();
|
this.queue_relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
if (box.get_width() > 0 && box.get_height() > 0) {
|
if (box.get_width() > 0 && box.get_height() > 0) {
|
||||||
let sizeRatio = box.get_width() / box.get_height();
|
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) {
|
_onPan(action) {
|
||||||
let [dist_, dx, dy_] = action.get_motion_delta(0);
|
let [dist_, dx, dy_] = action.get_motion_delta(0);
|
||||||
this.delta = this.delta + dx;
|
this.delta += dx;
|
||||||
|
|
||||||
if (this._currentKey != null) {
|
if (this._currentKey != null) {
|
||||||
this._currentKey.cancel();
|
this._currentKey.cancel();
|
||||||
@ -935,8 +935,7 @@ var EmojiSelection = GObject.registerClass({
|
|||||||
this.add_child(this._emojiPager);
|
this.add_child(this._emojiPager);
|
||||||
|
|
||||||
this._pageIndicator = new PageIndicators.PageIndicators(
|
this._pageIndicator = new PageIndicators.PageIndicators(
|
||||||
Clutter.Orientation.HORIZONTAL
|
Clutter.Orientation.HORIZONTAL);
|
||||||
);
|
|
||||||
this.add_child(this._pageIndicator);
|
this.add_child(this._pageIndicator);
|
||||||
this._pageIndicator.setReactive(false);
|
this._pageIndicator.setReactive(false);
|
||||||
|
|
||||||
@ -1119,7 +1118,7 @@ var KeyboardManager = class KeyBoardManager {
|
|||||||
this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this));
|
this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this));
|
||||||
|
|
||||||
this._lastDevice = null;
|
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)
|
if (device.device_type === Clutter.InputDeviceType.KEYBOARD_DEVICE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -1257,6 +1256,10 @@ class Keyboard extends St.BoxLayout {
|
|||||||
return this._keyboardVisible && super.visible;
|
return this._keyboardVisible && super.visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set visible(visible) {
|
||||||
|
super.visible = visible;
|
||||||
|
}
|
||||||
|
|
||||||
_onFocusPositionChanged(focusTracker) {
|
_onFocusPositionChanged(focusTracker) {
|
||||||
let rect = focusTracker.getCurrentRect();
|
let rect = focusTracker.getCurrentRect();
|
||||||
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
|
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
|
||||||
|
@ -246,7 +246,7 @@ var LayoutManager = GObject.registerClass({
|
|||||||
vertical: true });
|
vertical: true });
|
||||||
this.addChrome(this.panelBox, { affectsStruts: true,
|
this.addChrome(this.panelBox, { affectsStruts: true,
|
||||||
trackFullscreen: true });
|
trackFullscreen: true });
|
||||||
this.panelBox.connect('allocation-changed',
|
this.panelBox.connect('notify::allocation',
|
||||||
this._panelBoxChanged.bind(this));
|
this._panelBoxChanged.bind(this));
|
||||||
|
|
||||||
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
|
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
|
||||||
|
@ -27,13 +27,11 @@ var RadialShaderEffect = GObject.registerClass({
|
|||||||
'brightness': GObject.ParamSpec.float(
|
'brightness': GObject.ParamSpec.float(
|
||||||
'brightness', 'brightness', 'brightness',
|
'brightness', 'brightness', 'brightness',
|
||||||
GObject.ParamFlags.READWRITE,
|
GObject.ParamFlags.READWRITE,
|
||||||
0, 1, 1
|
0, 1, 1),
|
||||||
),
|
|
||||||
'sharpness': GObject.ParamSpec.float(
|
'sharpness': GObject.ParamSpec.float(
|
||||||
'sharpness', 'sharpness', 'sharpness',
|
'sharpness', 'sharpness', 'sharpness',
|
||||||
GObject.ParamFlags.READWRITE,
|
GObject.ParamFlags.READWRITE,
|
||||||
0, 1, 0
|
0, 1, 0),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
}, class RadialShaderEffect extends Shell.GLSLEffect {
|
}, class RadialShaderEffect extends Shell.GLSLEffect {
|
||||||
_init(params) {
|
_init(params) {
|
||||||
|
@ -37,10 +37,9 @@ const LG_ANIMATION_TIME = 500;
|
|||||||
|
|
||||||
function _getAutoCompleteGlobalKeywords() {
|
function _getAutoCompleteGlobalKeywords() {
|
||||||
const keywords = ['true', 'false', 'null', 'new'];
|
const keywords = ['true', 'false', 'null', 'new'];
|
||||||
// Don't add the private properties of window (i.e., ones starting with '_')
|
// Don't add the private properties of globalThis (i.e., ones starting with '_')
|
||||||
const windowProperties = Object.getOwnPropertyNames(window).filter(
|
const windowProperties = Object.getOwnPropertyNames(globalThis).filter(
|
||||||
a => a.charAt(0) != '_'
|
a => a.charAt(0) !== '_');
|
||||||
);
|
|
||||||
const headerProperties = JsParse.getDeclaredConstants(commandHeader);
|
const headerProperties = JsParse.getDeclaredConstants(commandHeader);
|
||||||
|
|
||||||
return keywords.concat(windowProperties).concat(headerProperties);
|
return keywords.concat(windowProperties).concat(headerProperties);
|
||||||
@ -555,8 +554,8 @@ var Inspector = GObject.registerClass({
|
|||||||
this._lookingGlass = lookingGlass;
|
this._lookingGlass = lookingGlass;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
if (!this._eventHandler)
|
if (!this._eventHandler)
|
||||||
return;
|
return;
|
||||||
@ -571,7 +570,7 @@ var Inspector = GObject.registerClass({
|
|||||||
childBox.x2 = childBox.x1 + natWidth;
|
childBox.x2 = childBox.x1 + natWidth;
|
||||||
childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
|
childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
|
||||||
childBox.y2 = childBox.y1 + natHeight;
|
childBox.y2 = childBox.y1 + natHeight;
|
||||||
this._eventHandler.allocate(childBox, flags);
|
this._eventHandler.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
_close() {
|
_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(
|
var LookingGlass = GObject.registerClass(
|
||||||
class LookingGlass extends St.BoxLayout {
|
class LookingGlass extends St.BoxLayout {
|
||||||
_init() {
|
_init() {
|
||||||
@ -834,9 +1018,9 @@ class LookingGlass extends St.BoxLayout {
|
|||||||
Main.uiGroup.add_actor(this);
|
Main.uiGroup.add_actor(this);
|
||||||
Main.uiGroup.set_child_below_sibling(this,
|
Main.uiGroup.set_child_below_sibling(this,
|
||||||
Main.layoutManager.panelBox);
|
Main.layoutManager.panelBox);
|
||||||
Main.layoutManager.panelBox.connect('allocation-changed',
|
Main.layoutManager.panelBox.connect('notify::allocation',
|
||||||
this._queueResize.bind(this));
|
this._queueResize.bind(this));
|
||||||
Main.layoutManager.keyboardBox.connect('allocation-changed',
|
Main.layoutManager.keyboardBox.connect('notify::allocation',
|
||||||
this._queueResize.bind(this));
|
this._queueResize.bind(this));
|
||||||
|
|
||||||
this._objInspector = new ObjInspector(this);
|
this._objInspector = new ObjInspector(this);
|
||||||
@ -918,6 +1102,9 @@ class LookingGlass extends St.BoxLayout {
|
|||||||
this._extensions = new Extensions(this);
|
this._extensions = new Extensions(this);
|
||||||
notebook.appendPage('Extensions', this._extensions);
|
notebook.appendPage('Extensions', this._extensions);
|
||||||
|
|
||||||
|
this._actorTreeViewer = new ActorTreeViewer(this);
|
||||||
|
notebook.appendPage('Actors', this._actorTreeViewer);
|
||||||
|
|
||||||
this._entry.clutter_text.connect('activate', (o, _e) => {
|
this._entry.clutter_text.connect('activate', (o, _e) => {
|
||||||
// Hide any completions we are currently showing
|
// Hide any completions we are currently showing
|
||||||
this._hideCompletions();
|
this._hideCompletions();
|
||||||
|
@ -643,8 +643,7 @@ var Magnifier = class Magnifier {
|
|||||||
// Applies only to the first zoom region.
|
// Applies only to the first zoom region.
|
||||||
if (this._zoomRegions.length) {
|
if (this._zoomRegions.length) {
|
||||||
this._zoomRegions[0].setClampScrollingAtEdges(
|
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.
|
// Applies only to the first zoom region.
|
||||||
if (this._zoomRegions.length) {
|
if (this._zoomRegions.length) {
|
||||||
this._zoomRegions[0].setMouseTrackingMode(
|
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.
|
// Applies only to the first zoom region.
|
||||||
if (this._zoomRegions.length) {
|
if (this._zoomRegions.length) {
|
||||||
this._zoomRegions[0].setFocusTrackingMode(
|
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.
|
// Applies only to the first zoom region.
|
||||||
if (this._zoomRegions.length) {
|
if (this._zoomRegions.length) {
|
||||||
this._zoomRegions[0].setCaretTrackingMode(
|
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.
|
// Applies only to the first zoom region.
|
||||||
if (this._zoomRegions.length) {
|
if (this._zoomRegions.length) {
|
||||||
this._zoomRegions[0].setInvertLightness(
|
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.
|
// Applies only to the first zoom region.
|
||||||
if (this._zoomRegions.length) {
|
if (this._zoomRegions.length) {
|
||||||
this._zoomRegions[0].setColorSaturation(
|
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.
|
// it modifies the brightness and/or contrast.
|
||||||
let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
|
let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
|
||||||
this._brightnessContrast.set_enabled(
|
this._brightnessContrast.set_enabled(
|
||||||
bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE ||
|
bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE ||
|
||||||
cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE
|
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1970,8 +1963,7 @@ var MagShaderEffects = class MagShaderEffects {
|
|||||||
// a null first argument.
|
// a null first argument.
|
||||||
let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
|
let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
|
||||||
this._brightnessContrast.set_enabled(
|
this._brightnessContrast.set_enabled(
|
||||||
cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE ||
|
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE ||
|
||||||
bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != 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 KbdA11yDialog = imports.ui.kbdA11yDialog;
|
||||||
const LocatePointer = imports.ui.locatePointer;
|
const LocatePointer = imports.ui.locatePointer;
|
||||||
const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
|
const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
|
||||||
|
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
||||||
|
|
||||||
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
|
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
|
||||||
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
|
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, 'delete_async', 'delete_finish');
|
||||||
Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish');
|
Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish');
|
||||||
|
|
||||||
|
let _remoteAccessInhibited = false;
|
||||||
|
|
||||||
function _sessionUpdated() {
|
function _sessionUpdated() {
|
||||||
if (sessionMode.isPrimary)
|
if (sessionMode.isPrimary)
|
||||||
_loadDefaultStylesheet();
|
_loadDefaultStylesheet();
|
||||||
@ -120,24 +123,41 @@ function _sessionUpdated() {
|
|||||||
if (lookingGlass)
|
if (lookingGlass)
|
||||||
lookingGlass.close();
|
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() {
|
function start() {
|
||||||
// These are here so we don't break compatibility.
|
// These are here so we don't break compatibility.
|
||||||
global.logError = window.log;
|
global.logError = globalThis.log;
|
||||||
global.log = window.log;
|
global.log = globalThis.log;
|
||||||
|
|
||||||
// Chain up async errors reported from C
|
// Chain up async errors reported from C
|
||||||
global.connect('notify-error', (global, msg, detail) => {
|
global.connect('notify-error', (global, msg, detail) => {
|
||||||
notifyError(msg, detail);
|
notifyError(msg, detail);
|
||||||
});
|
});
|
||||||
|
|
||||||
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
let currentDesktop = GLib.getenv('XDG_CURRENT_DESKTOP');
|
||||||
|
if (!currentDesktop || !currentDesktop.split(':').includes('GNOME'))
|
||||||
|
Gio.DesktopAppInfo.set_desktop_env('GNOME');
|
||||||
|
|
||||||
sessionMode = new SessionMode.SessionMode();
|
sessionMode = new SessionMode.SessionMode();
|
||||||
sessionMode.connect('updated', _sessionUpdated);
|
sessionMode.connect('updated', _sessionUpdated);
|
||||||
|
|
||||||
St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet);
|
St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet);
|
||||||
|
|
||||||
|
// Initialize ParentalControlsManager before the UI
|
||||||
|
ParentalControlsManager.getDefault();
|
||||||
|
|
||||||
_initializeUI();
|
_initializeUI();
|
||||||
|
|
||||||
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
|
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
|
||||||
@ -519,7 +539,9 @@ function pushModal(actor, params) {
|
|||||||
let prevFocusDestroyId;
|
let prevFocusDestroyId;
|
||||||
if (prevFocus != null) {
|
if (prevFocus != null) {
|
||||||
prevFocusDestroyId = prevFocus.connect('destroy', () => {
|
prevFocusDestroyId = prevFocus.connect('destroy', () => {
|
||||||
let index = _findModal(actor);
|
const index = modalActorFocusStack.findIndex(
|
||||||
|
record => record.prevFocus === prevFocus);
|
||||||
|
|
||||||
if (index >= 0)
|
if (index >= 0)
|
||||||
modalActorFocusStack[index].prevFocus = null;
|
modalActorFocusStack[index].prevFocus = null;
|
||||||
});
|
});
|
||||||
@ -795,7 +817,7 @@ function showRestartMessage(message) {
|
|||||||
|
|
||||||
var AnimationsSettings = class {
|
var AnimationsSettings = class {
|
||||||
constructor() {
|
constructor() {
|
||||||
let backend = Meta.get_backend();
|
let backend = global.backend;
|
||||||
if (!backend.is_rendering_hardware_accelerated()) {
|
if (!backend.is_rendering_hardware_accelerated()) {
|
||||||
St.Settings.get().inhibit_animations();
|
St.Settings.get().inhibit_animations();
|
||||||
return;
|
return;
|
||||||
|
@ -4,7 +4,6 @@ const { Atk, Clutter, Gio, GLib,
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageTray = imports.ui.messageTray;
|
const MessageTray = imports.ui.messageTray;
|
||||||
|
|
||||||
const Calendar = imports.ui.calendar;
|
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
var MESSAGE_ANIMATION_TIME = 100;
|
var MESSAGE_ANIMATION_TIME = 100;
|
||||||
@ -285,12 +284,12 @@ var LabelExpanderLayout = GObject.registerClass({
|
|||||||
return [min, nat];
|
return [min, nat];
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(container, box, flags) {
|
vfunc_allocate(container, box) {
|
||||||
for (let i = 0; i < container.get_n_children(); i++) {
|
for (let i = 0; i < container.get_n_children(); i++) {
|
||||||
let child = container.get_child_at_index(i);
|
let child = container.get_child_at_index(i);
|
||||||
|
|
||||||
if (child.visible)
|
if (child.visible)
|
||||||
child.allocate(box, flags);
|
child.allocate(box);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -572,7 +571,6 @@ var MessageListSection = GObject.registerClass({
|
|||||||
Main.sessionMode.disconnect(id);
|
Main.sessionMode.disconnect(id);
|
||||||
});
|
});
|
||||||
|
|
||||||
this._date = new Date();
|
|
||||||
this._empty = true;
|
this._empty = true;
|
||||||
this._canClear = false;
|
this._canClear = false;
|
||||||
this._sync();
|
this._sync();
|
||||||
@ -598,13 +596,6 @@ var MessageListSection = GObject.registerClass({
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDate(date) {
|
|
||||||
if (Calendar.sameDay(date, this._date))
|
|
||||||
return;
|
|
||||||
this._date = date;
|
|
||||||
this._sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
addMessage(message, animate) {
|
addMessage(message, animate) {
|
||||||
this.addMessageAtIndex(message, -1, animate);
|
this.addMessageAtIndex(message, -1, animate);
|
||||||
}
|
}
|
||||||
|
@ -136,29 +136,22 @@ var FocusGrabber = class FocusGrabber {
|
|||||||
var NotificationPolicy = GObject.registerClass({
|
var NotificationPolicy = GObject.registerClass({
|
||||||
Properties: {
|
Properties: {
|
||||||
'enable': GObject.ParamSpec.boolean(
|
'enable': GObject.ParamSpec.boolean(
|
||||||
'enable', 'enable', 'enable',
|
'enable', 'enable', 'enable', GObject.ParamFlags.READABLE, true),
|
||||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
|
||||||
true),
|
|
||||||
'enable-sound': GObject.ParamSpec.boolean(
|
'enable-sound': GObject.ParamSpec.boolean(
|
||||||
'enable-sound', 'enable-sound', 'enable-sound',
|
'enable-sound', 'enable-sound', 'enable-sound',
|
||||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
GObject.ParamFlags.READABLE, true),
|
||||||
true),
|
|
||||||
'show-banners': GObject.ParamSpec.boolean(
|
'show-banners': GObject.ParamSpec.boolean(
|
||||||
'show-banners', 'show-banners', 'show-banners',
|
'show-banners', 'show-banners', 'show-banners',
|
||||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
GObject.ParamFlags.READABLE, true),
|
||||||
true),
|
|
||||||
'force-expanded': GObject.ParamSpec.boolean(
|
'force-expanded': GObject.ParamSpec.boolean(
|
||||||
'force-expanded', 'force-expanded', 'force-expanded',
|
'force-expanded', 'force-expanded', 'force-expanded',
|
||||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
GObject.ParamFlags.READABLE, false),
|
||||||
false),
|
|
||||||
'show-in-lock-screen': GObject.ParamSpec.boolean(
|
'show-in-lock-screen': GObject.ParamSpec.boolean(
|
||||||
'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen',
|
'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen',
|
||||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
GObject.ParamFlags.READABLE, false),
|
||||||
false),
|
|
||||||
'details-in-lock-screen': GObject.ParamSpec.boolean(
|
'details-in-lock-screen': GObject.ParamSpec.boolean(
|
||||||
'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen',
|
'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen',
|
||||||
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
|
GObject.ParamFlags.READABLE, false),
|
||||||
false),
|
|
||||||
},
|
},
|
||||||
}, class NotificationPolicy extends GObject.Object {
|
}, class NotificationPolicy extends GObject.Object {
|
||||||
// Do nothing for the default policy. These methods are only useful for the
|
// Do nothing for the default policy. These methods are only useful for the
|
||||||
@ -169,24 +162,28 @@ var NotificationPolicy = GObject.registerClass({
|
|||||||
this.run_dispose();
|
this.run_dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get enable() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
get enableSound() {
|
get enableSound() {
|
||||||
return this.enable_sound;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get showBanners() {
|
get showBanners() {
|
||||||
return this.show_banners;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
get forceExpanded() {
|
get forceExpanded() {
|
||||||
return this.force_expanded;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get showInLockScreen() {
|
get showInLockScreen() {
|
||||||
return this.show_in_lock_screen;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
get detailsInLockScreen() {
|
get detailsInLockScreen() {
|
||||||
return this.details_in_lock_screen;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -689,8 +686,8 @@ class SourceActorWithLabel extends SourceActor {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
super.vfunc_allocate(box, flags);
|
super.vfunc_allocate(box);
|
||||||
|
|
||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
|
|
||||||
@ -710,7 +707,7 @@ class SourceActorWithLabel extends SourceActor {
|
|||||||
childBox.y1 = box.y2 - naturalHeight;
|
childBox.y1 = box.y2 - naturalHeight;
|
||||||
childBox.y2 = box.y2;
|
childBox.y2 = box.y2;
|
||||||
|
|
||||||
this._counterBin.allocate(childBox, flags);
|
this._counterBin.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateCount() {
|
_updateCount() {
|
||||||
@ -1167,8 +1164,7 @@ var MessageTray = GObject.registerClass({
|
|||||||
this._onNotificationDestroy.bind(this));
|
this._onNotificationDestroy.bind(this));
|
||||||
this._notificationQueue.push(notification);
|
this._notificationQueue.push(notification);
|
||||||
this._notificationQueue.sort(
|
this._notificationQueue.sort(
|
||||||
(n1, n2) => n2.urgency - n1.urgency
|
(n1, n2) => n2.urgency - n1.urgency);
|
||||||
);
|
|
||||||
this.emit('queue-changed');
|
this.emit('queue-changed');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
const { Gio, GObject, Shell, St } = imports.gi;
|
const { Gio, GObject, Shell, St } = imports.gi;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
|
|
||||||
const Calendar = imports.ui.calendar;
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const MessageList = imports.ui.messageList;
|
const MessageList = imports.ui.messageList;
|
||||||
|
|
||||||
@ -173,6 +172,11 @@ var MprisPlayer = class MprisPlayer {
|
|||||||
if (!this._mprisProxy.g_name_owner)
|
if (!this._mprisProxy.g_name_owner)
|
||||||
this._close();
|
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() {
|
_onPlayerProxyReady() {
|
||||||
@ -247,10 +251,6 @@ class MediaSection extends MessageList.MessageListSection {
|
|||||||
this._onProxyReady.bind(this));
|
this._onProxyReady.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
_shouldShow() {
|
|
||||||
return !this.empty && Calendar.isToday(this._date);
|
|
||||||
}
|
|
||||||
|
|
||||||
get allowed() {
|
get allowed() {
|
||||||
return !Main.sessionMode.isGreeter;
|
return !Main.sessionMode.isGreeter;
|
||||||
}
|
}
|
||||||
|
@ -10,13 +10,6 @@ const Params = imports.misc.params;
|
|||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
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');
|
const FdoNotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
|
||||||
|
|
||||||
var NotificationClosedReason = {
|
var NotificationClosedReason = {
|
||||||
@ -49,9 +42,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
|
|||||||
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
this._dbusImpl.export(Gio.DBus.session, '/org/freedesktop/Notifications');
|
||||||
|
|
||||||
this._sources = [];
|
this._sources = [];
|
||||||
this._senderToPid = {};
|
|
||||||
this._notifications = {};
|
this._notifications = {};
|
||||||
this._busProxy = new Bus();
|
|
||||||
|
|
||||||
this._nextNotificationId = 1;
|
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
|
// If no existing source is found, a new source is created as long as
|
||||||
// pid is provided.
|
// pid is provided.
|
||||||
//
|
|
||||||
// Either a pid or ndata.notification is needed to retrieve or
|
|
||||||
// create a source.
|
|
||||||
_getSource(title, pid, ndata, sender) {
|
_getSource(title, pid, ndata, sender) {
|
||||||
if (!pid && !(ndata && ndata.notification))
|
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
|
// We use notification's source for the notifications we still have
|
||||||
// around that are getting replaced because we don't keep sources
|
// around that are getting replaced because we don't keep sources
|
||||||
@ -218,42 +206,10 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
|
|||||||
this._notifications[id] = ndata;
|
this._notifications[id] = ndata;
|
||||||
|
|
||||||
let sender = invocation.get_sender();
|
let sender = invocation.get_sender();
|
||||||
let pid = this._senderToPid[sender];
|
let pid = hints['sender-pid'];
|
||||||
|
|
||||||
let source = this._getSource(appName, pid, ndata, sender, null);
|
let source = this._getSource(appName, pid, ndata, sender, null);
|
||||||
|
this._notifyForSource(source, ndata);
|
||||||
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);
|
|
||||||
});
|
|
||||||
|
|
||||||
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
return invocation.return_value(GLib.Variant.new('(u)', [id]));
|
||||||
}
|
}
|
||||||
@ -417,12 +373,11 @@ var FdoNotificationDaemonSource = GObject.registerClass(
|
|||||||
class FdoNotificationDaemonSource extends MessageTray.Source {
|
class FdoNotificationDaemonSource extends MessageTray.Source {
|
||||||
_init(title, pid, sender, appId) {
|
_init(title, pid, sender, appId) {
|
||||||
this.pid = pid;
|
this.pid = pid;
|
||||||
|
this.initialTitle = title;
|
||||||
this.app = this._getApp(appId);
|
this.app = this._getApp(appId);
|
||||||
|
|
||||||
super._init(title);
|
super._init(title);
|
||||||
|
|
||||||
this.initialTitle = title;
|
|
||||||
|
|
||||||
if (this.app)
|
if (this.app)
|
||||||
this.title = this.app.get_name();
|
this.title = this.app.get_name();
|
||||||
else
|
else
|
||||||
@ -470,19 +425,20 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_getApp(appId) {
|
_getApp(appId) {
|
||||||
|
const appSys = Shell.AppSystem.get_default();
|
||||||
let app;
|
let app;
|
||||||
|
|
||||||
app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
|
app = Shell.WindowTracker.get_default().get_app_from_pid(this.pid);
|
||||||
if (app != null)
|
if (app != null)
|
||||||
return app;
|
return app;
|
||||||
|
|
||||||
if (appId) {
|
if (appId)
|
||||||
app = Shell.AppSystem.get_default().lookup_app('%s.desktop'.format(appId));
|
app = appSys.lookup_app('%s.desktop'.format(appId));
|
||||||
if (app != null)
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
if (!app)
|
||||||
|
app = appSys.lookup_app('%s.desktop'.format(this.initialTitle));
|
||||||
|
|
||||||
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
setTitle(title) {
|
setTitle(title) {
|
||||||
|
@ -244,11 +244,11 @@ var Overview = class {
|
|||||||
_unshadeBackgrounds() {
|
_unshadeBackgrounds() {
|
||||||
let backgrounds = this._backgroundGroup.get_children();
|
let backgrounds = this._backgroundGroup.get_children();
|
||||||
for (let i = 0; i < backgrounds.length; i++) {
|
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,
|
duration: SHADE_ANIMATION_TIME,
|
||||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
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,
|
duration: SHADE_ANIMATION_TIME,
|
||||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
});
|
});
|
||||||
@ -258,14 +258,16 @@ var Overview = class {
|
|||||||
_shadeBackgrounds() {
|
_shadeBackgrounds() {
|
||||||
let backgrounds = this._backgroundGroup.get_children();
|
let backgrounds = this._backgroundGroup.get_children();
|
||||||
for (let i = 0; i < backgrounds.length; i++) {
|
for (let i = 0; i < backgrounds.length; i++) {
|
||||||
backgrounds[i].ease_property('brightness', Lightbox.VIGNETTE_BRIGHTNESS, {
|
backgrounds[i].ease_property('@content.brightness',
|
||||||
duration: SHADE_ANIMATION_TIME,
|
Lightbox.VIGNETTE_BRIGHTNESS, {
|
||||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
duration: SHADE_ANIMATION_TIME,
|
||||||
});
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
backgrounds[i].ease_property('vignette-sharpness', Lightbox.VIGNETTE_SHARPNESS, {
|
});
|
||||||
duration: SHADE_ANIMATION_TIME,
|
backgrounds[i].ease_property('@content.vignette-sharpness',
|
||||||
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
Lightbox.VIGNETTE_SHARPNESS, {
|
||||||
});
|
duration: SHADE_ANIMATION_TIME,
|
||||||
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,8 +402,7 @@ var Overview = class {
|
|||||||
|
|
||||||
_getDesktopClone() {
|
_getDesktopClone() {
|
||||||
let windows = global.get_window_actors().filter(
|
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)
|
if (windows.length == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
@ -576,7 +577,7 @@ var Overview = class {
|
|||||||
this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC;
|
this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC;
|
||||||
|
|
||||||
Meta.disable_unredirect_for_display(global.display);
|
Meta.disable_unredirect_for_display(global.display);
|
||||||
this.viewSelector.show();
|
this.viewSelector.animateToOverview();
|
||||||
|
|
||||||
this._overview.opacity = 0;
|
this._overview.opacity = 0;
|
||||||
this._overview.ease({
|
this._overview.ease({
|
||||||
|
@ -51,7 +51,7 @@ var SlideLayout = GObject.registerClass({
|
|||||||
return [minWidth, natWidth];
|
return [minWidth, natWidth];
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(container, box, flags) {
|
vfunc_allocate(container, box) {
|
||||||
let child = container.get_first_child();
|
let child = container.get_first_child();
|
||||||
|
|
||||||
let availWidth = Math.round(box.x2 - box.x1);
|
let availWidth = Math.round(box.x2 - box.x1);
|
||||||
@ -72,7 +72,7 @@ var SlideLayout = GObject.registerClass({
|
|||||||
actorBox.y1 = box.y1;
|
actorBox.y1 = box.y1;
|
||||||
actorBox.y2 = actorBox.y1 + availHeight;
|
actorBox.y2 = actorBox.y1 + availHeight;
|
||||||
|
|
||||||
child.allocate(actorBox, flags);
|
child.allocate(actorBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
@ -394,10 +394,10 @@ class DashSpacer extends St.Widget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var ControlsLayout = GObject.registerClass({
|
var ControlsLayout = GObject.registerClass({
|
||||||
Signals: { 'allocation-changed': { flags: GObject.SignalFlags.RUN_LAST } },
|
Signals: { 'allocation-changed': {} },
|
||||||
}, class ControlsLayout extends Clutter.BinLayout {
|
}, class ControlsLayout extends Clutter.BinLayout {
|
||||||
vfunc_allocate(container, box, flags) {
|
vfunc_allocate(container, box) {
|
||||||
super.vfunc_allocate(container, box, flags);
|
super.vfunc_allocate(container, box);
|
||||||
this.emit('allocation-changed');
|
this.emit('allocation-changed');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -473,6 +473,7 @@ class ControlsManager extends St.Widget {
|
|||||||
|
|
||||||
// A workspace might have been inserted or removed before the active
|
// A workspace might have been inserted or removed before the active
|
||||||
// one, causing the adjustment to go out of sync, so update the value
|
// one, causing the adjustment to go out of sync, so update the value
|
||||||
|
this._workspaceAdjustment.remove_transition('value');
|
||||||
this._workspaceAdjustment.value = activeIndex;
|
this._workspaceAdjustment.value = activeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
161
js/ui/padOsd.js
161
js/ui/padOsd.js
@ -2,7 +2,7 @@
|
|||||||
/* exported PadOsd, PadOsdService */
|
/* exported PadOsd, PadOsdService */
|
||||||
|
|
||||||
const { Atk, Clutter, GDesktopEnums, Gio,
|
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 Signals = imports.signals;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
@ -329,6 +329,7 @@ var PadDiagram = GObject.registerClass({
|
|||||||
|
|
||||||
this._imagePath = imagePath;
|
this._imagePath = imagePath;
|
||||||
this._handle = this._composeStyledDiagram();
|
this._handle = this._composeStyledDiagram();
|
||||||
|
this._initLabels();
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line camelcase
|
// eslint-disable-next-line camelcase
|
||||||
@ -343,6 +344,26 @@ var PadDiagram = GObject.registerClass({
|
|||||||
this.add_actor(actor);
|
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() {
|
_wrappingSvgHeader() {
|
||||||
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
|
return '<?xml version="1.0" encoding="UTF-8" standalone="no"?>' +
|
||||||
'<svg version="1.1" xmlns="http://www.w3.org/2000/svg" ' +
|
'<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++) {
|
for (let i = 0; i < this._activeButtons.length; i++) {
|
||||||
let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]);
|
let ch = String.fromCharCode('A'.charCodeAt() + this._activeButtons[i]);
|
||||||
css += '.%s {'.format(ch);
|
css += '.%s.Leader { stroke: %s !important; }'.format(ch, ACTIVE_COLOR);
|
||||||
css += ' stroke: %s !important;'.format(ACTIVE_COLOR);
|
css += '.%s.Button { stroke: %s !important; fill: %s !important; }'.format(ch, ACTIVE_COLOR, ACTIVE_COLOR);
|
||||||
css += ' fill: %s !important;'.format(ACTIVE_COLOR);
|
|
||||||
css += '}';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return css;
|
return css;
|
||||||
@ -390,9 +409,6 @@ var PadDiagram = GObject.registerClass({
|
|||||||
}
|
}
|
||||||
|
|
||||||
_updateDiagramScale() {
|
_updateDiagramScale() {
|
||||||
if (this._handle == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
[this._actorWidth, this._actorHeight] = this.get_size();
|
[this._actorWidth, this._actorHeight] = this.get_size();
|
||||||
let dimensions = this._handle.get_dimensions();
|
let dimensions = this._handle.get_dimensions();
|
||||||
let scaleX = this._actorWidth / dimensions.width;
|
let scaleX = this._actorWidth / dimensions.width;
|
||||||
@ -405,6 +421,11 @@ var PadDiagram = GObject.registerClass({
|
|||||||
let [, natWidth] = child.get_preferred_width(natHeight);
|
let [, natWidth] = child.get_preferred_width(natHeight);
|
||||||
let childBox = new Clutter.ActorBox();
|
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) {
|
if (direction == LTR) {
|
||||||
childBox.x1 = x;
|
childBox.x1 = x;
|
||||||
childBox.x2 = x + natWidth;
|
childBox.x2 = x + natWidth;
|
||||||
@ -415,22 +436,23 @@ var PadDiagram = GObject.registerClass({
|
|||||||
|
|
||||||
childBox.y1 = y - natHeight / 2;
|
childBox.y1 = y - natHeight / 2;
|
||||||
childBox.y2 = y + natHeight / 2;
|
childBox.y2 = y + natHeight / 2;
|
||||||
child.allocate(childBox, 0);
|
child.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
super.vfunc_allocate(box, flags);
|
super.vfunc_allocate(box);
|
||||||
|
if (this._handle === null)
|
||||||
|
return;
|
||||||
|
|
||||||
this._updateDiagramScale();
|
this._updateDiagramScale();
|
||||||
|
|
||||||
for (let i = 0; i < this._labels.length; i++) {
|
for (let i = 0; i < this._labels.length; i++) {
|
||||||
let [label, action, idx, dir] = this._labels[i];
|
const { label, x, y, arrangement } = this._labels[i];
|
||||||
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
|
||||||
this._allocateChild(label, x, y, arrangement);
|
this._allocateChild(label, x, y, arrangement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._editorActor && this._curEdited) {
|
if (this._editorActor && this._curEdited) {
|
||||||
let [label_, action, idx, dir] = this._curEdited;
|
const { x, y, arrangement } = this._curEdited;
|
||||||
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
|
||||||
this._allocateChild(this._editorActor, x, y, arrangement);
|
this._allocateChild(this._editorActor, x, y, arrangement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,17 +479,6 @@ var PadDiagram = GObject.registerClass({
|
|||||||
cr.$dispose();
|
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) {
|
_getItemLabelCoords(labelName, leaderName) {
|
||||||
if (this._handle == null)
|
if (this._handle == null)
|
||||||
return [false];
|
return [false];
|
||||||
@ -495,44 +506,39 @@ var PadDiagram = GObject.registerClass({
|
|||||||
pos.y = this._imageHeight - pos.y;
|
pos.y = this._imageHeight - pos.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [x, y] = this._transformPoint(pos.x, pos.y);
|
return [true, pos.x, pos.y, direction];
|
||||||
|
|
||||||
return [true, x, y, direction];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getButtonLabelCoords(button) {
|
_getButtonLabels(button) {
|
||||||
let ch = String.fromCharCode('A'.charCodeAt() + button);
|
let ch = String.fromCharCode('A'.charCodeAt() + button);
|
||||||
let labelName = 'Label%s'.format(ch);
|
let labelName = 'Label%s'.format(ch);
|
||||||
let leaderName = 'Leader%s'.format(ch);
|
let leaderName = 'Leader%s'.format(ch);
|
||||||
|
return [labelName, leaderName];
|
||||||
return this._getItemLabelCoords(labelName, leaderName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getRingLabelCoords(number, dir) {
|
_getRingLabels(number, dir) {
|
||||||
let numStr = number > 0 ? (number + 1).toString() : '';
|
let numStr = number > 0 ? (number + 1).toString() : '';
|
||||||
let dirStr = dir == CW ? 'CW' : 'CCW';
|
let dirStr = dir == CW ? 'CW' : 'CCW';
|
||||||
let labelName = 'LabelRing%s%s'.format(numStr, dirStr);
|
let labelName = 'LabelRing%s%s'.format(numStr, dirStr);
|
||||||
let leaderName = 'LeaderRing%s%s'.format(numStr, dirStr);
|
let leaderName = 'LeaderRing%s%s'.format(numStr, dirStr);
|
||||||
|
return [labelName, leaderName];
|
||||||
return this._getItemLabelCoords(labelName, leaderName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getStripLabelCoords(number, dir) {
|
_getStripLabels(number, dir) {
|
||||||
let numStr = number > 0 ? (number + 1).toString() : '';
|
let numStr = number > 0 ? (number + 1).toString() : '';
|
||||||
let dirStr = dir == UP ? 'Up' : 'Down';
|
let dirStr = dir == UP ? 'Up' : 'Down';
|
||||||
let labelName = 'LabelStrip%s%s'.format(numStr, dirStr);
|
let labelName = 'LabelStrip%s%s'.format(numStr, dirStr);
|
||||||
let leaderName = 'LeaderStrip%s%s'.format(numStr, dirStr);
|
let leaderName = 'LeaderStrip%s%s'.format(numStr, dirStr);
|
||||||
|
return [labelName, leaderName];
|
||||||
return this._getItemLabelCoords(labelName, leaderName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getLabelCoords(action, idx, dir) {
|
_getLabelCoords(action, idx, dir) {
|
||||||
if (action == Meta.PadActionType.BUTTON)
|
if (action == Meta.PadActionType.BUTTON)
|
||||||
return this.getButtonLabelCoords(idx);
|
return this._getItemLabelCoords(...this._getButtonLabels(idx));
|
||||||
else if (action == Meta.PadActionType.RING)
|
else if (action == Meta.PadActionType.RING)
|
||||||
return this.getRingLabelCoords(idx, dir);
|
return this._getItemLabelCoords(...this._getRingLabels(idx, dir));
|
||||||
else if (action == Meta.PadActionType.STRIP)
|
else if (action == Meta.PadActionType.STRIP)
|
||||||
return this.getStripLabelCoords(idx, dir);
|
return this._getItemLabelCoords(...this._getStripLabels(idx, dir));
|
||||||
|
|
||||||
return [false];
|
return [false];
|
||||||
}
|
}
|
||||||
@ -557,26 +563,30 @@ var PadDiagram = GObject.registerClass({
|
|||||||
this._invalidateSvg();
|
this._invalidateSvg();
|
||||||
}
|
}
|
||||||
|
|
||||||
addLabel(label, type, idx, dir) {
|
_addLabel(action, idx, dir) {
|
||||||
this._labels.push([label, type, 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);
|
this.add_actor(label);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateLabels(getText) {
|
updateLabels(getText) {
|
||||||
for (let i = 0; i < this._labels.length; i++) {
|
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);
|
let str = getText(action, idx, dir);
|
||||||
label.set_text(str);
|
label.set_text(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.queue_relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
_applyLabel(label, action, idx, dir, str) {
|
_applyLabel(label, action, idx, dir, str) {
|
||||||
if (str != null) {
|
if (str !== null)
|
||||||
label.set_text(str);
|
label.set_text(str);
|
||||||
|
|
||||||
let [found_, x, y, arrangement] = this.getLabelCoords(action, idx, dir);
|
|
||||||
this._allocateChild(label, x, y, arrangement);
|
|
||||||
}
|
|
||||||
label.show();
|
label.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,18 +594,20 @@ var PadDiagram = GObject.registerClass({
|
|||||||
this._editorActor.hide();
|
this._editorActor.hide();
|
||||||
|
|
||||||
if (this._prevEdited) {
|
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._applyLabel(label, action, idx, dir, str);
|
||||||
this._prevEdited = null;
|
this._prevEdited = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._curEdited) {
|
if (this._curEdited) {
|
||||||
let [label, action, idx, dir] = this._curEdited;
|
const { label, action, idx, dir } = this._curEdited;
|
||||||
this._applyLabel(label, action, idx, dir, str);
|
this._applyLabel(label, action, idx, dir, str);
|
||||||
if (continues)
|
if (continues)
|
||||||
this._prevEdited = this._curEdited;
|
this._prevEdited = this._curEdited;
|
||||||
this._curEdited = null;
|
this._curEdited = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.queue_relayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
startEdition(action, idx, dir) {
|
startEdition(action, idx, dir) {
|
||||||
@ -605,21 +617,19 @@ var PadDiagram = GObject.registerClass({
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (let i = 0; i < this._labels.length; i++) {
|
for (let i = 0; i < this._labels.length; i++) {
|
||||||
let [label, itemAction, itemIdx, itemDir] = this._labels[i];
|
if (action == this._labels[i].action &&
|
||||||
if (action == itemAction && idx == itemIdx && dir == itemDir) {
|
idx == this._labels[i].idx && dir == this._labels[i].dir) {
|
||||||
this._curEdited = this._labels[i];
|
this._curEdited = this._labels[i];
|
||||||
editedLabel = label;
|
editedLabel = this._curEdited.label;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._curEdited == null)
|
if (this._curEdited == null)
|
||||||
return;
|
return;
|
||||||
let [found] = this.getLabelCoords(action, idx, dir);
|
|
||||||
if (!found)
|
|
||||||
return;
|
|
||||||
this._editorActor.show();
|
this._editorActor.show();
|
||||||
editedLabel.hide();
|
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;',
|
this._titleLabel = new St.Label({ style: 'font-side: larger; font-weight: bold;',
|
||||||
x_align: Clutter.ActorAlign.CENTER });
|
x_align: Clutter.ActorAlign.CENTER });
|
||||||
|
this._titleLabel.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
|
||||||
this._titleLabel.clutter_text.set_text(padDevice.get_device_name());
|
this._titleLabel.clutter_text.set_text(padDevice.get_device_name());
|
||||||
labelBox.add_actor(this._titleLabel);
|
labelBox.add_actor(this._titleLabel);
|
||||||
|
|
||||||
@ -710,31 +721,7 @@ var PadOsd = GObject.registerClass({
|
|||||||
x_expand: true,
|
x_expand: true,
|
||||||
y_expand: true });
|
y_expand: true });
|
||||||
this.add_actor(this._padDiagram);
|
this.add_actor(this._padDiagram);
|
||||||
|
this._updateActionLabels();
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
let buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
let buttonBox = new St.Widget({ layout_manager: new Clutter.BinLayout(),
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
@ -787,11 +774,6 @@ var PadOsd = GObject.registerClass({
|
|||||||
return str ? str : _("None");
|
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() {
|
_updateActionLabels() {
|
||||||
this._padDiagram.updateLabels(this._getActionText.bind(this));
|
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._tipLabel.set_text(_("Press any key to exit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
this._titleLabel.clutter_text.set_markup(
|
this._titleLabel.set_text(title);
|
||||||
'<span size="larger"><b>%s</b></span>'.format(title));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_isEditedAction(type, number, dir) {
|
_isEditedAction(type, number, dir) {
|
||||||
|
@ -120,6 +120,10 @@ var PageIndicators = GObject.registerClass({
|
|||||||
for (let i = 0; i < children.length; i++)
|
for (let i = 0; i < children.length; i++)
|
||||||
this._updateIndicator(children[i], i);
|
this._updateIndicator(children[i], i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get nPages() {
|
||||||
|
return this._nPages;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var AnimatedPageIndicators = GObject.registerClass(
|
var AnimatedPageIndicators = GObject.registerClass(
|
||||||
|
107
js/ui/panel.js
107
js/ui/panel.js
@ -5,6 +5,7 @@ const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
|
|||||||
const Cairo = imports.cairo;
|
const Cairo = imports.cairo;
|
||||||
|
|
||||||
const Animation = imports.ui.animation;
|
const Animation = imports.ui.animation;
|
||||||
|
const AppDisplay = imports.ui.appDisplay;
|
||||||
const Config = imports.misc.config;
|
const Config = imports.misc.config;
|
||||||
const CtrlAltTab = imports.ui.ctrlAltTab;
|
const CtrlAltTab = imports.ui.ctrlAltTab;
|
||||||
const DND = imports.ui.dnd;
|
const DND = imports.ui.dnd;
|
||||||
@ -60,71 +61,20 @@ function _unpremultiply(color) {
|
|||||||
return new Clutter.Color({ red, green, blue, alpha: color.alpha });
|
return new Clutter.Color({ red, green, blue, alpha: color.alpha });
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppMenu extends PopupMenu.PopupMenu {
|
class AppMenu extends AppDisplay.BaseAppMenu {
|
||||||
constructor(sourceActor) {
|
constructor(sourceActor) {
|
||||||
super(sourceActor, 0.5, St.Side.TOP);
|
super(sourceActor, St.Side.TOP);
|
||||||
|
|
||||||
this.actor.add_style_class_name('app-menu');
|
this.actor.add_style_class_name('app-menu');
|
||||||
|
|
||||||
this._app = null;
|
this._app = null;
|
||||||
this._appSystem = Shell.AppSystem.get_default();
|
|
||||||
|
|
||||||
this._windowsChangedId = 0;
|
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"), () => {
|
|
||||||
let id = this._app.get_id();
|
|
||||||
let args = GLib.Variant.new('(ss)', [id, '']);
|
|
||||||
Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => {
|
|
||||||
let bus = Gio.DBus.get_finish(res);
|
|
||||||
bus.call('org.gnome.Software',
|
|
||||||
'/org/gnome/Software',
|
|
||||||
'org.gtk.Actions', 'Activate',
|
|
||||||
GLib.Variant.new('(sava{sv})',
|
|
||||||
['details', [args], null]),
|
|
||||||
null, 0, -1, null, null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
||||||
|
|
||||||
this.addAction(_("Quit"), () => {
|
|
||||||
this._app.request_quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
this._appSystem.connect('installed-changed', () => {
|
|
||||||
this._updateDetailsVisibility();
|
|
||||||
});
|
|
||||||
this._updateDetailsVisibility();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateDetailsVisibility() {
|
get app() {
|
||||||
let sw = this._appSystem.lookup_app('org.gnome.Software.desktop');
|
return this._app;
|
||||||
this._detailsItem.visible = sw != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
isEmpty() {
|
|
||||||
if (!this._app)
|
|
||||||
return true;
|
|
||||||
return super.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setApp(app) {
|
setApp(app) {
|
||||||
@ -159,25 +109,6 @@ class AppMenu extends PopupMenu.PopupMenu {
|
|||||||
this._newWindowItem.visible =
|
this._newWindowItem.visible =
|
||||||
app && app.can_open_new_window() && !actions.includes('new-window');
|
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));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,7 +147,10 @@ var AppMenuButton = GObject.registerClass({
|
|||||||
this._onIconThemeChanged.bind(this));
|
this._onIconThemeChanged.bind(this));
|
||||||
|
|
||||||
let iconEffect = new Clutter.DesaturateEffect();
|
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._iconBox.add_effect(iconEffect);
|
||||||
this._container.add_actor(this._iconBox);
|
this._container.add_actor(this._iconBox);
|
||||||
|
|
||||||
@ -283,7 +217,7 @@ var AppMenuButton = GObject.registerClass({
|
|||||||
this.remove_all_transitions();
|
this.remove_all_transitions();
|
||||||
this.ease({
|
this.ease({
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
mode: Clutter.Animation.EASE_OUT_QUAD,
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
duration: Overview.ANIMATION_TIME,
|
duration: Overview.ANIMATION_TIME,
|
||||||
onComplete: () => this.hide(),
|
onComplete: () => this.hide(),
|
||||||
});
|
});
|
||||||
@ -841,8 +775,8 @@ class Panel extends St.Widget {
|
|||||||
return [0, 0];
|
return [0, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
let allocWidth = box.x2 - box.x1;
|
let allocWidth = box.x2 - box.x1;
|
||||||
let allocHeight = box.y2 - box.y1;
|
let allocHeight = box.y2 - box.y1;
|
||||||
@ -878,13 +812,13 @@ class Panel extends St.Widget {
|
|||||||
childBox.x2 = Math.min(Math.floor(sideWidth),
|
childBox.x2 = Math.min(Math.floor(sideWidth),
|
||||||
leftNaturalWidth);
|
leftNaturalWidth);
|
||||||
}
|
}
|
||||||
this._leftBox.allocate(childBox, flags);
|
this._leftBox.allocate(childBox);
|
||||||
|
|
||||||
childBox.x1 = Math.ceil(sideWidth);
|
childBox.x1 = Math.ceil(sideWidth);
|
||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.x2 = childBox.x1 + centerWidth;
|
childBox.x2 = childBox.x1 + centerWidth;
|
||||||
childBox.y2 = allocHeight;
|
childBox.y2 = allocHeight;
|
||||||
this._centerBox.allocate(childBox, flags);
|
this._centerBox.allocate(childBox);
|
||||||
|
|
||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.y2 = allocHeight;
|
childBox.y2 = allocHeight;
|
||||||
@ -898,7 +832,7 @@ class Panel extends St.Widget {
|
|||||||
0);
|
0);
|
||||||
childBox.x2 = allocWidth;
|
childBox.x2 = allocWidth;
|
||||||
}
|
}
|
||||||
this._rightBox.allocate(childBox, flags);
|
this._rightBox.allocate(childBox);
|
||||||
|
|
||||||
let cornerWidth, cornerHeight;
|
let cornerWidth, cornerHeight;
|
||||||
|
|
||||||
@ -908,7 +842,7 @@ class Panel extends St.Widget {
|
|||||||
childBox.x2 = cornerWidth;
|
childBox.x2 = cornerWidth;
|
||||||
childBox.y1 = allocHeight;
|
childBox.y1 = allocHeight;
|
||||||
childBox.y2 = allocHeight + cornerHeight;
|
childBox.y2 = allocHeight + cornerHeight;
|
||||||
this._leftCorner.allocate(childBox, flags);
|
this._leftCorner.allocate(childBox);
|
||||||
|
|
||||||
[, cornerWidth] = this._rightCorner.get_preferred_width(-1);
|
[, cornerWidth] = this._rightCorner.get_preferred_width(-1);
|
||||||
[, cornerHeight] = this._rightCorner.get_preferred_height(-1);
|
[, cornerHeight] = this._rightCorner.get_preferred_height(-1);
|
||||||
@ -916,7 +850,7 @@ class Panel extends St.Widget {
|
|||||||
childBox.x2 = allocWidth;
|
childBox.x2 = allocWidth;
|
||||||
childBox.y1 = allocHeight;
|
childBox.y1 = allocHeight;
|
||||||
childBox.y2 = allocHeight + cornerHeight;
|
childBox.y2 = allocHeight + cornerHeight;
|
||||||
this._rightCorner.allocate(childBox, flags);
|
this._rightCorner.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
_tryDragWindow(event) {
|
_tryDragWindow(event) {
|
||||||
@ -1155,10 +1089,9 @@ class Panel extends St.Widget {
|
|||||||
|
|
||||||
_getDraggableWindowForPosition(stageX) {
|
_getDraggableWindowForPosition(stageX) {
|
||||||
let workspaceManager = global.workspace_manager;
|
let workspaceManager = global.workspace_manager;
|
||||||
let workspace = workspaceManager.get_active_workspace();
|
const windows = workspaceManager.get_active_workspace().list_windows();
|
||||||
let allWindowsByStacking = global.display.sort_windows_by_stacking(
|
const allWindowsByStacking =
|
||||||
workspace.list_windows()
|
global.display.sort_windows_by_stacking(windows).reverse();
|
||||||
).reverse();
|
|
||||||
|
|
||||||
return allWindowsByStacking.find(metaWindow => {
|
return allWindowsByStacking.find(metaWindow => {
|
||||||
let rect = metaWindow.get_frame_rect();
|
let rect = metaWindow.get_frame_rect();
|
||||||
|
@ -59,8 +59,8 @@ class ButtonBox extends St.Widget {
|
|||||||
return [0, 0];
|
return [0, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
let child = this.get_first_child();
|
let child = this.get_first_child();
|
||||||
if (!child)
|
if (!child)
|
||||||
@ -83,7 +83,7 @@ class ButtonBox extends St.Widget {
|
|||||||
childBox.y1 = 0;
|
childBox.y1 = 0;
|
||||||
childBox.y2 = availHeight;
|
childBox.y2 = availHeight;
|
||||||
|
|
||||||
child.allocate(childBox, flags);
|
child.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
|
@ -204,7 +204,7 @@ var RemoteSearchProvider = class {
|
|||||||
g_interface_info: proxyInfo,
|
g_interface_info: proxyInfo,
|
||||||
g_interface_name: proxyInfo.name,
|
g_interface_name: proxyInfo.name,
|
||||||
gFlags });
|
gFlags });
|
||||||
this.proxy.init_async(GLib.PRIORITY_DEFAULT, null, null);
|
this.proxy.init_async(GLib.PRIORITY_DEFAULT, null);
|
||||||
|
|
||||||
this.appInfo = appInfo;
|
this.appInfo = appInfo;
|
||||||
this.id = appInfo.get_id();
|
this.id = appInfo.get_id();
|
||||||
|
@ -198,7 +198,7 @@ var ScreenShield = class {
|
|||||||
let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
|
let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
|
||||||
let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
|
let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
|
||||||
let inhibit = this._loginSession && this._loginSession.Active &&
|
let inhibit = this._loginSession && this._loginSession.Active &&
|
||||||
!this._isActive && lockEnabled && !lockLocked;
|
!this._isActive && lockEnabled && !lockLocked && Main.sessionMode.unlockDialog;
|
||||||
if (inhibit) {
|
if (inhibit) {
|
||||||
this._loginManager.inhibit(_("GNOME needs to lock the screen"),
|
this._loginManager.inhibit(_("GNOME needs to lock the screen"),
|
||||||
inhibitor => {
|
inhibitor => {
|
||||||
@ -345,7 +345,7 @@ var ScreenShield = class {
|
|||||||
this._lockDialogGroup.remove_all_transitions();
|
this._lockDialogGroup.remove_all_transitions();
|
||||||
|
|
||||||
if (animate) {
|
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),
|
// if velocity is not specified (i.e. we come here from pressing ESC),
|
||||||
// use the same speed regardless of original position
|
// use the same speed regardless of original position
|
||||||
// if velocity is specified, it's in pixels per milliseconds
|
// if velocity is specified, it's in pixels per milliseconds
|
||||||
@ -498,6 +498,8 @@ var ScreenShield = class {
|
|||||||
if (Main.sessionMode.currentMode == 'unlock-dialog')
|
if (Main.sessionMode.currentMode == 'unlock-dialog')
|
||||||
Main.sessionMode.popMode('unlock-dialog');
|
Main.sessionMode.popMode('unlock-dialog');
|
||||||
|
|
||||||
|
this.emit('wake-up-screen');
|
||||||
|
|
||||||
if (this._isGreeter) {
|
if (this._isGreeter) {
|
||||||
// We don't want to "deactivate" any more than
|
// We don't want to "deactivate" any more than
|
||||||
// this. In particular, we don't want to drop
|
// this. In particular, we don't want to drop
|
||||||
@ -519,6 +521,9 @@ var ScreenShield = class {
|
|||||||
this._isModal = false;
|
this._isModal = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._longLightbox.lightOff();
|
||||||
|
this._shortLightbox.lightOff();
|
||||||
|
|
||||||
this._lockDialogGroup.ease({
|
this._lockDialogGroup.ease({
|
||||||
translation_y: -global.screen_height,
|
translation_y: -global.screen_height,
|
||||||
duration: Overview.ANIMATION_TIME,
|
duration: Overview.ANIMATION_TIME,
|
||||||
@ -533,8 +538,6 @@ var ScreenShield = class {
|
|||||||
this._dialog = null;
|
this._dialog = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._longLightbox.lightOff();
|
|
||||||
this._shortLightbox.lightOff();
|
|
||||||
this.actor.hide();
|
this.actor.hide();
|
||||||
|
|
||||||
if (this._becameActiveId != 0) {
|
if (this._becameActiveId != 0) {
|
||||||
@ -558,7 +561,8 @@ var ScreenShield = class {
|
|||||||
if (this._activationTime == 0)
|
if (this._activationTime == 0)
|
||||||
this._activationTime = GLib.get_monotonic_time();
|
this._activationTime = GLib.get_monotonic_time();
|
||||||
|
|
||||||
this._ensureUnlockDialog(true);
|
if (!this._ensureUnlockDialog(true))
|
||||||
|
return;
|
||||||
|
|
||||||
this.actor.show();
|
this.actor.show();
|
||||||
|
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported ScreenshotService */
|
/* 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 GrabHelper = imports.ui.grabHelper;
|
||||||
const Lightbox = imports.ui.lightbox;
|
const Lightbox = imports.ui.lightbox;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
Gio._promisify(Shell.Screenshot.prototype, 'pick_color', 'pick_color_finish');
|
||||||
|
Gio._promisify(Shell.Screenshot.prototype, 'screenshot', 'screenshot_finish');
|
||||||
|
Gio._promisify(Shell.Screenshot.prototype,
|
||||||
|
'screenshot_window', 'screenshot_window_finish');
|
||||||
|
Gio._promisify(Shell.Screenshot.prototype,
|
||||||
|
'screenshot_area', 'screenshot_area_finish');
|
||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||||
|
|
||||||
const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot');
|
const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot');
|
||||||
@ -30,7 +37,9 @@ var ScreenshotService = class {
|
|||||||
|
|
||||||
let sender = invocation.get_sender();
|
let sender = invocation.get_sender();
|
||||||
if (this._screenShooter.has(sender) || lockedDown) {
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +165,7 @@ var ScreenshotService = class {
|
|||||||
return [x, y, width, height];
|
return [x, y, width, height];
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenshotAreaAsync(params, invocation) {
|
async ScreenshotAreaAsync(params, invocation) {
|
||||||
let [x, y, width, height, flash, filename] = params;
|
let [x, y, width, height, flash, filename] = params;
|
||||||
[x, y, width, height] = this._scaleArea(x, y, width, height);
|
[x, y, width, height] = this._scaleArea(x, y, width, height);
|
||||||
if (!this._checkArea(x, y, width, height)) {
|
if (!this._checkArea(x, y, width, height)) {
|
||||||
@ -173,21 +182,17 @@ var ScreenshotService = class {
|
|||||||
if (!stream)
|
if (!stream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
screenshot.screenshot_area(x, y, width, height, stream,
|
try {
|
||||||
(o, res) => {
|
let [area] =
|
||||||
try {
|
await screenshot.screenshot_area(x, y, width, height, stream);
|
||||||
let [success_, area] =
|
this._onScreenshotComplete(area, stream, file, flash, invocation);
|
||||||
screenshot.screenshot_area_finish(res);
|
} catch (e) {
|
||||||
this._onScreenshotComplete(
|
this._removeShooterForSender(invocation.get_sender());
|
||||||
area, stream, file, flash, invocation);
|
invocation.return_value(new GLib.Variant('(bs)', [false, '']));
|
||||||
} catch (e) {
|
}
|
||||||
this._removeShooterForSender(invocation.get_sender());
|
|
||||||
invocation.return_value(new GLib.Variant('(bs)', [false, '']));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenshotWindowAsync(params, invocation) {
|
async ScreenshotWindowAsync(params, invocation) {
|
||||||
let [includeFrame, includeCursor, flash, filename] = params;
|
let [includeFrame, includeCursor, flash, filename] = params;
|
||||||
let screenshot = this._createScreenshot(invocation);
|
let screenshot = this._createScreenshot(invocation);
|
||||||
if (!screenshot)
|
if (!screenshot)
|
||||||
@ -197,21 +202,17 @@ var ScreenshotService = class {
|
|||||||
if (!stream)
|
if (!stream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
screenshot.screenshot_window(includeFrame, includeCursor, stream,
|
try {
|
||||||
(o, res) => {
|
let [area] =
|
||||||
try {
|
await screenshot.screenshot_window(includeFrame, includeCursor, stream);
|
||||||
let [success_, area] =
|
this._onScreenshotComplete(area, stream, file, flash, invocation);
|
||||||
screenshot.screenshot_window_finish(res);
|
} catch (e) {
|
||||||
this._onScreenshotComplete(
|
this._removeShooterForSender(invocation.get_sender());
|
||||||
area, stream, file, flash, invocation);
|
invocation.return_value(new GLib.Variant('(bs)', [false, '']));
|
||||||
} catch (e) {
|
}
|
||||||
this._removeShooterForSender(invocation.get_sender());
|
|
||||||
invocation.return_value(new GLib.Variant('(bs)', [false, '']));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenshotAsync(params, invocation) {
|
async ScreenshotAsync(params, invocation) {
|
||||||
let [includeCursor, flash, filename] = params;
|
let [includeCursor, flash, filename] = params;
|
||||||
let screenshot = this._createScreenshot(invocation);
|
let screenshot = this._createScreenshot(invocation);
|
||||||
if (!screenshot)
|
if (!screenshot)
|
||||||
@ -221,18 +222,13 @@ var ScreenshotService = class {
|
|||||||
if (!stream)
|
if (!stream)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
screenshot.screenshot(includeCursor, stream,
|
try {
|
||||||
(o, res) => {
|
let [area] = await screenshot.screenshot(includeCursor, stream);
|
||||||
try {
|
this._onScreenshotComplete(area, stream, file, flash, invocation);
|
||||||
let [success_, area] =
|
} catch (e) {
|
||||||
screenshot.screenshot_finish(res);
|
this._removeShooterForSender(invocation.get_sender());
|
||||||
this._onScreenshotComplete(
|
invocation.return_value(new GLib.Variant('(bs)', [false, '']));
|
||||||
area, stream, file, flash, invocation);
|
}
|
||||||
} catch (e) {
|
|
||||||
this._removeShooterForSender(invocation.get_sender());
|
|
||||||
invocation.return_value(new GLib.Variant('(bs)', [false, '']));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async SelectAreaAsync(params, invocation) {
|
async SelectAreaAsync(params, invocation) {
|
||||||
@ -265,31 +261,28 @@ var ScreenshotService = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async PickColorAsync(params, invocation) {
|
async PickColorAsync(params, invocation) {
|
||||||
let pickPixel = new PickPixel();
|
const screenshot = this._createScreenshot(invocation, false);
|
||||||
|
if (!screenshot)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const pickPixel = new PickPixel(screenshot);
|
||||||
try {
|
try {
|
||||||
const coords = await pickPixel.pickAsync();
|
const color = await pickPixel.pickAsync();
|
||||||
|
const { red, green, blue } = color;
|
||||||
let screenshot = this._createScreenshot(invocation, false);
|
const retval = GLib.Variant.new('(a{sv})', [{
|
||||||
if (!screenshot)
|
color: GLib.Variant.new('(ddd)', [
|
||||||
return;
|
red / 255.0,
|
||||||
|
green / 255.0,
|
||||||
screenshot.pick_color(coords.x, coords.y, (_o, res) => {
|
blue / 255.0,
|
||||||
let [success_, color] = screenshot.pick_color_finish(res);
|
]),
|
||||||
let { red, green, blue } = color;
|
}]);
|
||||||
let retval = GLib.Variant.new('(a{sv})', [{
|
invocation.return_value(retval);
|
||||||
color: GLib.Variant.new('(ddd)', [
|
|
||||||
red / 255.0,
|
|
||||||
green / 255.0,
|
|
||||||
blue / 255.0,
|
|
||||||
]),
|
|
||||||
}]);
|
|
||||||
this._removeShooterForSender(invocation.get_sender());
|
|
||||||
invocation.return_value(retval);
|
|
||||||
});
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
invocation.return_error_literal(
|
invocation.return_error_literal(
|
||||||
Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
|
Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
|
||||||
'Operation was cancelled');
|
'Operation was cancelled');
|
||||||
|
} finally {
|
||||||
|
this._removeShooterForSender(invocation.get_sender());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -387,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(
|
var PickPixel = GObject.registerClass(
|
||||||
class PickPixel extends St.Widget {
|
class PickPixel extends St.Widget {
|
||||||
_init() {
|
_init(screenshot) {
|
||||||
super._init({ visible: false, reactive: true });
|
super._init({ visible: false, reactive: true });
|
||||||
|
|
||||||
|
this._screenshot = screenshot;
|
||||||
|
|
||||||
this._result = null;
|
this._result = null;
|
||||||
|
this._color = null;
|
||||||
|
this._inPick = false;
|
||||||
|
|
||||||
Main.uiGroup.add_actor(this);
|
Main.uiGroup.add_actor(this);
|
||||||
|
|
||||||
@ -401,16 +527,44 @@ class PickPixel extends St.Widget {
|
|||||||
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
let constraint = new Clutter.BindConstraint({ source: global.stage,
|
||||||
coordinate: Clutter.BindCoordinate.ALL });
|
coordinate: Clutter.BindCoordinate.ALL });
|
||||||
this.add_constraint(constraint);
|
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() {
|
async pickAsync() {
|
||||||
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
|
global.display.set_cursor(Meta.Cursor.BLANK);
|
||||||
Main.uiGroup.set_child_above_sibling(this, null);
|
Main.uiGroup.set_child_above_sibling(this, null);
|
||||||
this.show();
|
this.show();
|
||||||
|
|
||||||
|
this._pickColor(...global.get_pointer());
|
||||||
|
|
||||||
await this._grabHelper.grabAsync({ actor: this });
|
await this._grabHelper.grabAsync({ actor: this });
|
||||||
|
|
||||||
global.display.set_cursor(Meta.Cursor.DEFAULT);
|
global.display.set_cursor(Meta.Cursor.DEFAULT);
|
||||||
|
this._previewCursor.destroy();
|
||||||
|
|
||||||
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||||
this.destroy();
|
this.destroy();
|
||||||
@ -420,10 +574,25 @@ class PickPixel extends St.Widget {
|
|||||||
return this._result;
|
return this._result;
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_button_release_event(buttonEvent) {
|
async _pickColor(x, y) {
|
||||||
let { x, y } = buttonEvent;
|
if (this._inPick)
|
||||||
this._result = new Graphene.Point({ x, y });
|
return;
|
||||||
this._grabHelper.ungrab();
|
|
||||||
|
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;
|
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 AppDisplay = imports.ui.appDisplay;
|
||||||
const IconGrid = imports.ui.iconGrid;
|
const IconGrid = imports.ui.iconGrid;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
const ParentalControlsManager = imports.misc.parentalControlsManager;
|
||||||
const RemoteSearch = imports.ui.remoteSearch;
|
const RemoteSearch = imports.ui.remoteSearch;
|
||||||
const Util = imports.misc.util;
|
const Util = imports.misc.util;
|
||||||
|
|
||||||
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
|
const SEARCH_PROVIDERS_SCHEMA = 'org.gnome.desktop.search-providers';
|
||||||
|
|
||||||
var MAX_LIST_SEARCH_RESULTS_ROWS = 5;
|
var MAX_LIST_SEARCH_RESULTS_ROWS = 5;
|
||||||
var MAX_GRID_SEARCH_RESULTS_ROWS = 1;
|
|
||||||
|
|
||||||
var MaxWidthBox = GObject.registerClass(
|
var MaxWidthBox = GObject.registerClass(
|
||||||
class MaxWidthBox extends St.BoxLayout {
|
class MaxWidthBox extends St.BoxLayout {
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
let themeNode = this.get_theme_node();
|
let themeNode = this.get_theme_node();
|
||||||
let maxWidth = themeNode.get_max_width();
|
let maxWidth = themeNode.get_max_width();
|
||||||
let availWidth = box.x2 - box.x1;
|
let availWidth = box.x2 - box.x1;
|
||||||
@ -28,7 +28,7 @@ class MaxWidthBox extends St.BoxLayout {
|
|||||||
adjustedBox.x2 -= Math.floor(excessWidth / 2);
|
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) {
|
_ensureResultActors(results, callback) {
|
||||||
let metasNeeded = results.filter(
|
let metasNeeded = results.filter(
|
||||||
resultId => this._resultDisplays[resultId] === undefined
|
resultId => this._resultDisplays[resultId] === undefined);
|
||||||
);
|
|
||||||
|
|
||||||
if (metasNeeded.length === 0) {
|
if (metasNeeded.length === 0) {
|
||||||
callback(true);
|
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(
|
var GridSearchResults = GObject.registerClass(
|
||||||
class GridSearchResults extends SearchResultsBase {
|
class GridSearchResults extends SearchResultsBase {
|
||||||
_init(provider, resultsView) {
|
_init(provider, resultsView) {
|
||||||
super._init(provider, resultsView);
|
super._init(provider, resultsView);
|
||||||
|
|
||||||
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
|
this._grid = new St.Widget({ style_class: 'grid-search-results' });
|
||||||
xAlign: St.Align.START });
|
this._grid.layout_manager = new GridSearchResultsLayout();
|
||||||
|
|
||||||
this._bin = new St.Bin({ x_align: Clutter.ActorAlign.CENTER });
|
this._grid.connect('style-changed', () => {
|
||||||
this._bin.set_child(this._grid);
|
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() {
|
_onDestroy() {
|
||||||
@ -400,12 +521,11 @@ class GridSearchResults extends SearchResultsBase {
|
|||||||
if (width == 0)
|
if (width == 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
let nCols = this._grid.columnsForWidth(width);
|
return this._grid.layout_manager.columnsForWidth(width);
|
||||||
return nCols * this._grid.getRowLimit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearResultDisplay() {
|
_clearResultDisplay() {
|
||||||
this._grid.removeAll();
|
this._grid.remove_all_children();
|
||||||
}
|
}
|
||||||
|
|
||||||
_createResultDisplay(meta) {
|
_createResultDisplay(meta) {
|
||||||
@ -414,14 +534,15 @@ class GridSearchResults extends SearchResultsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_addItem(display) {
|
_addItem(display) {
|
||||||
this._grid.addItem(display);
|
this._grid.add_child(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
getFirstResult() {
|
getFirstResult() {
|
||||||
if (this._grid.visibleItemsCount() > 0)
|
for (let child of this._grid) {
|
||||||
return this._grid.getItemAtIndex(0);
|
if (child.visible)
|
||||||
else
|
return child;
|
||||||
return null;
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -431,6 +552,9 @@ var SearchResultsView = GObject.registerClass({
|
|||||||
_init() {
|
_init() {
|
||||||
super._init({ name: 'searchResults', vertical: true });
|
super._init({ name: 'searchResults', vertical: true });
|
||||||
|
|
||||||
|
this._parentalControlsManager = ParentalControlsManager.getDefault();
|
||||||
|
this._parentalControlsManager.connect('app-filter-changed', this._reloadRemoteProviders.bind(this));
|
||||||
|
|
||||||
this._content = new MaxWidthBox({
|
this._content = new MaxWidthBox({
|
||||||
name: 'searchResultsContent',
|
name: 'searchResultsContent',
|
||||||
vertical: true,
|
vertical: true,
|
||||||
@ -505,6 +629,11 @@ var SearchResultsView = GObject.registerClass({
|
|||||||
|
|
||||||
_registerProvider(provider) {
|
_registerProvider(provider) {
|
||||||
provider.searchInProgress = false;
|
provider.searchInProgress = false;
|
||||||
|
|
||||||
|
// Filter out unwanted providers.
|
||||||
|
if (provider.appInfo && !this._parentalControlsManager.shouldShowApp(provider.appInfo))
|
||||||
|
return;
|
||||||
|
|
||||||
this._providers.push(provider);
|
this._providers.push(provider);
|
||||||
this._ensureProviderDisplay(provider);
|
this._ensureProviderDisplay(provider);
|
||||||
}
|
}
|
||||||
|
@ -316,17 +316,7 @@ var GnomeShellExtensions = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
OpenExtensionPrefs(uuid, parentWindow, options) {
|
OpenExtensionPrefs(uuid, parentWindow, options) {
|
||||||
Gio.DBus.session.call(
|
Main.extensionManager.openExtensionPrefs(uuid, parentWindow, options);
|
||||||
'org.gnome.Shell.Extensions',
|
|
||||||
'/org/gnome/Shell/Extensions',
|
|
||||||
'org.gnome.Shell.Extensions',
|
|
||||||
'OpenExtensionPrefs',
|
|
||||||
new GLib.Variant('(ssa{sv})', [uuid, parentWindow, options]),
|
|
||||||
null,
|
|
||||||
Gio.DBusCallFlags.NONE,
|
|
||||||
-1,
|
|
||||||
null,
|
|
||||||
(conn, res) => conn.call_finish(res));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReloadExtensionAsync(params, invocation) {
|
ReloadExtensionAsync(params, invocation) {
|
||||||
|
@ -295,8 +295,8 @@ var ShellMountPasswordDialog = GObject.registerClass({
|
|||||||
this._keyfilesLabel = new St.Label({ visible: false });
|
this._keyfilesLabel = new St.Label({ visible: false });
|
||||||
this._keyfilesLabel.clutter_text.set_markup(
|
this._keyfilesLabel.clutter_text.set_markup(
|
||||||
/* Translators: %s is the Disks application */
|
/* 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.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
this._keyfilesLabel.clutter_text.line_wrap = true;
|
this._keyfilesLabel.clutter_text.line_wrap = true;
|
||||||
content.add_child(this._keyfilesLabel);
|
content.add_child(this._keyfilesLabel);
|
||||||
@ -464,8 +464,7 @@ var ShellMountPasswordDialog = GObject.registerClass({
|
|||||||
/* Translators: %s is the Disks application */
|
/* Translators: %s is the Disks application */
|
||||||
_("Unable to start %s").format(app.get_name()),
|
_("Unable to start %s").format(app.get_name()),
|
||||||
/* Translators: %s is the Disks application */
|
/* 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();
|
this._onCancelButton();
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||||
/* exported Indicator */
|
/* exported Indicator */
|
||||||
|
|
||||||
const { Gio, GnomeBluetooth, GObject } = imports.gi;
|
const { Gio, GLib, GnomeBluetooth, GObject } = imports.gi;
|
||||||
|
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const PanelMenu = imports.ui.panelMenu;
|
const PanelMenu = imports.ui.panelMenu;
|
||||||
@ -35,7 +35,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
|
|
||||||
this._sync();
|
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 = new PopupMenu.PopupSubMenuMenuItem(_("Bluetooth"), true);
|
||||||
this._item.icon.icon_name = 'bluetooth-active-symbolic';
|
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._item.menu.addSettingsAction(_("Bluetooth Settings"), 'gnome-bluetooth-panel.desktop');
|
||||||
this.menu.addMenuItem(this._item);
|
this.menu.addMenuItem(this._item);
|
||||||
|
|
||||||
|
this._syncId = 0;
|
||||||
|
this._adapter = null;
|
||||||
|
|
||||||
this._client = new GnomeBluetooth.Client();
|
this._client = new GnomeBluetooth.Client();
|
||||||
this._model = this._client.get_model();
|
this._model = this._client.get_model();
|
||||||
this._model.connect('row-changed', this._sync.bind(this));
|
this._model.connect('row-deleted', this._queueSync.bind(this));
|
||||||
this._model.connect('row-deleted', this._sync.bind(this));
|
this._model.connect('row-changed', this._queueSync.bind(this));
|
||||||
this._model.connect('row-inserted', this._sync.bind(this));
|
this._model.connect('row-inserted', this._sync.bind(this));
|
||||||
Main.sessionMode.connect('updated', this._sync.bind(this));
|
Main.sessionMode.connect('updated', this._sync.bind(this));
|
||||||
this._sync();
|
this._sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_setHadSetupDevices(value) {
|
||||||
|
if (this._hadSetupDevices === value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._hadSetupDevices = value;
|
||||||
|
global.settings.set_boolean(
|
||||||
|
HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
|
||||||
|
}
|
||||||
|
|
||||||
_getDefaultAdapter() {
|
_getDefaultAdapter() {
|
||||||
let [ret, iter] = this._model.get_iter_first();
|
let [ret, iter] = this._model.get_iter_first();
|
||||||
while (ret) {
|
while (ret) {
|
||||||
@ -72,46 +84,53 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// nDevices is the number of devices setup for the current default
|
_getDeviceInfos(adapter) {
|
||||||
// adapter if one exists and is powered. If unpowered or unavailable,
|
|
||||||
// nDevice is "1" if it had setup devices associated to it the last
|
|
||||||
// time it was seen, and "-1" if not.
|
|
||||||
//
|
|
||||||
// nConnectedDevices is the number of devices connected to the default
|
|
||||||
// adapter if one exists and is powered, or -1 if it's not available.
|
|
||||||
_getNDevices() {
|
|
||||||
let adapter = this._getDefaultAdapter();
|
|
||||||
if (!adapter)
|
if (!adapter)
|
||||||
return [this._hadSetupDevices ? 1 : -1, -1];
|
return [];
|
||||||
|
|
||||||
let nConnectedDevices = 0;
|
let deviceInfos = [];
|
||||||
let nDevices = 0;
|
|
||||||
let [ret, iter] = this._model.iter_children(adapter);
|
let [ret, iter] = this._model.iter_children(adapter);
|
||||||
while (ret) {
|
while (ret) {
|
||||||
let isConnected = this._model.get_value(iter,
|
const isPaired = this._model.get_value(iter,
|
||||||
GnomeBluetooth.Column.CONNECTED);
|
GnomeBluetooth.Column.PAIRED);
|
||||||
if (isConnected)
|
const isTrusted = this._model.get_value(iter,
|
||||||
nConnectedDevices++;
|
GnomeBluetooth.Column.TRUSTED);
|
||||||
|
|
||||||
|
if (isPaired || isTrusted) {
|
||||||
|
deviceInfos.push({
|
||||||
|
connected: this._model.get_value(iter,
|
||||||
|
GnomeBluetooth.Column.CONNECTED),
|
||||||
|
name: this._model.get_value(iter,
|
||||||
|
GnomeBluetooth.Column.ALIAS),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
let isPaired = this._model.get_value(iter,
|
|
||||||
GnomeBluetooth.Column.PAIRED);
|
|
||||||
let isTrusted = this._model.get_value(iter,
|
|
||||||
GnomeBluetooth.Column.TRUSTED);
|
|
||||||
if (isPaired || isTrusted)
|
|
||||||
nDevices++;
|
|
||||||
ret = this._model.iter_next(iter);
|
ret = this._model.iter_next(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._hadSetupDevices != (nDevices > 0)) {
|
return deviceInfos;
|
||||||
this._hadSetupDevices = !this._hadSetupDevices;
|
}
|
||||||
global.settings.set_boolean(HAD_BLUETOOTH_DEVICES_SETUP, this._hadSetupDevices);
|
|
||||||
}
|
|
||||||
|
|
||||||
return [nDevices, nConnectedDevices];
|
_queueSync() {
|
||||||
|
if (this._syncId)
|
||||||
|
return;
|
||||||
|
this._syncId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
|
||||||
|
this._syncId = 0;
|
||||||
|
this._sync();
|
||||||
|
return GLib.SOURCE_REMOVE;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_sync() {
|
_sync() {
|
||||||
let [nDevices, nConnectedDevices] = this._getNDevices();
|
let adapter = this._getDefaultAdapter();
|
||||||
|
let devices = this._getDeviceInfos(adapter);
|
||||||
|
const connectedDevices = devices.filter(dev => dev.connected);
|
||||||
|
const nConnectedDevices = connectedDevices.length;
|
||||||
|
|
||||||
|
if (adapter && this._adapter)
|
||||||
|
this._setHadSetupDevices(devices.length > 0);
|
||||||
|
this._adapter = adapter;
|
||||||
|
|
||||||
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
let sensitive = !Main.sessionMode.isLocked && !Main.sessionMode.isGreeter;
|
||||||
|
|
||||||
this.menu.setSensitive(sensitive);
|
this.menu.setSensitive(sensitive);
|
||||||
@ -119,19 +138,21 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
|
|
||||||
// Remember if there were setup devices and show the menu
|
// Remember if there were setup devices and show the menu
|
||||||
// if we've seen setup devices and we're not hard blocked
|
// if we've seen setup devices and we're not hard blocked
|
||||||
if (nDevices > 0)
|
if (this._hadSetupDevices)
|
||||||
this._item.visible = !this._proxy.BluetoothHardwareAirplaneMode;
|
this._item.visible = !this._proxy.BluetoothHardwareAirplaneMode;
|
||||||
else
|
else
|
||||||
this._item.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
|
this._item.visible = this._proxy.BluetoothHasAirplaneMode && !this._proxy.BluetoothAirplaneMode;
|
||||||
|
|
||||||
if (nConnectedDevices > 0)
|
if (nConnectedDevices > 1)
|
||||||
/* Translators: this is the number of connected bluetooth devices */
|
/* Translators: this is the number of connected bluetooth devices */
|
||||||
this._item.label.text = ngettext("%d Connected", "%d Connected", nConnectedDevices).format(nConnectedDevices);
|
this._item.label.text = ngettext('%d Connected", "%d Connected', nConnectedDevices).format(nConnectedDevices);
|
||||||
else if (nConnectedDevices == -1)
|
else if (nConnectedDevices === 1)
|
||||||
this._item.label.text = _("Off");
|
this._item.label.text = connectedDevices[0].name;
|
||||||
|
else if (adapter === null)
|
||||||
|
this._item.label.text = _('Bluetooth Off');
|
||||||
else
|
else
|
||||||
this._item.label.text = _("On");
|
this._item.label.text = _('Bluetooth On');
|
||||||
|
|
||||||
this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
|
this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _('Turn On') : _('Turn Off');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -48,7 +48,9 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
this._item.connect('key-press-event', (actor, event) => {
|
this._item.connect('key-press-event', (actor, event) => {
|
||||||
return this._slider.emit('key-press-event', event);
|
return this._slider.emit('key-press-event', event);
|
||||||
});
|
});
|
||||||
|
this._item.connect('scroll-event', (actor, event) => {
|
||||||
|
return this._slider.emit('scroll-event', event);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_sliderChanged() {
|
_sliderChanged() {
|
||||||
|
@ -199,36 +199,36 @@ var InputSourceSystemSettings = class extends InputSourceSettings {
|
|||||||
this._reload.bind(this));
|
this._reload.bind(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
_reload() {
|
async _reload() {
|
||||||
Gio.DBus.system.call(this._BUS_NAME,
|
let props;
|
||||||
this._BUS_PATH,
|
try {
|
||||||
this._BUS_PROPS_IFACE,
|
const result = await Gio.DBus.system.call(
|
||||||
'GetAll',
|
this._BUS_NAME,
|
||||||
new GLib.Variant('(s)', [this._BUS_IFACE]),
|
this._BUS_PATH,
|
||||||
null, Gio.DBusCallFlags.NONE, -1, null,
|
this._BUS_PROPS_IFACE,
|
||||||
(conn, result) => {
|
'GetAll',
|
||||||
let props;
|
new GLib.Variant('(s)', [this._BUS_IFACE]),
|
||||||
try {
|
null, Gio.DBusCallFlags.NONE, -1, null);
|
||||||
props = conn.call_finish(result).deep_unpack()[0];
|
[props] = result.deep_unpack();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Could not get properties from %s'.format(this._BUS_NAME));
|
log('Could not get properties from %s'.format(this._BUS_NAME));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let layouts = props['X11Layout'].unpack();
|
|
||||||
let variants = props['X11Variant'].unpack();
|
|
||||||
let options = props['X11Options'].unpack();
|
|
||||||
|
|
||||||
if (layouts != this._layouts ||
|
const layouts = props['X11Layout'].unpack();
|
||||||
variants != this._variants) {
|
const variants = props['X11Variant'].unpack();
|
||||||
this._layouts = layouts;
|
const options = props['X11Options'].unpack();
|
||||||
this._variants = variants;
|
|
||||||
this._emitInputSourcesChanged();
|
if (layouts !== this._layouts ||
|
||||||
}
|
variants !== this._variants) {
|
||||||
if (options != this._options) {
|
this._layouts = layouts;
|
||||||
this._options = options;
|
this._variants = variants;
|
||||||
this._emitKeyboardOptionsChanged();
|
this._emitInputSourcesChanged();
|
||||||
}
|
}
|
||||||
});
|
if (options !== this._options) {
|
||||||
|
this._options = options;
|
||||||
|
this._emitKeyboardOptionsChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get inputSources() {
|
get inputSources() {
|
||||||
@ -805,8 +805,8 @@ class InputSourceIndicatorContainer extends St.Widget {
|
|||||||
}, [0, 0]);
|
}, [0, 0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
// translate box to (0, 0)
|
// translate box to (0, 0)
|
||||||
box.x2 -= box.x1;
|
box.x2 -= box.x1;
|
||||||
@ -815,7 +815,7 @@ class InputSourceIndicatorContainer extends St.Widget {
|
|||||||
box.y1 = 0;
|
box.y1 = 0;
|
||||||
|
|
||||||
this.get_children().forEach(c => {
|
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 {
|
var AppAuthorizer = class {
|
||||||
constructor(desktopId, reqAccuracyLevel, permStoreProxy, maxAccuracyLevel) {
|
constructor(desktopId, reqAccuracyLevel, permStoreProxy, maxAccuracyLevel) {
|
||||||
this.desktopId = desktopId;
|
this.desktopId = desktopId;
|
||||||
@ -313,9 +309,8 @@ var AppAuthorizer = class {
|
|||||||
|
|
||||||
_completeAuth() {
|
_completeAuth() {
|
||||||
if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
|
if (this._accuracyLevel != GeoclueAccuracyLevel.NONE) {
|
||||||
this._accuracyLevel = clamp(this._accuracyLevel,
|
this._accuracyLevel = Math.clamp(this._accuracyLevel,
|
||||||
0,
|
0, this._maxAccuracyLevel);
|
||||||
this._maxAccuracyLevel);
|
|
||||||
}
|
}
|
||||||
this._saveToPermissionStore();
|
this._saveToPermissionStore();
|
||||||
|
|
||||||
|
@ -15,6 +15,10 @@ const Util = imports.misc.util;
|
|||||||
|
|
||||||
const { loadInterfaceXML } = imports.misc.fileUtils;
|
const { loadInterfaceXML } = imports.misc.fileUtils;
|
||||||
|
|
||||||
|
Gio._promisify(NM.Client, 'new_async', 'new_finish');
|
||||||
|
Gio._promisify(NM.Client.prototype,
|
||||||
|
'check_connectivity_async', 'check_connectivity_finish');
|
||||||
|
|
||||||
const NMConnectionCategory = {
|
const NMConnectionCategory = {
|
||||||
INVALID: 'invalid',
|
INVALID: 'invalid',
|
||||||
WIRED: 'wired',
|
WIRED: 'wired',
|
||||||
@ -712,8 +716,7 @@ class NMWirelessDialog extends ModalDialog.ModalDialog {
|
|||||||
|
|
||||||
let connections = client.get_connections();
|
let connections = client.get_connections();
|
||||||
this._connections = connections.filter(
|
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._apAddedId = device.connect('access-point-added', this._accessPointAdded.bind(this));
|
||||||
this._apRemovedId = device.connect('access-point-removed', this._accessPointRemoved.bind(this));
|
this._apRemovedId = device.connect('access-point-removed', this._accessPointRemoved.bind(this));
|
||||||
@ -1627,11 +1630,11 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
this._ctypes[NM.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
|
this._ctypes[NM.SETTING_GSM_SETTING_NAME] = NMConnectionCategory.WWAN;
|
||||||
this._ctypes[NM.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
|
this._ctypes[NM.SETTING_VPN_SETTING_NAME] = NMConnectionCategory.VPN;
|
||||||
|
|
||||||
NM.Client.new_async(null, this._clientGot.bind(this));
|
this._getClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
_clientGot(obj, result) {
|
async _getClient() {
|
||||||
this._client = NM.Client.new_finish(result);
|
this._client = await NM.Client.new_async(null);
|
||||||
|
|
||||||
this._activeConnections = [];
|
this._activeConnections = [];
|
||||||
this._connections = [];
|
this._connections = [];
|
||||||
@ -1859,8 +1862,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
_syncVpnConnections() {
|
_syncVpnConnections() {
|
||||||
let activeConnections = this._client.get_active_connections() || [];
|
let activeConnections = this._client.get_active_connections() || [];
|
||||||
let vpnConnections = activeConnections.filter(
|
let vpnConnections = activeConnections.filter(
|
||||||
a => a instanceof NM.VpnConnection
|
a => a instanceof NM.VpnConnection);
|
||||||
);
|
|
||||||
vpnConnections.forEach(a => {
|
vpnConnections.forEach(a => {
|
||||||
ensureActiveConnectionProps(a);
|
ensureActiveConnectionProps(a);
|
||||||
});
|
});
|
||||||
@ -1982,7 +1984,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_portalHelperDone(proxy, emitter, parameters) {
|
async _portalHelperDone(proxy, emitter, parameters) {
|
||||||
let [path, result] = parameters;
|
let [path, result] = parameters;
|
||||||
|
|
||||||
if (result == PortalHelperResult.CANCELLED) {
|
if (result == PortalHelperResult.CANCELLED) {
|
||||||
@ -1993,13 +1995,11 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
} else if (result == PortalHelperResult.COMPLETED) {
|
} else if (result == PortalHelperResult.COMPLETED) {
|
||||||
this._closeConnectivityCheck(path);
|
this._closeConnectivityCheck(path);
|
||||||
} else if (result == PortalHelperResult.RECHECK) {
|
} else if (result == PortalHelperResult.RECHECK) {
|
||||||
this._client.check_connectivity_async(null, (client, res) => {
|
try {
|
||||||
try {
|
const state = await this._client.check_connectivity_async(null);
|
||||||
let state = client.check_connectivity_finish(res);
|
if (state >= NM.ConnectivityState.FULL)
|
||||||
if (state >= NM.ConnectivityState.FULL)
|
this._closeConnectivityCheck(path);
|
||||||
this._closeConnectivityCheck(path);
|
} catch (e) { }
|
||||||
} catch (e) { }
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
log('Invalid result from portal helper: %s'.format(result));
|
log('Invalid result from portal helper: %s'.format(result));
|
||||||
}
|
}
|
||||||
|
@ -112,12 +112,12 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
let chargingState = this._proxy.State == UPower.DeviceState.CHARGING
|
let chargingState = this._proxy.State == UPower.DeviceState.CHARGING
|
||||||
? '-charging' : '';
|
? '-charging' : '';
|
||||||
let fillLevel = 10 * Math.floor(this._proxy.Percentage / 10);
|
let fillLevel = 10 * Math.floor(this._proxy.Percentage / 10);
|
||||||
let icon;
|
const charged =
|
||||||
if (this._proxy.State == UPower.DeviceState.FULLY_CHARGED ||
|
this._proxy.State === UPower.DeviceState.FULLY_CHARGED ||
|
||||||
fillLevel === 100)
|
(this._proxy.State === UPower.DeviceState.CHARGING && fillLevel === 100);
|
||||||
icon = 'battery-level-100-charged-symbolic';
|
const icon = charged
|
||||||
else
|
? 'battery-level-100-charged-symbolic'
|
||||||
icon = 'battery-level-%d%s-symbolic'.format(fillLevel, chargingState);
|
: 'battery-level-%d%s-symbolic'.format(fillLevel, chargingState);
|
||||||
|
|
||||||
// Make sure we fall back to fallback-icon-name and not GThemedIcon's
|
// Make sure we fall back to fallback-icon-name and not GThemedIcon's
|
||||||
// default fallbacks
|
// default fallbacks
|
||||||
@ -139,7 +139,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
label = _("%d\u2009%%").format(100);
|
label = _("%d\u2009%%").format(100);
|
||||||
else
|
else
|
||||||
label = _("%d\u2009%%").format(this._proxy.Percentage);
|
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
|
// The status label
|
||||||
this._item.label.text = this._getStatus();
|
this._item.label.text = this._getStatus();
|
||||||
|
@ -11,8 +11,7 @@ class RemoteAccessApplet extends PanelMenu.SystemIndicator {
|
|||||||
_init() {
|
_init() {
|
||||||
super._init();
|
super._init();
|
||||||
|
|
||||||
let backend = Meta.get_backend();
|
let controller = global.backend.get_remote_access_controller();
|
||||||
let controller = backend.get_remote_access_controller();
|
|
||||||
|
|
||||||
if (!controller)
|
if (!controller)
|
||||||
return;
|
return;
|
||||||
|
@ -82,8 +82,7 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let app = this._settingsApp = Shell.AppSystem.get_default().lookup_app(
|
let app = this._settingsApp = Shell.AppSystem.get_default().lookup_app(
|
||||||
'gnome-control-center.desktop'
|
'gnome-control-center.desktop');
|
||||||
);
|
|
||||||
if (app) {
|
if (app) {
|
||||||
let [icon, name] = [app.app_info.get_icon().names[0],
|
let [icon, name] = [app.app_info.get_icon().names[0],
|
||||||
app.get_name()];
|
app.get_name()];
|
||||||
|
@ -52,22 +52,21 @@ const BOLT_DBUS_PATH = '/org/freedesktop/bolt';
|
|||||||
var Client = class {
|
var Client = class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._proxy = null;
|
this._proxy = null;
|
||||||
let nodeInfo = Gio.DBusNodeInfo.new_for_xml(BoltClientInterface);
|
|
||||||
Gio.DBusProxy.new(Gio.DBus.system,
|
|
||||||
Gio.DBusProxyFlags.DO_NOT_AUTO_START,
|
|
||||||
nodeInfo.lookup_interface(BOLT_DBUS_CLIENT_IFACE),
|
|
||||||
BOLT_DBUS_NAME,
|
|
||||||
BOLT_DBUS_PATH,
|
|
||||||
BOLT_DBUS_CLIENT_IFACE,
|
|
||||||
null,
|
|
||||||
this._onProxyReady.bind(this));
|
|
||||||
|
|
||||||
this.probing = false;
|
this.probing = false;
|
||||||
|
this._getProxy();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onProxyReady(o, res) {
|
async _getProxy() {
|
||||||
|
let nodeInfo = Gio.DBusNodeInfo.new_for_xml(BoltClientInterface);
|
||||||
try {
|
try {
|
||||||
this._proxy = Gio.DBusProxy.new_finish(res);
|
this._proxy = await Gio.DBusProxy.new(
|
||||||
|
Gio.DBus.system,
|
||||||
|
Gio.DBusProxyFlags.DO_NOT_AUTO_START,
|
||||||
|
nodeInfo.lookup_interface(BOLT_DBUS_CLIENT_IFACE),
|
||||||
|
BOLT_DBUS_NAME,
|
||||||
|
BOLT_DBUS_PATH,
|
||||||
|
BOLT_DBUS_CLIENT_IFACE,
|
||||||
|
null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('error creating bolt proxy: %s'.format(e.message));
|
log('error creating bolt proxy: %s'.format(e.message));
|
||||||
return;
|
return;
|
||||||
@ -243,14 +242,15 @@ class Indicator extends PanelMenu.SystemIndicator {
|
|||||||
|
|
||||||
this._source = null;
|
this._source = null;
|
||||||
this._perm = null;
|
this._perm = null;
|
||||||
|
this._createPermission();
|
||||||
|
}
|
||||||
|
|
||||||
Polkit.Permission.new('org.freedesktop.bolt.enroll', null, null, (source, res) => {
|
async _createPermission() {
|
||||||
try {
|
try {
|
||||||
this._perm = Polkit.Permission.new_finish(res);
|
this._perm = await Polkit.Permission.new('org.freedesktop.bolt.enroll', null, null);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log('Failed to get PolKit permission: %s'.format(e.toString()));
|
log('Failed to get PolKit permission: %s'.format(e.toString()));
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onDestroy() {
|
_onDestroy() {
|
||||||
|
@ -56,6 +56,9 @@ var StreamSlider = class {
|
|||||||
this.item.connect('key-press-event', (actor, event) => {
|
this.item.connect('key-press-event', (actor, event) => {
|
||||||
return this._slider.emit('key-press-event', 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._stream = null;
|
||||||
this._volumeCancellable = null;
|
this._volumeCancellable = null;
|
||||||
|
@ -28,10 +28,6 @@ const State = {
|
|||||||
SCROLLING: 1,
|
SCROLLING: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
function clamp(value, min, max) {
|
|
||||||
return Math.max(min, Math.min(max, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
const TouchpadSwipeGesture = GObject.registerClass({
|
const TouchpadSwipeGesture = GObject.registerClass({
|
||||||
Properties: {
|
Properties: {
|
||||||
'enabled': GObject.ParamSpec.boolean(
|
'enabled': GObject.ParamSpec.boolean(
|
||||||
@ -558,8 +554,8 @@ var SwipeTracker = GObject.registerClass({
|
|||||||
|
|
||||||
let firstPoint = this._snapPoints[0];
|
let firstPoint = this._snapPoints[0];
|
||||||
let lastPoint = this._snapPoints[this._snapPoints.length - 1];
|
let lastPoint = this._snapPoints[this._snapPoints.length - 1];
|
||||||
this._progress = clamp(this._progress, firstPoint, lastPoint);
|
this._progress = Math.clamp(this._progress, firstPoint, lastPoint);
|
||||||
this._progress = clamp(this._progress,
|
this._progress = Math.clamp(this._progress,
|
||||||
this._initialProgress - 1, this._initialProgress + 1);
|
this._initialProgress - 1, this._initialProgress + 1);
|
||||||
|
|
||||||
this.emit('update', this._progress);
|
this.emit('update', this._progress);
|
||||||
@ -606,7 +602,7 @@ var SwipeTracker = GObject.registerClass({
|
|||||||
|
|
||||||
let duration = Math.abs((this._progress - endProgress) / velocity * DURATION_MULTIPLIER);
|
let duration = Math.abs((this._progress - endProgress) / velocity * DURATION_MULTIPLIER);
|
||||||
if (duration > 0) {
|
if (duration > 0) {
|
||||||
duration = clamp(duration,
|
duration = Math.clamp(duration,
|
||||||
MIN_ANIMATION_DURATION, MAX_ANIMATION_DURATION);
|
MIN_ANIMATION_DURATION, MAX_ANIMATION_DURATION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,8 +66,8 @@ var SwitcherPopup = GObject.registerClass({
|
|||||||
this._disableHover();
|
this._disableHover();
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
let primary = Main.layoutManager.primaryMonitor;
|
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.x2 = Math.min(primary.x + primary.width - rightPadding, childBox.x1 + childNaturalWidth);
|
||||||
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
|
childBox.y1 = primary.y + Math.floor((primary.height - childNaturalHeight) / 2);
|
||||||
childBox.y2 = childBox.y1 + childNaturalHeight;
|
childBox.y2 = childBox.y1 + childNaturalHeight;
|
||||||
this._switcherList.allocate(childBox, flags);
|
this._switcherList.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
_initialSelection(backward, _binding) {
|
_initialSelection(backward, _binding) {
|
||||||
@ -317,7 +317,7 @@ var SwitcherPopup = GObject.registerClass({
|
|||||||
this.ease({
|
this.ease({
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
duration: POPUP_FADE_OUT_TIME,
|
duration: POPUP_FADE_OUT_TIME,
|
||||||
mode: Clutter.Animation.EASE_OUT_QUAD,
|
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
|
||||||
onComplete: () => this.destroy(),
|
onComplete: () => this.destroy(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -591,8 +591,8 @@ var SwitcherList = GObject.registerClass({
|
|||||||
return themeNode.adjust_preferred_height(maxChildMin, maxChildNat);
|
return themeNode.adjust_preferred_height(maxChildMin, maxChildNat);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
let contentBox = this.get_theme_node().get_content_box(box);
|
let contentBox = this.get_theme_node().get_content_box(box);
|
||||||
let width = contentBox.x2 - contentBox.x1;
|
let width = contentBox.x2 - contentBox.x1;
|
||||||
@ -606,7 +606,7 @@ var SwitcherList = GObject.registerClass({
|
|||||||
let childBox = new Clutter.ActorBox();
|
let childBox = new Clutter.ActorBox();
|
||||||
let scrollable = minListWidth > width;
|
let scrollable = minListWidth > width;
|
||||||
|
|
||||||
this._scrollView.allocate(contentBox, flags);
|
this._scrollView.allocate(contentBox);
|
||||||
|
|
||||||
let arrowWidth = Math.floor(leftPadding / 3);
|
let arrowWidth = Math.floor(leftPadding / 3);
|
||||||
let arrowHeight = arrowWidth * 2;
|
let arrowHeight = arrowWidth * 2;
|
||||||
@ -614,7 +614,7 @@ var SwitcherList = GObject.registerClass({
|
|||||||
childBox.y1 = this.height / 2 - arrowWidth;
|
childBox.y1 = this.height / 2 - arrowWidth;
|
||||||
childBox.x2 = childBox.x1 + arrowWidth;
|
childBox.x2 = childBox.x1 + arrowWidth;
|
||||||
childBox.y2 = childBox.y1 + arrowHeight;
|
childBox.y2 = childBox.y1 + arrowHeight;
|
||||||
this._leftArrow.allocate(childBox, flags);
|
this._leftArrow.allocate(childBox);
|
||||||
this._leftArrow.opacity = this._scrollableLeft && scrollable ? 255 : 0;
|
this._leftArrow.opacity = this._scrollableLeft && scrollable ? 255 : 0;
|
||||||
|
|
||||||
arrowWidth = Math.floor(rightPadding / 3);
|
arrowWidth = Math.floor(rightPadding / 3);
|
||||||
@ -623,7 +623,7 @@ var SwitcherList = GObject.registerClass({
|
|||||||
childBox.y1 = this.height / 2 - arrowWidth;
|
childBox.y1 = this.height / 2 - arrowWidth;
|
||||||
childBox.x2 = childBox.x1 + arrowWidth;
|
childBox.x2 = childBox.x1 + arrowWidth;
|
||||||
childBox.y2 = childBox.y1 + arrowHeight;
|
childBox.y2 = childBox.y1 + arrowHeight;
|
||||||
this._rightArrow.allocate(childBox, flags);
|
this._rightArrow.allocate(childBox);
|
||||||
this._rightArrow.opacity = this._scrollableRight && scrollable ? 255 : 0;
|
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);
|
return this._stack.get_preferred_height(forWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(container, box, flags) {
|
vfunc_allocate(container, box) {
|
||||||
let [width, height] = box.get_size();
|
let [width, height] = box.get_size();
|
||||||
|
|
||||||
let tenthOfHeight = height / 10.0;
|
let tenthOfHeight = height / 10.0;
|
||||||
@ -432,7 +432,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
|
|||||||
actorBox.x2 = columnX1 + columnWidth;
|
actorBox.x2 = columnX1 + columnWidth;
|
||||||
actorBox.y2 = actorBox.y1 + maxNotificationsHeight;
|
actorBox.y2 = actorBox.y1 + maxNotificationsHeight;
|
||||||
|
|
||||||
this._notifications.allocate(actorBox, flags);
|
this._notifications.allocate(actorBox);
|
||||||
|
|
||||||
// Authentication Box
|
// Authentication Box
|
||||||
let stackY = Math.min(
|
let stackY = Math.min(
|
||||||
@ -444,7 +444,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
|
|||||||
actorBox.x2 = columnX1 + columnWidth;
|
actorBox.x2 = columnX1 + columnWidth;
|
||||||
actorBox.y2 = stackY + stackHeight;
|
actorBox.y2 = stackY + stackHeight;
|
||||||
|
|
||||||
this._stack.allocate(actorBox, flags);
|
this._stack.allocate(actorBox);
|
||||||
|
|
||||||
// Switch User button
|
// Switch User button
|
||||||
if (this._switchUserButton.visible) {
|
if (this._switchUserButton.visible) {
|
||||||
@ -461,7 +461,7 @@ class UnlockDialogLayout extends Clutter.LayoutManager {
|
|||||||
actorBox.x2 = actorBox.x1 + natWidth;
|
actorBox.x2 = actorBox.x1 + natWidth;
|
||||||
actorBox.y2 = actorBox.y1 + natHeight;
|
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.set_pivot_point(0.5, 0.5);
|
||||||
this._otherUserButton.connect('clicked', this._otherUserClicked.bind(this));
|
this._otherUserButton.connect('clicked', this._otherUserClicked.bind(this));
|
||||||
|
|
||||||
let screenSaverSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.screensaver' });
|
this._screenSaverSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.screensaver' });
|
||||||
screenSaverSettings.bind('user-switch-enabled',
|
|
||||||
this._otherUserButton, 'visible', Gio.SettingsBindFlags.GET);
|
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
|
// Main Box
|
||||||
let mainBox = new St.Widget();
|
let mainBox = new St.Widget();
|
||||||
@ -605,7 +613,7 @@ var UnlockDialog = GObject.registerClass({
|
|||||||
this._showPrompt();
|
this._showPrompt();
|
||||||
|
|
||||||
if (GLib.unichar_isgraph(unichar))
|
if (GLib.unichar_isgraph(unichar))
|
||||||
this.addCharacter(unichar);
|
this._authPrompt.addCharacter(unichar);
|
||||||
|
|
||||||
return Clutter.EVENT_PROPAGATE;
|
return Clutter.EVENT_PROPAGATE;
|
||||||
}
|
}
|
||||||
@ -828,6 +836,21 @@ var UnlockDialog = GObject.registerClass({
|
|||||||
this._gdmClient = null;
|
this._gdmClient = null;
|
||||||
delete this._gdmClient;
|
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() {
|
cancel() {
|
||||||
@ -835,11 +858,6 @@ var UnlockDialog = GObject.registerClass({
|
|||||||
this._authPrompt.cancel();
|
this._authPrompt.cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
addCharacter(unichar) {
|
|
||||||
this._showPrompt();
|
|
||||||
this._authPrompt.addCharacter(unichar);
|
|
||||||
}
|
|
||||||
|
|
||||||
finish(onComplete) {
|
finish(onComplete) {
|
||||||
this._ensureAuthPrompt();
|
this._ensureAuthPrompt();
|
||||||
this._authPrompt.finish(onComplete);
|
this._authPrompt.finish(onComplete);
|
||||||
|
@ -144,8 +144,8 @@ class UserWidgetLabel extends St.Widget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_allocate(box, flags) {
|
vfunc_allocate(box) {
|
||||||
this.set_allocation(box, flags);
|
this.set_allocation(box);
|
||||||
|
|
||||||
let availWidth = box.x2 - box.x1;
|
let availWidth = box.x2 - box.x1;
|
||||||
let availHeight = box.y2 - box.y1;
|
let availHeight = box.y2 - box.y1;
|
||||||
@ -164,7 +164,7 @@ class UserWidgetLabel extends St.Widget {
|
|||||||
childBox.x2 = availWidth;
|
childBox.x2 = availWidth;
|
||||||
childBox.y2 = availHeight;
|
childBox.y2 = availHeight;
|
||||||
|
|
||||||
this._currentLabel.allocate(childBox, flags);
|
this._currentLabel.allocate(childBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
vfunc_paint(paintContext) {
|
vfunc_paint(paintContext) {
|
||||||
|
@ -132,6 +132,7 @@ var ViewSelector = GObject.registerClass({
|
|||||||
super._init({
|
super._init({
|
||||||
name: 'viewSelector',
|
name: 'viewSelector',
|
||||||
x_expand: true,
|
x_expand: true,
|
||||||
|
visible: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._showAppsButton = showAppsButton;
|
this._showAppsButton = showAppsButton;
|
||||||
@ -271,9 +272,10 @@ var ViewSelector = GObject.registerClass({
|
|||||||
Main.overview.show();
|
Main.overview.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
show() {
|
animateToOverview() {
|
||||||
|
this.show();
|
||||||
this.reset();
|
this.reset();
|
||||||
this._workspacesDisplay.show(this._showAppsButton.checked);
|
this._workspacesDisplay.animateToOverview(this._showAppsButton.checked);
|
||||||
this._activePage = null;
|
this._activePage = null;
|
||||||
if (this._showAppsButton.checked)
|
if (this._showAppsButton.checked)
|
||||||
this._showPage(this._appsPage);
|
this._showPage(this._appsPage);
|
||||||
@ -301,9 +303,11 @@ var ViewSelector = GObject.registerClass({
|
|||||||
this._workspacesDisplay.setWorkspacesFullGeometry(geom);
|
this._workspacesDisplay.setWorkspacesFullGeometry(geom);
|
||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
vfunc_hide() {
|
||||||
this.reset();
|
this.reset();
|
||||||
this._workspacesDisplay.hide();
|
this._workspacesDisplay.hide();
|
||||||
|
|
||||||
|
super.vfunc_hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
_addPage(actor, name, a11yIcon, params) {
|
_addPage(actor, name, a11yIcon, params) {
|
||||||
|
@ -82,8 +82,10 @@ class DisplayChangeDialog extends ModalDialog.ModalDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_formatCountDown() {
|
_formatCountDown() {
|
||||||
let fmt = ngettext("Settings changes will revert in %d second",
|
const fmt = ngettext(
|
||||||
"Settings changes will revert in %d seconds");
|
'Settings changes will revert in %d second',
|
||||||
|
'Settings changes will revert in %d seconds',
|
||||||
|
this._countDown);
|
||||||
return fmt.format(this._countDown);
|
return fmt.format(this._countDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -898,35 +900,47 @@ var WindowManager = class {
|
|||||||
|
|
||||||
global.display.connect('init-xserver', (display, task) => {
|
global.display.connect('init-xserver', (display, task) => {
|
||||||
IBusManager.getIBusManager().restartDaemon(['--xim']);
|
IBusManager.getIBusManager().restartDaemon(['--xim']);
|
||||||
Shell.util_start_systemd_unit('gsd-xsettings.target', 'fail');
|
|
||||||
|
|
||||||
/* Leave this watchdog timeout so don't block indefinitely here */
|
try {
|
||||||
let timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, () => {
|
if (!Shell.util_start_systemd_unit('gsd-xsettings.target', 'fail'))
|
||||||
Gio.DBus.session.unwatch_name(watchId);
|
log('Not starting gsd-xsettings; waiting for gnome-session to do so');
|
||||||
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 */
|
/* Leave this watchdog timeout so don't block indefinitely here */
|
||||||
let watchId = Gio.DBus.session.watch_name(
|
let timeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5, () => {
|
||||||
'org.gnome.SettingsDaemon.XSettings',
|
|
||||||
Gio.BusNameWatcherFlags.NONE,
|
|
||||||
() => {
|
|
||||||
Gio.DBus.session.unwatch_name(watchId);
|
Gio.DBus.session.unwatch_name(watchId);
|
||||||
if (timeoutId > 0) {
|
log('Warning: Failed to start gsd-xsettings');
|
||||||
task.return_boolean(true);
|
task.return_boolean(true);
|
||||||
GLib.source_remove(timeoutId);
|
timeoutId = 0;
|
||||||
}
|
return GLib.SOURCE_REMOVE;
|
||||||
},
|
});
|
||||||
null);
|
|
||||||
|
/* 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;
|
return true;
|
||||||
});
|
});
|
||||||
global.display.connect('x11-display-closing', () => {
|
global.display.connect('x11-display-closing', () => {
|
||||||
if (!Meta.is_wayland_compositor())
|
if (!Meta.is_wayland_compositor())
|
||||||
return;
|
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();
|
IBusManager.getIBusManager().restartDaemon();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1264,13 +1278,13 @@ var WindowManager = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_sizeChangeWindow(shellwm, actor, whichChange, oldFrameRect, _oldBufferRect) {
|
_sizeChangeWindow(shellwm, actor, whichChange, oldFrameRect, _oldBufferRect) {
|
||||||
let types = [Meta.WindowType.NORMAL];
|
const types = [Meta.WindowType.NORMAL];
|
||||||
if (!this._shouldAnimateActor(actor, types)) {
|
const shouldAnimate =
|
||||||
shellwm.completed_size_change(actor);
|
this._shouldAnimateActor(actor, types) &&
|
||||||
return;
|
oldFrameRect.width > 0 &&
|
||||||
}
|
oldFrameRect.height > 0;
|
||||||
|
|
||||||
if (oldFrameRect.width > 0 && oldFrameRect.height > 0)
|
if (shouldAnimate)
|
||||||
this._prepareAnimationInfo(shellwm, actor, oldFrameRect, whichChange);
|
this._prepareAnimationInfo(shellwm, actor, oldFrameRect, whichChange);
|
||||||
else
|
else
|
||||||
shellwm.completed_size_change(actor);
|
shellwm.completed_size_change(actor);
|
||||||
@ -1285,17 +1299,24 @@ var WindowManager = class {
|
|||||||
actorClone.set_position(oldFrameRect.x, oldFrameRect.y);
|
actorClone.set_position(oldFrameRect.x, oldFrameRect.y);
|
||||||
actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
|
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);
|
this._shellwm.completed_size_change(actor);
|
||||||
|
}
|
||||||
|
|
||||||
let destroyId = actor.connect('destroy', () => {
|
let destroyId = actor.connect('destroy', () => {
|
||||||
this._clearAnimationInfo(actor);
|
this._clearAnimationInfo(actor);
|
||||||
});
|
});
|
||||||
|
|
||||||
this._resizePending.add(actor);
|
this._resizePending.add(actor);
|
||||||
actor.__animationInfo = { clone: actorClone,
|
actor.__animationInfo = {
|
||||||
oldRect: oldFrameRect,
|
clone: actorClone,
|
||||||
destroyId };
|
oldRect: oldFrameRect,
|
||||||
|
frozen: true,
|
||||||
|
destroyId,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_sizeChangedWindow(shellwm, actor) {
|
_sizeChangedWindow(shellwm, actor) {
|
||||||
@ -1348,13 +1369,17 @@ var WindowManager = class {
|
|||||||
// Now unfreeze actor updates, to get it to the new size.
|
// 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
|
// 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.
|
// 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) {
|
_clearAnimationInfo(actor) {
|
||||||
if (actor.__animationInfo) {
|
if (actor.__animationInfo) {
|
||||||
actor.__animationInfo.clone.destroy();
|
actor.__animationInfo.clone.destroy();
|
||||||
actor.disconnect(actor.__animationInfo.destroyId);
|
actor.disconnect(actor.__animationInfo.destroyId);
|
||||||
|
if (actor.__animationInfo.frozen)
|
||||||
|
actor.thaw();
|
||||||
|
|
||||||
delete actor.__animationInfo;
|
delete actor.__animationInfo;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1369,10 +1394,13 @@ var WindowManager = class {
|
|||||||
actor.translation_x = 0;
|
actor.translation_x = 0;
|
||||||
actor.translation_y = 0;
|
actor.translation_y = 0;
|
||||||
this._clearAnimationInfo(actor);
|
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);
|
this._shellwm.completed_size_change(actor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_hasAttachedDialogs(window, ignoreWindow) {
|
_hasAttachedDialogs(window, ignoreWindow) {
|
||||||
@ -2087,8 +2115,16 @@ var WindowManager = class {
|
|||||||
newWs = workspaceManager.get_workspace_by_index(workspaceManager.n_workspaces - 1);
|
newWs = workspaceManager.get_workspace_by_index(workspaceManager.n_workspaces - 1);
|
||||||
} else if (isNaN(target)) {
|
} else if (isNaN(target)) {
|
||||||
// Prepend a new workspace dynamically
|
// Prepend a new workspace dynamically
|
||||||
if (workspaceManager.get_active_workspace_index() == 0 &&
|
let prependTarget;
|
||||||
action == 'move' && target == 'up' && this._isWorkspacePrepended == false) {
|
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.insertWorkspace(0);
|
||||||
this._isWorkspacePrepended = true;
|
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
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user