Compare commits

..

7 Commits

Author SHA1 Message Date
Alexander Mikhaylenko
b1afb946b2 workspaceAnimation: Support multiple monitors
Currently, there's one animation for the whole canvas. While it looks fine
with just one screen, it causes windows to move between screens when
switching workspaces. Instead, have a separate animation on each screen,
and sync their progress so that at any given time the progress "fraction"
is the same between all screens. Clip all animations to their screens so
that the windows don't leak to other screens.

If a window is placed between every screen, can end up in multiple
animations, in that case each part is still animated separately.

Fixes https://gitlab.gnome.org/GNOME/gnome-shell/issues/1213

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
Alexander Mikhaylenko
46d5bccfc6 workspaceAnimation: Use window clones
Instead of reparenting windows, clone them. This will allow to properly
support multi-monitor setups in subsequent commits.

Block window mapping animation while the animation is running to prevent
new windows appearing during the animation from being visible at the same
time as their clones.

Fixes https://gitlab.gnome.org/GNOME/mutter/issues/929

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
Alexander Mikhaylenko
f0d498062d workspaceAnimation: Only create moving window bin when needed
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
Alexander Mikhaylenko
eeac4a3b6d workspaceAnimation: Extract WorkspaceGroup
Reimplement _syncStacking().

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
Alexander Mikhaylenko
272cb4d523 workspaceAnimation: Extract WorkspaceAnimation
Simplify the logic a bit. Introduce WorkspaceAnimation class that reparents
the windows from current, surrounding and destination workspaces and manages
them. Expose 'progress' property and have WorkspaceAnimationController animate
it instead of animating everything separately.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
Alexander Mikhaylenko
6d5446e4a6 workspaceAnimation: Stop depending on shellwm
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
Alexander Mikhaylenko
fa31bcaa7a workspaceAnimation: Split from WindowManager
It's already too complex, and will get more complex in future, split it
out.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
369 changed files with 34144 additions and 51250 deletions

1
.gitignore vendored
View File

@@ -60,6 +60,7 @@ 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

View File

@@ -1,14 +1,11 @@
include: 'https://gitlab.gnome.org/GNOME/citemplates/raw/master/flatpak/flatpak_ci_initiative.yml'
stages: stages:
- review - review
- build - build
- test - test
- deploy
variables: variables:
BUNDLE: "extensions-git.flatpak"
JS_LOG: "js-report.txt" JS_LOG: "js-report.txt"
POT_LOG: "pot-update.txt"
.only_default: &only_default .only_default: &only_default
only: only:
@@ -17,7 +14,7 @@ variables:
- merge_requests - merge_requests
check_commit_log: check_commit_log:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: review stage: review
variables: variables:
GIT_DEPTH: "100" GIT_DEPTH: "100"
@@ -27,10 +24,10 @@ check_commit_log:
- merge_requests - merge_requests
js_check: js_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: review
script: script:
- find js -name '*.js' -exec js68 -c -s '{}' ';' 2>&1 | tee $JS_LOG - find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
- (! grep -q . $JS_LOG) - (! grep -q . $JS_LOG)
<<: *only_default <<: *only_default
artifacts: artifacts:
@@ -39,7 +36,7 @@ js_check:
when: on_failure when: on_failure
eslint: eslint:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: review
script: script:
- ./.gitlab-ci/run-eslint.sh - ./.gitlab-ci/run-eslint.sh
@@ -49,24 +46,9 @@ eslint:
- reports - reports
when: always when: always
potfile_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
stage: review
script:
- ./.gitlab-ci/check-potfiles.sh
<<: *only_default
no_template_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
stage: review
script:
- ./.gitlab-ci/check-template-strings.sh
<<: *only_default
build: build:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: build stage: build
needs: []
before_script: before_script:
- .gitlab-ci/checkout-mutter.sh - .gitlab-ci/checkout-mutter.sh
- meson mutter mutter/build --prefix=/usr -Dtests=false - meson mutter mutter/build --prefix=/usr -Dtests=false
@@ -83,9 +65,8 @@ build:
- build - build
test: test:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: test stage: test
needs: ["build"]
variables: variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir" XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
NO_AT_BRIDGE: "1" NO_AT_BRIDGE: "1"
@@ -100,20 +81,18 @@ test:
- build/meson-logs/testlog.txt - build/meson-logs/testlog.txt
when: on_failure when: on_failure
flatpak: test-pot:
stage: build image: registry.gitlab.gnome.org/gnome/mutter/master:v3
needs: [] stage: test
variables: before_script:
SUBPROJECT: "subprojects/extensions-app" - ninja -C mutter/build install
# Your manifest path script:
MANIFEST_PATH: "$SUBPROJECT/build-aux/flatpak/org.gnome.Extensions.json" # Check that pot files are generated correctly:
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo" # https://savannah.gnu.org/bugs/?50920#comment5
FLATPAK_MODULE: "gnome-extensions-app" - ninja -C build gnome-shell-pot 2>&1 | awk '
APP_ID: "org.gnome.Extensions" BEGIN { start=0; }
extends: .flatpak start==1 { print $0; }
/gnome-shell-pot/ { start=1; }
' | tee $POT_LOG
- (! grep -q . $POT_LOG)
<<: *only_default <<: *only_default
nightly:
extends: '.publish_nightly'
variables:
BUNDLES: '$BUNDLE'

View File

@@ -1,24 +0,0 @@
# 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

View File

@@ -0,0 +1,18 @@
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

View File

@@ -1,31 +0,0 @@
#!/usr/bin/env bash
srcdirs="js src subprojects/extensions-tool"
globs=('*.js' '*.c')
# find source files that contain gettext keywords
files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs)
# filter out excluded files
if [ -f po/POTFILES.skip ]; then
files=$(for f in $files; do ! grep -q ^$f po/POTFILES.skip && echo $f; done)
fi
# find those that aren't listed in POTFILES.in
missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done)
if [ ${#missing} -eq 0 ]; then
exit 0
fi
cat >&2 <<EOT
The following files are missing from po/POTFILES.po:
EOT
for f in $missing; do
echo " $f" >&2
done
echo >&2
exit 1

View File

@@ -1,23 +0,0 @@
#!/usr/bin/env bash
# find files from POTFILES.in that use js template strings
baddies=$(grep -l '${' $(grep ^js po/POTFILES.in))
if [ ${#baddies} -eq 0 ]; then
exit 0
fi
cat >&2 <<EOT
xgettext cannot handle template strings properly, so we ban their use
in files with translatable strings.
The following files are listed in po/POTFILES.in and use template strings:
EOT
for f in $baddies; do
echo " $f" >&2
done
echo >&2
exit 1

View File

@@ -18,14 +18,12 @@ 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 --cache --cache-location $cache ${!extra_args} -o $output \ eslint -f unix ${!extra_args} -o $output js
js subprojects/extensions-app/js
} }
list_commit_range_additions() { list_commit_range_additions() {

219
NEWS
View File

@@ -1,222 +1,3 @@
3.37.90
=======
* Fix extension updates when many extensions are installed [Jeremias; !1363]
* Fix missing icons in on-screen keyboard [Emre; #2631, #3007]
* Fix delay when showing calendar events [Sebastian; #2992]
* Allow rearranging items in app picker [Georges; !1284]
* Fix top bar navigation when NumLock is active [Olivier; #550]
* Delay login animation until wallpaper has loaded [Michael; #734996]
* Reset auth prompt on login screen on VT switch before fade in [Ray; #2997]
* Move screencasting into a separate service [Jonas Å.; !1372]
* Replace loaded terms with more descriptive one [Olivier; !1393]
* Add "Boot Options" support to restart dialog [Hans; !199]
* Move "Restart" into a separate menu item/dialog [Florian; #2202]
* Default to not installing updates on low battery [Michael; #2717]
* Misc. bug fixes and cleanups [Florian, Daniel V., Georges, Jonas Å.,
Daniel G., Carlos, Benjamin, Piotr, Andre, Jonas D., Andy; !1357, !1356,
#2969, #2969, !1358, !1371, #3005, !1380, #3022, !1381, !895, !1387, !1386,
!1385, #3037, !1389, !1390, !1391, !1383, !1399, #2983, !1403]
Contributors:
Jonas Ådahl, Benjamin Berg, Michael Catanzaro, Piotr Drąg, Jonas Dreßler,
Olivier Fourdan, Carlos Garnacho, Hans de Goede, Andy Holmes,
Sebastian Keller, Andre Moreira Magalhaes, Daniel García Moreno,
Florian Müllner, Georges Basile Stavracas Neto, Jeremias Ortega, Ray Strode,
Emre Uyguroglu, Daniel van Vugt
Translators:
Tim Sabsch [de], Boyuan Yang [zh_CN], Fabio Tomat [fur],
Efstathios Iosifidis [el], Rafael Fontenelle [pt_BR], Yuri Chornoivan [uk],
Daniel Șerbănescu [ro], Jordi Mas [ca], Daniel Mustieles [es],
Emin Tufan Çetin [tr], Asier Sarasua Garmendia [eu]
3.37.3
======
* Refactor and clean up window picker
[Jonas D., Florian; !1297, !1298, !1305, !1345, !1353]
* Move calendar events out of notifications list [Florian; !1282]
* Refine app folder dialogs [Georges; !1301]
* Hide switch-user button on lock screen if unsupported [Chingkai; #2687]
* Refactor and clean up app picker pagination [Georges; !1271]
* Add API to retrieve specified mimetypes from clipboards [Carlos; !1321]
* Support prepending workspace with horizontal layouts [Florian; #2916]
* Update microphone icon on input volume changes [fludixx; #2902]
* Cache labels on GPU [Daniel; !1329]
* Fix regressions in redesigned modal dialogs [Florian, Jonas D.; #2491, !1336]
* Use GIcon for all application icons [Florian; !1342]
* Support pre-authenticated logins in vmware environments [yun341; #1983]
* Better support sandboxed apps with multiple .desktop files [Florian; #219]
* Fix on-screen keyboard size in portrait orientation [Florian; #2349]
* Plugged leaks [Sebastian, Daniel, Florian; !1306, !1319, !1341]
* Misc. bug fixes and cleanups [Jonas D., Georges, Marco, Florian, Sebastian,
MOZGIII, Daniel, Mariana, Jonas Å.; !1296, !1295, #2643, !1300, !1309,
!1119, #2901, !1313, !1251, !1285, !1307, !1318, !1310, !1320, !1327, !1315,
!1289, !1331, !1332, !1333, !1334, !1340, !1287, !1308, !1346, !1299, !1343,
!1351, !1352, !1322]
Contributors:
Marco Trevisan (Treviño), Chingkai, Jonas Dreßler, Carlos Garnacho,
Sebastian Keller, MOZGIII, Florian Müllner, Georges Basile Stavracas Neto,
Mariana Picolo, Daniel van Vugt, fludixx, yun341, Jonas Ådahl
Translators:
Daniel Mustieles [es], Boyuan Yang [zh_CN], Yuri Chornoivan [uk],
Jordi Mas [ca], sicklylife [ja], Emin Tufan Çetin [tr],
Baurzhan Muftakhidinov [kk], Florentina Mușat [ro], Aurimas Černius [lt],
Rūdolfs Mazurs [lv]
3.37.2
======
* Add support for "PrefersNonDefaultGPU" desktop key [Bastien; !1226]
* Only start systemd units when running under systemd
[Carlos, Florian; #2755, !1242, !1252]
* Fix "ghost" media controls [Bryan; #2776]
* Fix zombie sockets from extensions downloader [Michael; #2774]
* Update world clocks offsets when timezone changes [Bryan; #2209]
* Support scrolling anywhere in slider menu items [Peter; #2795]
* Fix "Do Not Disturb" setting getting reset on startup [Florian; #2804]
* Only allow updates for extensions that aren't cached [Florian; !1248]
* Fix matching notifications by PID [Florian; #2592]
* Indicate extension errors in Extensions app [Florian; #2337]
* Add clipboard API for querying supported mimetypes [Andy; #2819]
* Add preview to color picker [Florian; #451]
* Improve world clocks styling [PrOF-kk; #2825]
* Remove Frequent view from app picker [Georges; !880]
* Fix pad OSD glitches [Carlos; !1290]
* Expose actor tree in looking glass [Georges; !1292]
* Fixed crashes [Jonas D., Florian; #2709, #2757]
* Misc. bug fixes and cleanups [Florian, AsciiWolf, Michael, Piotr, Ting-Wei,
Amr, Alexander, Bryan, Georges, Jonas D., Andy, Björn, Koki, Carlos; !1229,
!1231, !1233, !1235, #2578, #2735, #2751, #2602, #2777, !1249, #2796, !1268,
!1269, !1265, !1245, !1273, #2816, !1274, !1263, !1188, !1276, #2652, !1277,
!1281, #2286, !1267, !1286, !1279, !1288, !1293, !1294, !1291]
Contributors:
AsciiWolf, Michael Catanzaro, Björn Daase, Jonas Dreßler, Bryan Dunsmore,
Koki Fukuda, Carlos Garnacho, Andy Holmes, Amr Ibrahim, Soslan Khubulov,
Ting-Wei Lan, Michael Lass, Alexander Mikhaylenko, Florian Müllner,
Georges Basile Stavracas Neto, Bastien Nocera, PrOF-kk, Peter Simonyi
Translators:
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Yuri Chornoivan [uk],
Dušan Kazik [sk], Piotr Drąg [pl], Soslan Khubulov [os],
Daniel Mustieles [es], Nathan Follens [nl], Bruce Cowan [en_GB],
Florentina Mușat [ro], Milo Casagrande [it], Anders Jonsson [sv],
Charles Monzat [fr], Danial Behzadi [fa], sicklylife [ja], Kukuh Syafaat [id],
Jordi Mas [ca], Emin Tufan Çetin [tr], Jiri Grönroos [fi], Марко Костић [sr],
Christian Kirbach [de], Changwoo Ryu [ko], Matej Urbančič [sl]
3.37.1
======
* Improve bluetooth submenu title [Mariana; #2340]
* Add openPrefs() convenience method for extensions [Florian; !1163]
* Bring back support for empty StIcons [Andre, Jonas D.; !1173, !1178]
* Wake up screen when unlocking programmatically [Florian; !1158]
* Improve extensions tool error reporting [Florian; #2391]
* Improve handling of scale-factor changes [Georges; !1176]
* Tone down weekend days with events in calendar [Jakub; #2588]
* Fix showing bluetooth submenu when devices were set up [Florian; !1174]
* Add support for parental controls filtering [Philip W.; !465]
* Provide alternative extension templates [Florian; !812]
* Improve weather section's empty state [Mariana; #2179]
* Fix translations of folder names [Florian; #2623]
* Drop Tweener [Jonas Å.; !1200]
* Match ASCII alternatives of system actions [Will; #2688]
* Fix delay on lock screen after entering wrong password [Jonas D.; #2655]
* Use globalThis instead of window [Andy; #2322]
* Inhibit remote access when disabled by session mode [Jonas Å.; !1210]
* Improve calendar-server performance [Milan; #1875]
* Add gnome-shell-extension-prefs wrapper for compatibility [Florian; !1220]
* Fix stuck lock screen after unlock [Jonas D., Florian; #2446]
* Fixed crashes [Jonas D., Florian, Carlos; #2584, #2625, !1223, !1218]
* Misc. bug fixes and cleanups [Florian, Jonas Å., Marco, Andre, Georges,
Jonas D., Jan, Philip Ch.,, Xiaoguang, Will, Jordan, Matthew, qarmin;
!1126, !1155, !1156, !1165, !1168, !1169, #2551, #2563, !1172, !1175, !1179,
!1160, #2562, #2578, !1184, #2559, !1186, #2607, !1191, !1194, !1199, !1203,
#2649, #2628, !1205, !1206, !1208, !1207, !1211, !1214, !1213, !1192, !1217,
!1219, #1615, #2691, !1094, !1177]
Contributors:
Marco Trevisan (Treviño), Philip Chimento, Milan Crha, Jonas Dreßler,
Carlos Garnacho, Andy Holmes, Matthew Leeds, Andre Moreira Magalhaes,
Florian Müllner, Georges Basile Stavracas Neto, Jordan Petridis,
Mariana Picolo, Jakub Steiner, Will Thompson, Jan Tojnar, Xiaoguang Wang,
Philip Withnall, qarmin, Jonas Ådahl
Translators:
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Danial Behzadi [fa],
Jiri Grönroos [fi], Ibai Oihanguren Sala [eu], Марко Костић [sr],
Rūdolfs Mazurs [lv], Yuri Chornoivan [uk], Carmen Bianca BAKKER [eo],
Dingzhong Chen [zh_CN], Rafael Fontenelle [pt_BR], Petr Kovář [cs],
Asier Sarasua Garmendia [eu], Daniel Mustieles [es], Emin Tufan Çetin [tr]
3.36.0
======
* Fix off-by-1900 error in date conversions [Florian; !1061]
* Fix crash on startup with topIcons* extension enabled [Florian; #2308]
* Don't require gsd-xsettings for X11 support on wayland [Olivier; !1065]
* Fix ibus support in Xorg session [Carlos; #1690]
* Improve Extensions D-Bus API [Florian; !1074]
* Allow session modes to specify alternative resource name [Marco; !1063]
* Fix link to location settings in aggregate menu [Sebastian; #2316]
* Fix illegible app folder titles with light theme [ub; !1059]
* Really fix visual glitch in sliders [Jonas; #1569]
Contributors:
Marco Trevisan (Treviño), Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
Sebastian Keller, Florian Müllner, ub
Translators:
Aman Alam [pa], Goran Vidović [hr], Aurimas Černius [lt],
Milo Casagrande [it], Daniel Korostil [uk], sicklylife [ja],
Marek Černocký [cs], Nathan Follens [nl]
3.35.92
=======
* Plug a memory leak [Jonas D.; !1015]
* Fix missing "back" button on login screen [Florian; #2228]
* Fix width of window preview titles in overview [Jonas D.; #58]
* Fix looking glass text with light style variant [Feichtmeier; !1023]
* Center unlock entry [Florian; !1021]
* Hide overlay scrollbars in notification popup [Jonas D.; !1013]
* Work around add_actor() slowness in icon spring animation [Daniel; !1002]
* Add disable-animations heuristics [Jonas Å.; !757]
* Fix visual glitches in on-screen keyboard [Carlos; #2214]
* Fix clearing changed textures from cache [Florian; #2244]
* Fix visual glitch in sliders [Daniel; #1569]
* Stop using dedicated lock screen background [Florian; !1001]
* Fix entries disappearing after authentication errors [Florian; #2236]
* Fix crash when animations are disabled [Florian; #2255]
* Fix passing pointer events to clients when magnified [Jonas D.; !993]
* Fix keynav on new lock screen [Florian; #2210]
* Avoid short-lived allocations on actor removal [Christian; #2263]
* Fix super-sized default avatars in user list [Florian, Sam; #2242]
* Leave overview when locking the screen [Jonas D.; !1043]
* Hide message list on login screen [Florian; #2241]
* Avoid IO on the main thread [Christian, Florian; !1050, !1051]
* Fix window animations getting stuck when client doesn't respond [Jonas; !1055]
* Only subscribe to touchpad events for touchpad gestures [Daniel; !925]
* Start X11 session services before Xwayland clients [Carlos; !836, !1056]
* Only show switch-user button with unlock prompt [Florian; !1029]
* Misc. bug fixes and cleanups [Jonas D., Florian, Georges, Jonas Å., Daniel,
Jakub, Philippe; !1018, !1020, !1024, !1027, !1026, !1022, !1031, !1035,
!1032, !1025, !1039, #2157, !1037, !1042, !1047, !1048, #2270, !1046,
!167, !1016]
Contributors:
Jonas Dreßler, Feichtmeier, Carlos Garnacho, Christian Hergert, Sam Hewitt,
Florian Müllner, Georges Basile Stavracas Neto, Jakub Steiner, Philippe Troin,
Daniel van Vugt, Jonas Ådahl
Translators:
Danial Behzadi [fa], Efstathios Iosifidis [el], Daniel Mustieles [es],
Sabri Ünal [tr], sicklylife [ja], Piotr Drąg [pl], Jordi Mas [ca],
Anders Jonsson [sv], Chao-Hsiung Liao [zh_TW], Asier Sarasua Garmendia [eu],
Rafael Fontenelle [pt_BR], Марко Костић [sr], Changwoo Ryu [ko],
Charles Monzat [fr], Jiri Grönroos [fi], Jor Teron [mjw], Bruce Cowan [en_GB],
Emin Tufan Çetin [tr], Alan Mortensen [da], Balázs Úr [hu], Fran Dieguez [gl],
Kukuh Syafaat [id]
3.35.91 3.35.91
======= =======
* Improve magnifier [Carlos; !984] * Improve magnifier [Carlos; !984]

View File

@@ -161,16 +161,12 @@ def convert_file(source_file, destination_path):
try: try:
xkb_name = locale_to_xkb(root["locale"], root["name"]) xkb_name = locale_to_xkb(root["locale"], root["name"])
except KeyError as e: except KeyError as e:
logging.warning(e) logging.warn(e)
return False return False
destination_file = os.path.join(destination_path, xkb_name + ".json") destination_file = os.path.join(destination_path, xkb_name + ".json")
try: with open(destination_file, 'w', encoding="utf-8") as dest_fd:
with open(destination_file, 'x', encoding="utf-8") as dest_fd: json.dump(root, dest_fd, ensure_ascii=False, indent=2, sort_keys=True)
json.dump(root, dest_fd, ensure_ascii=False, indent=2, sort_keys=True)
except FileExistsError as e:
logging.info("File %s exists, not updating", destination_file)
return False
logging.debug("written %s", destination_file) logging.debug("written %s", destination_file)

View File

@@ -20,12 +20,6 @@
<method name="ListSessions"> <method name="ListSessions">
<arg name="sessions" type="a(susso)" direction="out"/> <arg name="sessions" type="a(susso)" direction="out"/>
</method> </method>
<method name="CanRebootToBootLoaderMenu">
<arg type="s" direction="out"/>
</method>
<method name="SetRebootToBootLoaderMenu">
<arg type="t" direction="in"/>
</method>
<signal name="PrepareForSleep"> <signal name="PrepareForSleep">
<arg type="b" direction="out"/> <arg type="b" direction="out"/>
</signal> </signal>

View File

@@ -1,191 +0,0 @@
<!DOCTYPE node PUBLIC
'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
<node>
<!--
org.gnome.Mutter.ScreenCast:
@short_description: Screen cast interface
This API is private and not intended to be used outside of the integrated
system that uses libmutter. No compatibility between versions are
promised.
-->
<interface name="org.gnome.Mutter.ScreenCast">
<!--
CreateSession:
@properties: Properties
@session_path: Path to the new session object
* "remote-desktop-session-id" (s): The ID of a remote desktop session.
Remote desktop driven screen casts
are started and stopped by the remote
desktop session.
* "disable-animations" (b): Set to "true" if the screen cast application
would prefer animations to be globally
disabled, while the session is running. Default
is "false". Available since version 3.
-->
<method name="CreateSession">
<arg name="properties" type="a{sv}" direction="in" />
<arg name="session_path" type="o" direction="out" />
</method>
<!--
Version:
@short_description: API version
-->
<property name="Version" type="i" access="read" />
</interface>
<!--
org.gnome.Mutter.ScreenCast.Session:
@short_description: Screen cast session
-->
<interface name="org.gnome.Mutter.ScreenCast.Session">
<!--
Start:
Start the screen cast session
-->
<method name="Start" />
<!--
Stop:
Stop the screen cast session
-->
<method name="Stop" />
<!--
Closed:
The session has closed.
-->
<signal name="Closed" />
<!--
RecordMonitor:
@connector: Connector of the monitor to record
@properties: Properties
@stream_path: Path to the new stream object
Record a single monitor.
Available @properties include:
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below)
Available since API version 2.
* "is-recording" (b): Whether this is a screen recording. May be
be used for choosing panel icon.
Default: false. Available since API version 4.
Available cursor mode values:
0: hidden - cursor is not included in the stream
1: embedded - cursor is included in the framebuffer
2: metadata - cursor is included as metadata in the PipeWire stream
-->
<method name="RecordMonitor">
<arg name="connector" type="s" direction="in" />
<arg name="properties" type="a{sv}" direction="in" />
<arg name="stream_path" type="o" direction="out" />
</method>
<!--
RecordWindow:
@properties: Properties used determining what window to select
@stream_path: Path to the new stream object
Supported since API version 2.
Record a single window. The cursor will not be included.
Available @properties include:
* "window-id" (t): Id of the window to record.
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see RecordMonitor).
* "is-recording" (b): Whether this is a screen recording. May be
be used for choosing panel icon.
Default: false. Available since API version 4.
-->
<method name="RecordWindow">
<arg name="properties" type="a{sv}" direction="in" />
<arg name="stream_path" type="o" direction="out" />
</method>
<!--
RecordArea:
@x: X position of the recorded area
@y: Y position of the recorded area
@width: width of the recorded area
@height: height of the recorded area
@properties: Properties
@stream_path: Path to the new stream object
Record an area of the stage. The coordinates are in stage coordinates.
The size of the stream does not necessarily match the size of the
recorded area, and will depend on DPI scale of the affected monitors.
Available @properties include:
* "cursor-mode" (u): Cursor mode. Default: 'hidden' (see below)
Available since API version 2.
* "is-recording" (b): Whether this is a screen recording. May be
be used for choosing panel icon.
Default: false. Available since API version 4.
Available cursor mode values:
0: hidden - cursor is not included in the stream
1: embedded - cursor is included in the framebuffer
2: metadata - cursor is included as metadata in the PipeWire stream
-->
<method name="RecordArea">
<arg name="x" type="i" direction="in" />
<arg name="y" type="i" direction="in" />
<arg name="width" type="i" direction="in" />
<arg name="height" type="i" direction="in" />
<arg name="properties" type="a{sv}" direction="in" />
<arg name="stream_path" type="o" direction="out" />
</method>
</interface>
<!--
org.gnome.Mutter.ScreenCast.Stream:
@short_description: Screen cast stream
-->
<interface name="org.gnome.Mutter.ScreenCast.Stream">
<!--
PipeWireStreamAdded:
@short_description: Pipewire stream added
A signal emitted when PipeWire stream for the screen cast stream has
been created. The @node_id corresponds to the PipeWire stream node.
-->
<signal name="PipeWireStreamAdded">
<annotation name="org.gtk.GDBus.C.Name" value="pipewire-stream-added"/>
<arg name="node_id" type="u" direction="out" />
</signal>
<!--
Parameters:
@short_description: Optional stream parameters
Available parameters include:
* "position" (ii): Position of the source of the stream in the
compositor coordinate space.
* "size" (ii): Size of the source of the stream in the compositor
coordinate space.
-->
<property name="Parameters" type="a{sv}" access="read" />
</interface>
</node>

View File

@@ -1,19 +1,12 @@
<node> <node>
<interface name="org.gnome.Shell.CalendarServer"> <interface name="org.gnome.Shell.CalendarServer">
<method name="SetTimeRange"> <method name="GetEvents">
<arg type="x" name="since" direction="in"/> <arg type="x" direction="in" />
<arg type="x" name="until" direction="in"/> <arg type="x" direction="in" />
<arg type="b" name="force_reload" direction="in"/> <arg type="b" 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>

View File

@@ -199,37 +199,14 @@
<!-- <!--
LaunchExtensionPrefs: LaunchExtensionPrefs:
Deprecated for OpenExtensionPrefs @uuid: The UUID of the extension
Launch preferences of an extension.
--> -->
<method name="LaunchExtensionPrefs"> <method name="LaunchExtensionPrefs">
<arg type="s" direction="in" name="uuid"/> <arg type="s" direction="in" name="uuid"/>
</method> </method>
<!--
OpenExtensionPrefs:
@uuid: The UUID of the extension
@parent_window: Identifier for the application window
@options: Vardict with further options
Opens the prefs dialog of extension @uuid.
The following @options are recognized:
<variablelist>
<varlistentry>
<term>modal b</term>
<listitem>
<para>Whether the prefs window should be modal, default: false</para>
</listitem>
</varlistentry>
</variablelist>
-->
<method name="OpenExtensionPrefs">
<arg type="s" direction="in" name="uuid"/>
<arg type="s" direction="in" name="parent_window"/>
<arg type="a{sv}" direction="in" name="options"/>
</method>
<!-- <!--
CheckForUpdates: CheckForUpdates:
Update all extensions for which updates are available Update all extensions for which updates are available
@@ -257,11 +234,5 @@
--> -->
<property name="ShellVersion" type="s" access="read"/> <property name="ShellVersion" type="s" access="read"/>
<!--
UserExtensionsEnabled:
Whether user extensions are enabled
-->
<property name="UserExtensionsEnabled" type="b" access="readwrite"/>
</interface> </interface>
</node> </node>

View File

@@ -70,14 +70,6 @@
--> -->
<property name="AnimationsEnabled" type="b" access="read"/> <property name="AnimationsEnabled" type="b" access="read"/>
<!--
ScreenSize:
@short_description: The size of the screen
Since: 3
-->
<property name="ScreenSize" type="(ii)" access="read"/>
<property name="version" type="u" access="read"/> <property name="version" type="u" access="read"/>
</interface> </interface>
</node> </node>

View File

@@ -2,6 +2,7 @@
<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>
@@ -28,7 +29,6 @@
<file preprocess="xml-stripblanks">org.freedesktop.UPower.xml</file> <file preprocess="xml-stripblanks">org.freedesktop.UPower.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Magnifier.xml</file> <file preprocess="xml-stripblanks">org.gnome.Magnifier.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Magnifier.ZoomRegion.xml</file> <file preprocess="xml-stripblanks">org.gnome.Magnifier.ZoomRegion.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Mutter.ScreenCast.xml</file>
<file preprocess="xml-stripblanks">org.gnome.ScreenSaver.xml</file> <file preprocess="xml-stripblanks">org.gnome.ScreenSaver.xml</file>
<file preprocess="xml-stripblanks">org.gnome.SessionManager.EndSessionDialog.xml</file> <file preprocess="xml-stripblanks">org.gnome.SessionManager.EndSessionDialog.xml</file>
<file preprocess="xml-stripblanks">org.gnome.SessionManager.Inhibitor.xml</file> <file preprocess="xml-stripblanks">org.gnome.SessionManager.Inhibitor.xml</file>

View File

@@ -6,25 +6,24 @@
<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/scalable/actions/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 alias="icons/scalable/status/message-indicator-symbolic.svg">message-indicator-symbolic.svg</file> <file alias="icons/message-indicator-symbolic.svg">message-indicator-symbolic.svg</file>
<file>no-events.svg</file> <file>no-events.svg</file>
<file>no-notifications.svg</file> <file>no-notifications.svg</file>
<file>pad-osd.css</file> <file>pad-osd.css</file>
<file alias="icons/scalable/status/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file> <file alias="icons/eye-open-negative-filled-symbolic.svg">eye-open-negative-filled-symbolic.svg</file>
<file alias="icons/scalable/status/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file> <file alias="icons/eye-not-looking-symbolic.svg">eye-not-looking-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file> <file alias="icons/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file> <file alias="icons/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file> <file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
<file alias="icons/scalable/actions/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file> <file alias="icons/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-caps-lock-filled-symbolic.svg">keyboard-caps-lock-filled-symbolic.svg</file> <file alias="icons/keyboard-caps-lock-filled-symbolic.svg">keyboard-caps-lock-filled-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-enter-symbolic.svg">keyboard-enter-symbolic.svg</file> <file alias="icons/keyboard-enter-symbolic.svg">keyboard-enter-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-hide-symbolic.svg">keyboard-hide-symbolic.svg</file> <file alias="icons/keyboard-hide-symbolic.svg">keyboard-hide-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-layout-filled-symbolic.svg">keyboard-layout-filled-symbolic.svg</file> <file alias="icons/keyboard-layout-filled-symbolic.svg">keyboard-layout-filled-symbolic.svg</file>
<file alias="icons/scalable/status/keyboard-shift-filled-symbolic.svg">keyboard-shift-filled-symbolic.svg</file> <file alias="icons/keyboard-shift-filled-symbolic.svg">keyboard-shift-filled-symbolic.svg</file>
<file>process-working.svg</file> <file>process-working.svg</file>
<file>toggle-off.svg</file> <file>toggle-off.svg</file>
<file>toggle-off-dark.svg</file> <file>toggle-off-dark.svg</file>

View File

@@ -0,0 +1,27 @@
[Unit]
Description=GNOME Shell on Wayland
# On wayland, force a session shutdown
OnFailure=gnome-shell-disable-extensions.service gnome-session-shutdown.target
OnFailureJobMode=replace-irreversibly
CollectMode=inactive-or-failed
RefuseManualStart=on
RefuseManualStop=on
After=gnome-session-manager.target
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
# The units already conflict because they use the same BusName
#Conflicts=gnome-shell-x11.service
[Service]
Type=notify
ExecStart=@bindir@/gnome-shell
# Exit code 1 means we are probably *not* dealing with an extension failure
SuccessExitStatus=1
# On wayland we cannot restart
Restart=no
# Kill any stubborn child processes after this long
TimeoutStopSec=5

View File

@@ -6,5 +6,5 @@ Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target Before=gnome-session-initialized.target
Wants=org.gnome.Shell@wayland.service Requires=gnome-shell-wayland.service
Wants=org.gnome.Shell@x11.service After=gnome-shell-wayland.service

View File

@@ -1,7 +1,7 @@
[Unit] [Unit]
Description=GNOME Shell on X11 Description=GNOME Shell on X11
# On X11, try to show the GNOME Session Failed screen # On X11, try to show the GNOME Session Failed screen
OnFailure=org.gnome.Shell-disable-extensions.service gnome-session-failed.target OnFailure=gnome-shell-disable-extensions.service gnome-session-failed.target
OnFailureJobMode=replace OnFailureJobMode=replace
CollectMode=inactive-or-failed CollectMode=inactive-or-failed
RefuseManualStart=on RefuseManualStart=on
@@ -13,24 +13,18 @@ Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target Before=gnome-session-initialized.target
# The units already conflict because they use the same BusName
#Conflicts=gnome-shell-wayland.service
# Limit startup frequency more than the default # Limit startup frequency more than the default
StartLimitIntervalSec=15s StartLimitIntervalSec=15s
StartLimitBurst=3 StartLimitBurst=3
[Service] [Service]
Slice=session.slice
Type=notify Type=notify
# NOTE: This can be replaced with ConditionEnvironment=XDG_SESSION_TYPE=%I
# with systemd >= 245. Also, the current solution is kind of painful
# as systemd had a bug where it retries the condition.
# Only start if the template instance matches the session type.
ExecCondition=/bin/sh -c 'test "$XDG_SESSION_TYPE" = "%I" || exit 2'
ExecStart=@bindir@/gnome-shell ExecStart=@bindir@/gnome-shell
# Exit code 1 means we are probably *not* dealing with an extension failure # Exit code 1 means we are probably *not* dealing with an extension failure
SuccessExitStatus=1 SuccessExitStatus=1
# On X11 we do not need to unset any variables
# On X11 we want to restart on-success (Alt+F2 + r) and on-failure. # On X11 we want to restart on-success (Alt+F2 + r) and on-failure.
Restart=always Restart=always
# Do not wait before restarting the shell # Do not wait before restarting the shell

View File

@@ -0,0 +1,10 @@
[Unit]
Description=GNOME Shell on X11
DefaultDependencies=no
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
Requires=gnome-shell-x11.service
After=gnome-shell-x11.service

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -1 +0,0 @@
<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>

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -1,6 +1,6 @@
desktop_files = [ desktop_files = [
'org.gnome.Shell.desktop', 'org.gnome.Shell.desktop',
'org.gnome.Shell.Extensions.desktop', 'org.gnome.Extensions.desktop',
] ]
service_files = [] service_files = []
@@ -101,21 +101,22 @@ if have_systemd
unitconf.set('bindir', bindir) unitconf.set('bindir', bindir)
configure_file( configure_file(
input: 'org.gnome.Shell@x11.service.in', input: 'gnome-shell-x11.service.in',
output: 'org.gnome.Shell@x11.service', output: 'gnome-shell-x11.service',
configuration: unitconf, configuration: unitconf,
install_dir: systemduserunitdir install_dir: systemduserunitdir
) )
configure_file( configure_file(
input: 'org.gnome.Shell@wayland.service.in', input: 'gnome-shell-wayland.service.in',
output: 'org.gnome.Shell@wayland.service', output: 'gnome-shell-wayland.service',
configuration: unitconf, configuration: unitconf,
install_dir: systemduserunitdir install_dir: systemduserunitdir
) )
units = files('org.gnome.Shell.target', units = files('gnome-shell-x11.target',
'org.gnome.Shell-disable-extensions.service') 'gnome-shell-wayland.target',
'gnome-shell-disable-extensions.service')
install_data(units, install_dir: systemduserunitdir) install_data(units, install_dir: systemduserunitdir)
endif endif

View File

@@ -2,9 +2,8 @@
Type=Application Type=Application
Name=Extensions Name=Extensions
# Translators: Do NOT translate or transliterate this text (this is an icon file name)! # Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=@app_id@ Icon=org.gnome.Extensions
Comment=Configure GNOME Shell Extensions Comment=Configure GNOME Shell Extensions
Exec=@bindir@/@prgname@ Exec=@bindir@/gnome-shell-extension-prefs %u
DBusActivatable=true Categories=GNOME;GTK;
Categories=GNOME;GTK;Utility;
OnlyShowIn=GNOME; OnlyShowIn=GNOME;

View File

@@ -1,10 +0,0 @@
[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

View File

@@ -1,34 +0,0 @@
[Unit]
Description=GNOME Shell on Wayland
# On wayland, force a session shutdown
OnFailure=org.gnome.Shell-disable-extensions.service gnome-session-shutdown.target
OnFailureJobMode=replace-irreversibly
CollectMode=inactive-or-failed
RefuseManualStart=on
RefuseManualStop=on
After=gnome-session-manager.target
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
[Service]
Slice=session.slice
Type=notify
# NOTE: This can be replaced with ConditionEnvironment=XDG_SESSION_TYPE=%I
# with systemd >= 245. Also, the current solution is kind of painful
# as systemd had a bug where it retries the condition.
# Only start if the template instance matches the session type.
ExecCondition=/bin/sh -c 'test "$XDG_SESSION_TYPE" = "%I" || exit 2'
ExecStart=@bindir@/gnome-shell
# Exit code 1 means we are probably *not* dealing with an extension failure
SuccessExitStatus=1
# unset some environment variables that were set by the shell and won't work now that the shell is gone
ExecStopPost=-systemctl --user unset-environment GNOME_SETUP_DISPLAY WAYLAND_DISPLAY DISPLAY XAUTHORITY
# On wayland we cannot restart
Restart=no
# Kill any stubborn child processes after this long
TimeoutStopSec=5

View File

@@ -109,17 +109,6 @@
the shell. the shell.
</description> </description>
</key> </key>
<key name="app-picker-layout" type="aa{sv}">
<default>[]</default>
<summary>Layout of the app picker</summary>
<description>
Layout of the app picker. Each entry in the array is a page. Pages are
stored in the order they appear in GNOME Shell. Each page contains an
“application id” → 'data' pair. Currently, the following values are
stored as 'data':
• “position”: the position of the application icon in the page
</description>
</key>
<child name="keybindings" schema="org.gnome.shell.keybindings"/> <child name="keybindings" schema="org.gnome.shell.keybindings"/>
</schema> </schema>

View File

@@ -12,9 +12,7 @@
"w" "w"
], ],
[ [
"e", "e"
"é",
"ë"
], ],
[ [
"r" "r"
@@ -23,58 +21,30 @@
"t" "t"
], ],
[ [
"y", "y"
"ý",
"ÿ"
], ],
[ [
"u", "u"
"ú",
"ü",
"û",
"ù",
"ū"
], ],
[ [
"i", "i"
"í",
"ï"
], ],
[ [
"o", "o"
"ó",
"ô",
"ò",
"õ",
"œ",
"ō"
], ],
[ [
"p" "p"
],
[
"å"
] ]
], ],
[ [
[ [
"a", "a"
"á",
"ä",
"à",
"â",
"ã",
"ā"
], ],
[ [
"s", "s"
"ß",
"ś",
"š"
], ],
[ [
"d", "d"
"ð"
], ],
[ [
"f" "f"
@@ -92,16 +62,7 @@
"k" "k"
], ],
[ [
"l", "l"
"ł"
],
[
"ø",
"ö"
],
[
"æ",
"ä"
] ]
], ],
[ [
@@ -121,9 +82,7 @@
"b" "b"
], ],
[ [
"n", "n"
"ñ",
"ń"
], ],
[ [
"m" "m"
@@ -162,9 +121,7 @@
"W" "W"
], ],
[ [
"E", "E"
"É",
"Ë"
], ],
[ [
"R" "R"
@@ -173,58 +130,30 @@
"T" "T"
], ],
[ [
"Y", "Y"
"Ý",
"Ÿ"
], ],
[ [
"U", "U"
"Ú",
"Ü",
"Û",
"Ù",
"Ū"
], ],
[ [
"I", "I"
"Í",
"Ï"
], ],
[ [
"O", "O"
"Ó",
"Ô",
"Ò",
"Õ",
"Œ",
"Ō"
], ],
[ [
"P" "P"
],
[
"Å"
] ]
], ],
[ [
[ [
"A", "A"
"Á",
"Ä",
"À",
"Â",
"Ã",
"Ā"
], ],
[ [
"S", "S"
"SS",
"Ś",
"Š"
], ],
[ [
"D", "D"
"Ð"
], ],
[ [
"F" "F"
@@ -242,16 +171,7 @@
"K" "K"
], ],
[ [
"L", "L"
"Ł"
],
[
"Ø",
"Ö"
],
[
"Æ",
"Ä"
] ]
], ],
[ [
@@ -271,9 +191,7 @@
"B" "B"
], ],
[ [
"N", "N"
"Ñ",
"Ń"
], ],
[ [
"M" "M"
@@ -359,10 +277,10 @@
"#" "#"
], ],
[ [
"", "$",
"¢", "¢",
"£", "£",
"$", "",
"¥", "¥",
"₱" "₱"
], ],
@@ -500,16 +418,15 @@
[ [
"£" "£"
], ],
[
"¢"
],
[
"€"
],
[ [
"¥" "¥"
], ],
[
"$",
"¢"
],
[
"¢"
],
[ [
"^", "^",
"↑", "↑",
@@ -587,4 +504,4 @@
], ],
"locale": "nb", "locale": "nb",
"name": "Norwegian Bokmål" "name": "Norwegian Bokmål"
} }

View File

@@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="5.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>

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -1,15 +1,21 @@
/* App Grid */ /* App Grid */
$app_icon_size: 96px; $app_icon_size: 96px;
$app_icon_padding: 24px;
// app icons // app icons
.icon-grid { .icon-grid {
row-spacing: $base_spacing * 6; -shell-grid-horizontal-item-size: $app_icon_size + $app_icon_padding * 2;
column-spacing: $base_spacing * 6; -shell-grid-vertical-item-size: $app_icon_size + $app_icon_padding * 2;
max-row-spacing: $base_spacing * 12; spacing: $base_spacing * 6;
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;
@@ -29,17 +35,17 @@ $app_grid_fg_color: #fff;
} }
/* App Folders */ /* App Folders */
.app-well-app.app-folder { .app-folder {
background-color: transparentize($osd_bg_color, 0.8); .overview-icon {
border-radius: $base_border_radius + 4px; // same as %icon_tile }
} }
// expanded folder // expanded folder
.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;
@@ -48,13 +54,13 @@ $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: 800; font-weight: bold;
} }
& .folder-name-entry { width: 300px } & .folder-name-entry { width: 300px }
/* FIXME: this is to keep the label in sync with the entry */ /* FIXME: this is to keep the label in sync with the entry */
& .folder-name-label { padding: 5px 7px; color: $osd_fg_color; } & .folder-name-label { padding: 5px 7px }
& .edit-folder-button { & .edit-folder-button {
@extend %button; @extend %button;
@@ -68,23 +74,14 @@ $app_grid_fg_color: #fff;
} }
} }
& .icon-grid { & StButton#vhandle,
row-spacing: $base_spacing * 2; & StButton#vhandle:hover,
column-spacing: $base_spacing * 5; & StButton#vhandle:active { background-color: transparent; }
}
& .page-indicators {
margin-bottom: 18px;
.page-indicator {
padding: 15px 12px;
}
}
} }
.app-folder-dialog-container { .app-folder-dialog-container {
padding: 12px; padding: 12px;
width: 620px; width: 800px;
height: 620px; height: 600px;
} }
.app-folder-icon { .app-folder-icon {
@@ -130,11 +127,15 @@ $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);
@@ -142,3 +143,44 @@ $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;
}
}

View File

@@ -153,11 +153,9 @@
} }
.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 {
@@ -177,32 +175,6 @@
} }
} }
/* 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;
@@ -230,11 +202,9 @@
.world-clocks-time { .world-clocks-time {
font-weight: bold; font-weight: bold;
color: $fg_color; color: $fg_color;
font-feature-settings: "tnum"; font-feature-settings: "lnum";
@include fontsize($base_font_size); @include fontsize($base_font_size);
text-align: right;
&:ltr { text-align: right; }
&:rtl { text-align: left; }
} }
// timezone offset label // timezone offset label

View File

@@ -138,10 +138,11 @@
.user-widget.horizontal .user-widget-label { .user-widget.horizontal .user-widget-label {
@include fontsize($base_font_size + 2); @include fontsize($base_font_size + 2);
font-weight: bold; font-weight: bold;
text-align: left;
padding-left: 15px; padding-left: 15px;
&:ltr { padding-left: 14px; text-align: left; } &:ltr { padding-left: 14px; }
&:rtl { padding-right: 14px; text-align: right; } &:rtl { padding-right: 14px; }
} }
.user-widget.vertical .user-widget-label { .user-widget.vertical .user-widget-label {

View File

@@ -1,7 +1,5 @@
/* Looking Glass */ /* Looking Glass */
$text_fg_color: #ccc;
// Dialog // Dialog
#LookingGlassDialog { #LookingGlassDialog {
background-color: $osd_bg_color; background-color: $osd_bg_color;
@@ -54,11 +52,6 @@ $text_fg_color: #ccc;
&: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 {

View File

@@ -71,11 +71,9 @@
> .event-time { > .event-time {
color: transparentize($fg_color, 0.5); color: transparentize($fg_color, 0.5);
@include fontsize($base_font_size - 2); @include fontsize($base_font_size - 2);
text-align: right;
/* HACK: the label should be baseline-aligned with a 1em label, fake this with some bottom padding */ /* HACK: the label should be baseline-aligned with a 1em label, fake this with some bottom padding */
padding-bottom: 0.13em; padding-bottom: 0.13em;
&:ltr { text-align: right };
&:rtl { text-align: left };
} }
} }

View File

@@ -76,10 +76,8 @@ $popover_arrow_height: 12px;
// container for radio and check boxes // container for radio and check boxes
.popup-menu-ornament { .popup-menu-ornament {
text-align: right;
width: 1.2em; width: 1.2em;
&:ltr { text-align: right };
&:rtl { text-align: left };
} }
// separator // separator

View File

@@ -54,10 +54,6 @@
@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;

View File

@@ -15,11 +15,13 @@
border: 1px solid transparent; border: 1px solid transparent;
&:outlined { &:outlined {
background-color: transparentize($osd_fg_color, 0.7); border: 1px solid darken($borders_color,5%);
background-color: transparentize($osd_fg_color, 0.9);
box-shadow: inset 0 2px 2px 0 rgba(0,0,0,0.4);
} }
&:selected { &:selected {
background-color: transparentize($osd_fg_color, 0.7); background-color: transparentize($osd_fg_color, 0.9);
color: $osd_fg_color; color: $osd_fg_color;
} }
} }

View File

@@ -1,20 +1,19 @@
/* Window Picker */ /* Window Picker */
$window_picker_spacing: $base_spacing; // 6px $window_picker_spacing: $base_spacing * 2; // 16px
$window_picker_padding: $base_padding * 2; // 12px $window_picker_padding: $base_padding * 2; // 16px
$window_thumbnail_border_color:transparentize($selected_fg_color, 0.65); $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 {
// Space between window thumbnails // Space between window thumbnails
spacing: $window_picker_spacing; -horizontal-spacing: $window_picker_spacing;
-vertical-spacing: $window_picker_spacing;
// Padding for container around window thumbnails // Padding for container around window thumbnails
padding: $window_picker_padding; padding: $window_picker_padding;
@@ -23,7 +22,7 @@ $window_clone_border_size: 6px;
// Borders on window thumbnails // Borders on window thumbnails
.window-clone-border { .window-clone-border {
border-width: $window_clone_border_size; border-width: 6px;
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;
@@ -55,6 +54,8 @@ $window_clone_border_size: 6px;
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%);
} }

View File

@@ -1,9 +1,10 @@
#!/bin/env bash #!/bin/env bash
CLDR_LAYOUTS_TARBALL="http://www.unicode.org/Public/cldr/latest/keyboards.zip" CLDR_LAYOUTS_TARBALL="http://www.unicode.org/Public/cldr/latest/keyboards.zip"
CLDR2JSON_GIT="git://repo.or.cz/cldr2json.git"
WORKDIR=".osk-layout-workbench" WORKDIR=".osk-layout-workbench"
CLDR2JSON="cldr2json/cldr2json.py" CLDR2JSON="$WORKDIR/cldr2json/cldr2json.py"
SRCDIR="$WORKDIR/keyboards/android" SRCDIR="$WORKDIR/keyboards/android"
DESTDIR="osk-layouts" DESTDIR="osk-layouts"
GRESOURCE_FILE="gnome-shell-osk-layouts.gresource.xml" GRESOURCE_FILE="gnome-shell-osk-layouts.gresource.xml"
@@ -19,6 +20,7 @@ mkdir -p "osk-layouts"
# Download stuff on the work dir # Download stuff on the work dir
pushd $WORKDIR pushd $WORKDIR
gio copy $CLDR_LAYOUTS_TARBALL . gio copy $CLDR_LAYOUTS_TARBALL .
git clone $CLDR2JSON_GIT
unzip keyboards.zip unzip keyboards.zip
popd popd

View File

@@ -3,8 +3,13 @@ private_headers = [
'gactionobservable.h', 'gactionobservable.h',
'gactionobserver.h', 'gactionobserver.h',
'shell-network-agent.h', 'shell-network-agent.h',
'shell-recorder-src.h'
] ]
if not enable_recorder
private_headers += 'shell-recorder.h'
endif
exclude_directories = [ exclude_directories = [
'calendar-server', 'calendar-server',
'hotplug-sniffer', 'hotplug-sniffer',

View File

@@ -1,5 +0,0 @@
imports.package.start({
name: '@PACKAGE_NAME@',
prefix: '@prefix@',
libdir: '@libdir@',
});

View File

@@ -1,3 +0,0 @@
[D-BUS Service]
Name=@service@
Exec=@gjs@ @pkgdatadir@/@service@

View File

@@ -1,179 +0,0 @@
/* exported DBusService, ServiceImplementation */
const { Gio, GLib } = imports.gi;
const Signals = imports.signals;
const IDLE_SHUTDOWN_TIME = 2; // s
var ServiceImplementation = class {
constructor(info, objectPath) {
this._objectPath = objectPath;
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(info, this);
this._injectTracking('return_dbus_error');
this._injectTracking('return_error_literal');
this._injectTracking('return_gerror');
this._injectTracking('return_value');
this._injectTracking('return_value_with_unix_fd_list');
this._senders = new Map();
this._holdCount = 0;
this._hasSignals = this._dbusImpl.get_info().signals.length > 0;
this._shutdownTimeoutId = 0;
// subclasses may override this to disable automatic shutdown
this._autoShutdown = true;
this._queueShutdownCheck();
}
// subclasses may override this to own additional names
register() {
}
export() {
this._dbusImpl.export(Gio.DBus.session, this._objectPath);
}
unexport() {
this._dbusImpl.unexport();
}
hold() {
this._holdCount++;
}
release() {
if (this._holdCount === 0) {
logError(new Error('Unmatched call to release()'));
return;
}
this._holdCount--;
if (this._holdCount === 0)
this._queueShutdownCheck();
}
/**
* _handleError:
* @param {Gio.DBusMethodInvocation}
* @param {Error}
*
* Complete @invocation with an appropriate error if @error is set;
* useful for implementing early returns from method implementations.
*
* @returns {bool} - true if @invocation was completed
*/
_handleError(invocation, error) {
if (error === null)
return false;
if (error instanceof GLib.Error) {
invocation.return_gerror(error);
} else {
let name = error.name;
if (!name.includes('.')) // likely a normal JS error
name = `org.gnome.gjs.JSError.${name}`;
invocation.return_dbus_error(name, error.message);
}
return true;
}
_maybeShutdown() {
if (!this._autoShutdown)
return;
if (this._holdCount > 0)
return;
this.emit('shutdown');
}
_queueShutdownCheck() {
if (this._shutdownTimeoutId)
GLib.source_remove(this._shutdownTimeoutId);
this._shutdownTimeoutId = GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT, IDLE_SHUTDOWN_TIME,
() => {
this._shutdownTimeoutId = 0;
this._maybeShutdown();
return GLib.SOURCE_REMOVE;
});
}
_trackSender(sender) {
if (this._senders.has(sender))
return;
this.hold();
this._senders.set(sender,
this._dbusImpl.get_connection().watch_name(
sender,
Gio.BusNameWatcherFlags.NONE,
null,
() => this._untrackSender(sender)));
}
_untrackSender(sender) {
const id = this._senders.get(sender);
if (id)
this._dbusImpl.get_connection().unwatch_name(id);
if (this._senders.delete(sender))
this.release();
}
_injectTracking(methodName) {
const { prototype } = Gio.DBusMethodInvocation;
const origMethod = prototype[methodName];
const that = this;
prototype[methodName] = function (...args) {
origMethod.apply(this, args);
if (that._hasSignals)
that._trackSender(this.get_sender());
that._queueShutdownCheck();
};
}
};
Signals.addSignalMethods(ServiceImplementation.prototype);
var DBusService = class {
constructor(name, service) {
this._name = name;
this._service = service;
this._loop = new GLib.MainLoop(null, false);
this._service.connect('shutdown', () => this._loop.quit());
}
run() {
// Bail out when not running under gnome-shell
Gio.DBus.watch_name(Gio.BusType.SESSION,
'org.gnome.Shell',
Gio.BusNameWatcherFlags.NONE,
null,
() => this._loop.quit());
this._service.register();
Gio.DBus.own_name(Gio.BusType.SESSION,
this._name,
Gio.BusNameOwnerFlags.REPLACE,
() => this._service.export(),
null,
() => this._loop.quit());
this._loop.run();
}
};

View File

@@ -1,2 +0,0 @@
.expander-frame > * { border-top-width: 0; }
.expander-toolbar { border: 0 solid @borders; border-top-width: 1px; }

View File

@@ -1,274 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ExtensionsService */
const { Gdk, Gio, GLib, GObject, Gtk, Shew } = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const { loadInterfaceXML } = imports.misc.fileUtils;
const { ServiceImplementation } = imports.dbusService;
const ExtensionsIface = loadInterfaceXML('org.gnome.Shell.Extensions');
const ExtensionsProxy = Gio.DBusProxy.makeProxyWrapper(ExtensionsIface);
var ExtensionsService = class extends ServiceImplementation {
constructor() {
super(ExtensionsIface, '/org/gnome/Shell/Extensions');
this._proxy = new ExtensionsProxy(Gio.DBus.session,
'org.gnome.Shell', '/org/gnome/Shell');
this._proxy.connectSignal('ExtensionStateChanged',
(proxy, sender, params) => {
this._dbusImpl.emit_signal('ExtensionStateChanged',
new GLib.Variant('(sa{sv})', params));
});
this._proxy.connect('g-properties-changed', () => {
this._dbusImpl.emit_property_changed('UserExtensionsEnabled',
new GLib.Variant('b', this._proxy.UserExtensionsEnabled));
});
}
get ShellVersion() {
return this._proxy.ShellVersion;
}
get UserExtensionsEnabled() {
return this._proxy.UserExtensionsEnabled;
}
set UserExtensionsEnabled(enable) {
this._proxy.UserExtensionsEnabled = enable;
}
ListExtensionsAsync(params, invocation) {
this._proxy.ListExtensionsRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(a{sa{sv}})', res));
});
}
GetExtensionInfoAsync(params, invocation) {
this._proxy.GetExtensionInfoRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(a{sv})', res));
});
}
GetExtensionErrorsAsync(params, invocation) {
this._proxy.GetExtensionErrorsRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(as)', res));
});
}
InstallRemoteExtensionAsync(params, invocation) {
this._proxy.InstallRemoteExtensionRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(s)', res));
});
}
UninstallExtensionAsync(params, invocation) {
this._proxy.UninstallExtensionRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(b)', res));
});
}
EnableExtensionAsync(params, invocation) {
this._proxy.EnableExtensionRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(b)', res));
});
}
DisableExtensionAsync(params, invocation) {
this._proxy.DisableExtensionRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(b)', res));
});
}
LaunchExtensionPrefsAsync([uuid], invocation) {
this.OpenExtensionPrefsAsync([uuid, '', {}], invocation);
}
OpenExtensionPrefsAsync(params, invocation) {
const [uuid, parentWindow, options] = params;
this._proxy.GetExtensionInfoRemote(uuid, (res, error) => {
if (this._handleError(invocation, error))
return;
const [serialized] = res;
const extension = ExtensionUtils.deserializeExtension(serialized);
const window = new ExtensionPrefsDialog(extension);
window.realize();
let externalWindow = null;
if (parentWindow)
externalWindow = Shew.ExternalWindow.new_from_handle(parentWindow);
if (externalWindow)
externalWindow.set_parent_of(window.window);
if (options.modal)
window.modal = options.modal.get_boolean();
window.connect('destroy', () => this.release());
this.hold();
window.show();
invocation.return_value(null);
});
}
CheckForUpdatesAsync(params, invocation) {
this._proxy.CheckForUpdatesRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(null);
});
}
};
var ExtensionPrefsDialog = GObject.registerClass({
GTypeName: 'ExtensionPrefsDialog',
Template: 'resource:///org/gnome/Shell/Extensions/ui/extension-prefs-dialog.ui',
InternalChildren: [
'headerBar',
'stack',
'expander',
'expanderArrow',
'revealer',
'errorView',
],
}, class ExtensionPrefsDialog extends Gtk.Window {
_init(extension) {
super._init();
this._uuid = extension.uuid;
this._url = extension.metadata.url || '';
this._headerBar.title = extension.metadata.name;
this._actionGroup = new Gio.SimpleActionGroup();
this.insert_action_group('win', this._actionGroup);
this._initActions();
this._addCustomStylesheet();
this._gesture = new Gtk.GestureMultiPress({
widget: this._expander,
button: 0,
exclusive: true,
});
this._gesture.connect('released', (gesture, nPress) => {
if (nPress === 1)
this._revealer.reveal_child = !this._revealer.reveal_child;
});
this._revealer.connect('notify::reveal-child', () => {
this._expanderArrow.icon_name = this._revealer.reveal_child
? 'pan-down-symbolic'
: 'pan-end-symbolic';
});
try {
ExtensionUtils.installImporter(extension);
// give extension prefs access to their own extension object
ExtensionUtils.getCurrentExtension = () => extension;
const prefsModule = extension.imports.prefs;
prefsModule.init(extension.metadata);
const widget = prefsModule.buildPrefsWidget();
this._stack.add(widget);
this._stack.visible_child = widget;
} catch (e) {
this._setError(e);
}
}
_setError(exc) {
this._errorView.buffer.text = `${exc}\n\nStack trace:\n`;
// Indent stack trace.
this._errorView.buffer.text +=
exc.stack.split('\n').map(line => ` ${line}`).join('\n');
// markdown for pasting in gitlab issues
let lines = [
`The settings of extension ${this._uuid} had an error:`,
'```',
`${exc}`,
'```',
'',
'Stack trace:',
'```',
exc.stack.replace(/\n$/, ''), // stack without trailing newline
'```',
'',
];
this._errorMarkdown = lines.join('\n');
this._actionGroup.lookup('copy-error').enabled = true;
}
_initActions() {
let action;
action = new Gio.SimpleAction({
name: 'copy-error',
enabled: false,
});
action.connect('activate', () => {
const clipboard = Gtk.Clipboard.get_default(this.get_display());
clipboard.set_text(this._errorMarkdown, -1);
});
this._actionGroup.add_action(action);
action = new Gio.SimpleAction({
name: 'show-url',
enabled: this._url !== '',
});
action.connect('activate', () => {
Gio.AppInfo.launch_default_for_uri(this._url,
this.get_display().get_app_launch_context());
});
this._actionGroup.add_action(action);
}
_addCustomStylesheet() {
let provider = new Gtk.CssProvider();
let uri = 'resource:///org/gnome/Shell/Extensions/css/application.css';
try {
provider.load_from_file(Gio.File.new_for_uri(uri));
} catch (e) {
logError(e, 'Failed to add application style');
}
Gtk.StyleContext.add_provider_for_screen(Gdk.Screen.get_default(),
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
}
});

View File

@@ -1,20 +0,0 @@
/* exported main */
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.Gtk = '3.0';
const { Gtk } = imports.gi;
const pkg = imports.package;
const { DBusService } = imports.dbusService;
const { ExtensionsService } = imports.extensionsService;
function main() {
Gtk.init(null);
pkg.initFormat();
const service = new DBusService(
'org.gnome.Shell.Extensions',
new ExtensionsService());
service.run();
}

View File

@@ -1,197 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<template class="ExtensionPrefsDialog" parent="GtkWindow">
<property name="default_width">600</property>
<property name="default_height">400</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerBar">
<property name="visible">True</property>
<property name="show_close_button">True</property>
</object>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="hscrollbar_policy">never</property>
<property name="propagate_natural_height">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin">100</property>
<property name="margin_bottom">60</property>
<property name="spacing">12</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Somethings gone wrong</property>
<attributes>
<attribute name="scale" value="1.44"/> <!-- x-large -->
</attributes>
<style>
<class name="dim-label"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Were very sorry, but theres been a problem: the settings for this extension cant be displayed. We recommend that you report the issue to the extension authors.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="xalign">0.5</property>
<property name="yalign">0.5</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="margin_top">12</property>
<child>
<object class="GtkFrame" id="expander">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkEventBox">
<property name="visible">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="margin">12</property>
<property name="spacing">6</property>
<child>
<object class="GtkImage" id="expanderArrow">
<property name="visible">True</property>
<property name="icon_name">pan-end-symbolic</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="label" translatable="yes">Technical Details</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkRevealer" id="revealer">
<property name="visible">True</property>
<child>
<object class="GtkFrame">
<property name="visible">True</property>
<property name="shadow_type">in</property>
<style>
<class name="expander-frame"/>
</style>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkTextView" id="errorView">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="monospace">True</property>
<property name="editable">False</property>
<property name="wrap_mode">word</property>
<property name="left_margin">12</property>
<property name="right_margin">12</property>
<property name="top_margin">12</property>
<property name="bottom_margin">12</property>
</object>
</child>
<child>
<object class="GtkToolbar">
<property name="visible">True</property>
<style>
<class name="expander-toolbar"/>
</style>
<child>
<object class="GtkToolItem">
<property name="visible">True</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">win.copy-error</property>
<style>
<class name="flat"/>
<class name="image-button"/>
</style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon_name">edit-copy-symbolic</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSeparatorToolItem">
<property name="visible">True</property>
<property name="draw">False</property>
</object>
<packing>
<property name="expand">True</property>
</packing>
</child>
<child>
<object class="GtkToolItem">
<property name="visible">True</property>
<child>
<object class="GtkButton" id="homeButton">
<property name="visible"
bind-source="homeButton"
bind-property="sensitive"
bind-flags="sync-create"/>
<property name="label" translatable="yes">Homepage</property>
<property name="tooltip_text" translatable="yes">Visit extension homepage</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="no_show_all">True</property>
<property name="action_name">win.show-url</property>
<style>
<class name="flat"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -1,48 +0,0 @@
launcherconf = configuration_data()
launcherconf.set('PACKAGE_NAME', meson.project_name())
launcherconf.set('prefix', prefix)
launcherconf.set('libdir', libdir)
dbus_services = {
'org.gnome.Shell.Extensions': 'extensions',
'org.gnome.Shell.Notifications': 'notifications',
}
if enable_recorder
dbus_services += {
'org.gnome.Shell.Screencast': 'screencast',
}
endif
config_dir = '@0@/..'.format(meson.current_build_dir())
foreach service, dir : dbus_services
configure_file(
input: 'dbus-service.in',
output: service,
configuration: launcherconf,
install_dir: pkgdatadir,
)
serviceconf = configuration_data()
serviceconf.set('service', service)
serviceconf.set('gjs', gjs.path())
serviceconf.set('pkgdatadir', pkgdatadir)
configure_file(
input: 'dbus-service.service.in',
output: service + '.service',
configuration: serviceconf,
install_dir: servicedir
)
gnome.compile_resources(
service + '.src',
service + '.src.gresource.xml',
dependencies: [config_js],
source_dir: ['.', '..', dir, config_dir],
gresource_bundle: true,
install: true,
install_dir: pkgdatadir
)
endforeach

View File

@@ -1,11 +0,0 @@
/* exported main */
const { DBusService } = imports.dbusService;
const { NotificationDaemon } = imports.notificationDaemon;
function main() {
const service = new DBusService(
'org.gnome.Shell.Notifications',
new NotificationDaemon());
service.run();
}

View File

@@ -1,105 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NotificationDaemon */
const { Gio, GLib } = imports.gi;
const { loadInterfaceXML } = imports.misc.fileUtils;
const { ServiceImplementation } = imports.dbusService;
const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface);
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
var NotificationDaemon = class extends ServiceImplementation {
constructor() {
super(NotificationsIface, '/org/freedesktop/Notifications');
this._autoShutdown = false;
this._proxy = new NotificationsProxy(Gio.DBus.session,
'org.gnome.Shell',
'/org/freedesktop/Notifications',
(proxy, error) => {
if (error)
log(error.message);
});
this._proxy.connectSignal('ActionInvoked',
(proxy, sender, params) => {
this._dbusImpl.emit_signal('ActionInvoked',
new GLib.Variant('(us)', params));
});
this._proxy.connectSignal('NotificationClosed',
(proxy, sender, params) => {
this._dbusImpl.emit_signal('NotificationClosed',
new GLib.Variant('(uu)', params));
});
}
register() {
Gio.DBus.session.own_name(
'org.freedesktop.Notifications',
Gio.BusNameOwnerFlags.REPLACE,
null, null);
}
async NotifyAsync(params, invocation) {
const pid = await this._getSenderPid(invocation.get_sender());
const hints = params[6];
params[6] = {
...hints,
'sender-pid': new GLib.Variant('u', pid),
};
this._proxy.NotifyRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(u)', res));
});
}
CloseNotificationAsync(params, invocation) {
this._proxy.CloseNotificationRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(null);
});
}
GetCapabilitiesAsync(params, invocation) {
this._proxy.GetCapabilitiesRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(as)', res));
});
}
GetServerInformationAsync(params, invocation) {
this._proxy.GetServerInformationRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
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;
}
};

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Shell/Extensions/js">
<file>main.js</file>
<file>extensionsService.js</file>
<file>dbusService.js</file>
<file>misc/config.js</file>
<file>misc/extensionUtils.js</file>
<file>misc/fileUtils.js</file>
<file>misc/params.js</file>
</gresource>
<gresource prefix="/org/gnome/Shell/Extensions">
<file>css/application.css</file>
<file>ui/extension-prefs-dialog.ui</file>
</gresource>
</gresources>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Shell/Notifications/js">
<file>main.js</file>
<file>notificationDaemon.js</file>
<file>dbusService.js</file>
<file>misc/config.js</file>
<file>misc/fileUtils.js</file>
</gresource>
</gresources>

View File

@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/Shell/Screencast/js">
<file>main.js</file>
<file>screencastService.js</file>
<file>dbusService.js</file>
<file>misc/config.js</file>
<file>misc/fileUtils.js</file>
</gresource>
</gresources>

View File

@@ -1,11 +0,0 @@
/* exported main */
const { DBusService } = imports.dbusService;
const { ScreencastService } = imports.screencastService;
function main() {
const service = new DBusService(
'org.gnome.Shell.Screencast',
new ScreencastService());
service.run();
}

View File

@@ -1,458 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ScreencastService */
const { Gio, GLib, Gst } = imports.gi;
const { loadInterfaceXML, loadSubInterfaceXML } = imports.misc.fileUtils;
const { ServiceImplementation } = imports.dbusService;
const ScreencastIface = loadInterfaceXML('org.gnome.Shell.Screencast');
const IntrospectIface = loadInterfaceXML('org.gnome.Shell.Introspect');
const IntrospectProxy = Gio.DBusProxy.makeProxyWrapper(IntrospectIface);
const ScreenCastIface = loadSubInterfaceXML(
'org.gnome.Mutter.ScreenCast', 'org.gnome.Mutter.ScreenCast');
const ScreenCastSessionIface = loadSubInterfaceXML(
'org.gnome.Mutter.ScreenCast.Session', 'org.gnome.Mutter.ScreenCast');
const ScreenCastStreamIface = loadSubInterfaceXML(
'org.gnome.Mutter.ScreenCast.Stream', 'org.gnome.Mutter.ScreenCast');
const ScreenCastProxy = Gio.DBusProxy.makeProxyWrapper(ScreenCastIface);
const ScreenCastSessionProxy = Gio.DBusProxy.makeProxyWrapper(ScreenCastSessionIface);
const ScreenCastStreamProxy = Gio.DBusProxy.makeProxyWrapper(ScreenCastStreamIface);
const DEFAULT_PIPELINE = 'vp8enc min_quantizer=13 max_quantizer=13 cpu-used=5 deadline=1000000 threads=%T ! queue ! webmmux';
const DEFAULT_FRAMERATE = 30;
const DEFAULT_DRAW_CURSOR = true;
const PipelineState = {
INIT: 0,
PLAYING: 1,
FLUSHING: 2,
STOPPED: 3,
};
const SessionState = {
INIT: 0,
ACTIVE: 1,
STOPPED: 2,
};
var Recorder = class {
constructor(sessionPath, x, y, width, height, filePath, options,
invocation,
onErrorCallback) {
this._startInvocation = invocation;
this._dbusConnection = invocation.get_connection();
this._onErrorCallback = onErrorCallback;
this._stopInvocation = null;
this._pipelineIsPlaying = false;
this._sessionIsActive = false;
this._x = x;
this._y = y;
this._width = width;
this._height = height;
this._filePath = filePath;
this._pipelineString = DEFAULT_PIPELINE;
this._framerate = DEFAULT_FRAMERATE;
this._drawCursor = DEFAULT_DRAW_CURSOR;
this._applyOptions(options);
this._watchSender(invocation.get_sender());
this._initSession(sessionPath);
}
_applyOptions(options) {
for (const option in options)
options[option] = options[option].deep_unpack();
if (options['pipeline'] !== undefined)
this._pipelineString = options['pipeline'];
if (options['framerate'] !== undefined)
this._framerate = options['framerate'];
if ('draw-cursor' in options)
this._drawCursor = options['draw-cursor'];
}
_watchSender(sender) {
this._nameWatchId = this._dbusConnection.watch_name(
sender,
Gio.BusNameWatcherFlags.NONE,
null,
this._senderVanished.bind(this));
}
_unwatchSender() {
if (this._nameWatchId !== 0) {
this._dbusConnection.unwatch_name(this._nameWatchId);
this._nameWatchId = 0;
}
}
_senderVanished() {
this._unwatchSender();
this.stopRecording(null);
}
_notifyStopped() {
this._unwatchSender();
if (this._onStartedCallback)
this._onStartedCallback(this, false);
else if (this._onStoppedCallback)
this._onStoppedCallback(this);
else
this._onErrorCallback(this);
}
_onSessionClosed() {
switch (this._pipelineState) {
case PipelineState.STOPPED:
break;
default:
this._pipeline.set_state(Gst.State.NULL);
log(`Unexpected pipeline state: ${this._pipelineState}`);
break;
}
this._notifyStopped();
}
_initSession(sessionPath) {
this._sessionProxy = new ScreenCastSessionProxy(Gio.DBus.session,
'org.gnome.Mutter.ScreenCast',
sessionPath);
this._sessionProxy.connectSignal('Closed', this._onSessionClosed.bind(this));
}
_startPipeline(nodeId) {
this._ensurePipeline(nodeId);
const bus = this._pipeline.get_bus();
bus.add_watch(bus, this._onBusMessage.bind(this));
this._pipeline.set_state(Gst.State.PLAYING);
this._pipelineState = PipelineState.PLAYING;
this._onStartedCallback(this, true);
this._onStartedCallback = null;
}
startRecording(onStartedCallback) {
this._onStartedCallback = onStartedCallback;
const [streamPath] = this._sessionProxy.RecordAreaSync(
this._x, this._y,
this._width, this._height,
{
'is-recording': GLib.Variant.new('b', true),
'cursor-mode': GLib.Variant.new('u', this._drawCursor ? 1 : 0),
});
this._streamProxy = new ScreenCastStreamProxy(Gio.DBus.session,
'org.gnome.ScreenCast.Stream',
streamPath);
this._streamProxy.connectSignal('PipeWireStreamAdded',
(proxy, sender, params) => {
const [nodeId] = params;
this._startPipeline(nodeId);
});
this._sessionProxy.StartSync();
this._sessionState = SessionState.ACTIVE;
}
stopRecording(onStoppedCallback) {
this._pipelineState = PipelineState.FLUSHING;
this._onStoppedCallback = onStoppedCallback;
this._pipeline.send_event(Gst.Event.new_eos());
}
_stopSession() {
this._sessionProxy.StopSync();
this._sessionState = SessionState.STOPPED;
}
_onBusMessage(bus, message, _) {
switch (message.type) {
case Gst.MessageType.EOS:
this._pipeline.set_state(Gst.State.NULL);
switch (this._pipelineState) {
case PipelineState.FLUSHING:
this._pipelineState = PipelineState.STOPPED;
break;
default:
break;
}
switch (this._sessionState) {
case SessionState.ACTIVE:
this._stopSession();
break;
case SessionState.STOPPED:
this._notifyStopped();
break;
default:
break;
}
break;
default:
break;
}
return true;
}
_substituteThreadCount(pipelineDescr) {
const numProcessors = GLib.get_num_processors();
const numThreads = Math.min(Math.max(1, numProcessors), 64);
return pipelineDescr.replace(/%T/, numThreads);
}
_ensurePipeline(nodeId) {
const framerate = this._framerate;
let fullPipeline = `
pipewiresrc path=${nodeId}
do-timestamp=true
keepalive-time=1000
resend-last=true !
video/x-raw,max-framerate=${framerate}/1 !
videoconvert !
${this._pipelineString} !
filesink location="${this._filePath}"`;
fullPipeline = this._substituteThreadCount(fullPipeline);
this._pipeline = Gst.parse_launch_full(fullPipeline,
null,
Gst.ParseFlags.FATAL_ERRORS);
}
};
var ScreencastService = class extends ServiceImplementation {
constructor() {
super(ScreencastIface, '/org/gnome/Shell/Screencast');
Gst.init(null);
this._recorders = new Map();
this._senders = new Map();
this._lockdownSettings = new Gio.Settings({
schema_id: 'org.gnome.desktop.lockdown',
});
this._proxy = new ScreenCastProxy(Gio.DBus.session,
'org.gnome.Mutter.ScreenCast',
'/org/gnome/Mutter/ScreenCast');
this._introspectProxy = new IntrospectProxy(Gio.DBus.session,
'org.gnome.Shell.Introspect',
'/org/gnome/Shell/Introspect');
}
_removeRecorder(sender) {
this._recorders.delete(sender);
if (this._recorders.size === 0)
this.release();
}
_addRecorder(sender, recorder) {
this._recorders.set(sender, recorder);
if (this._recorders.size === 1)
this.hold();
}
_getAbsolutePath(filename) {
if (GLib.path_is_absolute(filename))
return filename;
let videoDir = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_VIDEOS);
if (!GLib.file_test(videoDir, GLib.FileTest.EXISTS))
videoDir = GLib.get_home_dir();
return GLib.build_filenamev([videoDir, filename]);
}
_generateFilePath(template) {
let filename = '';
let escape = false;
[...template].forEach(c => {
if (escape) {
switch (c) {
case '%':
filename += '%';
break;
case 'd': {
const datetime = GLib.DateTime.new_now_local();
const datestr = datetime.format('%0x');
const datestrEscaped = datestr.replace(/\//g, '-');
filename += datestrEscaped;
break;
}
case 't': {
const datetime = GLib.DateTime.new_now_local();
const datestr = datetime.format('%0X');
const datestrEscaped = datestr.replace(/\//g, ':');
filename += datestrEscaped;
break;
}
default:
log(`Warning: Unknown escape ${c}`);
}
escape = false;
} else if (c === '%') {
escape = true;
} else {
filename += c;
}
});
if (escape)
filename += '%';
return this._getAbsolutePath(filename);
}
ScreencastAsync(params, invocation) {
let returnValue = [false, ''];
if (this._lockdownSettings.get_boolean('disable-save-to-disk')) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const sender = invocation.get_sender();
if (this._recorders.get(sender)) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const [sessionPath] = this._proxy.CreateSessionSync({});
const [fileTemplate, options] = params;
const [screenWidth, screenHeight] = this._introspectProxy.ScreenSize;
const filePath = this._generateFilePath(fileTemplate);
let recorder;
try {
recorder = new Recorder(
sessionPath,
0, 0,
screenWidth, screenHeight,
fileTemplate,
options,
invocation,
_recorder => this._removeRecorder(sender));
} catch (error) {
log(`Failed to create recorder: ${error.message}`);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
this._addRecorder(sender, recorder);
try {
recorder.startRecording(
(_, result) => {
if (result) {
returnValue = [true, filePath];
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
} else {
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
});
} catch (error) {
log(`Failed to start recorder: ${error.message}`);
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
}
ScreencastAreaAsync(params, invocation) {
let returnValue = [false, ''];
if (this._lockdownSettings.get_boolean('disable-save-to-disk')) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const sender = invocation.get_sender();
if (this._recorders.get(sender)) {
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
const [sessionPath] = this._proxy.CreateSessionSync({});
const [x, y, width, height, fileTemplate, options] = params;
const filePath = this._generateFilePath(fileTemplate);
let recorder;
try {
recorder = new Recorder(
sessionPath,
x, y,
width, height,
filePath,
options,
invocation,
_recorder => this._removeRecorder(sender));
} catch (error) {
log(`Failed to create recorder: ${error.message}`);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
return;
}
this._addRecorder(sender, recorder);
try {
recorder.startRecording(
(_, result) => {
if (result) {
returnValue = [true, filePath];
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
} else {
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
});
} catch (error) {
log(`Failed to start recorder: ${error.message}`);
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(bs)', returnValue));
}
}
StopScreencastAsync(params, invocation) {
const sender = invocation.get_sender();
const recorder = this._recorders.get(sender);
if (!recorder) {
invocation.return_value(GLib.Variant.new('(b)', [false]));
return;
}
recorder.stopRecording(() => {
this._removeRecorder(sender);
invocation.return_value(GLib.Variant.new('(b)', [true]));
});
}
};

View File

@@ -8,5 +8,4 @@
-gtk-icon-transform: rotate(-0.25turn); -gtk-icon-transform: rotate(-0.25turn);
} }
image.error { color: @error_color; }
image.warning { color: @warning_color; } image.warning { color: @warning_color; }

View File

@@ -3,45 +3,34 @@ imports.gi.versions.Gdk = '3.0';
imports.gi.versions.Gtk = '3.0'; imports.gi.versions.Gtk = '3.0';
const Gettext = imports.gettext; const Gettext = imports.gettext;
const Package = imports.package; const { Gdk, GLib, Gio, GObject, Gtk } = imports.gi;
const { Gdk, GLib, Gio, GObject, Gtk, Shew } = imports.gi; const Format = imports.format;
Package.initFormat(); const _ = Gettext.gettext;
const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const { loadInterfaceXML } = imports.misc.fileUtils;
const { ExtensionState, ExtensionType } = ExtensionUtils; const { ExtensionState, ExtensionType } = ExtensionUtils;
const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions'); const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface); const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish'); function stripPrefix(string, prefix) {
Gio._promisify(Shew.WindowExporter.prototype, 'export', 'export_finish'); if (string.slice(0, prefix.length) == prefix)
return string.slice(prefix.length);
function loadInterfaceXML(iface) { return string;
const uri = 'resource:///org/gnome/Extensions/dbus-interfaces/%s.xml'.format(iface);
const f = Gio.File.new_for_uri(uri);
try {
let [ok_, bytes] = f.load_contents(null);
return imports.byteArray.toString(bytes);
} catch (e) {
log('Failed to load D-Bus interface %s'.format(iface));
}
return null;
}
function toggleState(action) {
let state = action.get_state();
action.change_state(new GLib.Variant('b', !state.get_boolean()));
} }
var Application = GObject.registerClass( var Application = GObject.registerClass(
class Application extends Gtk.Application { class Application extends Gtk.Application {
_init() { _init() {
GLib.set_prgname('gnome-extensions-app'); GLib.set_prgname('gnome-shell-extension-prefs');
super._init({ application_id: 'org.gnome.Extensions' }); super._init({
application_id: 'org.gnome.Extensions',
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
});
} }
get shellProxy() { get shellProxy() {
@@ -57,7 +46,7 @@ class Application extends Gtk.Application {
super.vfunc_startup(); super.vfunc_startup();
let provider = new Gtk.CssProvider(); let provider = new Gtk.CssProvider();
let uri = 'resource:///org/gnome/Extensions/css/application.css'; let uri = 'resource:///org/gnome/shell/css/application.css';
try { try {
provider.load_from_file(Gio.File.new_for_uri(uri)); provider.load_from_file(Gio.File.new_for_uri(uri));
} catch (e) { } catch (e) {
@@ -67,19 +56,34 @@ class Application extends Gtk.Application {
provider, provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
'org.gnome.Shell.Extensions', '/org/gnome/Shell/Extensions');
this._window = new ExtensionsWindow({ application: this }); this._window = new ExtensionsWindow({ application: this });
} }
vfunc_command_line(commandLine) {
let args = commandLine.get_arguments();
if (args.length) {
let uuid = args[0];
// Strip off "extension:///" prefix which fakes a URI, if it exists
uuid = stripPrefix(uuid, 'extension:///');
this._window.openPrefs(uuid);
} else {
this.activate();
}
return 0;
}
}); });
var ExtensionsWindow = GObject.registerClass({ var ExtensionsWindow = GObject.registerClass({
GTypeName: 'ExtensionsWindow', GTypeName: 'ExtensionsWindow',
Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui', Template: 'resource:///org/gnome/shell/ui/extensions-window.ui',
InternalChildren: [ InternalChildren: [
'userList', 'userList',
'systemList', 'systemList',
'killSwitch',
'mainBox', 'mainBox',
'mainStack', 'mainStack',
'scrolledWindow', 'scrolledWindow',
@@ -90,11 +94,11 @@ var ExtensionsWindow = GObject.registerClass({
_init(params) { _init(params) {
super._init(params); super._init(params);
this._startupUuid = null;
this._loaded = false;
this._prefsDialog = null;
this._updatesCheckId = 0; this._updatesCheckId = 0;
this._exporter = new Shew.WindowExporter({ window: this });
this._exportedHandle = '';
this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment); this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
let action; let action;
@@ -106,15 +110,10 @@ var ExtensionsWindow = GObject.registerClass({
action.connect('activate', this._logout.bind(this)); action.connect('activate', this._logout.bind(this));
this.add_action(action); this.add_action(action);
action = new Gio.SimpleAction({ this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
name: 'user-extensions-enabled', this._settings.bind('disable-user-extensions',
state: new GLib.Variant('b', false), this._killSwitch, 'active',
}); Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
action.connect('activate', toggleState);
action.connect('change-state', (a, state) => {
this._shellProxy.UserExtensionsEnabled = state.get_boolean();
});
this.add_action(action);
this._userList.set_sort_func(this._sortList.bind(this)); this._userList.set_sort_func(this._sortList.bind(this));
this._userList.set_header_func(this._updateHeader.bind(this)); this._userList.set_header_func(this._updateHeader.bind(this));
@@ -125,10 +124,6 @@ var ExtensionsWindow = GObject.registerClass({
this._shellProxy.connectSignal('ExtensionStateChanged', this._shellProxy.connectSignal('ExtensionStateChanged',
this._onExtensionStateChanged.bind(this)); this._onExtensionStateChanged.bind(this));
this._shellProxy.connect('g-properties-changed',
this._onUserExtensionsEnabledChanged.bind(this));
this._onUserExtensionsEnabledChanged();
this._scanExtensions(); this._scanExtensions();
} }
@@ -158,18 +153,58 @@ var ExtensionsWindow = GObject.registerClass({
dialog.present(); dialog.present();
} }
async openPrefs(uuid) { openPrefs(uuid) {
if (!this._exportedHandle) { if (!this._loaded)
try { this._startupUuid = uuid;
this._exportedHandle = await this._exporter.export(); else if (!this._showPrefs(uuid))
} catch (e) { this.present();
log('Failed to export window: %s'.format(e.message)); }
}
_showPrefs(uuid) {
if (this._prefsDialog)
return false;
let row = this._findExtensionRow(uuid);
if (!row || !row.hasPrefs)
return false;
let widget;
try {
widget = row.prefsModule.buildPrefsWidget();
} catch (e) {
widget = this._buildErrorUI(row, e);
} }
this._shellProxy.OpenExtensionPrefsRemote(uuid, this._prefsDialog = new Gtk.Window({
this._exportedHandle, application: this.application,
{ modal: new GLib.Variant('b', true) }); default_width: 600,
default_height: 400,
modal: this.visible,
type_hint: Gdk.WindowTypeHint.DIALOG,
window_position: Gtk.WindowPosition.CENTER,
});
this._prefsDialog.set_titlebar(new Gtk.HeaderBar({
show_close_button: true,
title: row.name,
visible: true,
}));
if (this.visible)
this._prefsDialog.transient_for = this;
this._prefsDialog.connect('destroy', () => {
this._prefsDialog = null;
if (!this.visible)
this.destroy();
});
this._prefsDialog.add(widget);
this._prefsDialog.show();
return true;
} }
_showAbout() { _showAbout() {
@@ -184,7 +219,7 @@ var ExtensionsWindow = GObject.registerClass({
comments: _('Manage your GNOME Extensions'), comments: _('Manage your GNOME Extensions'),
license_type: Gtk.License.GPL_2_0, license_type: Gtk.License.GPL_2_0,
logo_icon_name: 'org.gnome.Extensions', logo_icon_name: 'org.gnome.Extensions',
version: imports.package.version, version: Config.PACKAGE_VERSION,
transient_for: this, transient_for: this,
modal: true, modal: true,
@@ -202,7 +237,125 @@ var ExtensionsWindow = GObject.registerClass({
null, null,
Gio.DBusCallFlags.NONE, Gio.DBusCallFlags.NONE,
-1, -1,
null); null,
(o, res) => {
o.call_finish(res);
});
}
_buildErrorUI(row, exc) {
let scroll = new Gtk.ScrolledWindow({
hscrollbar_policy: Gtk.PolicyType.NEVER,
propagate_natural_height: true,
});
let box = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
spacing: 12,
margin: 100,
margin_bottom: 60,
});
scroll.add(box);
let label = new Gtk.Label({
label: '<span size="x-large">%s</span>'.format(_("Somethings gone wrong")),
use_markup: true,
});
label.get_style_context().add_class(Gtk.STYLE_CLASS_DIM_LABEL);
box.add(label);
label = new Gtk.Label({
label: _("Were very sorry, but theres been a problem: the settings for this extension cant be displayed. We recommend that you report the issue to the extension authors."),
justify: Gtk.Justification.CENTER,
wrap: true,
});
box.add(label);
let expander = new Expander({
label: _("Technical Details"),
margin_top: 12,
});
box.add(expander);
let errortext = '%s\n\nStack trace:\n'.format(exc);
// Indent stack trace.
errortext +=
exc.stack.split('\n').map(line => ' %s'.format(line)).join('\n');
let buffer = new Gtk.TextBuffer({ text: errortext });
let textview = new Gtk.TextView({
buffer,
wrap_mode: Gtk.WrapMode.WORD,
monospace: true,
editable: false,
top_margin: 12,
bottom_margin: 12,
left_margin: 12,
right_margin: 12,
});
let toolbar = new Gtk.Toolbar();
let provider = new Gtk.CssProvider();
provider.load_from_data(`* {
border: 0 solid @borders;
border-top-width: 1px;
}`);
toolbar.get_style_context().add_provider(
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
);
let copyButton = new Gtk.ToolButton({
icon_name: 'edit-copy-symbolic',
tooltip_text: _("Copy Error"),
});
toolbar.add(copyButton);
copyButton.connect('clicked', w => {
let clipboard = Gtk.Clipboard.get_default(w.get_display());
// markdown for pasting in gitlab issues
let lines = [
'The settings of extension %s had an error:'.format(row.uuid),
'```', // '`' (xgettext throws up on odd number of backticks)
exc.toString(),
'```', // '`'
'',
'Stack trace:',
'```', // '`'
exc.stack.replace(/\n$/, ''), // stack without trailing newline
'```', // '`'
'',
];
clipboard.set_text(lines.join('\n'), -1);
});
let spacing = new Gtk.SeparatorToolItem({ draw: false });
toolbar.add(spacing);
toolbar.child_set_property(spacing, "expand", true);
let urlButton = new Gtk.ToolButton({
label: _("Homepage"),
tooltip_text: _("Visit extension homepage"),
no_show_all: true,
visible: row.url !== '',
});
toolbar.add(urlButton);
urlButton.connect('clicked', w => {
let context = w.get_display().get_app_launch_context();
Gio.AppInfo.launch_default_for_uri(row.url, context);
});
let expandedBox = new Gtk.Box({
orientation: Gtk.Orientation.VERTICAL,
});
expandedBox.add(textview);
expandedBox.add(toolbar);
expander.add(expandedBox);
scroll.show_all();
return scroll;
} }
_sortList(row1, row2) { _sortList(row1, row2) {
@@ -224,12 +377,6 @@ var ExtensionsWindow = GObject.registerClass({
].find(c => c.uuid === uuid); ].find(c => c.uuid === uuid);
} }
_onUserExtensionsEnabledChanged() {
let action = this.lookup_action('user-extensions-enabled');
action.set_state(
new GLib.Variant('b', this._shellProxy.UserExtensionsEnabled));
}
_onExtensionStateChanged(proxy, senderName, [uuid, newState]) { _onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
let extension = ExtensionUtils.deserializeExtension(newState); let extension = ExtensionUtils.deserializeExtension(newState);
let row = this._findExtensionRow(uuid); let row = this._findExtensionRow(uuid);
@@ -247,11 +394,9 @@ var ExtensionsWindow = GObject.registerClass({
if (row) { if (row) {
if (extension.state === ExtensionState.UNINSTALLED) if (extension.state === ExtensionState.UNINSTALLED)
row.destroy(); row.destroy();
} else { return; // we only deal with new and deleted extensions here
this._addExtensionRow(extension);
} }
this._addExtensionRow(extension);
this._syncListVisibility();
} }
_scanExtensions() { _scanExtensions() {
@@ -297,16 +442,6 @@ var ExtensionsWindow = GObject.registerClass({
}); });
} }
_syncListVisibility() {
this._userList.visible = this._userList.get_children().length > 0;
this._systemList.visible = this._systemList.get_children().length > 0;
if (this._userList.visible || this._systemList.visible)
this._mainStack.visible_child_name = 'main';
else
this._mainStack.visible_child_name = 'placeholder';
}
_checkUpdates() { _checkUpdates() {
let nUpdates = this._userList.get_children().filter(c => c.hasUpdate).length; let nUpdates = this._userList.get_children().filter(c => c.hasUpdate).length;
@@ -318,23 +453,131 @@ var ExtensionsWindow = GObject.registerClass({
} }
_extensionsLoaded() { _extensionsLoaded() {
this._syncListVisibility(); this._userList.visible = this._userList.get_children().length > 0;
this._systemList.visible = this._systemList.get_children().length > 0;
if (this._userList.visible || this._systemList.visible)
this._mainStack.visible_child_name = 'main';
else
this._mainStack.visible_child_name = 'placeholder';
this._checkUpdates(); this._checkUpdates();
if (this._startupUuid)
this._showPrefs(this._startupUuid);
this._startupUuid = null;
this._loaded = true;
}
});
var Expander = GObject.registerClass({
Properties: {
'label': GObject.ParamSpec.string(
'label', 'label', 'label',
GObject.ParamFlags.READWRITE,
null
),
},
}, class Expander extends Gtk.Box {
_init(params = {}) {
this._labelText = null;
super._init(Object.assign(params, {
orientation: Gtk.Orientation.VERTICAL,
spacing: 0,
}));
this._frame = new Gtk.Frame({
shadow_type: Gtk.ShadowType.IN,
hexpand: true,
});
let eventBox = new Gtk.EventBox();
this._frame.add(eventBox);
let hbox = new Gtk.Box({
spacing: 6,
margin: 12,
});
eventBox.add(hbox);
this._arrow = new Gtk.Image({
icon_name: 'pan-end-symbolic',
});
hbox.add(this._arrow);
this._label = new Gtk.Label({ label: this._labelText });
hbox.add(this._label);
this._revealer = new Gtk.Revealer();
this._childBin = new Gtk.Frame({
shadow_type: Gtk.ShadowType.IN,
});
this._revealer.add(this._childBin);
// Directly chain up to parent for internal children
super.add(this._frame);
super.add(this._revealer);
let provider = new Gtk.CssProvider();
provider.load_from_data('* { border-top-width: 0; }');
this._childBin.get_style_context().add_provider(
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
);
this._gesture = new Gtk.GestureMultiPress({
widget: this._frame,
button: 0,
exclusive: true,
});
this._gesture.connect('released', (gesture, nPress) => {
if (nPress == 1)
this._revealer.reveal_child = !this._revealer.reveal_child;
});
this._revealer.connect('notify::reveal-child', () => {
if (this._revealer.reveal_child)
this._arrow.icon_name = 'pan-down-symbolic';
else
this._arrow.icon_name = 'pan-end-symbolic';
});
}
get label() {
return this._labelText;
}
set label(text) {
if (this._labelText == text)
return;
if (this._label)
this._label.label = text;
this._labelText = text;
this.notify('label');
}
add(child) {
// set expanded child
this._childBin.get_children().forEach(c => {
this._childBin.remove(c);
});
if (child)
this._childBin.add(child);
} }
}); });
var ExtensionRow = GObject.registerClass({ var ExtensionRow = GObject.registerClass({
GTypeName: 'ExtensionRow', GTypeName: 'ExtensionRow',
Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui', Template: 'resource:///org/gnome/shell/ui/extension-row.ui',
InternalChildren: [ InternalChildren: [
'nameLabel', 'nameLabel',
'descriptionLabel', 'descriptionLabel',
'versionLabel', 'versionLabel',
'authorLabel', 'authorLabel',
'errorLabel',
'errorIcon',
'updatesIcon', 'updatesIcon',
'switch',
'revealButton', 'revealButton',
'revealer', 'revealer',
], ],
@@ -378,7 +621,10 @@ var ExtensionRow = GObject.registerClass({
name: 'enabled', name: 'enabled',
state: new GLib.Variant('b', false), state: new GLib.Variant('b', false),
}); });
action.connect('activate', toggleState); action.connect('activate', () => {
let state = action.get_state();
action.change_state(new GLib.Variant('b', !state.get_boolean()));
});
action.connect('change-state', (a, state) => { action.connect('change-state', (a, state) => {
if (state.get_boolean()) if (state.get_boolean())
this._app.shellProxy.EnableExtensionRemote(this.uuid); this._app.shellProxy.EnableExtensionRemote(this.uuid);
@@ -387,7 +633,8 @@ var ExtensionRow = GObject.registerClass({
}); });
this._actionGroup.add_action(action); this._actionGroup.add_action(action);
this._nameLabel.label = this.name; let name = GLib.markup_escape_text(this.name, -1);
this._nameLabel.label = name;
let desc = this._extension.metadata.description.split('\n')[0]; let desc = this._extension.metadata.description.split('\n')[0];
this._descriptionLabel.label = desc; this._descriptionLabel.label = desc;
@@ -431,12 +678,6 @@ var ExtensionRow = GObject.registerClass({
return this._extension.hasUpdate || false; return this._extension.hasUpdate || false;
} }
get hasError() {
const { state } = this._extension;
return state === ExtensionState.OUT_OF_DATE ||
state === ExtensionState.ERROR;
}
get type() { get type() {
return this._extension.type; return this._extension.type;
} }
@@ -453,17 +694,6 @@ var ExtensionRow = GObject.registerClass({
return this._extension.metadata.version || ''; return this._extension.metadata.version || '';
} }
get error() {
if (!this.hasError)
return '';
if (this._extension.state === ExtensionState.OUT_OF_DATE)
return _('The extension is incompatible with the current GNOME version');
return this._extension.error
? this._extension.error : _('The extension had an error');
}
_updateState() { _updateState() {
let state = this._extension.state === ExtensionState.ENABLED; let state = this._extension.state === ExtensionState.ENABLED;
@@ -471,14 +701,7 @@ var ExtensionRow = GObject.registerClass({
action.set_state(new GLib.Variant('b', state)); action.set_state(new GLib.Variant('b', state));
action.enabled = this._canToggle(); action.enabled = this._canToggle();
if (!action.enabled)
this._switch.active = state;
this._updatesIcon.visible = this.hasUpdate; this._updatesIcon.visible = this.hasUpdate;
this._errorIcon.visible = this.hasError;
this._errorLabel.label = this.error;
this._errorLabel.visible = this.error !== '';
this._versionLabel.label = this.version.toString(); this._versionLabel.label = this.version.toString();
this._versionLabel.visible = this.version !== ''; this._versionLabel.visible = this.version !== '';
@@ -499,12 +722,26 @@ var ExtensionRow = GObject.registerClass({
_canToggle() { _canToggle() {
return this._extension.canChange; return this._extension.canChange;
} }
get prefsModule() {
// give extension prefs access to their own extension object
ExtensionUtils.getCurrentExtension = () => this._extension;
if (!this._prefsModule) {
ExtensionUtils.installImporter(this._extension);
this._prefsModule = this._extension.imports.prefs;
this._prefsModule.init(this._extension.metadata);
}
return this._prefsModule;
}
}); });
function initEnvironment() { function initEnvironment() {
// Monkey-patch in a "global" object that fakes some Shell utilities // Monkey-patch in a "global" object that fakes some Shell utilities
// that ExtensionUtils depends on. // that ExtensionUtils depends on.
globalThis.global = { window.global = {
log(...args) { log(...args) {
print(args.join(', ')); print(args.join(', '));
}, },
@@ -515,11 +752,12 @@ function initEnvironment() {
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']), userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']),
}; };
String.prototype.format = Format.format;
} }
function main(argv) { function main(argv) {
initEnvironment(); initEnvironment();
Package.initGettext();
new Application().run(argv); new Application().run(argv);
} }

View File

@@ -15,15 +15,6 @@
<property name="visible">True</property> <property name="visible">True</property>
</object> </object>
</child> </child>
<child>
<object class="GtkImage" id="errorIcon">
<property name="no_show_all">True</property>
<property name="icon_name">dialog-error-symbolic</property>
<style>
<class name="error"/>>
</style>
</object>
</child>
<child> <child>
<object class="GtkImage" id="updatesIcon"> <object class="GtkImage" id="updatesIcon">
<property name="no_show_all">True</property> <property name="no_show_all">True</property>
@@ -63,7 +54,7 @@
</object> </object>
</child> </child>
<child> <child>
<object class="GtkSwitch" id="switch"> <object class="GtkSwitch">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="valign">center</property> <property name="valign">center</property>
@@ -178,38 +169,6 @@
<property name="top_attach">2</property> <property name="top_attach">2</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkLabel">
<property name="visible"
bind-source="errorLabel"
bind-property="visible"
bind-flags="sync-create"/>
<property name="no_show_all">True</property>
<property name="label" translatable="yes">Error</property>
<property name="xalign">0</property>
<property name="yalign">0</property>
<style>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="errorLabel">
<property name="no_show_all">True</property>
<property name="selectable">True</property>
<property name="wrap">True</property>
<property name="max_width_chars">60</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">3</property>
</packing>
</child>
<child> <child>
<object class="GtkButton"> <object class="GtkButton">
<property name="visible">True</property> <property name="visible">True</property>
@@ -220,7 +179,7 @@
</object> </object>
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">4</property> <property name="top_attach">3</property>
</packing> </packing>
</child> </child>
<child> <child>
@@ -241,7 +200,7 @@
</object> </object>
<packing> <packing>
<property name="left_attach">1</property> <property name="left_attach">1</property>
<property name="top_attach">4</property> <property name="top_attach">3</property>
</packing> </packing>
</child> </child>
</object> </object>
@@ -250,7 +209,7 @@
<packing> <packing>
<property name="left_attach">0</property> <property name="left_attach">0</property>
<property name="top_attach">1</property> <property name="top_attach">1</property>
<property name="width">8</property> <property name="width">7</property>
</packing> </packing>
</child> </child>
</object> </object>

View File

@@ -90,10 +90,8 @@
</packing> </packing>
</child> </child>
<child> <child>
<object class="GtkSwitch"> <object class="GtkSwitch" id="killSwitch">
<property name="visible">True</property> <property name="visible">True</property>
<property name="action-name">win.user-extensions-enabled</property>
<property name="valign">center</property>
</object> </object>
<packing> <packing>
<property name="pack_type">end</property> <property name="pack_type">end</property>
@@ -270,7 +268,7 @@
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="visible">True</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Extension Updates Ready</property> <property name="label">Extension Updates Ready</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>

View File

@@ -71,7 +71,7 @@ var AuthPrompt = GObject.registerClass({
this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this)); this._userVerifier.connect('verification-complete', this._onVerificationComplete.bind(this));
this._userVerifier.connect('reset', this._onReset.bind(this)); this._userVerifier.connect('reset', this._onReset.bind(this));
this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this)); this._userVerifier.connect('smartcard-status-changed', this._onSmartcardStatusChanged.bind(this));
this._userVerifier.connect('credential-manager-authenticated', this._onCredentialManagerAuthenticated.bind(this)); this._userVerifier.connect('ovirt-user-authenticated', this._onOVirtUserAuthenticated.bind(this));
this.smartcardDetected = this._userVerifier.smartcardDetected; this.smartcardDetected = this._userVerifier.smartcardDetected;
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
@@ -120,7 +120,7 @@ var AuthPrompt = GObject.registerClass({
vfunc_key_press_event(keyPressEvent) { vfunc_key_press_event(keyPressEvent) {
if (keyPressEvent.keyval == Clutter.KEY_Escape) if (keyPressEvent.keyval == Clutter.KEY_Escape)
this.cancel(); this.cancel();
return super.vfunc_key_press_event(keyPressEvent); return Clutter.EVENT_PROPAGATE;
} }
_initEntryRow() { _initEntryRow() {
@@ -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.WIDTH, coordinate: Clutter.BindCoordinate.SIZE,
})); }));
this._mainBox.add_child(this._defaultButtonWell); this._mainBox.add_child(this._defaultButtonWell);
@@ -242,7 +242,7 @@ var AuthPrompt = GObject.registerClass({
this.emit('prompted'); this.emit('prompted');
} }
_onCredentialManagerAuthenticated() { _onOVirtUserAuthenticated() {
if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED) if (this.verificationStatus != AuthPromptStatus.VERIFICATION_SUCCEEDED)
this.reset(); this.reset();
} }
@@ -424,13 +424,8 @@ var AuthPrompt = GObject.registerClass({
} }
updateSensitivity(sensitive) { updateSensitivity(sensitive) {
if (this._entry.reactive === sensitive)
return;
this._entry.reactive = sensitive; this._entry.reactive = sensitive;
this._entry.clutter_text.editable = sensitive;
if (sensitive)
this._entry.grab_key_focus();
} }
vfunc_hide() { vfunc_hide() {

View File

@@ -1,24 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported CredentialManager */
class CredentialManager {
constructor(service) {
this._token = null;
this._service = service;
this._authenticatedSignalId = null;
}
get token() {
return this._token;
}
set token(t) {
this._token = t;
if (this._token)
this.emit('user-authenticated', this._token);
}
get service() {
return this._service;
}
}

View File

@@ -35,6 +35,7 @@ const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 250; const _FADE_ANIMATION_TIME = 250;
const _SCROLL_ANIMATION_TIME = 500; const _SCROLL_ANIMATION_TIME = 500;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 48;
var UserListItem = GObject.registerClass({ var UserListItem = GObject.registerClass({
Signals: { 'activate': {} }, Signals: { 'activate': {} },
@@ -177,7 +178,6 @@ var UserList = GObject.registerClass({
} }
vfunc_key_focus_in() { vfunc_key_focus_in() {
super.vfunc_key_focus_in();
this._moveFocusToItems(); this._moveFocusToItems();
} }
@@ -456,6 +456,7 @@ var LoginDialog = GObject.registerClass({
let notListedLabel = new St.Label({ let notListedLabel = new St.Label({
text: _("Not listed?"), text: _("Not listed?"),
style_class: 'login-dialog-not-listed-label', style_class: 'login-dialog-not-listed-label',
x_align: Clutter.ActorAlign.START,
}); });
this._notListedButton = new St.Button({ this._notListedButton = new St.Button({
style_class: 'login-dialog-not-listed-button', style_class: 'login-dialog-not-listed-button',
@@ -463,7 +464,6 @@ var LoginDialog = GObject.registerClass({
can_focus: true, can_focus: true,
child: notListedLabel, child: notListedLabel,
reactive: true, reactive: true,
x_align: Clutter.ActorAlign.START,
}); });
this._notListedButton.connect('clicked', this._hideUserListAskForUsernameAndBeginVerification.bind(this)); this._notListedButton.connect('clicked', this._hideUserListAskForUsernameAndBeginVerification.bind(this));
@@ -589,8 +589,8 @@ var LoginDialog = GObject.registerClass({
return actorBox; return actorBox;
} }
vfunc_allocate(dialogBox) { vfunc_allocate(dialogBox, flags) {
this.set_allocation(dialogBox); this.set_allocation(dialogBox, flags);
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); this._bannerView.allocate(bannerAllocation, flags);
if (authPromptAllocation) if (authPromptAllocation)
this._authPrompt.allocate(authPromptAllocation); this._authPrompt.allocate(authPromptAllocation, flags);
if (userSelectionAllocation) if (userSelectionAllocation)
this._userSelectionBox.allocate(userSelectionAllocation); this._userSelectionBox.allocate(userSelectionAllocation, flags);
if (logoAllocation) if (logoAllocation)
this._logoBin.allocate(logoAllocation); this._logoBin.allocate(logoAllocation, flags);
if (sessionMenuButtonAllocation) if (sessionMenuButtonAllocation)
this._sessionMenuButton.allocate(sessionMenuButtonAllocation); this._sessionMenuButton.allocate(sessionMenuButtonAllocation, flags);
} }
_ensureUserListLoaded() { _ensureUserListLoaded() {
@@ -810,13 +810,12 @@ var LoginDialog = GObject.registerClass({
return; return;
this._logoBin.destroy_all_children(); this._logoBin.destroy_all_children();
const resourceScale = this._logoBin.get_resource_scale(); if (this._logoFile && this._logoBin.resource_scale > 0) {
if (this._logoFile) {
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, _LOGO_ICON_HEIGHT,
scaleFactor, scaleFactor,
resourceScale)); this._logoBin.resource_scale));
} }
} }
@@ -953,15 +952,16 @@ var LoginDialog = GObject.registerClass({
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING) if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
return; return;
if (this._authPrompt.verificationStatus !== AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset();
this._bindOpacity(); this._bindOpacity();
this.ease({ this.ease({
opacity: 255, opacity: 255,
duration: _FADE_ANIMATION_TIME, duration: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._unbindOpacity(), onComplete: () => {
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset();
this._unbindOpacity();
},
}); });
} }

View File

@@ -3,9 +3,6 @@
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Signals = imports.signals; const Signals = imports.signals;
const Credential = imports.gdm.credentialManager;
var SERVICE_NAME = 'gdm-ovirtcred';
const OVirtCredentialsIface = ` const OVirtCredentialsIface = `
<node> <node>
@@ -31,14 +28,30 @@ function OVirtCredentials() {
return self; return self;
} }
var OVirtCredentialsManager = class OVirtCredentialsManager extends Credential.CredentialManager { var OVirtCredentialsManager = class {
constructor() { constructor() {
super(SERVICE_NAME); this._token = null;
this._credentials = new OVirtCredentials(); this._credentials = new OVirtCredentials();
this._credentials.connectSignal('UserAuthenticated', this._credentials.connectSignal('UserAuthenticated',
(proxy, sender, [token]) => { this._onUserAuthenticated.bind(this));
this.token = token; }
});
_onUserAuthenticated(proxy, sender, [token]) {
this._token = token;
this.emit('user-authenticated', token);
}
hasToken() {
return this._token != null;
}
getToken() {
return this._token;
}
resetToken() {
this._token = null;
} }
}; };
Signals.addSignalMethods(OVirtCredentialsManager.prototype); Signals.addSignalMethods(OVirtCredentialsManager.prototype);

View File

@@ -2,29 +2,20 @@
/* 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, Gdm, Gio, GLib } = imports.gi; const { Clutter, Gio, GLib } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Batch = imports.gdm.batch; const Batch = imports.gdm.batch;
const Fprint = imports.gdm.fingerprint; const Fprint = imports.gdm.fingerprint;
const OVirt = imports.gdm.oVirt; const OVirt = imports.gdm.oVirt;
const Vmware = imports.gdm.vmware;
const Main = imports.ui.main; 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';
var OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
var FADE_ANIMATION_TIME = 160; var FADE_ANIMATION_TIME = 160;
var CLONE_FADE_ANIMATION_TIME = 250; var CLONE_FADE_ANIMATION_TIME = 250;
@@ -160,20 +151,13 @@ var ShellUserVerifier = class {
this._failCounter = 0; this._failCounter = 0;
this._credentialManagers = {}; this._oVirtCredentialsManager = OVirt.getOVirtCredentialsManager();
this._credentialManagers[OVirt.SERVICE_NAME] = OVirt.getOVirtCredentialsManager();
this._credentialManagers[Vmware.SERVICE_NAME] = Vmware.getVmwareCredentialsManager();
for (let service in this._credentialManagers) { if (this._oVirtCredentialsManager.hasToken())
if (this._credentialManagers[service].token) { this._oVirtUserAuthenticated(this._oVirtCredentialsManager.getToken());
this._onCredentialManagerAuthenticated(this._credentialManagers[service],
this._credentialManagers[service].token);
}
this._credentialManagers[service]._authenticatedSignalId = this._oVirtUserAuthenticatedId = this._oVirtCredentialsManager.connect('user-authenticated',
this._credentialManagers[service].connect('user-authenticated', this._oVirtUserAuthenticated.bind(this));
this._onCredentialManagerAuthenticated.bind(this));
}
} }
begin(userName, hold) { begin(userName, hold) {
@@ -184,12 +168,14 @@ var ShellUserVerifier = class {
this._checkForFingerprintReader(); this._checkForFingerprintReader();
// If possible, reauthenticate an already running session, if (userName) {
// so any session specific credentials get updated appropriately // If possible, reauthenticate an already running session,
if (userName) // so any session specific credentials get updated appropriately
this._openReauthenticationChannel(userName); this._client.open_reauthentication_channel(userName, this._cancellable,
else this._reauthenticationChannelOpened.bind(this));
this._getUserVerifier(); } else {
this._client.get_user_verifier(this._cancellable, this._userVerifierGot.bind(this));
}
} }
cancel() { cancel() {
@@ -229,11 +215,8 @@ var ShellUserVerifier = class {
this._smartcardManager.disconnect(this._smartcardRemovedId); this._smartcardManager.disconnect(this._smartcardRemovedId);
this._smartcardManager = null; this._smartcardManager = null;
for (let service in this._credentialManagers) { this._oVirtCredentialsManager.disconnect(this._oVirtUserAuthenticatedId);
let credentialManager = this._credentialManagers[service]; this._oVirtCredentialsManager = null;
credentialManager.disconnect(credentialManager._authenticatedSignalId);
credentialManager = null;
}
} }
answerQuery(serviceName, answer) { answerQuery(serviceName, answer) {
@@ -321,9 +304,9 @@ var ShellUserVerifier = class {
}); });
} }
_onCredentialManagerAuthenticated(credentialManager, _token) { _oVirtUserAuthenticated(_token) {
this._preemptingService = credentialManager.service; this._preemptingService = OVIRT_SERVICE_NAME;
this.emit('credential-manager-authenticated'); this.emit('ovirt-user-authenticated');
} }
_checkForSmartcard() { _checkForSmartcard() {
@@ -356,11 +339,10 @@ var ShellUserVerifier = class {
this._verificationFailed(false); this._verificationFailed(false);
} }
async _openReauthenticationChannel(userName) { _reauthenticationChannelOpened(client, result) {
try { try {
this._clearUserVerifier(); this._clearUserVerifier();
this._userVerifier = await this._client.open_reauthentication_channel( this._userVerifier = client.open_reauthentication_channel_finish(result);
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;
@@ -369,7 +351,8 @@ 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
this._getUserVerifier(); client.get_user_verifier(this._cancellable,
this._userVerifierGot.bind(this));
return; return;
} }
@@ -383,11 +366,10 @@ var ShellUserVerifier = class {
this._hold.release(); this._hold.release();
} }
async _getUserVerifier() { _userVerifierGot(client, result) {
try { try {
this._clearUserVerifier(); this._clearUserVerifier();
this._userVerifier = this._userVerifier = client.get_user_verifier_finish(result);
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;
@@ -439,25 +421,35 @@ var ShellUserVerifier = class {
} }
} }
async _startService(serviceName) { _startService(serviceName) {
this._hold.acquire(); this._hold.acquire();
try { if (this._userName) {
if (this._userName) { this._userVerifier.call_begin_verification_for_user(serviceName, this._userName, this._cancellable, (obj, result) => {
await this._userVerifier.call_begin_verification_for_user( try {
serviceName, this._userName, this._cancellable); obj.call_begin_verification_for_user_finish(result);
} else { } catch (e) {
await this._userVerifier.call_begin_verification( if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
serviceName, this._cancellable); return;
} this._reportInitError('Failed to start verification for user', e);
} catch (e) { return;
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) }
return;
this._reportInitError(this._userName this._hold.release();
? 'Failed to start verification for user' });
: 'Failed to start verification', e); } else {
return; this._userVerifier.call_begin_verification(serviceName, this._cancellable, (obj, result) => {
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() {
@@ -500,12 +492,9 @@ var ShellUserVerifier = class {
if (!this.serviceIsForeground(serviceName)) if (!this.serviceIsForeground(serviceName))
return; return;
let token = null; if (serviceName == OVIRT_SERVICE_NAME) {
if (this._credentialManagers[serviceName]) // The only question asked by this service is "Token?"
token = this._credentialManagers[serviceName].token; this.answerQuery(serviceName, this._oVirtCredentialsManager.getToken());
if (token) {
this.answerQuery(serviceName, token);
return; return;
} }
@@ -573,10 +562,8 @@ var ShellUserVerifier = class {
// If the login failed with the preauthenticated oVirt credentials // If the login failed with the preauthenticated oVirt credentials
// then discard the credentials and revert to default authentication // then discard the credentials and revert to default authentication
// mechanism. // mechanism.
let foregroundService = Object.keys(this._credentialManagers).find(service => if (this.serviceIsForeground(OVIRT_SERVICE_NAME)) {
this.serviceIsForeground(service)); this._oVirtCredentialsManager.resetToken();
if (foregroundService) {
this._credentialManagers[foregroundService].token = null;
this._preemptingService = null; this._preemptingService = null;
this._verificationFailed(false); this._verificationFailed(false);
return; return;

View File

@@ -1,54 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getVmwareCredentialsManager */
const Gio = imports.gi.Gio;
const Signals = imports.signals;
const Credential = imports.gdm.credentialManager;
const dbusPath = '/org/vmware/viewagent/Credentials';
const dbusInterface = 'org.vmware.viewagent.Credentials';
var SERVICE_NAME = 'gdm-vmwcred';
const VmwareCredentialsIface = '<node> \
<interface name="' + dbusInterface + '"> \
<signal name="UserAuthenticated"> \
<arg type="s" name="token"/> \
</signal> \
</interface> \
</node>';
const VmwareCredentialsInfo = Gio.DBusInterfaceInfo.new_for_xml(VmwareCredentialsIface);
let _vmwareCredentialsManager = null;
function VmwareCredentials() {
var self = new Gio.DBusProxy({ g_connection: Gio.DBus.session,
g_interface_name: VmwareCredentialsInfo.name,
g_interface_info: VmwareCredentialsInfo,
g_name: dbusInterface,
g_object_path: dbusPath,
g_flags: Gio.DBusProxyFlags.DO_NOT_LOAD_PROPERTIES });
self.init(null);
return self;
}
var VmwareCredentialsManager = class VmwareCredentialsManager extends Credential.CredentialManager {
constructor() {
super(SERVICE_NAME);
this._credentials = new VmwareCredentials();
this._credentials.connectSignal('UserAuthenticated',
(proxy, sender, [token]) => {
this.token = token;
});
}
};
Signals.addSignalMethods(VmwareCredentialsManager.prototype);
function getVmwareCredentialsManager() {
if (!_vmwareCredentialsManager)
_vmwareCredentialsManager = new VmwareCredentialsManager();
return _vmwareCredentialsManager;
}

View File

@@ -6,8 +6,6 @@
<file>gdm/fingerprint.js</file> <file>gdm/fingerprint.js</file>
<file>gdm/loginDialog.js</file> <file>gdm/loginDialog.js</file>
<file>gdm/oVirt.js</file> <file>gdm/oVirt.js</file>
<file>gdm/credentialManager.js</file>
<file>gdm/vmware.js</file>
<file>gdm/realmd.js</file> <file>gdm/realmd.js</file>
<file>gdm/util.js</file> <file>gdm/util.js</file>
@@ -25,14 +23,12 @@
<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>
<file>misc/util.js</file> <file>misc/util.js</file>
<file>misc/weather.js</file> <file>misc/weather.js</file>
<file>perf/basic.js</file>
<file>perf/core.js</file> <file>perf/core.js</file>
<file>perf/hwtest.js</file> <file>perf/hwtest.js</file>
@@ -93,6 +89,7 @@
<file>ui/ripples.js</file> <file>ui/ripples.js</file>
<file>ui/runDialog.js</file> <file>ui/runDialog.js</file>
<file>ui/screenShield.js</file> <file>ui/screenShield.js</file>
<file>ui/screencast.js</file>
<file>ui/screenshot.js</file> <file>ui/screenshot.js</file>
<file>ui/scripting.js</file> <file>ui/scripting.js</file>
<file>ui/search.js</file> <file>ui/search.js</file>
@@ -104,14 +101,15 @@
<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/workspaceAnimation.js</file>
<file>ui/workspaceSwitcherPopup.js</file> <file>ui/workspaceSwitcherPopup.js</file>
<file>ui/workspaceThumbnail.js</file> <file>ui/workspaceThumbnail.js</file>
<file>ui/workspacesView.js</file> <file>ui/workspacesView.js</file>
@@ -137,6 +135,7 @@
<file>ui/status/volume.js</file> <file>ui/status/volume.js</file>
<file>ui/status/bluetooth.js</file> <file>ui/status/bluetooth.js</file>
<file>ui/status/remoteAccess.js</file> <file>ui/status/remoteAccess.js</file>
<file>ui/status/screencast.js</file>
<file>ui/status/system.js</file> <file>ui/status/system.js</file>
<file>ui/status/thunderbolt.js</file> <file>ui/status/thunderbolt.js</file>
</gresource> </gresource>

View File

@@ -1,5 +1,4 @@
subdir('misc') subdir('misc')
subdir('dbusServices')
js_resources = gnome.compile_resources( js_resources = gnome.compile_resources(
'js-resources', 'js-resources.gresource.xml', 'js-resources', 'js-resources.gresource.xml',
@@ -14,3 +13,10 @@ portal_resources = gnome.compile_resources(
c_name: 'portal_js_resources', c_name: 'portal_js_resources',
dependencies: [config_js] dependencies: [config_js]
) )
prefs_resources = gnome.compile_resources(
'prefs-resources', 'prefs-resources.gresource.xml',
source_dir: ['.', meson.current_build_dir()],
c_name: 'prefs_js_resources',
dependencies: [config_js]
)

View File

@@ -15,5 +15,6 @@ var LOCALEDIR = '@datadir@/locale';
/* other standard directories */ /* other standard directories */
var LIBEXECDIR = '@libexecdir@'; var LIBEXECDIR = '@libexecdir@';
var PKGDATADIR = '@datadir@/@PACKAGE_NAME@'; var PKGDATADIR = '@datadir@/@PACKAGE_NAME@';
var VPNDIR = '@vpndir@';
/* g-i package versions */ /* g-i package versions */
var LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@' var LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'

View 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, openPrefs, isOutOfDate, getSettings, initTranslations, isOutOfDate, installImporter,
installImporter, serializeExtension, deserializeExtension */ 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,27 +153,6 @@ 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

View File

@@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported collectFromDatadirs, recursivelyDeleteDir, /* exported collectFromDatadirs, recursivelyDeleteDir,
recursivelyMoveDir, loadInterfaceXML, loadSubInterfaceXML */ recursivelyMoveDir, loadInterfaceXML */
const { Gio, GLib } = imports.gi; const { Gio, GLib } = imports.gi;
const Config = imports.misc.config; const Config = imports.misc.config;
@@ -67,51 +67,28 @@ function recursivelyMoveDir(srcDir, destDir) {
} }
let _ifaceResource = null; let _ifaceResource = null;
function ensureIfaceResource() {
if (_ifaceResource)
return;
// don't use global.datadir so the method is usable from tests/tools
let dir = GLib.getenv('GNOME_SHELL_DATADIR') || Config.PKGDATADIR;
let path = `${dir}/gnome-shell-dbus-interfaces.gresource`;
_ifaceResource = Gio.Resource.load(path);
_ifaceResource._register();
}
function loadInterfaceXML(iface) { function loadInterfaceXML(iface) {
ensureIfaceResource(); if (!_ifaceResource) {
// don't use global.datadir so the method is usable from tests/tools
let dir = GLib.getenv('GNOME_SHELL_DATADIR') || Config.PKGDATADIR;
let path = `${dir}/gnome-shell-dbus-interfaces.gresource`;
_ifaceResource = Gio.Resource.load(path);
_ifaceResource._register();
}
let xml = null;
let uri = `resource:///org/gnome/shell/dbus-interfaces/${iface}.xml`; let uri = `resource:///org/gnome/shell/dbus-interfaces/${iface}.xml`;
let f = Gio.File.new_for_uri(uri); let f = Gio.File.new_for_uri(uri);
try { try {
let [ok_, bytes] = f.load_contents(null); let [ok_, bytes] = f.load_contents(null);
return imports.byteArray.toString(bytes); if (bytes instanceof Uint8Array)
xml = imports.byteArray.toString(bytes);
else
xml = bytes.toString();
} catch (e) { } catch (e) {
log(`Failed to load D-Bus interface ${iface}`); log(`Failed to load D-Bus interface ${iface}`);
} }
return null; return xml;
}
function loadSubInterfaceXML(iface, ifaceFile) {
let xml = loadInterfaceXML(ifaceFile);
if (!xml)
return null;
let ifaceStartTag = `<interface name="${iface}">`;
let ifaceStopTag = '</interface>';
let ifaceStartIndex = xml.indexOf(ifaceStartTag);
let ifaceEndIndex = xml.indexOf(ifaceStopTag, ifaceStartIndex + 1) + ifaceStopTag.length;
let xmlHeader = '<!DOCTYPE node PUBLIC\n' +
'\'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\'\n' +
'\'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\'>\n' +
'<node>\n';
let xmlFooter = '</node>';
return (
xmlHeader +
xml.substr(ifaceStartIndex, ifaceEndIndex - ifaceStartIndex) +
xmlFooter);
} }

View File

@@ -1,20 +1,11 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getIBusManager */ /* exported getIBusManager */
const { Gio, GLib, IBus, Meta } = imports.gi; const { Gio, GLib, IBus } = imports.gi;
const Signals = imports.signals; 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);
@@ -64,18 +55,13 @@ var IBusManager = class {
this._ibus.set_watch_ibus_signal(true); this._ibus.set_watch_ibus_signal(true);
this._ibus.connect('global-engine-changed', this._engineChanged.bind(this)); this._ibus.connect('global-engine-changed', this._engineChanged.bind(this));
this._spawn(Meta.is_wayland_compositor() ? [] : ['--xim']); this._spawn();
} }
_spawn(extraArgs = []) { _spawn(extraArgs = []) {
try { try {
let cmdLine = ['ibus-daemon', '--panel', 'disable', ...extraArgs]; let cmdLine = ['ibus-daemon', '--panel', 'disable', ...extraArgs];
let launcher = Gio.SubprocessLauncher.new(Gio.SubprocessFlags.NONE); Gio.Subprocess.new(cmdLine, Gio.SubprocessFlags.NONE);
// Forward the right X11 Display for ibus-x11
let display = GLib.getenv('GNOME_SETUP_DISPLAY');
if (display)
launcher.setenv('DISPLAY', display, true);
launcher.spawnv(cmdLine);
} catch (e) { } catch (e) {
log(`Failed to launch ibus-daemon: ${e.message}`); log(`Failed to launch ibus-daemon: ${e.message}`);
} }
@@ -111,14 +97,16 @@ var IBusManager = class {
_onConnected() { _onConnected() {
this._cancellable = new Gio.Cancellable(); this._cancellable = new Gio.Cancellable();
this._initEngines(); this._ibus.list_engines_async(-1, this._cancellable,
this._initPanelService(); this._initEngines.bind(this));
this._ibus.request_name_async(IBus.SERVICE_PANEL,
IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable,
this._initPanelService.bind(this));
} }
async _initEngines() { _initEngines(ibus, result) {
try { try {
const enginesList = let enginesList = this._ibus.list_engines_async_finish(result);
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]);
@@ -133,52 +121,56 @@ var IBusManager = class {
} }
} }
async _initPanelService() { _initPanelService(ibus, result) {
let success = false;
try { try {
await this._ibus.request_name_async(IBus.SERVICE_PANEL, success = !!this._ibus.request_name_async_finish(result);
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); return;
this._clear(); logError(e);
}
if (success) {
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL });
this._candidatePopup.setPanelService(this._panelService);
this._panelService.connect('update-property', this._updateProperty.bind(this));
this._panelService.connect('set-cursor-location', (ps, x, y, w, h) => {
let cursorLocation = { x, y, width: w, height: h };
this.emit('set-cursor-location', cursorLocation);
});
this._panelService.connect('focus-in', (panel, path) => {
if (!GLib.str_has_suffix(path, '/InputContext_1'))
this.emit('focus-in');
});
this._panelService.connect('focus-out', () => this.emit('focus-out'));
try {
// IBus versions older than 1.5.10 have a bug which
// causes spurious set-content-type emissions when
// switching input focus that temporarily lose purpose
// and hints defeating its intended semantics and
// confusing users. We thus don't use it in that case.
_checkIBusVersion(1, 5, 10);
this._panelService.connect('set-content-type', this._setContentType.bind(this));
} catch (e) {
} }
return;
}
this._panelService = new IBus.PanelService({
connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL,
});
this._candidatePopup.setPanelService(this._panelService);
this._panelService.connect('update-property', this._updateProperty.bind(this));
this._panelService.connect('set-cursor-location', (ps, x, y, w, h) => {
let cursorLocation = { x, y, width: w, height: h };
this.emit('set-cursor-location', cursorLocation);
});
this._panelService.connect('focus-in', (panel, path) => {
if (!GLib.str_has_suffix(path, '/InputContext_1'))
this.emit('focus-in');
});
this._panelService.connect('focus-out', () => this.emit('focus-out'));
try {
// IBus versions older than 1.5.10 have a bug which
// causes spurious set-content-type emissions when
// switching input focus that temporarily lose purpose
// and hints defeating its intended semantics and
// confusing users. We thus don't use it in that case.
_checkIBusVersion(1, 5, 10);
this._panelService.connect('set-content-type', this._setContentType.bind(this));
} catch (e) {
}
this._updateReadiness();
try {
// If an engine is already active we need to get its properties // If an engine is already active we need to get its properties
const engine = this._ibus.get_global_engine_async(-1, this._cancellable, (_bus, res) => {
await this._ibus.get_global_engine_async(-1, this._cancellable); let engine;
this._engineChanged(this._ibus, engine.get_name()); try {
} catch (e) { engine = this._ibus.get_global_engine_async_finish(res);
if (!engine)
return;
} catch (e) {
return;
}
this._engineChanged(this._ibus, engine.get_name());
});
this._updateReadiness();
} else {
this._clear();
} }
} }
@@ -227,7 +219,7 @@ var IBusManager = class {
return this._engines.get(id); return this._engines.get(id);
} }
async setEngine(id, callback) { 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.
@@ -237,16 +229,18 @@ var IBusManager = class {
return; return;
} }
try { this._ibus.set_global_engine_async(id,
await this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
this._MAX_INPUT_SOURCE_ACTIVATION_TIME, this._cancellable, (_bus, res) => {
this._cancellable); try {
} catch (e) { this._ibus.set_global_engine_async_finish(res);
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) } catch (e) {
logError(e); if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
} logError(e);
if (callback) }
callback(); if (callback)
callback();
});
} }
preloadEngines(ids) { preloadEngines(ids) {

View File

@@ -4,9 +4,6 @@ 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(
@@ -49,11 +46,15 @@ class InputMethod extends Clutter.InputMethod {
this._currentSource = this._inputSourceManager.currentSource; this._currentSource = this._inputSourceManager.currentSource;
} }
async _onConnected() { _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 = await this._ibus.create_input_context_async( this._context = this._ibus.create_input_context_async_finish(res);
'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);
@@ -96,13 +97,8 @@ class InputMethod extends Clutter.InputMethod {
this.commit(text.get_text()); this.commit(text.get_text());
} }
_onDeleteSurroundingText(_context, offset, nchars) { _onDeleteSurroundingText() {
try { this.delete_surrounding();
this.delete_surrounding(offset, nchars);
} catch (e) {
// We may get out of bounds for negative offset on older mutter
this.delete_surrounding(0, nchars + offset);
}
} }
_onUpdatePreeditText(_context, text, pos, visible) { _onUpdatePreeditText(_context, text, pos, visible) {

View File

@@ -3,9 +3,9 @@ const { Gio, GLib, Meta, Shell, St } = imports.gi;
const INTROSPECT_SCHEMA = 'org.gnome.shell'; const INTROSPECT_SCHEMA = 'org.gnome.shell';
const INTROSPECT_KEY = 'introspect'; const INTROSPECT_KEY = 'introspect';
const APP_ALLOWLIST = ['org.freedesktop.impl.portal.desktop.gtk']; const APP_WHITELIST = ['org.freedesktop.impl.portal.desktop.gtk'];
const INTROSPECT_DBUS_API_VERSION = 3; const INTROSPECT_DBUS_API_VERSION = 2;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
@@ -46,24 +46,19 @@ var IntrospectService = class {
this._syncRunningApplications(); this._syncRunningApplications();
this._allowlistMap = new Map(); this._whitelistMap = new Map();
APP_ALLOWLIST.forEach(appName => { APP_WHITELIST.forEach(appName => {
Gio.DBus.watch_name(Gio.BusType.SESSION, Gio.DBus.watch_name(Gio.BusType.SESSION,
appName, appName,
Gio.BusNameWatcherFlags.NONE, Gio.BusNameWatcherFlags.NONE,
(conn, name, owner) => this._allowlistMap.set(name, owner), (conn, name, owner) => this._whitelistMap.set(name, owner),
(conn, name) => this._allowlistMap.delete(name)); (conn, name) => this._whitelistMap.delete(name));
}); });
this._settings = St.Settings.get(); this._settings = St.Settings.get();
this._settings.connect('notify::enable-animations', this._settings.connect('notify::enable-animations',
this._syncAnimationsEnabled.bind(this)); this._syncAnimationsEnabled.bind(this));
this._syncAnimationsEnabled(); this._syncAnimationsEnabled();
const monitorManager = Meta.MonitorManager.get();
monitorManager.connect('monitors-changed',
this._syncScreenSize.bind(this));
this._syncScreenSize();
} }
_isStandaloneApp(app) { _isStandaloneApp(app) {
@@ -74,8 +69,8 @@ var IntrospectService = class {
return this._introspectSettings.get_boolean(INTROSPECT_KEY); return this._introspectSettings.get_boolean(INTROSPECT_KEY);
} }
_isSenderAllowed(sender) { _isSenderWhitelisted(sender) {
return [...this._allowlistMap.values()].includes(sender); return [...this._whitelistMap.values()].includes(sender);
} }
_getSandboxedAppId(app) { _getSandboxedAppId(app) {
@@ -138,7 +133,7 @@ var IntrospectService = class {
if (this._isIntrospectEnabled()) if (this._isIntrospectEnabled())
return true; return true;
if (this._isSenderAllowed(invocation.get_sender())) if (this._isSenderWhitelisted(invocation.get_sender()))
return true; return true;
return false; return false;
@@ -214,28 +209,10 @@ var IntrospectService = class {
} }
} }
_syncScreenSize() {
const oldScreenWidth = this._screenWidth;
const oldScreenHeight = this._screenHeight;
this._screenWidth = global.screen_width;
this._screenHeight = global.screen_height;
if (oldScreenWidth !== this._screenWidth ||
oldScreenHeight !== this._screenHeight) {
const variant = new GLib.Variant('(ii)',
[this._screenWidth, this._screenHeight]);
this._dbusImpl.emit_property_changed('ScreenSize', variant);
}
}
get AnimationsEnabled() { get AnimationsEnabled() {
return this._animationsEnabled; return this._animationsEnabled;
} }
get ScreenSize() {
return [this._screenWidth, this._screenHeight];
}
get version() { get version() {
return INTROSPECT_DBUS_API_VERSION; return INTROSPECT_DBUS_API_VERSION;
} }

View File

@@ -24,7 +24,8 @@ 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
@@ -33,7 +34,8 @@ 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
);
} }
} }

View 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 getKeyboardManager, holdKeyboard, releaseKeyboard */ /* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
const { GLib, GnomeDesktop } = imports.gi; const { GLib, GnomeDesktop, Meta } = 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 };
global.backend.set_keymap(layouts, variants, options); Meta.get_backend().set_keymap(layouts, variants, options);
} }
_applyLayoutGroupIndex(idx) { _applyLayoutGroupIndex(idx) {
global.backend.lock_layout_group(idx); Meta.get_backend().lock_layout_group(idx);
} }
apply(id) { apply(id) {

View File

@@ -50,22 +50,25 @@ function canLock() {
} }
async function registerSessionWithGDM() { function registerSessionWithGDM() {
log("Registering session with GDM"); log("Registering session with GDM");
try { Gio.DBus.system.call('org.gnome.DisplayManager',
await Gio.DBus.system.call( '/org/gnome/DisplayManager/Manager',
'org.gnome.DisplayManager', 'org.gnome.DisplayManager.Manager',
'/org/gnome/DisplayManager/Manager', 'RegisterSession',
'org.gnome.DisplayManager.Manager', GLib.Variant.new('(a{sv})', [{}]), null,
'RegisterSession', Gio.DBusCallFlags.NONE, -1, null,
GLib.Variant.new('(a{sv})', [{}]), null, (source, result) => {
Gio.DBusCallFlags.NONE, -1, null); try {
} catch (e) { source.call_finish(result);
if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD)) } catch (e) {
log(`Error registering session with GDM: ${e.message}`); if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
else log(`Error registering session with GDM: ${e.message}`);
log('Not calling RegisterSession(): method not exported, GDM too old?'); else
} log("Not calling RegisterSession(): method not exported, GDM too old?");
}
}
);
} }
let _loginManager = null; let _loginManager = null;
@@ -158,23 +161,6 @@ var LoginManagerSystemd = class {
}); });
} }
canRebootToBootLoaderMenu(asyncCallback) {
this._proxy.CanRebootToBootLoaderMenuRemote((result, error) => {
if (error) {
asyncCallback(false, false);
} else {
const needsAuth = result[0] === 'challenge';
const canRebootToBootLoaderMenu = needsAuth || result[0] === 'yes';
asyncCallback(canRebootToBootLoaderMenu, needsAuth);
}
});
}
setRebootToBootLoaderMenu() {
/* Parameter is timeout in usec, show to menu for 60 seconds */
this._proxy.SetRebootToBootLoaderMenuRemote(60000000);
}
listSessions(asyncCallback) { listSessions(asyncCallback) {
this._proxy.ListSessionsRemote((result, error) => { this._proxy.ListSessionsRemote((result, error) => {
if (error) if (error)
@@ -188,19 +174,24 @@ var LoginManagerSystemd = class {
this._proxy.SuspendRemote(true); this._proxy.SuspendRemote(true);
} }
async inhibit(reason, callback) { inhibit(reason, callback) {
try { let inVariant = GLib.Variant.new('(ssss)',
const inVariant = new GLib.Variant('(ssss)', ['sleep',
['sleep', 'GNOME Shell', reason, 'delay']); 'GNOME Shell',
const [outVariant_, fdList] = reason,
await this._proxy.call_with_unix_fd_list('Inhibit', 'delay']);
inVariant, 0, -1, null, null); this._proxy.call_with_unix_fd_list('Inhibit', inVariant, 0, -1, null, null,
const [fd] = fdList.steal_fds(); (proxy, result) => {
callback(new Gio.UnixInputStream({ fd })); let fd = -1;
} catch (e) { try {
logError(e, 'Error getting systemd inhibitor'); let [outVariant_, fdList] = proxy.call_with_unix_fd_list_finish(result);
callback(null); fd = fdList.steal_fds()[0];
} callback(new Gio.UnixInputStream({ fd }));
} catch (e) {
logError(e, "Error getting systemd inhibitor");
callback(null);
}
});
} }
_prepareForSleep(proxy, sender, [aboutToSuspend]) { _prepareForSleep(proxy, sender, [aboutToSuspend]) {
@@ -220,13 +211,6 @@ var LoginManagerDummy = class {
asyncCallback(false, false); asyncCallback(false, false);
} }
canRebootToBootLoaderMenu(asyncCallback) {
asyncCallback(false, false);
}
setRebootToBootLoaderMenu() {
}
listSessions(asyncCallback) { listSessions(asyncCallback) {
asyncCallback([]); asyncCallback([]);
} }

View File

@@ -7,6 +7,7 @@ jsconf.set10('HAVE_BLUETOOTH', bt_dep.found())
jsconf.set10('HAVE_NETWORKMANAGER', have_networkmanager) jsconf.set10('HAVE_NETWORKMANAGER', have_networkmanager)
jsconf.set('datadir', datadir) jsconf.set('datadir', datadir)
jsconf.set('libexecdir', libexecdir) jsconf.set('libexecdir', libexecdir)
jsconf.set('vpndir', vpndir)
config_js = configure_file( config_js = configure_file(
input: 'config.js.in', input: 'config.js.in',

View File

@@ -223,7 +223,7 @@ var BroadbandModem = GObject.registerClass({
}, class BroadbandModem extends ModemBase { }, class BroadbandModem extends ModemBase {
_init(path, capabilities) { _init(path, capabilities) {
super._init({ capabilities }); super._init({ capabilities });
this._proxy = new BroadbandModemProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path); this._proxy = new BroadbandModemProxy(Gio.DBus.system, 'org.freedesktop.ModemManager', path);
this._proxy_3gpp = new BroadbandModem3gppProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path); this._proxy_3gpp = new BroadbandModem3gppProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path);
this._proxy_cdma = new BroadbandModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path); this._proxy_cdma = new BroadbandModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path);
@@ -249,7 +249,7 @@ var BroadbandModem = GObject.registerClass({
} }
_reloadSignalQuality() { _reloadSignalQuality() {
let [quality, recent_] = this._proxy.SignalQuality; let [quality, recent_] = this.SignalQuality;
this._setSignalQuality(quality); this._setSignalQuality(quality);
} }

View File

@@ -57,7 +57,9 @@ 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._initManagerProxy(); this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
this._cancellable,
this._onManagerProxyLoaded.bind(this));
} }
_tryToCompleteLoad() { _tryToCompleteLoad() {
@@ -71,7 +73,7 @@ var ObjectManager = class {
} }
} }
async _addInterface(objectPath, interfaceName, onFinished) { _addInterface(objectPath, interfaceName, onFinished) {
let info = this._interfaceInfos[interfaceName]; let info = this._interfaceInfos[interfaceName];
if (!info) { if (!info) {
@@ -87,38 +89,40 @@ 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 });
try { proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => {
await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable); try {
} catch (e) { initable.init_finish(result);
logError(e, `could not initialize proxy for interface ${interfaceName}`); } catch (e) {
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) {
@@ -147,10 +151,9 @@ var ObjectManager = class {
} }
} }
async _initManagerProxy() { _onManagerProxyLoaded(initable, result) {
try { try {
await this._managerProxy.init_async( initable.init_finish(result);
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}`);

View File

@@ -1,146 +0,0 @@
// -*- 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 users
// parental controls settings. Its possible for the users parental controls
// to change at runtime if the Parental Controls application is used by an
// administrator from within the users 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 its 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 doesnt say it should be hidden.
// - The executable from the .desktop files Exec line isnt denied in
// the users parental controls.
// - None of the flatpak app IDs from the X-Flatpak and the
// X-Flatpak-RenamedFrom lines are denied in the users 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);
}
});

View File

@@ -21,7 +21,6 @@ const SENSOR_OBJECT_PATH = '/net/hadess/SensorProxy';
const SensorProxyInterface = loadInterfaceXML('net.hadess.SensorProxy'); const SensorProxyInterface = loadInterfaceXML('net.hadess.SensorProxy');
const POWER_OFF_ACTION_ID = 'power-off'; const POWER_OFF_ACTION_ID = 'power-off';
const RESTART_ACTION_ID = 'restart';
const LOCK_SCREEN_ACTION_ID = 'lock-screen'; const LOCK_SCREEN_ACTION_ID = 'lock-screen';
const LOGOUT_ACTION_ID = 'logout'; const LOGOUT_ACTION_ID = 'logout';
const SUSPEND_ACTION_ID = 'suspend'; const SUSPEND_ACTION_ID = 'suspend';
@@ -41,38 +40,41 @@ function getDefault() {
const SystemActions = GObject.registerClass({ const SystemActions = GObject.registerClass({
Properties: { Properties: {
'can-power-off': GObject.ParamSpec.boolean( 'can-power-off': GObject.ParamSpec.boolean('can-power-off',
'can-power-off', 'can-power-off', 'can-power-off', 'can-power-off',
GObject.ParamFlags.READABLE, 'can-power-off',
false), GObject.ParamFlags.READABLE,
'can-restart': GObject.ParamSpec.boolean( false),
'can-restart', 'can-restart', 'can-restart', 'can-suspend': GObject.ParamSpec.boolean('can-suspend',
GObject.ParamFlags.READABLE, 'can-suspend',
false), 'can-suspend',
'can-suspend': GObject.ParamSpec.boolean( GObject.ParamFlags.READABLE,
'can-suspend', 'can-suspend', 'can-suspend', false),
GObject.ParamFlags.READABLE, 'can-lock-screen': GObject.ParamSpec.boolean('can-lock-screen',
false), 'can-lock-screen',
'can-lock-screen': GObject.ParamSpec.boolean( 'can-lock-screen',
'can-lock-screen', 'can-lock-screen', 'can-lock-screen', GObject.ParamFlags.READABLE,
GObject.ParamFlags.READABLE, false),
false), 'can-switch-user': GObject.ParamSpec.boolean('can-switch-user',
'can-switch-user': GObject.ParamSpec.boolean( 'can-switch-user',
'can-switch-user', 'can-switch-user', 'can-switch-user', 'can-switch-user',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
false), false),
'can-logout': GObject.ParamSpec.boolean( 'can-logout': GObject.ParamSpec.boolean('can-logout',
'can-logout', 'can-logout', 'can-logout', 'can-logout',
GObject.ParamFlags.READABLE, 'can-logout',
false), GObject.ParamFlags.READABLE,
'can-lock-orientation': GObject.ParamSpec.boolean( false),
'can-lock-orientation', 'can-lock-orientation', 'can-lock-orientation', 'can-lock-orientation': GObject.ParamSpec.boolean('can-lock-orientation',
GObject.ParamFlags.READABLE, 'can-lock-orientation',
false), 'can-lock-orientation',
'orientation-lock-icon': GObject.ParamSpec.string( GObject.ParamFlags.READABLE,
'orientation-lock-icon', 'orientation-lock-icon', 'orientation-lock-icon', false),
GObject.ParamFlags.READWRITE, 'orientation-lock-icon': GObject.ParamSpec.string('orientation-lock-icon',
null), 'orientation-lock-icon',
'orientation-lock-icon',
GObject.ParamFlags.READWRITE,
null),
}, },
}, class SystemActions extends GObject.Object { }, class SystemActions extends GObject.Object {
_init() { _init() {
@@ -81,25 +83,13 @@ 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: tokenizeKeywords(_('power off;shutdown;halt;stop')), keywords: _('power off;shutdown;reboot;restart;halt;stop').split(/[; ]/),
available: false,
});
this._actions.set(RESTART_ACTION_ID, {
// Translators: The name of the restart action in search
name: C_('search-result', 'Restart'),
iconName: 'system-reboot-symbolic',
// Translators: A list of keywords that match the restart action, separated by semicolons
keywords: tokenizeKeywords(_('reboot;restart;')),
available: false, available: false,
}); });
this._actions.set(LOCK_SCREEN_ACTION_ID, { this._actions.set(LOCK_SCREEN_ACTION_ID, {
@@ -107,15 +97,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: tokenizeKeywords(_('lock screen')), keywords: _("lock screen").split(/[; ]/),
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: 'system-log-out-symbolic', iconName: 'application-exit-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: tokenizeKeywords(_('logout;log out;sign off')), keywords: _("logout;log out;sign off").split(/[; ]/),
available: false, available: false,
}); });
this._actions.set(SUSPEND_ACTION_ID, { this._actions.set(SUSPEND_ACTION_ID, {
@@ -123,7 +113,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: tokenizeKeywords(_('suspend;sleep')), keywords: _("suspend;sleep").split(/[; ]/),
available: false, available: false,
}); });
this._actions.set(SWITCH_USER_ACTION_ID, { this._actions.set(SWITCH_USER_ACTION_ID, {
@@ -131,14 +121,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: tokenizeKeywords(_('switch user')), keywords: _("switch user").split(/[; ]/),
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: tokenizeKeywords(_('lock orientation;unlock orientation;screen;rotation')), keywords: _("lock orientation;unlock orientation;screen;rotation").split(/[; ]/),
available: false, available: false,
}); });
@@ -209,11 +199,6 @@ const SystemActions = GObject.registerClass({
return this._actions.get(POWER_OFF_ACTION_ID).available; return this._actions.get(POWER_OFF_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get can_restart() {
return this._actions.get(RESTART_ACTION_ID).available;
}
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
get can_suspend() { get can_suspend() {
return this._actions.get(SUSPEND_ACTION_ID).available; return this._actions.get(SUSPEND_ACTION_ID).available;
@@ -292,7 +277,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 => GLib.str_tokenize_and_fold(term, null)[0]); terms = terms.map(term => term.toLowerCase());
let results = []; let results = [];
@@ -317,9 +302,6 @@ const SystemActions = GObject.registerClass({
case POWER_OFF_ACTION_ID: case POWER_OFF_ACTION_ID:
this.activatePowerOff(); this.activatePowerOff();
break; break;
case RESTART_ACTION_ID:
this.activateRestart();
break;
case LOCK_SCREEN_ACTION_ID: case LOCK_SCREEN_ACTION_ID:
this.activateLockScreen(); this.activateLockScreen();
break; break;
@@ -361,9 +343,6 @@ const SystemActions = GObject.registerClass({
this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY)); this._loginScreenSettings.get_boolean(DISABLE_RESTART_KEY));
this._actions.get(POWER_OFF_ACTION_ID).available = this._canHavePowerOff && !disabled; this._actions.get(POWER_OFF_ACTION_ID).available = this._canHavePowerOff && !disabled;
this.notify('can-power-off'); this.notify('can-power-off');
this._actions.get(RESTART_ACTION_ID).available = this._canHavePowerOff && !disabled;
this.notify('can-restart');
} }
_updateHaveSuspend() { _updateHaveSuspend() {
@@ -462,13 +441,6 @@ const SystemActions = GObject.registerClass({
this._session.ShutdownRemote(0); this._session.ShutdownRemote(0);
} }
activateRestart() {
if (!this._actions.get(RESTART_ACTION_ID).available)
throw new Error('The restart action is not available!');
this._session.RebootRemote();
}
activateSuspend() { activateSuspend() {
if (!this._actions.get(SUSPEND_ACTION_ID).available) if (!this._actions.get(SUSPEND_ACTION_ID).available)
throw new Error('The suspend action is not available!'); throw new Error('The suspend action is not available!');

View File

@@ -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,
ensureActorVisibleInScrollView, wiggle */ makeCloseButton, ensureActorVisibleInScrollView, wiggle */
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi; const { Clutter, Gio, GLib, GObject, Shell, St, GnomeDesktop } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
const Main = imports.ui.main; const Main = imports.ui.main;
@@ -363,6 +363,51 @@ 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();

View File

@@ -7,8 +7,6 @@ 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';
@@ -81,7 +79,16 @@ var WeatherClient = class {
this._weatherApp = null; this._weatherApp = null;
this._weatherProxy = null; this._weatherProxy = null;
this._createWeatherProxy(); let nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
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',
@@ -139,17 +146,9 @@ var WeatherClient = class {
(!this._needsAuth || this._weatherAuthorized); (!this._needsAuth || this._weatherAuthorized);
} }
async _createWeatherProxy() { _onWeatherProxyReady(o, res) {
const nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
try { try {
this._weatherProxy = await Gio.DBusProxy.new( this._weatherProxy = Gio.DBusProxy.new_finish(res);
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;
@@ -240,23 +239,25 @@ var WeatherClient = class {
} }
} }
async _startGClueService() { _startGClueService() {
if (this._gclueStarting) if (this._gclueStarting)
return; return;
this._gclueStarting = true; this._gclueStarting = true;
try { Geoclue.Simple.new('org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null,
this._gclueService = await Geoclue.Simple.new( (o, res) => {
'org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null); try {
} catch (e) { this._gclueService = Geoclue.Simple.new_finish(res);
log(`Failed to connect to Geoclue2 service: ${e.message}`); } catch (e) {
this._setLocation(this._mostRecentLocation); log(`Failed to connect to Geoclue2 service: ${e.message}`);
return; this._setLocation(this._mostRecentLocation);
} return;
this._gclueStarted = true; }
this._gclueService.get_client().distance_threshold = 100; this._gclueStarted = true;
this._updateLocationMonitoring(); this._gclueService.get_client().distance_threshold = 100;
this._updateLocationMonitoring();
});
} }
_onGClueLocationChanged() { _onGClueLocationChanged() {

View File

@@ -1,146 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported run, finish, script_topBarNavDone, script_notificationShowDone,
script_notificationCloseDone, script_overviewShowDone,
script_applicationsShowStart, script_applicationsShowDone, METRICS,
*/
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_"] }] */
const { St } = imports.gi;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Scripting = imports.ui.scripting;
// This script tests the most important (basic) functionality of the shell.
var METRICS = {};
async function run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent('topBarNavStart', 'Starting to navigate the top bar');
Scripting.defineScriptEvent('topBarNavDone', 'Done navigating the top bar');
Scripting.defineScriptEvent('notificationShowStart', 'Showing a notification');
Scripting.defineScriptEvent('notificationShowDone', 'Done showing a notification');
Scripting.defineScriptEvent('notificationCloseStart', 'Closing a notification');
Scripting.defineScriptEvent('notificationCloseDone', 'Done closing a notification');
Scripting.defineScriptEvent('overviewShowStart', 'Starting to show the overview');
Scripting.defineScriptEvent('overviewShowDone', 'Overview finished showing');
Scripting.defineScriptEvent('applicationsShowStart', 'Starting to switch to applications view');
Scripting.defineScriptEvent('applicationsShowDone', 'Done switching to applications view');
Main.overview.connect('shown',
() => Scripting.scriptEvent('overviewShowDone'));
await Scripting.sleep(1000);
// navigate through top bar
Scripting.scriptEvent('topBarNavStart');
Main.panel.statusArea.aggregateMenu.menu.open();
await Scripting.sleep(400);
const { menuManager } = Main.panel;
while (menuManager.activeMenu &&
Main.panel.navigate_focus(menuManager.activeMenu.sourceActor,
St.DirectionType.TAB_BACKWARD, false))
await Scripting.sleep(400);
Scripting.scriptEvent('topBarNavDone');
await Scripting.sleep(1000);
// notification
const source = new MessageTray.SystemNotificationSource();
Main.messageTray.add(source);
Scripting.scriptEvent('notificationShowStart');
source.connect('notification-show',
() => Scripting.scriptEvent('notificationShowDone'));
const notification = new MessageTray.Notification(source,
'A test notification');
source.showNotification(notification);
await Scripting.sleep(400);
Main.panel.statusArea.dateMenu.menu.open();
await Scripting.sleep(400);
Scripting.scriptEvent('notificationCloseStart');
notification.connect('destroy',
() => Scripting.scriptEvent('notificationCloseDone'));
notification.destroy();
await Scripting.sleep(400);
Main.panel.statusArea.dateMenu.menu.close();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
// overview (window picker)
Scripting.scriptEvent('overviewShowStart');
Main.overview.show();
await Scripting.waitLeisure();
Main.overview.hide();
await Scripting.waitLeisure();
await Scripting.sleep(1000);
// overview (app picker)
Main.overview.show();
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone');
// eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = false;
await Scripting.waitLeisure();
Main.overview.hide();
await Scripting.waitLeisure();
/* eslint-enable no-await-in-loop */
}
let topBarNav = false;
let notificationShown = false;
let notificationClosed = false;
let windowPickerShown = false;
let appPickerShown = false;
function script_topBarNavDone() {
topBarNav = true;
}
function script_notificationShowDone() {
notificationShown = true;
}
function script_notificationCloseDone() {
notificationClosed = true;
}
function script_overviewShowDone() {
windowPickerShown = true;
}
function script_applicationsShowDone() {
appPickerShown = true;
}
function finish() {
if (!topBarNav)
throw new Error('Failed to navigate top bar');
if (!notificationShown)
throw new Error('Failed to show notification');
if (!notificationClosed)
throw new Error('Failed to close notification');
if (!windowPickerShown)
throw new Error('Failed to show window picker');
if (!appPickerShown)
throw new Error('Failed to show app picker');
}

View File

@@ -70,8 +70,7 @@ let WINDOW_CONFIGS = [
{ width: 640, height: 480, alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha' }, { width: 640, height: 480, alpha: true, maximized: false, count: 10, metric: 'overviewFps10Alpha' },
]; ];
async function run() { function *run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview"); Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview");
@@ -85,7 +84,7 @@ async function run() {
Scripting.scriptEvent('overviewShowDone'); Scripting.scriptEvent('overviewShowDone');
}); });
await Scripting.sleep(1000); yield Scripting.sleep(1000);
for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) { for (let i = 0; i < 2 * WINDOW_CONFIGS.length; i++) {
// We go to the overview twice for each configuration; the first time // We go to the overview twice for each configuration; the first time
@@ -93,50 +92,49 @@ async function run() {
// a clean set of numbers. // a clean set of numbers.
if ((i % 2) == 0) { if ((i % 2) == 0) {
let config = WINDOW_CONFIGS[i / 2]; let config = WINDOW_CONFIGS[i / 2];
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
for (let k = 0; k < config.count; k++) { for (let k = 0; k < config.count; k++) {
await Scripting.createTestWindow({ width: config.width, yield Scripting.createTestWindow({ width: config.width,
height: config.height, height: config.height,
alpha: config.alpha, alpha: config.alpha,
maximized: config.maximized }); maximized: config.maximized });
} }
await Scripting.waitTestWindows(); yield Scripting.waitTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
} }
Scripting.scriptEvent('overviewShowStart'); Scripting.scriptEvent('overviewShowStart');
Main.overview.show(); Main.overview.show();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Main.overview.hide(); Main.overview.hide();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
System.gc(); System.gc();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.collectStatistics(); Scripting.collectStatistics();
Scripting.scriptEvent('afterShowHide'); Scripting.scriptEvent('afterShowHide');
} }
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Main.overview.show(); Main.overview.show();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true; Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = false; Main.overview.dash.showAppsButton.checked = false;
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
} }
/* eslint-enable no-await-in-loop */
} }
let showingOverview = false; let showingOverview = false;

View File

@@ -94,8 +94,7 @@ function extractBootTimestamp() {
return result; return result;
} }
async function run() { function *run() {
/* eslint-disable no-await-in-loop */
Scripting.defineScriptEvent("desktopShown", "Finished initial animation"); Scripting.defineScriptEvent("desktopShown", "Finished initial animation");
Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview");
Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing");
@@ -111,7 +110,7 @@ async function run() {
Scripting.defineScriptEvent("geditLaunch", "gedit application launch"); Scripting.defineScriptEvent("geditLaunch", "gedit application launch");
Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn"); Scripting.defineScriptEvent("geditFirstFrame", "first frame of gedit window drawn");
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('desktopShown'); Scripting.scriptEvent('desktopShown');
let interfaceSettings = new Gio.Settings({ let interfaceSettings = new Gio.Settings({
@@ -121,22 +120,22 @@ async function run() {
Scripting.scriptEvent('overviewShowStart'); Scripting.scriptEvent('overviewShowStart');
Main.overview.show(); Main.overview.show();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('overviewShowDone'); Scripting.scriptEvent('overviewShowDone');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true; Main.overview.dash.showAppsButton.checked = true;
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Main.overview.hide(); Main.overview.hide();
await Scripting.waitLeisure(); yield Scripting.waitLeisure();
// --------------------- // // --------------------- //
// Tests of redraw speed // // Tests of redraw speed //
@@ -146,46 +145,46 @@ async function run() {
global.frame_finish_timestamp = true; global.frame_finish_timestamp = true;
for (let k = 0; k < 5; k++) for (let k = 0; k < 5; k++)
await Scripting.createTestWindow({ maximized: true }); yield Scripting.createTestWindow({ maximized: true });
await Scripting.waitTestWindows(); yield Scripting.waitTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('mainViewDrawStart'); Scripting.scriptEvent('mainViewDrawStart');
await waitAndDraw(1000); yield waitAndDraw(1000);
Scripting.scriptEvent('mainViewDrawDone'); Scripting.scriptEvent('mainViewDrawDone');
Main.overview.show(); Main.overview.show();
Scripting.waitLeisure(); Scripting.waitLeisure();
await Scripting.sleep(1500); yield Scripting.sleep(1500);
Scripting.scriptEvent('overviewDrawStart'); Scripting.scriptEvent('overviewDrawStart');
await waitAndDraw(1000); yield waitAndDraw(1000);
Scripting.scriptEvent('overviewDrawDone'); Scripting.scriptEvent('overviewDrawDone');
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
Main.overview.hide(); Main.overview.hide();
await Scripting.createTestWindow({ maximized: true, yield Scripting.createTestWindow({ maximized: true,
redraws: true }); redraws: true });
await Scripting.waitTestWindows(); yield Scripting.waitTestWindows();
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestStart'); Scripting.scriptEvent('redrawTestStart');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('redrawTestDone'); Scripting.scriptEvent('redrawTestDone');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('collectTimings'); Scripting.scriptEvent('collectTimings');
await Scripting.destroyTestWindows(); yield Scripting.destroyTestWindows();
global.frame_timestamps = false; global.frame_timestamps = false;
global.frame_finish_timestamp = false; global.frame_finish_timestamp = false;
await Scripting.sleep(1000); yield Scripting.sleep(1000);
let appSys = Shell.AppSystem.get_default(); let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('org.gnome.gedit.desktop'); let app = appSys.lookup_app('org.gnome.gedit.desktop');
@@ -198,22 +197,21 @@ async function run() {
throw new Error('gedit was already running'); throw new Error('gedit was already running');
while (windows.length == 0) { while (windows.length == 0) {
await waitSignal(global.display, 'window-created'); yield waitSignal(global.display, 'window-created');
windows = app.get_windows(); windows = app.get_windows();
} }
let actor = windows[0].get_compositor_private(); let actor = windows[0].get_compositor_private();
await waitSignal(actor, 'first-frame'); yield waitSignal(actor, 'first-frame');
Scripting.scriptEvent('geditFirstFrame'); Scripting.scriptEvent('geditFirstFrame');
await Scripting.sleep(1000); yield Scripting.sleep(1000);
windows[0].delete(global.get_current_time()); windows[0].delete(global.get_current_time());
await Scripting.sleep(1000); yield Scripting.sleep(1000);
interfaceSettings.set_boolean('enable-animations', true); interfaceSettings.set_boolean('enable-animations', true);
/* eslint-enable no-await-in-loop */
} }
let overviewShowStart; let overviewShowStart;

View File

@@ -5,5 +5,6 @@
<file>misc/config.js</file> <file>misc/config.js</file>
<file>misc/fileUtils.js</file> <file>misc/fileUtils.js</file>
<file>misc/params.js</file>
</gresource> </gresource>
</gresources> </gresources>

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gnome/shell">
<file>extensionPrefs/main.js</file>
<file>misc/config.js</file>
<file>misc/extensionUtils.js</file>
<file>misc/fileUtils.js</file>
<file>misc/params.js</file>
<file alias="css/application.css">extensionPrefs/css/application.css</file>
<file alias="ui/extension-row.ui">extensionPrefs/ui/extension-row.ui</file>
<file alias="ui/extensions-window.ui">extensionPrefs/ui/extensions-window.ui</file>
</gresource>
</gresources>

View File

@@ -68,8 +68,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._items = this._switcherList.icons; this._items = this._switcherList.icons;
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
super.vfunc_allocate(box); super.vfunc_allocate(box, flags);
// 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); this._thumbnails.allocate(childBox, flags);
} }
} }
@@ -280,10 +280,12 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
} }
_onDestroy() { _onDestroy() {
super._onDestroy();
if (this._thumbnails)
this._destroyThumbnails();
if (this._thumbnailTimeoutId != 0) if (this._thumbnailTimeoutId != 0)
GLib.source_remove(this._thumbnailTimeoutId); GLib.source_remove(this._thumbnailTimeoutId);
super._onDestroy();
} }
/** /**
@@ -363,7 +365,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
}, },
}); });
this._thumbnails = null; this._thumbnails = null;
this._switcherList.removeAccessibleState(this._selectedIndex, Atk.StateType.EXPANDED); if (this._switcherList._items[this._selectedIndex])
this._switcherList._items[this._selectedIndex].remove_accessible_state(Atk.StateType.EXPANDED);
} }
_createThumbnails() { _createThumbnails() {
@@ -392,7 +395,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
}, },
}); });
this._switcherList.addAccessibleState(this._selectedIndex, Atk.StateType.EXPANDED); this._switcherList._items[this._selectedIndex].add_accessible_state(Atk.StateType.EXPANDED);
} }
}); });
@@ -681,7 +684,8 @@ 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);
} }
@@ -749,9 +753,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
return super.vfunc_get_preferred_height(forWidth); return super.vfunc_get_preferred_height(forWidth);
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
// Allocate the main list items // Allocate the main list items
super.vfunc_allocate(box); super.vfunc_allocate(box, flags);
let contentBox = this.get_theme_node().get_content_box(box); let contentBox = this.get_theme_node().get_content_box(box);
@@ -766,15 +770,13 @@ 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); this._arrows[i].allocate(childBox, flags);
} }
} }
// We override SwitcherList's _onItemEnter method to delay // We override SwitcherList's _onItemEnter method to delay
// activation when the thumbnail list is open // activation when the thumbnail list is open
_onItemEnter(item) { _onItemEnter(index) {
const index = this._items.indexOf(item);
if (this._mouseTimeOutId != 0) if (this._mouseTimeOutId != 0)
GLib.source_remove(this._mouseTimeOutId); GLib.source_remove(this._mouseTimeOutId);
if (this._altTabPopup.thumbnailsVisible) { if (this._altTabPopup.thumbnailsVisible) {
@@ -852,9 +854,6 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
if (index === -1) if (index === -1)
return; return;
this._arrows[index].destroy();
this._arrows.splice(index, 1);
this.icons.splice(index, 1); this.icons.splice(index, 1);
this.removeItem(index); this.removeItem(index);
} }
@@ -1059,28 +1058,28 @@ class WindowSwitcher extends SwitcherPopup.SwitcherList {
return [minHeight, natHeight]; return [minHeight, natHeight];
} }
vfunc_allocate(box) { vfunc_allocate(box, flags) {
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);
box.y2 -= totalLabelHeight; let childBox = new Clutter.ActorBox();
super.vfunc_allocate(box); childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2;
childBox.y1 = childBox.y2 - this._label.height;
this._label.allocate(childBox, flags);
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM);
childBox.x1 = box.x1;
childBox.x2 = box.x2;
childBox.y1 = box.y1;
childBox.y2 = box.y2 - totalLabelHeight;
super.vfunc_allocate(childBox, flags);
// 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.
box.y2 += totalLabelHeight; this.set_allocation(box, flags);
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) {

View File

@@ -15,7 +15,8 @@ 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({
style: `width: ${width}px; height: ${height}px;`, width: width * themeContext.scale_factor,
height: height * themeContext.scale_factor,
}); });
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
@@ -60,7 +61,7 @@ class Animation extends St.Bin {
} }
_loadFile(file, width, height) { _loadFile(file, width, height) {
const resourceScale = this.get_resource_scale(); let [validResourceScale, resourceScale] = this.get_resource_scale();
let wasPlaying = this._isPlaying; let wasPlaying = this._isPlaying;
if (this._isPlaying) if (this._isPlaying)
@@ -69,6 +70,12 @@ class Animation extends St.Bin {
this._isLoaded = false; this._isLoaded = false;
this.destroy_all_children(); this.destroy_all_children();
if (!validResourceScale) {
if (wasPlaying)
this.play();
return;
}
let textureCache = St.TextureCache.get_default(); let textureCache = St.TextureCache.get_default();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._animations = textureCache.load_sliced_image(file, width, height, this._animations = textureCache.load_sliced_image(file, width, height,

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,6 @@
/* 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;
@@ -13,7 +12,6 @@ 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',
@@ -66,13 +64,6 @@ const RENAMED_DESKTOP_IDS = {
class AppFavorites { class AppFavorites {
constructor() { constructor() {
// Filter the apps through the users 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));
@@ -104,7 +95,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 && this._parentalControlsManager.shouldShowApp(app.app_info)); .filter(app => app != null);
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];
@@ -143,9 +134,6 @@ 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);

View File

@@ -147,8 +147,9 @@ 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();
const deviceName = Object.keys(AudioDevice) let deviceName = Object.keys(AudioDevice).filter(
.filter(dev => AudioDevice[dev] === device)[0].toLowerCase(); dev => AudioDevice[dev] == device
)[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,

View File

@@ -347,8 +347,6 @@ var Background = GObject.registerClass({
this.set_color(color); this.set_color(color);
else else
this.set_gradient(shadingType, color, secondColor); this.set_gradient(shadingType, color, secondColor);
this._setLoaded();
} }
_watchFile(file) { _watchFile(file) {
@@ -514,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');
@@ -714,18 +712,13 @@ var BackgroundManager = class BackgroundManager {
} }
let newBackgroundActor = this._createBackgroundActor(); let newBackgroundActor = this._createBackgroundActor();
newBackgroundActor.vignette_sharpness = this.backgroundActor.vignette_sharpness;
const oldContent = this.backgroundActor.content; newBackgroundActor.brightness = this.backgroundActor.brightness;
const newContent = newBackgroundActor.content;
newContent.vignette_sharpness = oldContent.vignette_sharpness;
newContent.brightness = oldContent.brightness;
newBackgroundActor.visible = this.backgroundActor.visible; newBackgroundActor.visible = this.backgroundActor.visible;
this._newBackgroundActor = newBackgroundActor; this._newBackgroundActor = newBackgroundActor;
const { background } = newBackgroundActor.content; let background = newBackgroundActor.background;
if (background.isLoaded) { if (background.isLoaded) {
this._swapBackgroundActor(); this._swapBackgroundActor();
@@ -745,8 +738,6 @@ 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,
@@ -767,27 +758,10 @@ var BackgroundManager = class BackgroundManager {
this._updateBackgroundActor(); this._updateBackgroundActor();
}); });
let loadedSignalId;
if (background.isLoaded) {
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.emit('loaded');
return GLib.SOURCE_REMOVE;
});
} else {
loadedSignalId = background.connect('loaded', () => {
background.disconnect(loadedSignalId);
loadedSignalId = null;
this.emit('loaded');
});
}
backgroundActor.connect('destroy', () => { backgroundActor.connect('destroy', () => {
if (changeSignalId) if (changeSignalId)
background.disconnect(changeSignalId); background.disconnect(changeSignalId);
if (loadedSignalId)
background.disconnect(loadedSignalId);
if (backgroundActor.loadedSignalId) if (backgroundActor.loadedSignalId)
background.disconnect(backgroundActor.loadedSignalId); background.disconnect(backgroundActor.loadedSignalId);
}); });

View File

@@ -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('notify::allocation', () => { this.connect('allocation-changed', (actor, box) => {
this._barLevelWidth = this.allocation.get_width(); this._barLevelWidth = box.get_width();
}); });
this._customAccessible = St.GenericAccessible.new_for_actor(this); this._customAccessible = St.GenericAccessible.new_for_actor(this);

Some files were not shown because too many files have changed in this diff Show More