Compare commits

..

2 Commits

Author SHA1 Message Date
Milan Crha
13ddf1eb83 calendar-server: Add 'Dismiss' button and application action
- adds 'Dismiss' button to the notification
- introduces org.gnome.Shell.CalendarServer.desktop.in.in to benefit from GNotification API

Related to https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/1064
2020-03-03 15:58:13 +01:00
Milan Crha
15ab33a11a Move functionality from evolution-alarm-notify to gnome-shell-calendar-server
Closes https://gitlab.gnome.org/GNOME/gnome-shell/issues/155
2020-03-03 12:00:27 +01:00
265 changed files with 15516 additions and 24589 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,13 +1,9 @@
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" POT_LOG: "pot-update.txt"
@@ -18,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"
@@ -28,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:
@@ -40,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
@@ -51,21 +47,21 @@ eslint:
when: always when: always
potfile_check: potfile_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:
- ./.gitlab-ci/check-potfiles.sh - ./.gitlab-ci/check-potfiles.sh
<<: *only_default <<: *only_default
no_template_check: no_template_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: review
script: script:
- ./.gitlab-ci/check-template-strings.sh - ./.gitlab-ci/check-template-strings.sh
<<: *only_default <<: *only_default
build: build:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: build stage: build
before_script: before_script:
- .gitlab-ci/checkout-mutter.sh - .gitlab-ci/checkout-mutter.sh
@@ -83,7 +79,7 @@ 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
variables: variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir" XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
@@ -100,7 +96,7 @@ test:
when: on_failure when: on_failure
test-pot: test-pot:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4 image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: test stage: test
before_script: before_script:
- ninja -C mutter/build install - ninja -C mutter/build install
@@ -114,20 +110,3 @@ test-pot:
' | tee $POT_LOG ' | tee $POT_LOG
- (! grep -q . $POT_LOG) - (! grep -q . $POT_LOG)
<<: *only_default <<: *only_default
flatpak:
stage: build
variables:
SUBPROJECT: "subprojects/extensions-app"
# Your manifest path
MANIFEST_PATH: "$SUBPROJECT/build-aux/flatpak/org.gnome.Extensions.json"
RUNTIME_REPO: "https://nightly.gnome.org/gnome-nightly.flatpakrepo"
FLATPAK_MODULE: "gnome-extensions-app"
APP_ID: "org.gnome.Extensions"
extends: .flatpak
<<: *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

@@ -6,11 +6,6 @@ globs=('*.js' '*.c')
# find source files that contain gettext keywords # find source files that contain gettext keywords
files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs) files=$(grep -lR ${globs[@]/#/--include=} '\(gettext\|[^I_)]_\)(' $srcdirs)
# filter out excluded files
if [ -f po/POTFILES.skip ]; then
files=$(for f in $files; do ! grep -q ^$f po/POTFILES.skip && echo $f; done)
fi
# find those that aren't listed in POTFILES.in # find those that aren't listed in POTFILES.in
missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done) missing=$(for f in $files; do ! grep -q ^$f po/POTFILES.in && echo $f; done)

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() {

65
NEWS
View File

@@ -1,68 +1,3 @@
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 3.35.92
======= =======
* Plug a memory leak [Jonas D.; !1015] * Plug a memory leak [Jonas D.; !1015]

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

@@ -5,7 +5,7 @@
<arg type="x" name="until" direction="in"/> <arg type="x" name="until" direction="in"/>
<arg type="b" name="force_reload" direction="in"/> <arg type="b" name="force_reload" direction="in"/>
</method> </method>
<signal name="EventsAddedOrUpdated"> <signal name="EventsAdded">
<arg type="a(ssbxxa{sv})" name="events" direction="out"/> <arg type="a(ssbxxa{sv})" name="events" direction="out"/>
</signal> </signal>
<signal name="EventsRemoved"> <signal name="EventsRemoved">

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

@@ -19,10 +19,6 @@ Before=gnome-session-initialized.target
[Service] [Service]
Type=notify Type=notify
ExecStart=@bindir@/gnome-shell ExecStart=@bindir@/gnome-shell
# 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
# 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 wayland we cannot restart # On wayland we cannot restart

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,7 @@
desktop_files = [ desktop_files = [
'org.gnome.Shell.desktop', 'org.gnome.Shell.desktop',
'org.gnome.Shell.Extensions.desktop', 'org.gnome.Shell.CalendarServer.desktop',
'org.gnome.Extensions.desktop',
] ]
service_files = [] service_files = []
@@ -13,6 +14,7 @@ desktopconf = configuration_data()
# We substitute in bindir so it works as an autostart # We substitute in bindir so it works as an autostart
# file when built in a non-system prefix # file when built in a non-system prefix
desktopconf.set('bindir', bindir) desktopconf.set('bindir', bindir)
desktopconf.set('libexecdir', libexecdir)
desktopconf.set('systemd_hidden', have_systemd ? 'true' : 'false') desktopconf.set('systemd_hidden', have_systemd ? 'true' : 'false')
foreach desktop_file : desktop_files foreach desktop_file : desktop_files

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

@@ -0,0 +1,9 @@
[Desktop Entry]
Type=Application
Name=Clock Applet
Icon=appointment-soon
Exec=@libexecdir@/gnome-shell-calendar-server
Terminal=false
Categories=
OnlyShowIn=GNOME
NoDisplay=true

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

@@ -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

@@ -35,9 +35,9 @@ $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
@@ -60,7 +60,7 @@ $app_grid_fg_color: #fff;
& .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;
@@ -73,6 +73,10 @@ $app_grid_fg_color: #fff;
& > StIcon { icon-size: 16px } & > StIcon { icon-size: 16px }
} }
} }
& StButton#vhandle,
& StButton#vhandle:hover,
& StButton#vhandle:active { background-color: transparent; }
} }
.app-folder-dialog-container { .app-folder-dialog-container {
padding: 12px; padding: 12px;

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 {

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,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

@@ -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,177 +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;
}
// 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,42 +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',
}
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,80 +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);
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);
}
NotifyAsync(params, invocation) {
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));
});
}
};

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

@@ -3,44 +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(Shew.WindowExporter.prototype, 'export', 'export_finish'); function stripPrefix(string, prefix) {
if (string.slice(0, prefix.length) == prefix)
function loadInterfaceXML(iface) { return string.slice(prefix.length);
const uri = 'resource:///org/gnome/Extensions/dbus-interfaces/%s.xml'.format(iface); return string;
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() {
@@ -56,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) {
@@ -66,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',
@@ -89,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;
@@ -105,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));
@@ -124,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();
} }
@@ -157,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() {
@@ -183,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,
@@ -201,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) {
@@ -223,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);
@@ -246,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() {
@@ -296,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;
@@ -317,14 +453,125 @@ 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',
@@ -374,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);
@@ -383,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;
@@ -471,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(', '));
}, },
@@ -487,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

@@ -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>

View File

@@ -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);
@@ -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

@@ -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();
} }
@@ -810,13 +810,12 @@ var LoginDialog = GObject.registerClass({
return; return;
this._logoBin.destroy_all_children(); this._logoBin.destroy_all_children();
const [valid, resourceScale] = this._logoBin.get_resource_scale(); if (this._logoFile && this._logoBin.resource_scale > 0) {
if (this._logoFile && valid) {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile, this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
-1, -1, -1, _LOGO_ICON_HEIGHT,
scaleFactor, scaleFactor,
resourceScale)); this._logoBin.resource_scale));
} }
} }

View File

@@ -2,7 +2,7 @@
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY, /* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */ DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */
const { Clutter, 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;
@@ -12,15 +12,6 @@ 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';
@@ -177,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() {
@@ -346,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;
@@ -359,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;
} }
@@ -373,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;
@@ -429,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() {

View File

@@ -23,7 +23,6 @@
<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>
@@ -102,6 +101,7 @@
<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>

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

@@ -76,15 +76,19 @@ function loadInterfaceXML(iface) {
_ifaceResource._register(); _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;
} }

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,7 +55,7 @@ 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 = []) {
@@ -75,7 +66,7 @@ var IBusManager = class {
let display = GLib.getenv('GNOME_SETUP_DISPLAY'); let display = GLib.getenv('GNOME_SETUP_DISPLAY');
if (display) if (display)
launcher.setenv('DISPLAY', display, true); launcher.setenv('DISPLAY', display, true);
launcher.spawnv(cmdLine); launcher.launch(cmdLine);
} catch (e) { } catch (e) {
log(`Failed to launch ibus-daemon: ${e.message}`); log(`Failed to launch ibus-daemon: ${e.message}`);
} }
@@ -111,14 +102,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 +126,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) {
}
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 {
engine = this._ibus.get_global_engine_async_finish(res);
if (!engine)
return;
} catch (e) {
return;
}
this._engineChanged(this._ibus, engine.get_name());
});
this._updateReadiness(); this._updateReadiness();
} catch (e) { } else {
this._clear();
} }
} }
@@ -227,7 +224,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 +234,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

@@ -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;
@@ -171,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]) {

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 blacklisted in
// the users parental controls.
// - None of the flatpak app IDs from the X-Flatpak and the
// X-Flatpak-RenamedFrom lines are blacklisted 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

@@ -83,17 +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;reboot;restart;halt;stop')), keywords: _('power off;shutdown;reboot;restart;halt;stop').split(/[; ]/),
available: false, available: false,
}); });
this._actions.set(LOCK_SCREEN_ACTION_ID, { this._actions.set(LOCK_SCREEN_ACTION_ID, {
@@ -101,7 +97,7 @@ 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, {
@@ -109,7 +105,7 @@ const SystemActions = GObject.registerClass({
name: C_("search-result", "Log Out"), name: C_("search-result", "Log Out"),
iconName: 'application-exit-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, {
@@ -117,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, {
@@ -125,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,
}); });
@@ -281,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 = [];

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

@@ -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

@@ -681,7 +681,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);
} }
@@ -1059,25 +1060,25 @@ class WindowSwitcher extends SwitcherPopup.SwitcherList {
vfunc_allocate(box, flags) { 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, flags); 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, flags);
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, flags);
} }
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));

View File

@@ -10,7 +10,6 @@ const GrabHelper = imports.ui.grabHelper;
const IconGrid = imports.ui.iconGrid; const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main; const Main = imports.ui.main;
const PageIndicators = imports.ui.pageIndicators; const PageIndicators = imports.ui.pageIndicators;
const ParentalControlsManager = imports.misc.parentalControlsManager;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const Search = imports.ui.search; const Search = imports.ui.search;
const SwipeTracker = imports.ui.swipeTracker; const SwipeTracker = imports.ui.swipeTracker;
@@ -72,9 +71,15 @@ function _getFolderName(folder) {
let name = folder.get_string('name'); let name = folder.get_string('name');
if (folder.get_boolean('translate')) { if (folder.get_boolean('translate')) {
let translated = Shell.util_get_translated_folder_name(name); let keyfile = new GLib.KeyFile();
if (translated !== null) let path = 'desktop-directories/%s'.format(name);
return translated;
try {
keyfile.load_from_data_dirs(path, GLib.KeyFileFlags.NONE);
name = keyfile.get_locale_string('Desktop Entry', 'Name', null);
} catch (e) {
return name;
}
} }
return name; return name;
@@ -115,10 +120,15 @@ function _findBestFolderName(apps) {
}, commonCategories); }, commonCategories);
for (let category of commonCategories) { for (let category of commonCategories) {
const directory = '%s.directory'.format(category); let keyfile = new GLib.KeyFile();
const translated = Shell.util_get_translated_folder_name(directory); let path = 'desktop-directories/%s.directory'.format(category);
if (translated !== null)
return translated; try {
keyfile.load_from_data_dirs(path, GLib.KeyFileFlags.NONE);
return keyfile.get_locale_string('Desktop Entry', 'Name', null);
} catch (e) {
continue;
}
} }
return null; return null;
@@ -159,16 +169,6 @@ var BaseAppView = GObject.registerClass({
this._items = new Map(); this._items = new Map();
this._orderedItems = []; this._orderedItems = [];
this._animateLaterId = 0;
this._viewLoadedHandlerId = 0;
this._viewIsReady = false;
// Filter the apps through the users parental controls.
this._parentalControlsManager = ParentalControlsManager.getDefault();
this._parentalControlsManager.connect('app-filter-changed', () => {
this._redisplay();
});
} }
_childFocused(_actor) { _childFocused(_actor) {
@@ -204,7 +204,6 @@ var BaseAppView = GObject.registerClass({
this._items.set(icon.id, icon); this._items.set(icon.id, icon);
}); });
this._viewIsReady = true;
this.emit('view-loaded'); this.emit('view-loaded');
} }
@@ -254,18 +253,6 @@ var BaseAppView = GObject.registerClass({
Main.overview.dash.showAppsButton); Main.overview.dash.showAppsButton);
} }
_clearAnimateLater() {
if (this._animateLaterId) {
Meta.later_remove(this._animateLaterId);
this._animateLaterId = 0;
}
if (this._viewLoadedHandlerId) {
this.disconnect(this._viewLoadedHandlerId);
this._viewLoadedHandlerId = 0;
}
this._grid.opacity = 255;
}
animate(animationDirection, onComplete) { animate(animationDirection, onComplete) {
if (onComplete) { if (onComplete) {
let animationDoneId = this._grid.connect('animation-done', () => { let animationDoneId = this._grid.connect('animation-done', () => {
@@ -274,38 +261,16 @@ var BaseAppView = GObject.registerClass({
}); });
} }
this._clearAnimateLater();
if (animationDirection == IconGrid.AnimationDirection.IN) { if (animationDirection == IconGrid.AnimationDirection.IN) {
const doSpringAnimationLater = laterType => { let id = this._grid.connect('paint', () => {
this._animateLaterId = Meta.later_add(laterType, this._grid.disconnect(id);
() => { this._doSpringAnimation(animationDirection);
this._animateLaterId = 0; });
this._doSpringAnimation(animationDirection);
return GLib.SOURCE_REMOVE;
});
};
if (this._viewIsReady) {
this._grid.opacity = 0;
doSpringAnimationLater(Meta.LaterType.IDLE);
} else {
this._viewLoadedHandlerId = this.connect('view-loaded',
() => {
this._clearAnimateLater();
doSpringAnimationLater(Meta.LaterType.BEFORE_REDRAW);
});
}
} else { } else {
this._doSpringAnimation(animationDirection); this._doSpringAnimation(animationDirection);
} }
} }
vfunc_unmap() {
this._clearAnimateLater();
super.vfunc_unmap();
}
animateSwitch(animationDirection) { animateSwitch(animationDirection) {
this.remove_all_transitions(); this.remove_all_transitions();
this._grid.remove_all_transitions(); this._grid.remove_all_transitions();
@@ -342,37 +307,14 @@ var AllView = GObject.registerClass({
use_pagination: true, use_pagination: true,
}); });
this._grid._delegate = this;
this._stack = new St.Widget({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true,
});
this.add_actor(this._stack);
let box = new St.BoxLayout({
vertical: true,
y_align: Clutter.ActorAlign.START,
});
box.add_child(this._grid);
this._scrollView = new St.ScrollView({ this._scrollView = new St.ScrollView({
style_class: 'all-apps', style_class: 'all-apps',
x_expand: true, x_expand: true,
y_expand: true, y_expand: true,
reactive: true, reactive: true,
}); });
this._scrollView.add_actor(box); this.add_actor(this._scrollView);
this._stack.add_actor(this._scrollView); this._grid._delegate = this;
this._eventBlocker = new St.Widget({
x_expand: true,
y_expand: true,
reactive: true,
visible: false,
});
this._stack.add_actor(this._eventBlocker);
this._scrollView.set_policy(St.PolicyType.NEVER, this._scrollView.set_policy(St.PolicyType.NEVER,
St.PolicyType.EXTERNAL); St.PolicyType.EXTERNAL);
@@ -393,7 +335,24 @@ var AllView = GObject.registerClass({
this._folderIcons = []; this._folderIcons = [];
this._stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
let box = new St.BoxLayout({
vertical: true,
y_align: Clutter.ActorAlign.START,
});
this._grid.currentPage = 0; this._grid.currentPage = 0;
this._stack.add_actor(this._grid);
this._eventBlocker = new St.Widget({
x_expand: true,
y_expand: true,
reactive: true,
visible: false,
});
this._stack.add_actor(this._eventBlocker);
box.add_actor(this._stack);
this._scrollView.add_actor(box);
this._scrollView.connect('scroll-event', this._onScroll.bind(this)); this._scrollView.connect('scroll-event', this._onScroll.bind(this));
@@ -433,12 +392,10 @@ var AllView = GObject.registerClass({
this._redisplayWorkId = Main.initializeDeferredWork(this, this._redisplay.bind(this)); this._redisplayWorkId = Main.initializeDeferredWork(this, this._redisplay.bind(this));
Shell.AppSystem.get_default().connect('installed-changed', () => { Shell.AppSystem.get_default().connect('installed-changed', () => {
this._viewIsReady = false;
Main.queueDeferredWork(this._redisplayWorkId); Main.queueDeferredWork(this._redisplayWorkId);
}); });
this._folderSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' }); this._folderSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' });
this._folderSettings.connect('changed::folder-children', () => { this._folderSettings.connect('changed::folder-children', () => {
this._viewIsReady = false;
Main.queueDeferredWork(this._redisplayWorkId); Main.queueDeferredWork(this._redisplayWorkId);
}); });
@@ -474,10 +431,6 @@ var AllView = GObject.registerClass({
_redisplay() { _redisplay() {
super._redisplay(); super._redisplay();
this._folderIcons.forEach(icon => {
icon.view._redisplay();
});
this._refilterApps(); this._refilterApps();
} }
@@ -528,7 +481,7 @@ var AllView = GObject.registerClass({
} catch (e) { } catch (e) {
return false; return false;
} }
return this._parentalControlsManager.shouldShowApp(appInfo); return appInfo.should_show();
}); });
let apps = this._appInfoList.map(app => app.get_id()); let apps = this._appInfoList.map(app => app.get_id());
@@ -638,7 +591,7 @@ var AllView = GObject.registerClass({
this._grid.currentPage = pageNumber; this._grid.currentPage = pageNumber;
// Animate the change between pages. // Tween the change between pages.
this._adjustment.ease(this._grid.getPageY(this._grid.currentPage), { this._adjustment.ease(this._grid.getPageY(this._grid.currentPage), {
mode: Clutter.AnimationMode.EASE_OUT_CUBIC, mode: Clutter.AnimationMode.EASE_OUT_CUBIC,
duration: animate ? PAGE_SWITCH_TIME : 0, duration: animate ? PAGE_SWITCH_TIME : 0,
@@ -669,7 +622,8 @@ var AllView = GObject.registerClass({
this._canScroll = true; this._canScroll = true;
this._scrollTimeoutId = 0; this._scrollTimeoutId = 0;
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); }
);
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
@@ -745,6 +699,8 @@ var AllView = GObject.registerClass({
// Toggle search entry // Toggle search entry
Main.overview.searchEntry.reactive = !isOpen; Main.overview.searchEntry.reactive = !isOpen;
Main.overview.searchEntry.clutter_text.reactive = !isOpen;
Main.overview.searchEntry.clutter_text.editable = !isOpen;
this._displayingPopup = isOpen; this._displayingPopup = isOpen;
}); });
@@ -1017,7 +973,7 @@ class FrequentView extends BaseAppView {
let favoritesWritable = global.settings.is_writable('favorite-apps'); let favoritesWritable = global.settings.is_writable('favorite-apps');
for (let i = 0; i < mostUsed.length; i++) { for (let i = 0; i < mostUsed.length; i++) {
if (!this._parentalControlsManager.shouldShowApp(mostUsed[i].get_app_info())) if (!mostUsed[i].get_app_info().should_show())
continue; continue;
let appIcon = this._items.get(mostUsed[i].get_id()); let appIcon = this._items.get(mostUsed[i].get_id());
if (!appIcon) { if (!appIcon) {
@@ -1263,8 +1219,6 @@ var AppSearchProvider = class AppSearchProvider {
this.canLaunchSearch = false; this.canLaunchSearch = false;
this._systemActions = new SystemActions.getDefault(); this._systemActions = new SystemActions.getDefault();
this._parentalControlsManager = ParentalControlsManager.getDefault();
} }
getResultMetas(apps, callback) { getResultMetas(apps, callback) {
@@ -1299,30 +1253,18 @@ var AppSearchProvider = class AppSearchProvider {
} }
getInitialResultSet(terms, callback, _cancellable) { getInitialResultSet(terms, callback, _cancellable) {
// Defer until the parental controls manager is initialised, so the
// results can be filtered correctly.
if (!this._parentalControlsManager.initialized) {
let initializedId = this._parentalControlsManager.connect('app-filter-changed', () => {
if (this._parentalControlsManager.initialized) {
this._parentalControlsManager.disconnect(initializedId);
this.getInitialResultSet(terms, callback, _cancellable);
}
});
return;
}
let query = terms.join(' '); let query = terms.join(' ');
let groups = Shell.AppSystem.search(query); let groups = Shell.AppSystem.search(query);
let usage = Shell.AppUsage.get_default(); let usage = Shell.AppUsage.get_default();
let results = []; let results = [];
groups.forEach(group => { groups.forEach(group => {
group = group.filter(appID => { group = group.filter(appID => {
const app = this._appSys.lookup_app(appID); let app = Gio.DesktopAppInfo.new(appID);
return app && this._parentalControlsManager.shouldShowApp(app.app_info); return app && app.should_show();
}); });
results = results.concat(group.sort( results = results.concat(group.sort(
(a, b) => usage.compare(a, b))); (a, b) => usage.compare(a, b)
));
}); });
results = results.concat(this._systemActions.getMatchingActions(terms)); results = results.concat(this._systemActions.getMatchingActions(terms));
@@ -1366,7 +1308,7 @@ class FolderView extends BaseAppView {
x_expand: true, x_expand: true,
y_expand: true, y_expand: true,
}); });
this._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); this._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.AUTOMATIC);
this.add_actor(this._scrollView); this.add_actor(this._scrollView);
let scrollableContainer = new St.BoxLayout({ let scrollableContainer = new St.BoxLayout({
@@ -1382,6 +1324,7 @@ class FolderView extends BaseAppView {
action.connect('pan', this._onPan.bind(this)); action.connect('pan', this._onPan.bind(this));
this._scrollView.add_action(action); this._scrollView.add_action(action);
this._folder.connect('changed', this._redisplay.bind(this));
this._redisplay(); this._redisplay();
} }
@@ -1403,12 +1346,12 @@ class FolderView extends BaseAppView {
}); });
layout.hookup_style(icon); layout.hookup_style(icon);
let subSize = Math.floor(FOLDER_SUBICON_FRACTION * size); let subSize = Math.floor(FOLDER_SUBICON_FRACTION * size);
let scale = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let numItems = this._orderedItems.length; let numItems = this._orderedItems.length;
let rtl = icon.get_text_direction() == Clutter.TextDirection.RTL; let rtl = icon.get_text_direction() == Clutter.TextDirection.RTL;
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
const style = 'width: %dpx; height: %dpx;'.format(subSize, subSize); let bin = new St.Bin({ width: subSize * scale, height: subSize * scale });
let bin = new St.Bin({ style });
if (i < numItems) if (i < numItems)
bin.child = this._orderedItems[i].app.create_icon_texture(subSize); bin.child = this._orderedItems[i].app.create_icon_texture(subSize);
layout.attach(bin, rtl ? (i + 1) % 2 : i % 2, Math.floor(i / 2), 1, 1); layout.attach(bin, rtl ? (i + 1) % 2 : i % 2, Math.floor(i / 2), 1, 1);
@@ -1457,7 +1400,7 @@ class FolderView extends BaseAppView {
if (!app) if (!app)
return; return;
if (!this._parentalControlsManager.shouldShowApp(app.get_app_info())) if (!app.get_app_info().should_show())
return; return;
if (apps.some(appIcon => appIcon.id == appId)) if (apps.some(appIcon => appIcon.id == appId))
@@ -1486,22 +1429,6 @@ class FolderView extends BaseAppView {
return apps; return apps;
} }
addApp(app) {
let folderApps = this._folder.get_strv('apps');
folderApps.push(app.id);
this._folder.set_strv('apps', folderApps);
// Also remove from 'excluded-apps' if the app id is listed
// there. This is only possible on categories-based folders.
let excludedApps = this._folder.get_strv('excluded-apps');
let index = excludedApps.indexOf(app.id);
if (index >= 0) {
excludedApps.splice(index, 1);
this._folder.set_strv('excluded-apps', excludedApps);
}
}
removeApp(app) { removeApp(app) {
let folderApps = this._folder.get_strv('apps'); let folderApps = this._folder.get_strv('apps');
let index = folderApps.indexOf(app.id); let index = folderApps.indexOf(app.id);
@@ -1532,6 +1459,8 @@ class FolderView extends BaseAppView {
} else { } else {
this._folder.set_strv('apps', folderApps); this._folder.set_strv('apps', folderApps);
} }
return true;
} }
}); });
@@ -1565,26 +1494,26 @@ var FolderIcon = GObject.registerClass({
this.view = new FolderView(this._folder, id, parentView); this.view = new FolderView(this._folder, id, parentView);
this._iconIsHovering = false; this._itemDragBeginId = Main.overview.connect(
'item-drag-begin', this._onDragBegin.bind(this));
this._itemDragEndId = Main.overview.connect(
'item-drag-end', this._onDragEnd.bind(this));
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
this._folderChangedId = this._folder.connect( this._folder.connect('changed', this._redisplay.bind(this));
'changed', this._sync.bind(this)); this._redisplay();
this._sync();
} }
_onDestroy() { _onDestroy() {
if (this._dragMonitor) { Main.overview.disconnect(this._itemDragBeginId);
DND.removeDragMonitor(this._dragMonitor); Main.overview.disconnect(this._itemDragEndId);
this._dragMonitor = null;
}
this.view.destroy(); this.view.destroy();
if (this._folderChangedId) { if (this._spaceReadySignalId) {
this._folder.disconnect(this._folderChangedId); this._parentView.disconnect(this._spaceReadySignalId);
delete this._folderChangedId; this._spaceReadySignalId = 0;
} }
if (this._dialog) if (this._dialog)
@@ -1612,32 +1541,29 @@ var FolderIcon = GObject.registerClass({
return this.view.getAllItems().map(item => item.id); return this.view.getAllItems().map(item => item.id);
} }
_setHoveringByDnd(hovering) { _onDragBegin() {
if (this._iconIsHovering == hovering) this._dragMonitor = {
return; dragMotion: this._onDragMotion.bind(this),
};
this._iconIsHovering = hovering; DND.addDragMonitor(this._dragMonitor);
if (hovering) {
this._dragMonitor = {
dragMotion: this._onDragMotion.bind(this),
};
DND.addDragMonitor(this._dragMonitor);
this.add_style_pseudo_class('drop');
} else {
DND.removeDragMonitor(this._dragMonitor);
this.remove_style_pseudo_class('drop');
}
} }
_onDragMotion(dragEvent) { _onDragMotion(dragEvent) {
if (!this.contains(dragEvent.targetActor) || let target = dragEvent.targetActor;
!this._canAccept(dragEvent.source))
this._setHoveringByDnd(false); if (!this.contains(target) || !this._canAccept(dragEvent.source))
this.remove_style_pseudo_class('drop');
else
this.add_style_pseudo_class('drop');
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
} }
_onDragEnd() {
this.remove_style_pseudo_class('drop');
DND.removeDragMonitor(this._dragMonitor);
}
_canAccept(source) { _canAccept(source) {
if (!(source instanceof AppIcon)) if (!(source instanceof AppIcon))
return false; return false;
@@ -1656,18 +1582,27 @@ var FolderIcon = GObject.registerClass({
if (!this._canAccept(source)) if (!this._canAccept(source))
return DND.DragMotionResult.NO_DROP; return DND.DragMotionResult.NO_DROP;
this._setHoveringByDnd(true);
return DND.DragMotionResult.MOVE_DROP; return DND.DragMotionResult.MOVE_DROP;
} }
acceptDrop(source) { acceptDrop(source) {
this._setHoveringByDnd(false);
if (!this._canAccept(source)) if (!this._canAccept(source))
return false; return false;
this.view.addApp(source.app); let app = source.app;
let folderApps = this._folder.get_strv('apps');
folderApps.push(app.id);
this._folder.set_strv('apps', folderApps);
// Also remove from 'excluded-apps' if the app id is listed
// there. This is only possible on categories-based folders.
let excludedApps = this._folder.get_strv('excluded-apps');
let index = excludedApps.indexOf(app.id);
if (index >= 0) {
excludedApps.splice(index, 1);
this._folder.set_strv('excluded-apps', excludedApps);
}
return true; return true;
} }
@@ -1682,11 +1617,11 @@ var FolderIcon = GObject.registerClass({
this.emit('name-changed'); this.emit('name-changed');
} }
_sync() { _redisplay() {
this.emit('apps-changed');
this._updateName(); this._updateName();
this.visible = this.view.getAllItems().length > 0; this.visible = this.view.getAllItems().length > 0;
this.icon.update(); this.icon.update();
this.emit('apps-changed');
} }
_createIcon(iconSize) { _createIcon(iconSize) {
@@ -1967,7 +1902,6 @@ var AppFolderDialog = GObject.registerClass({
vfunc_allocate(box, flags) { vfunc_allocate(box, flags) {
let contentBox = this.get_theme_node().get_content_box(box); let contentBox = this.get_theme_node().get_content_box(box);
contentBox = this._viewBox.get_theme_node().get_content_box(contentBox);
let [, entryBoxHeight] = this._entryBox.get_size(); let [, entryBoxHeight] = this._entryBox.get_size();
let spacing = this._viewBox.layout_manager.spacing; let spacing = this._viewBox.layout_manager.spacing;
@@ -1976,8 +1910,6 @@ var AppFolderDialog = GObject.registerClass({
contentBox.get_width(), contentBox.get_width(),
contentBox.get_height() - entryBoxHeight - spacing); contentBox.get_height() - entryBoxHeight - spacing);
this._view._grid.topPadding = 0;
super.vfunc_allocate(box, flags); super.vfunc_allocate(box, flags);
// We can only start zooming after receiving an allocation // We can only start zooming after receiving an allocation
@@ -2093,6 +2025,7 @@ var AppIcon = GObject.registerClass({
this._delegate = this; this._delegate = this;
this._hasDndHover = false;
this._folderPreviewId = 0; this._folderPreviewId = 0;
// Get the isDraggable property without passing it on to the BaseIcon: // Get the isDraggable property without passing it on to the BaseIcon:
@@ -2141,7 +2074,11 @@ var AppIcon = GObject.registerClass({
}); });
} }
this._otherIconIsHovering = false; this._dragMonitor = null;
this._itemDragBeginId = Main.overview.connect(
'item-drag-begin', this._onDragBegin.bind(this));
this._itemDragEndId = Main.overview.connect(
'item-drag-end', this._onDragEnd.bind(this));
this._menuTimeoutId = 0; this._menuTimeoutId = 0;
this._stateChangedId = this.app.connect('notify::state', () => { this._stateChangedId = this.app.connect('notify::state', () => {
@@ -2153,6 +2090,9 @@ var AppIcon = GObject.registerClass({
} }
_onDestroy() { _onDestroy() {
Main.overview.disconnect(this._itemDragBeginId);
Main.overview.disconnect(this._itemDragEndId);
if (this._folderPreviewId > 0) { if (this._folderPreviewId > 0) {
GLib.source_remove(this._folderPreviewId); GLib.source_remove(this._folderPreviewId);
this._folderPreviewId = 0; this._folderPreviewId = 0;
@@ -2203,7 +2143,7 @@ var AppIcon = GObject.registerClass({
} }
vfunc_leave_event(crossingEvent) { vfunc_leave_event(crossingEvent) {
const ret = super.vfunc_leave_event(crossingEvent); let ret = super.vfunc_leave_event(crossingEvent);
this.fake_release(); this.fake_release();
this._removeMenuTimeout(); this._removeMenuTimeout();
@@ -2211,22 +2151,22 @@ var AppIcon = GObject.registerClass({
} }
vfunc_button_press_event(buttonEvent) { vfunc_button_press_event(buttonEvent) {
const ret = super.vfunc_button_press_event(buttonEvent); super.vfunc_button_press_event(buttonEvent);
if (buttonEvent.button == 1) { if (buttonEvent.button == 1) {
this._setPopupTimeout(); this._setPopupTimeout();
} else if (buttonEvent.button == 3) { } else if (buttonEvent.button == 3) {
this.popupMenu(); this.popupMenu();
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
return ret; return Clutter.EVENT_PROPAGATE;
} }
vfunc_touch_event(touchEvent) { vfunc_touch_event(touchEvent) {
const ret = super.vfunc_touch_event(touchEvent); super.vfunc_touch_event(touchEvent);
if (touchEvent.type == Clutter.EventType.TOUCH_BEGIN) if (touchEvent.type == Clutter.EventType.TOUCH_BEGIN)
this._setPopupTimeout(); this._setPopupTimeout();
return ret; return Clutter.EVENT_PROPAGATE;
} }
vfunc_clicked(button) { vfunc_clicked(button) {
@@ -2399,17 +2339,7 @@ var AppIcon = GObject.registerClass({
} }
_setHoveringByDnd(hovering) { _setHoveringByDnd(hovering) {
if (this._otherIconIsHovering == hovering)
return;
this._otherIconIsHovering = hovering;
if (hovering) { if (hovering) {
this._dragMonitor = {
dragMotion: this._onDragMotion.bind(this),
};
DND.addDragMonitor(this._dragMonitor);
if (this._folderPreviewId > 0) if (this._folderPreviewId > 0)
return; return;
@@ -2421,8 +2351,6 @@ var AppIcon = GObject.registerClass({
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
} else { } else {
DND.removeDragMonitor(this._dragMonitor);
if (this._folderPreviewId > 0) { if (this._folderPreviewId > 0) {
GLib.source_remove(this._folderPreviewId); GLib.source_remove(this._folderPreviewId);
this._folderPreviewId = 0; this._folderPreviewId = 0;
@@ -2432,13 +2360,32 @@ var AppIcon = GObject.registerClass({
} }
} }
_onDragBegin() {
this._dragMonitor = {
dragMotion: this._onDragMotion.bind(this),
};
DND.addDragMonitor(this._dragMonitor);
}
_onDragMotion(dragEvent) { _onDragMotion(dragEvent) {
if (!this.contains(dragEvent.targetActor)) let target = dragEvent.targetActor;
this._setHoveringByDnd(false); let isHovering = target == this || this.contains(target);
let canDrop = this._canAccept(dragEvent.source);
let hasDndHover = isHovering && canDrop;
if (this._hasDndHover != hasDndHover) {
this._setHoveringByDnd(hasDndHover);
this._hasDndHover = hasDndHover;
}
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
} }
_onDragEnd() {
this.remove_style_pseudo_class('drop');
DND.removeDragMonitor(this._dragMonitor);
}
handleDragOver(source) { handleDragOver(source) {
if (source == this) if (source == this)
return DND.DragMotionResult.NO_DROP; return DND.DragMotionResult.NO_DROP;
@@ -2446,8 +2393,6 @@ var AppIcon = GObject.registerClass({
if (!this._canAccept(source)) if (!this._canAccept(source))
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
this._setHoveringByDnd(true);
return DND.DragMotionResult.MOVE_DROP; return DND.DragMotionResult.MOVE_DROP;
} }
@@ -2492,16 +2437,18 @@ var AppIconMenu = class AppIconMenu extends PopupMenu.PopupMenu {
Main.uiGroup.add_actor(this.actor); Main.uiGroup.add_actor(this.actor);
} }
_rebuildMenu() { _redisplay() {
this.removeAll(); this.removeAll();
let windows = this._source.app.get_windows().filter( let windows = this._source.app.get_windows().filter(
w => !w.skip_taskbar); w => !w.skip_taskbar
);
if (windows.length > 0) { if (windows.length > 0) {
this.addMenuItem( this.addMenuItem(
/* Translators: This is the heading of a list of open windows */ /* Translators: This is the heading of a list of open windows */
new PopupMenu.PopupSeparatorMenuItem(_('Open Windows'))); new PopupMenu.PopupSeparatorMenuItem(_("Open Windows"))
);
} }
windows.forEach(window => { windows.forEach(window => {
@@ -2576,18 +2523,19 @@ var AppIconMenu = class AppIconMenu extends PopupMenu.PopupMenu {
if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) { if (Shell.AppSystem.get_default().lookup_app('org.gnome.Software.desktop')) {
this._appendSeparator(); this._appendSeparator();
let item = this._appendMenuItem(_("Show Details")); let item = this._appendMenuItem(_("Show Details"));
item.connect('activate', async () => { item.connect('activate', () => {
let id = this._source.app.get_id(); let id = this._source.app.get_id();
let args = GLib.Variant.new('(ss)', [id, '']); let args = GLib.Variant.new('(ss)', [id, '']);
const bus = await Gio.DBus.get(Gio.BusType.SESSION, null); Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => {
bus.call( let bus = Gio.DBus.get_finish(res);
'org.gnome.Software', bus.call('org.gnome.Software',
'/org/gnome/Software', '/org/gnome/Software',
'org.gtk.Actions', 'Activate', 'org.gtk.Actions', 'Activate',
new GLib.Variant.new( GLib.Variant.new('(sava{sv})',
'(sava{sv})', ['details', [args], null]), ['details', [args], null]),
null, 0, -1, null); null, 0, -1, null, null);
Main.overview.hide(); Main.overview.hide();
});
}); });
} }
} }
@@ -2606,7 +2554,7 @@ var AppIconMenu = class AppIconMenu extends PopupMenu.PopupMenu {
} }
popup(_activatingButton) { popup(_activatingButton) {
this._rebuildMenu(); this._redisplay();
this.open(); this.open();
} }
}; };

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;
@@ -65,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));
@@ -103,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];
@@ -142,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

@@ -197,11 +197,6 @@ var BoxPointer = GObject.registerClass({
} }
vfunc_allocate(box, flags) { vfunc_allocate(box, flags) {
if (this._sourceActor && this._sourceActor.mapped) {
this._reposition(box);
this._updateFlip(box);
}
this.set_allocation(box, flags); this.set_allocation(box, flags);
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
@@ -235,6 +230,12 @@ var BoxPointer = GObject.registerClass({
break; break;
} }
this.bin.allocate(childBox, flags); this.bin.allocate(childBox, flags);
if (this._sourceActor && this._sourceActor.mapped) {
this._reposition(box);
this._updateFlip(box);
this.set_allocation(box, flags);
}
} }
_drawBorder(area) { _drawBorder(area) {

View File

@@ -199,52 +199,48 @@ class DBusEventSource extends EventSourceBase {
this._initialized = false; this._initialized = false;
this._dbusProxy = new CalendarServer(); this._dbusProxy = new CalendarServer();
this._initProxy(); this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, (object, result) => {
} let loaded = false;
async _initProxy() { try {
let loaded = false; this._dbusProxy.init_finish(result);
loaded = true;
try { } catch (e) {
await this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null); if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
loaded = true; // Ignore timeouts and install signals as normal, because with high
} catch (e) { // probability the service will appear later on, and we will get a
// Ignore timeouts and install signals as normal, because with high // NameOwnerChanged which will finish loading
// probability the service will appear later on, and we will get a //
// NameOwnerChanged which will finish loading // (But still _initialized to false, because the proxy does not know
// // about the HasCalendars property and would cause an exception trying
// (But still _initialized to false, because the proxy does not know // to read it)
// about the HasCalendars property and would cause an exception trying } else {
// to read it) log('Error loading calendars: %s'.format(e.message));
if (!e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) { return;
log('Error loading calendars: %s'.format(e.message)); }
return;
} }
}
this._dbusProxy.connectSignal('EventsAddedOrUpdated', this._dbusProxy.connectSignal('EventsAdded', this._onEventsAdded.bind(this));
this._onEventsAddedOrUpdated.bind(this)); this._dbusProxy.connectSignal('EventsRemoved', this._onEventsRemoved.bind(this));
this._dbusProxy.connectSignal('EventsRemoved', this._dbusProxy.connectSignal('ClientDisappeared', this._onClientDisappeared.bind(this));
this._onEventsRemoved.bind(this));
this._dbusProxy.connectSignal('ClientDisappeared',
this._onClientDisappeared.bind(this));
this._dbusProxy.connect('notify::g-name-owner', () => { this._dbusProxy.connect('notify::g-name-owner', () => {
if (this._dbusProxy.g_name_owner) if (this._dbusProxy.g_name_owner)
this._onNameAppeared();
else
this._onNameVanished();
});
this._dbusProxy.connect('g-properties-changed', () => {
this.notify('has-calendars');
});
this._initialized = loaded;
if (loaded) {
this.notify('has-calendars');
this._onNameAppeared(); this._onNameAppeared();
else }
this._onNameVanished();
}); });
this._dbusProxy.connect('g-properties-changed', () => {
this.notify('has-calendars');
});
this._initialized = loaded;
if (loaded) {
this.notify('has-calendars');
this._onNameAppeared();
}
} }
destroy() { destroy() {
@@ -279,14 +275,17 @@ class DBusEventSource extends EventSourceBase {
this.emit('changed'); this.emit('changed');
} }
_onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) { _onEventsAdded(dbusProxy, nameOwner, argArray) {
const [appointments = []] = argArray; let appointments = argArray[0] || [];
let changed = false; let changed = false;
for (let n = 0; n < appointments.length; n++) { for (let n = 0; n < appointments.length; n++) {
const [id, summary, allDay, startTime, endTime] = appointments[n]; let a = appointments[n];
const date = new Date(startTime * 1000); let id = a[0];
const end = new Date(endTime * 1000); let summary = a[1];
let allDay = a[2];
let date = new Date(a[3] * 1000);
let end = new Date(a[4] * 1000);
let event = new CalendarEvent(id, date, end, summary, allDay); let event = new CalendarEvent(id, date, end, summary, allDay);
this._events.set(event.id, event); this._events.set(event.id, event);
@@ -298,24 +297,33 @@ class DBusEventSource extends EventSourceBase {
} }
_onEventsRemoved(dbusProxy, nameOwner, argArray) { _onEventsRemoved(dbusProxy, nameOwner, argArray) {
const [ids = []] = argArray; let ids = argArray[0] || [];
let changed = false; let changed = false;
for (const id of ids)
changed |= this._events.delete(id); for (let n = 0; n < ids.length; n++) {
let id = ids[n];
if (this._events.delete(id))
changed = true;
}
if (changed) if (changed)
this.emit('changed'); this.emit('changed');
} }
_onClientDisappeared(dbusProxy, nameOwner, argArray) { _onClientDisappeared(dbusProxy, nameOwner, argArray) {
let [sourceUid = ''] = argArray; let sourceUid = argArray[0] || "";
let changed = false;
let idsIter = this._events.keys();
sourceUid += '\n'; sourceUid += '\n';
let changed = false; for (let item = idsIter.next(); !item.done; item = idsIter.next()) {
for (const id of this._events.keys()) { let id = item.value;
if (id.startsWith(sourceUid))
changed |= this._events.delete(id); if (id.startsWith(sourceUid) &&
this._events.delete(id))
changed = true;
} }
if (changed) if (changed)
@@ -332,11 +340,10 @@ class DBusEventSource extends EventSourceBase {
this._events.clear(); this._events.clear();
this.emit('changed'); this.emit('changed');
} }
this._dbusProxy.SetTimeRangeRemote( this._dbusProxy.SetTimeRangeRemote(this._curRequestBegin.getTime() / 1000,
this._curRequestBegin.getTime() / 1000, this._curRequestEnd.getTime() / 1000,
this._curRequestEnd.getTime() / 1000, forceReload,
forceReload, Gio.DBusCallFlags.NONE);
Gio.DBusCallFlags.NONE);
} }
} }
@@ -350,16 +357,20 @@ class DBusEventSource extends EventSourceBase {
} }
} }
*_getFilteredEvents(begin, end) { getEvents(begin, end, onlyCheckExistence) {
for (const event of this._events.values()) { let result = [];
if (_dateIntervalsOverlap(event.date, event.end, begin, end)) let eventsIter = this._events.values();
yield event;
for (let item = eventsIter.next(); !item.done; item = eventsIter.next()) {
let event = item.value;
if (_dateIntervalsOverlap(event.date, event.end, begin, end)) {
result.push(event);
if (onlyCheckExistence)
return result;
}
} }
}
getEvents(begin, end) {
let result = [...this._getFilteredEvents(begin, end)];
result.sort((event1, event2) => { result.sort((event1, event2) => {
// sort events by end time on ending day // sort events by end time on ending day
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date; let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
@@ -373,8 +384,12 @@ class DBusEventSource extends EventSourceBase {
let dayBegin = _getBeginningOfDay(day); let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day); let dayEnd = _getEndOfDay(day);
const { done } = this._getFilteredEvents(dayBegin, dayEnd).next(); let events = this.getEvents(dayBegin, dayEnd, true);
return !done;
if (events.length == 0)
return false;
return true;
} }
}); });
@@ -726,11 +741,12 @@ var Calendar = GObject.registerClass({
var EventMessage = GObject.registerClass( var EventMessage = GObject.registerClass(
class EventMessage extends MessageList.Message { class EventMessage extends MessageList.Message {
_init(event, date) { _init(event, date) {
super._init('', ''); super._init('', event.summary);
this._event = event;
this._date = date; this._date = date;
this.update(event); this.setTitle(this._formatEventTime());
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' }); this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
this.setIcon(this._icon); this.setIcon(this._icon);
@@ -742,13 +758,6 @@ class EventMessage extends MessageList.Message {
super.vfunc_style_changed(); super.vfunc_style_changed();
} }
update(event) {
this._event = event;
this.setTitle(this._formatEventTime());
this.setBody(event.summary);
}
_formatEventTime() { _formatEventTime() {
let periodBegin = _getBeginningOfDay(this._date); let periodBegin = _getBeginningOfDay(this._date);
let periodEnd = _getEndOfDay(this._date); let periodEnd = _getEndOfDay(this._date);
@@ -869,9 +878,8 @@ class EventsSection extends MessageList.MessageListSection {
this._title.connect('clicked', this._onTitleClicked.bind(this)); this._title.connect('clicked', this._onTitleClicked.bind(this));
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this)); this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
this._appSys = Shell.AppSystem.get_default(); Shell.AppSystem.get_default().connect('installed-changed',
this._appSys.connect('installed-changed', this._appInstalledChanged.bind(this));
this._appInstalledChanged.bind(this));
this._appInstalledChanged(); this._appInstalledChanged();
} }
@@ -915,10 +923,7 @@ class EventsSection extends MessageList.MessageListSection {
let periodEnd = _getEndOfDay(this._date); let periodEnd = _getEndOfDay(this._date);
let events = this._eventSource.getEvents(periodBegin, periodEnd); let events = this._eventSource.getEvents(periodBegin, periodEnd);
let ids = events.map(e => e.id);
this._messageById.forEach((message, id) => { this._messageById.forEach((message, id) => {
if (ids.includes(id))
return;
this._messageById.delete(id); this._messageById.delete(id);
this.removeMessage(message); this.removeMessage(message);
}); });
@@ -932,7 +937,6 @@ class EventsSection extends MessageList.MessageListSection {
this._messageById.set(event.id, message); this._messageById.set(event.id, message);
this.addMessage(message, false); this.addMessage(message, false);
} else { } else {
message.update(event);
this.moveMessage(message, i, false); this.moveMessage(message, i, false);
} }
} }
@@ -965,13 +969,10 @@ class EventsSection extends MessageList.MessageListSection {
Main.overview.hide(); Main.overview.hide();
Main.panel.closeCalendar(); Main.panel.closeCalendar();
let appInfo = this._getCalendarApp(); let app = this._getCalendarApp();
if (appInfo.get_id() === 'org.gnome.Evolution.desktop') { if (app.get_id() == 'evolution.desktop')
let app = this._appSys.lookup_app('evolution-calendar.desktop'); app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
if (app) app.launch([], global.create_app_launch_context(0, -1));
appInfo = app.app_info;
}
appInfo.launch([], global.create_app_launch_context(0, -1));
} }
setDate(date) { setDate(date) {
@@ -1186,22 +1187,17 @@ class CalendarMessageList extends St.Widget {
let hbox = new St.BoxLayout({ style_class: 'message-list-controls' }); let hbox = new St.BoxLayout({ style_class: 'message-list-controls' });
box.add_child(hbox); box.add_child(hbox);
const dndLabel = new St.Label({ hbox.add_child(new St.Label({
text: _('Do Not Disturb'), text: _('Do Not Disturb'),
y_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER,
}); }));
hbox.add_child(dndLabel);
this._dndSwitch = new DoNotDisturbSwitch(); this._dndSwitch = new DoNotDisturbSwitch();
this._dndButton = new St.Button({ this._dndButton = new St.Button({
can_focus: true, can_focus: true,
toggle_mode: true,
child: this._dndSwitch, child: this._dndSwitch,
label_actor: dndLabel,
}); });
this._dndButton.bind_property('checked', this._dndButton.connect('clicked', () => this._dndSwitch.toggle());
this._dndSwitch, 'state',
GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE);
hbox.add_child(this._dndButton); hbox.add_child(this._dndButton);
this._clearButton = new St.Button({ this._clearButton = new St.Button({

View File

@@ -1,5 +1,5 @@
/* exported CheckBox */ /* exported CheckBox */
const { Atk, Clutter, GObject, Pango, St } = imports.gi; const { Clutter, GObject, Pango, St } = imports.gi;
var CheckBox = GObject.registerClass( var CheckBox = GObject.registerClass(
class CheckBox extends St.Button { class CheckBox extends St.Button {
@@ -15,7 +15,6 @@ class CheckBox extends St.Button {
toggle_mode: true, toggle_mode: true,
can_focus: true, can_focus: true,
}); });
this.set_accessible_role(Atk.Role.CHECK_BOX);
this._box = new St.Bin({ y_align: Clutter.ActorAlign.START }); this._box = new St.Bin({ y_align: Clutter.ActorAlign.START });
container.add_actor(this._box); container.add_actor(this._box);
@@ -23,7 +22,6 @@ class CheckBox extends St.Button {
this._label = new St.Label({ y_align: Clutter.ActorAlign.CENTER }); this._label = new St.Label({ y_align: Clutter.ActorAlign.CENTER });
this._label.clutter_text.set_line_wrap(true); this._label.clutter_text.set_line_wrap(true);
this._label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE); this._label.clutter_text.set_ellipsize(Pango.EllipsizeMode.NONE);
this.set_label_actor(this._label);
container.add_actor(this._label); container.add_actor(this._label);
if (label) if (label)

View File

@@ -188,8 +188,6 @@ var CloseDialog = GObject.registerClass({
global.stage.disconnect(this._keyFocusChangedId); global.stage.disconnect(this._keyFocusChangedId);
this._keyFocusChangedId = 0; this._keyFocusChangedId = 0;
this._dialog._dialog.remove_all_transitions();
let dialog = this._dialog; let dialog = this._dialog;
this._dialog = null; this._dialog = null;
this._removeWindowEffect(); this._removeWindowEffect();

View File

@@ -13,13 +13,17 @@ var ComponentManager = class {
_sessionUpdated() { _sessionUpdated() {
let newEnabledComponents = Main.sessionMode.components; let newEnabledComponents = Main.sessionMode.components;
newEnabledComponents newEnabledComponents.filter(
.filter(name => !this._enabledComponents.includes(name)) name => !this._enabledComponents.includes(name)
.forEach(name => this._enableComponent(name)); ).forEach(name => {
this._enableComponent(name);
});
this._enabledComponents this._enabledComponents.filter(
.filter(name => !newEnabledComponents.includes(name)) name => !newEnabledComponents.includes(name)
.forEach(name => this._disableComponent(name)); ).forEach(name => {
this._disableComponent(name);
});
this._enabledComponents = newEnabledComponents; this._enabledComponents = newEnabledComponents;
} }

View File

@@ -125,7 +125,8 @@ var ContentTypeDiscoverer = class {
_emitCallback(mount, contentTypes = []) { _emitCallback(mount, contentTypes = []) {
// we're not interested in win32 software content types here // we're not interested in win32 software content types here
contentTypes = contentTypes.filter( contentTypes = contentTypes.filter(
type => type !== 'x-content/win32-software'); type => type != 'x-content/win32-software'
);
let apps = []; let apps = [];
contentTypes.forEach(type => { contentTypes.forEach(type => {

View File

@@ -111,11 +111,15 @@ class KeyringDialog extends ModalDialog.ModalDialog {
} }
_updateSensitivity(sensitive) { _updateSensitivity(sensitive) {
if (this._passwordEntry) if (this._passwordEntry) {
this._passwordEntry.reactive = sensitive; this._passwordEntry.reactive = sensitive;
this._passwordEntry.clutter_text.editable = sensitive;
}
if (this._confirmEntry) if (this._confirmEntry) {
this._confirmEntry.reactive = sensitive; this._confirmEntry.reactive = sensitive;
this._confirmEntry.clutter_text.editable = sensitive;
}
this._continueButton.can_focus = sensitive; this._continueButton.can_focus = sensitive;
this._continueButton.reactive = sensitive; this._continueButton.reactive = sensitive;

View File

@@ -4,16 +4,13 @@
const { Clutter, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Config = imports.misc.config;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
const Main = imports.ui.main; const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray; const MessageTray = imports.ui.messageTray;
const ModalDialog = imports.ui.modalDialog; const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry; const ShellEntry = imports.ui.shellEntry;
Gio._promisify(Shell.NetworkAgent.prototype, 'init_async', 'init_finish');
Gio._promisify(Shell.NetworkAgent.prototype,
'search_vpn_plugin', 'search_vpn_plugin_finish');
const VPN_UI_GROUP = 'VPN Plugin UI'; const VPN_UI_GROUP = 'VPN Plugin UI';
var NetworkSecretDialog = GObject.registerClass( var NetworkSecretDialog = GObject.registerClass(
@@ -483,37 +480,39 @@ var VPNRequestHandler = class {
} }
} }
async _readStdoutOldStyle() { _readStdoutOldStyle() {
const [line, len_] = this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, (stream, result) => {
await this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null); let [line, len_] = this._dataStdout.read_line_finish_utf8(result);
if (line === null) { if (line == null) {
// end of file // end of file
this._stdout.close(null); this._stdout.close(null);
return; return;
} }
this._vpnChildProcessLineOldStyle(line); this._vpnChildProcessLineOldStyle(line);
// try to read more! // try to read more!
this._readStdoutOldStyle(); this._readStdoutOldStyle();
});
} }
async _readStdoutNewStyle() { _readStdoutNewStyle() {
const cnt = this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null, (stream, result) => {
await this._dataStdout.fill_async(-1, GLib.PRIORITY_DEFAULT, null); let cnt = this._dataStdout.fill_finish(result);
if (cnt === 0) { if (cnt == 0) {
// end of file // end of file
this._showNewStyleDialog(); this._showNewStyleDialog();
this._stdout.close(null); this._stdout.close(null);
return; return;
} }
// Try to read more // Try to read more
this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size()); this._dataStdout.set_buffer_size(2 * this._dataStdout.get_buffer_size());
this._readStdoutNewStyle(); this._readStdoutNewStyle();
});
} }
_showNewStyleDialog() { _showNewStyleDialog() {
@@ -616,21 +615,27 @@ var NetworkAgent = class {
this._vpnRequests = { }; this._vpnRequests = { };
this._notifications = { }; this._notifications = { };
this._pluginDir = Gio.file_new_for_path(Config.VPNDIR);
try {
let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null);
monitor.connect('changed', () => (this._vpnCacheBuilt = false));
} catch (e) {
log('Failed to create monitor for VPN plugin dir: %s'.format(e.message));
}
this._native.connect('new-request', this._newRequest.bind(this)); this._native.connect('new-request', this._newRequest.bind(this));
this._native.connect('cancel-request', this._cancelRequest.bind(this)); this._native.connect('cancel-request', this._cancelRequest.bind(this));
this._initialized = false; this._initialized = false;
this._initNative(); this._native.init_async(GLib.PRIORITY_DEFAULT, null, (o, res) => {
} try {
this._native.init_finish(res);
async _initNative() { this._initialized = true;
try { } catch (e) {
await this._native.init_async(GLib.PRIORITY_DEFAULT, null); this._native = null;
this._initialized = true; logError(e, 'error initializing the NetworkManager Agent');
} catch (e) { }
this._native = null; });
logError(e, 'error initializing the NetworkManager Agent');
}
} }
enable() { enable() {
@@ -761,11 +766,13 @@ var NetworkAgent = class {
} }
} }
async _vpnRequest(requestId, connection, hints, flags) { _vpnRequest(requestId, connection, hints, flags) {
let vpnSetting = connection.get_setting_vpn(); let vpnSetting = connection.get_setting_vpn();
let serviceType = vpnSetting.service_type; let serviceType = vpnSetting.service_type;
let binary = await this._findAuthBinary(serviceType); this._buildVPNServiceCache();
let binary = this._vpnBinaries[serviceType];
if (!binary) { if (!binary) {
log('Invalid VPN service type (cannot find authentication binary)'); log('Invalid VPN service type (cannot find authentication binary)');
@@ -781,30 +788,36 @@ var NetworkAgent = class {
this._vpnRequests[requestId] = vpnRequest; this._vpnRequests[requestId] = vpnRequest;
} }
async _findAuthBinary(serviceType) { _buildVPNServiceCache() {
let plugin; if (this._vpnCacheBuilt)
return;
try { this._vpnCacheBuilt = true;
plugin = await this._native.search_vpn_plugin(serviceType); this._vpnBinaries = { };
} catch (e) {
logError(e);
return null;
}
const fileName = plugin.get_auth_dialog(); NM.VpnPluginInfo.list_load().forEach(plugin => {
if (!GLib.file_test(fileName, GLib.FileTest.IS_EXECUTABLE)) { let service = plugin.get_service();
log('VPN plugin at %s is not executable'.format(fileName)); let fileName = plugin.get_auth_dialog();
return null; let supportsHints = plugin.supports_hints();
} let externalUIMode = false;
const prop = plugin.lookup_property('GNOME', 'supports-external-ui-mode'); let prop = plugin.lookup_property('GNOME', 'supports-external-ui-mode');
const trimmedProp = prop ? prop.trim().toLowerCase() : ''; if (prop) {
prop = prop.trim().toLowerCase();
externalUIMode = ['true', 'yes', 'on', '1'].includes(prop);
}
return { if (GLib.file_test(fileName, GLib.FileTest.IS_EXECUTABLE)) {
fileName, let binary = { fileName, externalUIMode, supportsHints };
supportsHints: plugin.supports_hints(), this._vpnBinaries[service] = binary;
externalUIMode: ['true', 'yes', 'on', '1'].includes(trimmedProp),
}; plugin.get_aliases().forEach(alias => {
this._vpnBinaries[alias] = binary;
});
} else {
log('VPN plugin at %s is not executable'.format(fileName));
}
});
} }
}; };
var Component = NetworkAgent; var Component = NetworkAgent;

View File

@@ -327,16 +327,12 @@ var AuthenticationDialog = GObject.registerClass({
} }
let resetDialog = () => { let resetDialog = () => {
this._sessionRequestTimeoutId = 0;
if (this.state != ModalDialog.State.OPENED) if (this.state != ModalDialog.State.OPENED)
return GLib.SOURCE_REMOVE; return;
this._passwordEntry.hide(); this._passwordEntry.hide();
this._cancelButton.grab_key_focus(); this._cancelButton.grab_key_focus();
this._okButton.reactive = false; this._okButton.reactive = false;
return GLib.SOURCE_REMOVE;
}; };
if (delay) { if (delay) {

View File

@@ -2,19 +2,12 @@
/* exported Component */ /* exported Component */
const { Clutter, Gio, GLib, GObject, St } = imports.gi; const { Clutter, Gio, GLib, GObject, St } = imports.gi;
const Lang = imports.lang;
var Tpl = null; var Tpl = null;
var Tp = null; var Tp = null;
try { try {
({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi); ({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi);
Gio._promisify(Tp.Channel.prototype, 'close_async', 'close_finish');
Gio._promisify(Tp.Channel.prototype,
'send_message_async', 'send_message_finish');
Gio._promisify(Tp.ChannelDispatchOperation.prototype,
'claim_with_async', 'claim_with_finish');
Gio._promisify(Tpl.LogManager.prototype,
'get_filtered_events_async', 'get_filtered_events_finish');
} catch (e) { } catch (e) {
log('Telepathy is not available, chat integration will be disabled.'); log('Telepathy is not available, chat integration will be disabled.');
} }
@@ -47,59 +40,36 @@ var NotificationDirection = {
RECEIVED: 'chat-received', RECEIVED: 'chat-received',
}; };
const ChatMessage = HAVE_TP ? GObject.registerClass({ function makeMessageFromTpMessage(tpMessage, direction) {
Properties: { let [text, flags_] = tpMessage.to_text();
'message-type': GObject.ParamSpec.int(
'message-type', 'message-type', 'message-type',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
Math.min(...Object.values(Tp.ChannelTextMessageType)),
Math.max(...Object.values(Tp.ChannelTextMessageType)),
Tp.ChannelTextMessageType.NORMAL),
'text': GObject.ParamSpec.string(
'text', 'text', 'text',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
null),
'sender': GObject.ParamSpec.string(
'sender', 'sender', 'sender',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
null),
'timestamp': GObject.ParamSpec.int64(
'timestamp', 'timestamp', 'timestamp',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
0, Number.MAX_SAFE_INTEGER, 0),
'direction': GObject.ParamSpec.string(
'direction', 'direction', 'direction',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
null),
},
}, class ChatMessageClass extends GObject.Object {
static newFromTpMessage(tpMessage, direction) {
return new ChatMessage({
'message-type': tpMessage.get_message_type(),
'text': tpMessage.to_text()[0],
'sender': tpMessage.sender.alias,
'timestamp': direction === NotificationDirection.RECEIVED
? tpMessage.get_received_timestamp() : tpMessage.get_sent_timestamp(),
direction,
});
}
static newFromTplTextEvent(tplTextEvent) { let timestamp = tpMessage.get_sent_timestamp();
let direction = if (timestamp == 0)
tplTextEvent.get_sender().get_entity_type() === Tpl.EntityType.SELF timestamp = tpMessage.get_received_timestamp();
? NotificationDirection.SENT : NotificationDirection.RECEIVED;
return new ChatMessage({ return {
'message-type': tplTextEvent.get_message_type(), messageType: tpMessage.get_message_type(),
'text': tplTextEvent.get_message(), text,
'sender': tplTextEvent.get_sender().get_alias(), sender: tpMessage.sender.alias,
'timestamp': tplTextEvent.get_timestamp(), timestamp,
direction, direction,
}); };
} }
}) : null;
function makeMessageFromTplEvent(event) {
let sent = event.get_sender().get_entity_type() == Tpl.EntityType.SELF;
let direction = sent ? NotificationDirection.SENT : NotificationDirection.RECEIVED;
return {
messageType: event.get_message_type(),
text: event.get_message(),
sender: event.get_sender().get_alias(),
timestamp: event.get_timestamp(),
direction,
};
}
var TelepathyComponent = class { var TelepathyComponent = class {
constructor() { constructor() {
this._client = null; this._client = null;
@@ -223,7 +193,7 @@ class TelepathyClient extends Tp.BaseClient {
// We can only handle text channel, so close any other channel // We can only handle text channel, so close any other channel
if (!(channel instanceof Tp.TextChannel)) { if (!(channel instanceof Tp.TextChannel)) {
channel.close_async(); channel.close_async(null);
continue; continue;
} }
@@ -269,7 +239,7 @@ class TelepathyClient extends Tp.BaseClient {
} }
} }
async _approveTextChannel(account, conn, channel, dispatchOp, context) { _approveTextChannel(account, conn, channel, dispatchOp, context) {
let [targetHandle_, targetHandleType] = channel.get_handle(); let [targetHandle_, targetHandleType] = channel.get_handle();
if (targetHandleType != Tp.HandleType.CONTACT) { if (targetHandleType != Tp.HandleType.CONTACT) {
@@ -278,15 +248,17 @@ class TelepathyClient extends Tp.BaseClient {
return; return;
} }
context.accept();
// Approve private text channels right away as we are going to handle it // Approve private text channels right away as we are going to handle it
try { dispatchOp.claim_with_async(this, (o, result) => {
await dispatchOp.claim_with_async(this); try {
this._handlingChannels(account, conn, [channel], false); dispatchOp.claim_with_finish(result);
} catch (err) { this._handlingChannels(account, conn, [channel], false);
log('Failed to Claim channel: %s'.format(err.toString())); } catch (err) {
} log('Failed to Claim channel: %s'.format(err.toString()));
}
});
context.accept();
} }
_delegatedChannelsCb(_client, _channels) { _delegatedChannelsCb(_client, _channels) {
@@ -298,12 +270,12 @@ class TelepathyClient extends Tp.BaseClient {
var ChatSource = HAVE_TP ? GObject.registerClass( var ChatSource = HAVE_TP ? GObject.registerClass(
class ChatSource extends MessageTray.Source { class ChatSource extends MessageTray.Source {
_init(account, conn, channel, contact, client) { _init(account, conn, channel, contact, client) {
super._init(contact.get_alias());
this._account = account; this._account = account;
this._contact = contact; this._contact = contact;
this._client = client; this._client = client;
super._init(contact.get_alias());
this.isChat = true; this.isChat = true;
this._pendingMessages = []; this._pendingMessages = [];
@@ -447,16 +419,19 @@ class ChatSource extends MessageTray.Source {
} }
} }
async _getLogMessages() { _getLogMessages() {
let logManager = Tpl.LogManager.dup_singleton(); let logManager = Tpl.LogManager.dup_singleton();
let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT); let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
const [events] = await logManager.get_filtered_events_async( logManager.get_filtered_events_async(this._account, entity,
this._account, entity, Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES, null, this._displayPendingMessages.bind(this));
null); }
let logMessages = events.map(e => ChatMessage.newFromTplTextEvent(e)); _displayPendingMessages(logManager, result) {
let [success_, events] = logManager.get_filtered_events_finish(result);
let logMessages = events.map(makeMessageFromTplEvent);
this._ensureNotification(); this._ensureNotification();
let pendingTpMessages = this._channel.get_pending_messages(); let pendingTpMessages = this._channel.get_pending_messages();
@@ -468,8 +443,7 @@ class ChatSource extends MessageTray.Source {
if (message.get_message_type() == Tp.ChannelTextMessageType.DELIVERY_REPORT) if (message.get_message_type() == Tp.ChannelTextMessageType.DELIVERY_REPORT)
continue; continue;
pendingMessages.push(ChatMessage.newFromTpMessage(message, pendingMessages.push(makeMessageFromTpMessage(message, NotificationDirection.RECEIVED));
NotificationDirection.RECEIVED));
this._pendingMessages.push(message); this._pendingMessages.push(message);
} }
@@ -512,7 +486,9 @@ class ChatSource extends MessageTray.Source {
this._ackMessages(); this._ackMessages();
// The chat box has been destroyed so it can't // The chat box has been destroyed so it can't
// handle the channel any more. // handle the channel any more.
this._channel.close_async(); this._channel.close_async((channel, result) => {
channel.close_finish(result);
});
} else { } else {
// Don't indicate any unread messages when the notification // Don't indicate any unread messages when the notification
// that represents them has been destroyed. // that represents them has been destroyed.
@@ -565,8 +541,7 @@ class ChatSource extends MessageTray.Source {
this._pendingMessages.push(message); this._pendingMessages.push(message);
this.countUpdated(); this.countUpdated();
message = ChatMessage.newFromTpMessage(message, message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
NotificationDirection.RECEIVED);
this._notification.appendMessage(message); this._notification.appendMessage(message);
// Wait a bit before notifying for the received message, a handler // Wait a bit before notifying for the received message, a handler
@@ -591,8 +566,7 @@ class ChatSource extends MessageTray.Source {
// our client and other clients as well. // our client and other clients as well.
_messageSent(channel, message, _flags, _token) { _messageSent(channel, message, _flags, _token) {
this._ensureNotification(); this._ensureNotification();
message = ChatMessage.newFromTpMessage(message, message = makeMessageFromTpMessage(message, NotificationDirection.SENT);
NotificationDirection.SENT);
this._notification.appendMessage(message); this._notification.appendMessage(message);
} }
@@ -610,7 +584,9 @@ class ChatSource extends MessageTray.Source {
} }
let msg = Tp.ClientMessage.new_text(type, text); let msg = Tp.ClientMessage.new_text(type, text);
this._channel.send_message_async(msg, 0); this._channel.send_message_async(msg, 0, (src, result) => {
this._channel.send_message_finish(result);
});
} }
setChatState(state) { setChatState(state) {
@@ -654,19 +630,11 @@ class ChatSource extends MessageTray.Source {
} }
}) : null; }) : null;
const ChatNotificationMessage = HAVE_TP ? GObject.registerClass(
class ChatNotificationMessage extends GObject.Object {
_init(props = {}) {
super._init();
this.set(props);
}
}) : null;
var ChatNotification = HAVE_TP ? GObject.registerClass({ var ChatNotification = HAVE_TP ? GObject.registerClass({
Signals: { Signals: {
'message-removed': { param_types: [ChatNotificationMessage.$gtype] }, 'message-removed': { param_types: [Tp.Message.$gtype] },
'message-added': { param_types: [ChatNotificationMessage.$gtype] }, 'message-added': { param_types: [Tp.Message.$gtype] },
'timestamp-changed': { param_types: [ChatNotificationMessage.$gtype] }, 'timestamp-changed': { param_types: [Tp.Message.$gtype] },
}, },
}, class ChatNotification extends MessageTray.Notification { }, class ChatNotification extends MessageTray.Notification {
_init(source) { _init(source) {
@@ -767,24 +735,21 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
styles: [], styles: [],
timestamp: currentTime, timestamp: currentTime,
noTimestamp: false }); noTimestamp: false });
const { noTimestamp } = props;
delete props.noTimestamp;
// Reset the old message timeout // Reset the old message timeout
if (this._timestampTimeoutId) if (this._timestampTimeoutId)
GLib.source_remove(this._timestampTimeoutId); GLib.source_remove(this._timestampTimeoutId);
this._timestampTimeoutId = 0; this._timestampTimeoutId = 0;
let message = new ChatNotificationMessage({ let message = { realMessage: props.group != 'meta',
realMessage: props.group !== 'meta', showTimestamp: false };
showTimestamp: false, Lang.copyProperties(props, message);
...props, delete message.noTimestamp;
});
this.messages.unshift(message); this.messages.unshift(message);
this.emit('message-added', message); this.emit('message-added', message);
if (!noTimestamp) { if (!props.noTimestamp) {
let timestamp = props.timestamp; let timestamp = props.timestamp;
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME) { if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME) {
this.appendTimestamp(); this.appendTimestamp();

View File

@@ -180,27 +180,14 @@ class WorldClocksSection extends St.Button {
let time = new St.Label({ style_class: 'world-clocks-time' }); let time = new St.Label({ style_class: 'world-clocks-time' });
const utcOffset = this._getTimeAtLocation(l).get_utc_offset(); let otherOffset = this._getTimeAtLocation(l).get_utc_offset();
const offsetCurrentTz = utcOffset - localOffset; let offset = (otherOffset - localOffset) / GLib.TIME_SPAN_HOUR;
const offsetHours = Math.abs(offsetCurrentTz) / GLib.TIME_SPAN_HOUR; let fmt = Math.trunc(offset) == offset ? '%s%.0f' : '%s%.1f';
const offsetMinutes = let prefix = offset >= 0 ? '+' : '-';
(Math.abs(offsetCurrentTz) % GLib.TIME_SPAN_HOUR) / let tz = new St.Label({ style_class: 'world-clocks-timezone',
GLib.TIME_SPAN_MINUTE; text: fmt.format(prefix, Math.abs(offset)),
x_align: Clutter.ActorAlign.END,
const prefix = offsetCurrentTz >= 0 ? '+' : '-'; y_align: Clutter.ActorAlign.CENTER });
const text = offsetMinutes === 0
? '%s%d'.format(prefix, offsetHours)
: '%s%d\u2236%d'.format(prefix, offsetHours, offsetMinutes);
const tz = new St.Label({
style_class: 'world-clocks-timezone',
text,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER,
});
time.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
tz.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
if (this._grid.text_direction == Clutter.TextDirection.RTL) { if (this._grid.text_direction == Clutter.TextDirection.RTL) {
layout.attach(tz, 0, i + 1, 1, 1); layout.attach(tz, 0, i + 1, 1, 1);
@@ -281,13 +268,13 @@ class WeatherSection extends St.Button {
this.child = box; this.child = box;
let titleBox = new St.BoxLayout({ style_class: 'weather-header-box' }); let titleBox = new St.BoxLayout({ style_class: 'weather-header-box' });
this._titleLabel = new St.Label({ titleBox.add_child(new St.Label({
style_class: 'weather-header', style_class: 'weather-header',
x_align: Clutter.ActorAlign.START, x_align: Clutter.ActorAlign.START,
x_expand: true, x_expand: true,
y_align: Clutter.ActorAlign.END, y_align: Clutter.ActorAlign.END,
}); text: _('Weather'),
titleBox.add_child(this._titleLabel); }));
box.add_child(titleBox); box.add_child(titleBox);
this._titleLocation = new St.Label({ this._titleLocation = new St.Label({
@@ -397,28 +384,21 @@ class WeatherSection extends St.Button {
layout.attach(label, 0, 0, 1, 1); layout.attach(label, 0, 0, 1, 1);
} }
_findBestLocationName(loc) {
const locName = loc.get_name();
if (loc.get_level() === GWeather.LocationLevel.CITY ||
!loc.has_coords())
return locName;
const world = GWeather.Location.get_world();
const city = world.find_nearest_city(...loc.get_coords());
const cityName = city.get_name();
return locName.includes(cityName) ? cityName : locName;
}
_updateForecasts() { _updateForecasts() {
this._forecastGrid.destroy_all_children(); this._forecastGrid.destroy_all_children();
if (!this._weatherClient.hasLocation) if (!this._weatherClient.hasLocation) {
this._setStatusLabel(_("Select a location…"));
return; return;
}
const { info } = this._weatherClient; let info = this._weatherClient.info;
this._titleLocation.text = this._findBestLocationName(info.location); let loc = info.get_location();
if (loc.get_level() !== GWeather.LocationLevel.CITY && loc.has_coords()) {
let world = GWeather.Location.get_world();
loc = world.find_nearest_city(...loc.get_coords());
}
this._titleLocation.text = loc.get_name();
if (this._weatherClient.loading) { if (this._weatherClient.loading) {
this._setStatusLabel(_("Loading…")); this._setStatusLabel(_("Loading…"));
@@ -442,12 +422,6 @@ class WeatherSection extends St.Button {
if (!this.visible) if (!this.visible)
return; return;
if (this._weatherClient.hasLocation)
this._titleLabel.text = _('Weather');
else
this._titleLabel.text = _('Select weather location…');
this._forecastGrid.visible = this._weatherClient.hasLocation;
this._titleLocation.visible = this._weatherClient.hasLocation; this._titleLocation.visible = this._weatherClient.hasLocation;
this._updateForecasts(); this._updateForecasts();

View File

@@ -278,7 +278,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog'); this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
} }
async _onPkOfflineProxyCreated(proxy, error) { _onPkOfflineProxyCreated(proxy, error) {
if (error) { if (error) {
log(error.message); log(error.message);
return; return;
@@ -293,12 +293,15 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
} }
// It only makes sense to check for this permission if PackageKit is available. // It only makes sense to check for this permission if PackageKit is available.
try { Polkit.Permission.new(
this._updatesPermission = await Polkit.Permission.new( 'org.freedesktop.packagekit.trigger-offline-update', null, null,
'org.freedesktop.packagekit.trigger-offline-update', null, null); (source, res) => {
} catch (e) { try {
log('No permission to trigger offline updates: %s'.format(e.toString())); this._updatesPermission = Polkit.Permission.new_finish(res);
} } catch (e) {
log('No permission to trigger offline updates: %s'.format(e.toString()));
}
});
} }
_onDestroy() { _onDestroy() {
@@ -343,8 +346,10 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
// Use a different description when we are installing a system upgrade // Use a different description when we are installing a system upgrade
// if the PackageKit proxy is available (i.e. PackageKit is available). // if the PackageKit proxy is available (i.e. PackageKit is available).
if (dialogContent.upgradeDescription) { if (this._pkOfflineProxy && dialogContent.upgradeDescription) {
const { name, version } = this._updateInfo.PreparedUpgrade; let name = this._pkOfflineProxy.PreparedUpgrade['name'].deep_unpack();
let version = this._pkOfflineProxy.PreparedUpgrade['version'].deep_unpack();
if (name != null && version != null) if (name != null && version != null)
description = dialogContent.upgradeDescription(name, version); description = dialogContent.upgradeDescription(name, version);
} }
@@ -603,46 +608,16 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
}); });
} }
async _getUpdateInfo() { OpenAsync(parameters, invocation) {
const connection = this._pkOfflineProxy.get_connection();
const reply = await connection.call(
this._pkOfflineProxy.g_name,
this._pkOfflineProxy.g_object_path,
'org.freedesktop.DBus.Properties',
'GetAll',
new GLib.Variant('(s)', [this._pkOfflineProxy.g_interface_name]),
null,
Gio.DBusCallFlags.NONE,
-1,
null);
const [info] = reply.recursiveUnpack();
return info;
}
async OpenAsync(parameters, invocation) {
let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters; let [type, timestamp, totalSecondsToStayOpen, inhibitorObjectPaths] = parameters;
this._totalSecondsToStayOpen = totalSecondsToStayOpen; this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._type = type; this._type = type;
try {
this._updateInfo = await this._getUpdateInfo();
} catch (e) {
if (this._pkOfflineProxy !== null)
log('Failed to get update info from PackageKit: %s'.format(e.message));
this._updateInfo = {
UpdateTriggered: false,
UpdatePrepared: false,
UpgradeTriggered: false,
PreparedUpgrade: {},
};
}
// Only consider updates and upgrades if PackageKit is available. // Only consider updates and upgrades if PackageKit is available.
if (this._pkOfflineProxy && this._type == DialogType.RESTART) { if (this._pkOfflineProxy && this._type == DialogType.RESTART) {
if (this._updateInfo.UpdateTriggered) if (this._pkOfflineProxy.UpdateTriggered)
this._type = DialogType.UPDATE_RESTART; this._type = DialogType.UPDATE_RESTART;
else if (this._updateInfo.UpgradeTriggered) else if (this._pkOfflineProxy.UpgradeTriggered)
this._type = DialogType.UPGRADE_RESTART; this._type = DialogType.UPGRADE_RESTART;
} }
@@ -671,13 +646,14 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
if (dialogContent.showOtherSessions) if (dialogContent.showOtherSessions)
this._loadSessions(); this._loadSessions();
let updateTriggered = this._updateInfo.UpdateTriggered; // Only consider updates and upgrades if PackageKit is available.
let updatePrepared = this._updateInfo.UpdatePrepared; let updateTriggered = this._pkOfflineProxy ? this._pkOfflineProxy.UpdateTriggered : false;
let updatePrepared = this._pkOfflineProxy ? this._pkOfflineProxy.UpdatePrepared : false;
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed; let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || ''); _setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || '');
this._checkBox.visible = dialogContent.checkBoxText && updatePrepared && updatesAllowed; this._checkBox.visible = dialogContent.checkBoxText && updatePrepared && updatesAllowed;
this._checkBox.checked = this._checkBox.visible; this._checkBox.checked = updatePrepared && updateTriggered;
// We show the warning either together with the checkbox, or when // We show the warning either together with the checkbox, or when
// updates have already been triggered, but the user doesn't have // updates have already been triggered, but the user doesn't have

View File

@@ -10,21 +10,10 @@ imports.gi.versions.Gtk = '3.0';
imports.gi.versions.TelepathyGLib = '0.12'; imports.gi.versions.TelepathyGLib = '0.12';
imports.gi.versions.TelepathyLogger = '0.2'; imports.gi.versions.TelepathyLogger = '0.2';
const { Clutter, Gio, GLib, GObject, Meta, Polkit, Shell, St } = imports.gi; const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
const System = imports.system; const System = imports.system;
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async', 'fill_finish');
Gio._promisify(Gio.DataInputStream.prototype,
'read_line_async', 'read_line_finish');
Gio._promisify(Gio.DBus, 'get', 'get_finish');
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
Gio._promisify(Gio.DBusProxy, 'new', 'new_finish');
Gio._promisify(Gio.DBusProxy.prototype, 'init_async', 'init_finish');
Gio._promisify(Gio.DBusProxy.prototype,
'call_with_unix_fd_list', 'call_with_unix_fd_list_finish');
Gio._promisify(Polkit.Permission, 'new', 'new_finish');
let _localTimeZone = null; let _localTimeZone = null;
// We can't import shell JS modules yet, because they may have // We can't import shell JS modules yet, because they may have
@@ -245,15 +234,16 @@ function _loggingFunc(...args) {
} }
function init() { function init() {
// Add some bindings to the global JS namespace // Add some bindings to the global JS namespace; (gjs keeps the web
globalThis.global = Shell.Global.get(); // browser convention of having that namespace be called 'window'.)
window.global = Shell.Global.get();
globalThis.log = _loggingFunc; window.log = _loggingFunc;
globalThis._ = Gettext.gettext; window._ = Gettext.gettext;
globalThis.C_ = Gettext.pgettext; window.C_ = Gettext.pgettext;
globalThis.ngettext = Gettext.ngettext; window.ngettext = Gettext.ngettext;
globalThis.N_ = s => s; window.N_ = s => s;
GObject.gtypeNameBasedOnJSPath = true; GObject.gtypeNameBasedOnJSPath = true;
@@ -298,13 +288,6 @@ function init() {
}, },
}); });
Gio._LocalFilePrototype.touch_async = function (callback) {
Shell.util_touch_file_async(this, callback);
};
Gio._LocalFilePrototype.touch_finish = function (result) {
return Shell.util_touch_file_finish(this, result);
};
St.set_slow_down_factor = function (factor) { St.set_slow_down_factor = function (factor) {
let { stack } = new Error(); let { stack } = new Error();
log(`St.set_slow_down_factor() is deprecated, use St.Settings.slow_down_factor\n${stack}`); log(`St.set_slow_down_factor() is deprecated, use St.Settings.slow_down_factor\n${stack}`);
@@ -355,7 +338,9 @@ function init() {
// OK, now things are initialized enough that we can import shell JS // OK, now things are initialized enough that we can import shell JS
const Format = imports.format; const Format = imports.format;
const Tweener = imports.ui.tweener;
Tweener.init();
String.prototype.format = Format.format; String.prototype.format = Format.format;
} }

View File

@@ -56,15 +56,6 @@ function uninstallExtension(uuid) {
return false; return false;
FileUtils.recursivelyDeleteDir(extension.dir, true); FileUtils.recursivelyDeleteDir(extension.dir, true);
try {
const updatesDir = Gio.File.new_for_path(GLib.build_filenamev(
[global.userdatadir, 'extension-updates', extension.uuid]));
FileUtils.recursivelyDeleteDir(updatesDir, true);
} catch (e) {
// not an error
}
return true; return true;
} }
@@ -108,9 +99,6 @@ function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
} }
function downloadExtensionUpdate(uuid) { function downloadExtensionUpdate(uuid) {
if (!Main.extensionManager.updatesSupported)
return;
let dir = Gio.File.new_for_path( let dir = Gio.File.new_for_path(
GLib.build_filenamev([global.userdatadir, 'extension-updates', uuid])); GLib.build_filenamev([global.userdatadir, 'extension-updates', uuid]));
@@ -129,9 +117,6 @@ function downloadExtensionUpdate(uuid) {
} }
function checkForUpdates() { function checkForUpdates() {
if (!Main.extensionManager.updatesSupported)
return;
let metadatas = {}; let metadatas = {};
Main.extensionManager.getUuids().forEach(uuid => { Main.extensionManager.getUuids().forEach(uuid => {
let extension = Main.extensionManager.lookup(uuid); let extension = Main.extensionManager.lookup(uuid);
@@ -142,9 +127,6 @@ function checkForUpdates() {
metadatas[uuid] = extension.metadata; metadatas[uuid] = extension.metadata;
}); });
if (Object.keys(metadatas).length === 0)
return; // nothing to update
let versionCheck = global.settings.get_boolean( let versionCheck = global.settings.get_boolean(
'disable-extension-version-validation'); 'disable-extension-version-validation');
let params = { let params = {
@@ -162,7 +144,9 @@ function checkForUpdates() {
let operations = JSON.parse(message.response_body.data); let operations = JSON.parse(message.response_body.data);
for (let uuid in operations) { for (let uuid in operations) {
let operation = operations[uuid]; let operation = operations[uuid];
if (operation === 'upgrade' || operation === 'downgrade') if (operation == 'blacklist')
uninstallExtension(uuid);
else if (operation == 'upgrade' || operation == 'downgrade')
downloadExtensionUpdate(uuid); downloadExtensionUpdate(uuid);
} }
}); });

View File

@@ -60,11 +60,6 @@ var ExtensionManager = class {
ExtensionDownloader.checkForUpdates(); ExtensionDownloader.checkForUpdates();
} }
get updatesSupported() {
const appSys = Shell.AppSystem.get_default();
return appSys.lookup_app('org.gnome.Extensions.desktop') !== null;
}
lookup(uuid) { lookup(uuid) {
return this._extensions.get(uuid); return this._extensions.get(uuid);
} }
@@ -215,24 +210,6 @@ var ExtensionManager = class {
return true; return true;
} }
openExtensionPrefs(uuid, parentWindow, options) {
const extension = this.lookup(uuid);
if (!extension || !extension.hasPrefs)
return false;
Gio.DBus.session.call(
'org.gnome.Shell.Extensions',
'/org/gnome/Shell/Extensions',
'org.gnome.Shell.Extensions',
'OpenExtensionPrefs',
new GLib.Variant('(ssa{sv})', [uuid, parentWindow, options]),
null,
Gio.DBusCallFlags.NONE,
-1,
null);
return true;
}
notifyExtensionUpdate(uuid) { notifyExtensionUpdate(uuid) {
let extension = this.lookup(uuid); let extension = this.lookup(uuid);
if (!extension) if (!extension)
@@ -463,15 +440,19 @@ var ExtensionManager = class {
// Find and enable all the newly enabled extensions: UUIDs found in the // Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one. // new setting, but not in the old one.
newEnabledExtensions newEnabledExtensions.filter(
.filter(uuid => !this._enabledExtensions.includes(uuid)) uuid => !this._enabledExtensions.includes(uuid)
.forEach(uuid => this._callExtensionEnable(uuid)); ).forEach(uuid => {
this._callExtensionEnable(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the // Find and disable all the newly disabled extensions: UUIDs found in the
// old setting, but not in the new one. // old setting, but not in the new one.
this._extensionOrder this._extensionOrder.filter(
.filter(uuid => !newEnabledExtensions.includes(uuid)) uuid => !newEnabledExtensions.includes(uuid)
.reverse().forEach(uuid => this._callExtensionDisable(uuid)); ).reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
this._enabledExtensions = newEnabledExtensions; this._enabledExtensions = newEnabledExtensions;
} }
@@ -500,9 +481,6 @@ var ExtensionManager = class {
} }
_installExtensionUpdates() { _installExtensionUpdates() {
if (!this.updatesSupported)
return;
FileUtils.collectFromDatadirs('extension-updates', true, (dir, info) => { FileUtils.collectFromDatadirs('extension-updates', true, (dir, info) => {
let fileType = info.get_file_type(); let fileType = info.get_file_type();
if (fileType !== Gio.FileType.DIRECTORY) if (fileType !== Gio.FileType.DIRECTORY)
@@ -511,14 +489,9 @@ var ExtensionManager = class {
let extensionDir = Gio.File.new_for_path( let extensionDir = Gio.File.new_for_path(
GLib.build_filenamev([global.userdatadir, 'extensions', uuid])); GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
try { FileUtils.recursivelyDeleteDir(extensionDir, false);
FileUtils.recursivelyDeleteDir(extensionDir, false); FileUtils.recursivelyMoveDir(dir, extensionDir);
FileUtils.recursivelyMoveDir(dir, extensionDir); FileUtils.recursivelyDeleteDir(dir, true);
} catch (e) {
log('Failed to install extension updates for %s'.format(uuid));
} finally {
FileUtils.recursivelyDeleteDir(dir, true);
}
}); });
} }

View File

@@ -114,11 +114,8 @@ class BaseIcon extends St.Bin {
if (this._setSizeManually) { if (this._setSizeManually) {
size = this.iconSize; size = this.iconSize;
} else { } else {
const { scaleFactor } =
St.ThemeContext.get_for_stage(global.stage);
let [found, len] = node.lookup_length('icon-size', false); let [found, len] = node.lookup_length('icon-size', false);
size = found ? len / scaleFactor : ICON_SIZE; size = found ? len : ICON_SIZE;
} }
if (this.iconSize == size && this._iconBin.child) if (this.iconSize == size && this._iconBin.child)

View File

@@ -498,7 +498,7 @@ var Key = GObject.registerClass({
var KeyboardModel = class { var KeyboardModel = class {
constructor(groupName) { constructor(groupName) {
let names = [groupName]; let names = [groupName];
if (groupName.includes('+')) if (names.includes('+'))
names.push(groupName.replace(/\+.*/, '')); names.push(groupName.replace(/\+.*/, ''));
names.push('us'); names.push('us');
@@ -722,7 +722,7 @@ var EmojiPager = GObject.registerClass({
_onPan(action) { _onPan(action) {
let [dist_, dx, dy_] = action.get_motion_delta(0); let [dist_, dx, dy_] = action.get_motion_delta(0);
this.delta += dx; this.delta = this.delta + dx;
if (this._currentKey != null) { if (this._currentKey != null) {
this._currentKey.cancel(); this._currentKey.cancel();
@@ -935,7 +935,8 @@ var EmojiSelection = GObject.registerClass({
this.add_child(this._emojiPager); this.add_child(this._emojiPager);
this._pageIndicator = new PageIndicators.PageIndicators( this._pageIndicator = new PageIndicators.PageIndicators(
Clutter.Orientation.HORIZONTAL); Clutter.Orientation.HORIZONTAL
);
this.add_child(this._pageIndicator); this.add_child(this._pageIndicator);
this._pageIndicator.setReactive(false); this._pageIndicator.setReactive(false);
@@ -1118,12 +1119,11 @@ var KeyboardManager = class KeyBoardManager {
this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this)); this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this));
this._lastDevice = null; this._lastDevice = null;
global.backend.connect('last-device-changed', (backend, device) => { Meta.get_backend().connect('last-device-changed', (backend, device) => {
if (device.device_type === Clutter.InputDeviceType.KEYBOARD_DEVICE) if (device.get_device_name().indexOf('XTEST') < 0) {
return; this._lastDevice = device;
this._syncEnabled();
this._lastDevice = device; }
this._syncEnabled();
}); });
this._syncEnabled(); this._syncEnabled();
} }
@@ -1148,9 +1148,9 @@ var KeyboardManager = class KeyBoardManager {
this._keyboard = new Keyboard(); this._keyboard = new Keyboard();
} else if (!enabled && this._keyboard) { } else if (!enabled && this._keyboard) {
this._keyboard.setCursorLocation(null); this._keyboard.setCursorLocation(null);
Main.layoutManager.hideKeyboard(true);
this._keyboard.destroy(); this._keyboard.destroy();
this._keyboard = null; this._keyboard = null;
Main.layoutManager.hideKeyboard(true);
} }
} }
@@ -1256,10 +1256,6 @@ class Keyboard extends St.BoxLayout {
return this._keyboardVisible && super.visible; return this._keyboardVisible && super.visible;
} }
set visible(visible) {
super.visible = visible;
}
_onFocusPositionChanged(focusTracker) { _onFocusPositionChanged(focusTracker) {
let rect = focusTracker.getCurrentRect(); let rect = focusTracker.getCurrentRect();
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height); this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
@@ -1872,10 +1868,6 @@ var KeyboardController = class {
Main.inputMethod.disconnect(this._notifyContentPurposeId); Main.inputMethod.disconnect(this._notifyContentPurposeId);
Main.inputMethod.disconnect(this._notifyContentHintsId); Main.inputMethod.disconnect(this._notifyContentHintsId);
Main.inputMethod.disconnect(this._notifyInputPanelStateId); Main.inputMethod.disconnect(this._notifyInputPanelStateId);
// Make sure any buttons pressed by the virtual device are released
// immediately instead of waiting for the next GC cycle
this._virtualDevice.run_dispose();
} }
_onSourcesModified() { _onSourcesModified() {

View File

@@ -612,20 +612,10 @@ var LayoutManager = GObject.registerClass({
let signalId = this._systemBackground.connect('loaded', () => { let signalId = this._systemBackground.connect('loaded', () => {
this._systemBackground.disconnect(signalId); this._systemBackground.disconnect(signalId);
this._systemBackground.show();
global.stage.show();
// We're mostly prepared for the startup animation this._prepareStartupAnimation();
// now, but since a lot is going on asynchronously
// during startup, let's defer the startup animation
// until the event loop is uncontended and idle.
// This helps to prevent us from running the animation
// when the system is bogged down
const id = GLib.idle_add(GLib.PRIORITY_LOW, () => {
this._systemBackground.show();
global.stage.show();
this._prepareStartupAnimation();
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(id, '[gnome-shell] Startup Animation');
}); });
} }
@@ -682,7 +672,17 @@ var LayoutManager = GObject.registerClass({
this.emit('startup-prepared'); this.emit('startup-prepared');
this._startupAnimation(); // We're mostly prepared for the startup animation
// now, but since a lot is going on asynchronously
// during startup, let's defer the startup animation
// until the event loop is uncontended and idle.
// This helps to prevent us from running the animation
// when the system is bogged down
let id = GLib.idle_add(GLib.PRIORITY_LOW, () => {
this._startupAnimation();
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(id, '[gnome-shell] this._startupAnimation');
} }
_startupAnimation() { _startupAnimation() {
@@ -765,7 +765,7 @@ var LayoutManager = GObject.registerClass({
this._keyboardHeightNotifyId = 0; this._keyboardHeightNotifyId = 0;
} }
this.keyboardBox.ease({ this.keyboardBox.ease({
translation_y: 0, translation_y: this.keyboardBox.height,
opacity: 0, opacity: 0,
duration: immediate ? 0 : KEYBOARD_ANIMATION_TIME, duration: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_QUAD, mode: Clutter.AnimationMode.EASE_IN_QUAD,

View File

@@ -27,11 +27,13 @@ var RadialShaderEffect = GObject.registerClass({
'brightness': GObject.ParamSpec.float( 'brightness': GObject.ParamSpec.float(
'brightness', 'brightness', 'brightness', 'brightness', 'brightness', 'brightness',
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
0, 1, 1), 0, 1, 1
),
'sharpness': GObject.ParamSpec.float( 'sharpness': GObject.ParamSpec.float(
'sharpness', 'sharpness', 'sharpness', 'sharpness', 'sharpness', 'sharpness',
GObject.ParamFlags.READWRITE, GObject.ParamFlags.READWRITE,
0, 1, 0), 0, 1, 0
),
}, },
}, class RadialShaderEffect extends Shell.GLSLEffect { }, class RadialShaderEffect extends Shell.GLSLEffect {
_init(params) { _init(params) {

View File

@@ -37,9 +37,10 @@ const LG_ANIMATION_TIME = 500;
function _getAutoCompleteGlobalKeywords() { function _getAutoCompleteGlobalKeywords() {
const keywords = ['true', 'false', 'null', 'new']; const keywords = ['true', 'false', 'null', 'new'];
// Don't add the private properties of globalThis (i.e., ones starting with '_') // Don't add the private properties of window (i.e., ones starting with '_')
const windowProperties = Object.getOwnPropertyNames(globalThis).filter( const windowProperties = Object.getOwnPropertyNames(window).filter(
a => a.charAt(0) !== '_'); a => a.charAt(0) != '_'
);
const headerProperties = JsParse.getDeclaredConstants(commandHeader); const headerProperties = JsParse.getDeclaredConstants(commandHeader);
return keywords.concat(windowProperties).concat(headerProperties); return keywords.concat(windowProperties).concat(headerProperties);
@@ -1126,7 +1127,7 @@ class LookingGlass extends St.BoxLayout {
else if (symbol == Clutter.KEY_Page_Down) else if (symbol == Clutter.KEY_Page_Down)
this._notebook.nextTab(); this._notebook.nextTab();
} }
return super.vfunc_key_press_event(keyPressEvent); return Clutter.EVENT_PROPAGATE;
} }
open() { open() {

View File

@@ -643,7 +643,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setClampScrollingAtEdges( this._zoomRegions[0].setClampScrollingAtEdges(
!this._settings.get_boolean(CLAMP_MODE_KEY)); !this._settings.get_boolean(CLAMP_MODE_KEY)
);
} }
} }
@@ -651,7 +652,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setMouseTrackingMode( this._zoomRegions[0].setMouseTrackingMode(
this._settings.get_enum(MOUSE_TRACKING_KEY)); this._settings.get_enum(MOUSE_TRACKING_KEY)
);
} }
} }
@@ -659,7 +661,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setFocusTrackingMode( this._zoomRegions[0].setFocusTrackingMode(
this._settings.get_enum(FOCUS_TRACKING_KEY)); this._settings.get_enum(FOCUS_TRACKING_KEY)
);
} }
} }
@@ -667,7 +670,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setCaretTrackingMode( this._zoomRegions[0].setCaretTrackingMode(
this._settings.get_enum(CARET_TRACKING_KEY)); this._settings.get_enum(CARET_TRACKING_KEY)
);
} }
} }
@@ -675,7 +679,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setInvertLightness( this._zoomRegions[0].setInvertLightness(
this._settings.get_boolean(INVERT_LIGHTNESS_KEY)); this._settings.get_boolean(INVERT_LIGHTNESS_KEY)
);
} }
} }
@@ -683,7 +688,8 @@ var Magnifier = class Magnifier {
// Applies only to the first zoom region. // Applies only to the first zoom region.
if (this._zoomRegions.length) { if (this._zoomRegions.length) {
this._zoomRegions[0].setColorSaturation( this._zoomRegions[0].setColorSaturation(
this._settings.get_double(COLOR_SATURATION_KEY)); this._settings.get_double(COLOR_SATURATION_KEY)
);
} }
} }
@@ -1935,8 +1941,9 @@ var MagShaderEffects = class MagShaderEffects {
// it modifies the brightness and/or contrast. // it modifies the brightness and/or contrast.
let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast(); let [cRed, cGreen, cBlue] = this._brightnessContrast.get_contrast();
this._brightnessContrast.set_enabled( this._brightnessContrast.set_enabled(
bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE || bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE ||
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE); cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE
);
} }
/** /**
@@ -1963,7 +1970,8 @@ var MagShaderEffects = class MagShaderEffects {
// a null first argument. // a null first argument.
let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness(); let [bRed, bGreen, bBlue] = this._brightnessContrast.get_brightness();
this._brightnessContrast.set_enabled( this._brightnessContrast.set_enabled(
cRed !== NO_CHANGE || cGreen !== NO_CHANGE || cBlue !== NO_CHANGE || cRed != NO_CHANGE || cGreen != NO_CHANGE || cBlue != NO_CHANGE ||
bRed !== NO_CHANGE || bGreen !== NO_CHANGE || bBlue !== NO_CHANGE); bRed != NO_CHANGE || bGreen != NO_CHANGE || bBlue != NO_CHANGE
);
} }
}; };

View File

@@ -46,7 +46,6 @@ const XdndHandler = imports.ui.xdndHandler;
const KbdA11yDialog = imports.ui.kbdA11yDialog; const KbdA11yDialog = imports.ui.kbdA11yDialog;
const LocatePointer = imports.ui.locatePointer; const LocatePointer = imports.ui.locatePointer;
const PointerA11yTimeout = imports.ui.pointerA11yTimeout; const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
const ParentalControlsManager = imports.misc.parentalControlsManager;
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard'; const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const STICKY_KEYS_ENABLE = 'stickykeys-enable'; const STICKY_KEYS_ENABLE = 'stickykeys-enable';
@@ -94,11 +93,6 @@ let _a11ySettings = null;
let _themeResource = null; let _themeResource = null;
let _oskResource = null; let _oskResource = null;
Gio._promisify(Gio._LocalFilePrototype, 'delete_async', 'delete_finish');
Gio._promisify(Gio._LocalFilePrototype, 'touch_async', 'touch_finish');
let _remoteAccessInhibited = false;
function _sessionUpdated() { function _sessionUpdated() {
if (sessionMode.isPrimary) if (sessionMode.isPrimary)
_loadDefaultStylesheet(); _loadDefaultStylesheet();
@@ -123,41 +117,24 @@ function _sessionUpdated() {
if (lookingGlass) if (lookingGlass)
lookingGlass.close(); lookingGlass.close();
} }
let remoteAccessController = global.backend.get_remote_access_controller();
if (remoteAccessController) {
if (sessionMode.allowScreencast && _remoteAccessInhibited) {
remoteAccessController.uninhibit_remote_access();
_remoteAccessInhibited = false;
} else if (!sessionMode.allowScreencast && !_remoteAccessInhibited) {
remoteAccessController.inhibit_remote_access();
_remoteAccessInhibited = true;
}
}
} }
function start() { function start() {
// These are here so we don't break compatibility. // These are here so we don't break compatibility.
global.logError = globalThis.log; global.logError = window.log;
global.log = globalThis.log; global.log = window.log;
// Chain up async errors reported from C // Chain up async errors reported from C
global.connect('notify-error', (global, msg, detail) => { global.connect('notify-error', (global, msg, detail) => {
notifyError(msg, detail); notifyError(msg, detail);
}); });
let currentDesktop = GLib.getenv('XDG_CURRENT_DESKTOP'); Gio.DesktopAppInfo.set_desktop_env('GNOME');
if (!currentDesktop || !currentDesktop.split(':').includes('GNOME'))
Gio.DesktopAppInfo.set_desktop_env('GNOME');
sessionMode = new SessionMode.SessionMode(); sessionMode = new SessionMode.SessionMode();
sessionMode.connect('updated', _sessionUpdated); sessionMode.connect('updated', _sessionUpdated);
St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet); St.Settings.get().connect('notify::gtk-theme', _loadDefaultStylesheet);
// Initialize ParentalControlsManager before the UI
ParentalControlsManager.getDefault();
_initializeUI(); _initializeUI();
shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus(); shellAccessDialogDBusService = new AccessDialog.AccessDialogDBus();
@@ -165,11 +142,6 @@ function start() {
shellDBusService = new ShellDBus.GnomeShell(); shellDBusService = new ShellDBus.GnomeShell();
shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler(); shellMountOpDBusService = new ShellMountOperation.GnomeShellMountOpHandler();
const watchId = Gio.DBus.session.watch_name('org.gnome.Shell.Notifications',
Gio.BusNameWatcherFlags.AUTO_START,
bus => bus.unwatch_name(watchId),
bus => bus.unwatch_name(watchId));
_sessionUpdated(); _sessionUpdated();
} }
@@ -299,8 +271,11 @@ function _initializeUI() {
} }
if (sessionMode.currentMode !== 'gdm' && if (sessionMode.currentMode !== 'gdm' &&
sessionMode.currentMode !== 'initial-setup') sessionMode.currentMode !== 'initial-setup' &&
_handleLockScreenWarning(); screenShield === null) {
notify(_('Screen Lock disabled'),
_('Screen Locking requires the GNOME display manager.'));
}
LoginManager.registerSessionWithGDM(); LoginManager.registerSessionWithGDM();
@@ -313,32 +288,6 @@ function _initializeUI() {
}); });
} }
async function _handleLockScreenWarning() {
const path = '%s/lock-warning-shown'.format(global.userdatadir);
const file = Gio.File.new_for_path(path);
const hasLockScreen = screenShield !== null;
if (hasLockScreen) {
try {
await file.delete_async(0, null);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
logError(e);
}
} else {
try {
if (!await file.touch_async())
return;
} catch (e) {
logError(e);
}
notify(
_('Screen Lock disabled'),
_('Screen Locking requires the GNOME display manager.'));
}
}
function _getStylesheet(name) { function _getStylesheet(name) {
let stylesheet; let stylesheet;
@@ -412,8 +361,7 @@ function reloadThemeResource() {
if (_themeResource) if (_themeResource)
_themeResource._unregister(); _themeResource._unregister();
_themeResource = Gio.Resource.load('%s/%s'.format(global.datadir, _themeResource = Gio.Resource.load('%s/gnome-shell-theme.gresource'.format(global.datadir));
sessionMode.themeResourceName));
_themeResource._register(); _themeResource._register();
} }
@@ -539,9 +487,7 @@ function pushModal(actor, params) {
let prevFocusDestroyId; let prevFocusDestroyId;
if (prevFocus != null) { if (prevFocus != null) {
prevFocusDestroyId = prevFocus.connect('destroy', () => { prevFocusDestroyId = prevFocus.connect('destroy', () => {
const index = modalActorFocusStack.findIndex( let index = _findModal(actor);
record => record.prevFocus === prevFocus);
if (index >= 0) if (index >= 0)
modalActorFocusStack[index].prevFocus = null; modalActorFocusStack[index].prevFocus = null;
}); });
@@ -817,7 +763,7 @@ function showRestartMessage(message) {
var AnimationsSettings = class { var AnimationsSettings = class {
constructor() { constructor() {
let backend = global.backend; let backend = Meta.get_backend();
if (!backend.is_rendering_hardware_accelerated()) { if (!backend.is_rendering_hardware_accelerated()) {
St.Settings.get().inhibit_animations(); St.Settings.get().inhibit_animations();
return; return;

View File

@@ -530,7 +530,7 @@ var Message = GObject.registerClass({
this.close(); this.close();
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
return super.vfunc_key_press_event(keyEvent); return Clutter.EVENT_PROPAGATE;
} }
}); });

View File

@@ -136,22 +136,29 @@ var FocusGrabber = class FocusGrabber {
var NotificationPolicy = GObject.registerClass({ var NotificationPolicy = GObject.registerClass({
Properties: { Properties: {
'enable': GObject.ParamSpec.boolean( 'enable': GObject.ParamSpec.boolean(
'enable', 'enable', 'enable', GObject.ParamFlags.READABLE, true), 'enable', 'enable', 'enable',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'enable-sound': GObject.ParamSpec.boolean( 'enable-sound': GObject.ParamSpec.boolean(
'enable-sound', 'enable-sound', 'enable-sound', 'enable-sound', 'enable-sound', 'enable-sound',
GObject.ParamFlags.READABLE, true), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'show-banners': GObject.ParamSpec.boolean( 'show-banners': GObject.ParamSpec.boolean(
'show-banners', 'show-banners', 'show-banners', 'show-banners', 'show-banners', 'show-banners',
GObject.ParamFlags.READABLE, true), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'force-expanded': GObject.ParamSpec.boolean( 'force-expanded': GObject.ParamSpec.boolean(
'force-expanded', 'force-expanded', 'force-expanded', 'force-expanded', 'force-expanded', 'force-expanded',
GObject.ParamFlags.READABLE, false), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
'show-in-lock-screen': GObject.ParamSpec.boolean( 'show-in-lock-screen': GObject.ParamSpec.boolean(
'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen',
GObject.ParamFlags.READABLE, false), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
'details-in-lock-screen': GObject.ParamSpec.boolean( 'details-in-lock-screen': GObject.ParamSpec.boolean(
'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen',
GObject.ParamFlags.READABLE, false), GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
}, },
}, class NotificationPolicy extends GObject.Object { }, class NotificationPolicy extends GObject.Object {
// Do nothing for the default policy. These methods are only useful for the // Do nothing for the default policy. These methods are only useful for the
@@ -163,23 +170,23 @@ var NotificationPolicy = GObject.registerClass({
} }
get enableSound() { get enableSound() {
return true; return this.enable_sound;
} }
get showBanners() { get showBanners() {
return true; return this.show_banners;
} }
get forceExpanded() { get forceExpanded() {
return false; return this.force_expanded;
} }
get showInLockScreen() { get showInLockScreen() {
return false; return this.show_in_lock_screen;
} }
get detailsInLockScreen() { get detailsInLockScreen() {
return false; return this.details_in_lock_screen;
} }
}); });
@@ -755,10 +762,12 @@ var Source = GObject.registerClass({
this.notifications = []; this.notifications = [];
this._policy = this._createPolicy(); this._policy = null;
} }
get policy() { get policy() {
if (!this._policy)
this._policy = this._createPolicy();
return this._policy; return this._policy;
} }
@@ -871,6 +880,8 @@ var Source = GObject.registerClass({
} }
destroy(reason) { destroy(reason) {
this.policy.destroy();
let notifications = this.notifications; let notifications = this.notifications;
this.notifications = []; this.notifications = [];
@@ -879,7 +890,6 @@ var Source = GObject.registerClass({
this.emit('destroy', reason); this.emit('destroy', reason);
this.policy.destroy();
this.run_dispose(); this.run_dispose();
} }
@@ -1160,7 +1170,8 @@ var MessageTray = GObject.registerClass({
this._onNotificationDestroy.bind(this)); this._onNotificationDestroy.bind(this));
this._notificationQueue.push(notification); this._notificationQueue.push(notification);
this._notificationQueue.sort( this._notificationQueue.sort(
(n1, n2) => n2.urgency - n1.urgency); (n1, n2) => n2.urgency - n1.urgency
);
this.emit('queue-changed'); this.emit('queue-changed');
} }
} }

View File

@@ -416,11 +416,11 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
var FdoNotificationDaemonSource = GObject.registerClass( var FdoNotificationDaemonSource = GObject.registerClass(
class FdoNotificationDaemonSource extends MessageTray.Source { class FdoNotificationDaemonSource extends MessageTray.Source {
_init(title, pid, sender, appId) { _init(title, pid, sender, appId) {
super._init(title);
this.pid = pid; this.pid = pid;
this.app = this._getApp(appId); this.app = this._getApp(appId);
super._init(title);
this.initialTitle = title; this.initialTitle = title;
if (this.app) if (this.app)
@@ -631,12 +631,12 @@ class GtkNotificationDaemonAppSource extends MessageTray.Source {
if (!app) if (!app)
throw new InvalidAppError(); throw new InvalidAppError();
super._init(app.get_name());
this._appId = appId; this._appId = appId;
this._app = app; this._app = app;
this._objectPath = objectPath; this._objectPath = objectPath;
super._init(app.get_name());
this._notifications = {}; this._notifications = {};
this._notificationPending = false; this._notificationPending = false;
} }

View File

@@ -400,7 +400,8 @@ var Overview = class {
_getDesktopClone() { _getDesktopClone() {
let windows = global.get_window_actors().filter( let windows = global.get_window_actors().filter(
w => w.meta_window.get_window_type() === Meta.WindowType.DESKTOP); w => w.meta_window.get_window_type() == Meta.WindowType.DESKTOP
);
if (windows.length == 0) if (windows.length == 0)
return null; return null;

View File

@@ -473,7 +473,6 @@ class ControlsManager extends St.Widget {
// A workspace might have been inserted or removed before the active // A workspace might have been inserted or removed before the active
// one, causing the adjustment to go out of sync, so update the value // one, causing the adjustment to go out of sync, so update the value
this._workspaceAdjustment.remove_transition('value');
this._workspaceAdjustment.value = activeIndex; this._workspaceAdjustment.value = activeIndex;
} }

View File

@@ -89,7 +89,7 @@ var PadChooser = GObject.registerClass({
}); });
var KeybindingEntry = GObject.registerClass({ var KeybindingEntry = GObject.registerClass({
Signals: { 'keybinding-edited': { param_types: [GObject.TYPE_STRING] } }, Signals: { 'keybinding-edited': {} },
}, class KeybindingEntry extends St.Entry { }, class KeybindingEntry extends St.Entry {
_init() { _init() {
super._init({ hint_text: _("New shortcut…"), style: 'width: 10em' }); super._init({ hint_text: _("New shortcut…"), style: 'width: 10em' });

View File

@@ -90,16 +90,18 @@ class AppMenu extends PopupMenu.PopupMenu {
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._detailsItem = this.addAction(_('Show Details'), async () => { this._detailsItem = this.addAction(_("Show Details"), () => {
let id = this._app.get_id(); let id = this._app.get_id();
let args = GLib.Variant.new('(ss)', [id, '']); let args = GLib.Variant.new('(ss)', [id, '']);
const bus = await Gio.DBus.get(Gio.BusType.SESSION, null); Gio.DBus.get(Gio.BusType.SESSION, null, (o, res) => {
bus.call( let bus = Gio.DBus.get_finish(res);
'org.gnome.Software', bus.call('org.gnome.Software',
'/org/gnome/Software', '/org/gnome/Software',
'org.gtk.Actions', 'Activate', 'org.gtk.Actions', 'Activate',
new GLib.Variant('(sava{sv})', ['details', [args], null]), GLib.Variant.new('(sava{sv})',
null, 0, -1, null); ['details', [args], null]),
null, 0, -1, null, null);
});
}); });
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
@@ -281,7 +283,7 @@ var AppMenuButton = GObject.registerClass({
this.remove_all_transitions(); this.remove_all_transitions();
this.ease({ this.ease({
opacity: 0, opacity: 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, mode: Clutter.Animation.EASE_OUT_QUAD,
duration: Overview.ANIMATION_TIME, duration: Overview.ANIMATION_TIME,
onComplete: () => this.hide(), onComplete: () => this.hide(),
}); });
@@ -962,7 +964,7 @@ class Panel extends St.Widget {
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
return super.vfunc_key_press_event(keyEvent); return Clutter.EVENT_PROPAGATE;
} }
_toggleMenu(indicator) { _toggleMenu(indicator) {
@@ -1153,9 +1155,10 @@ class Panel extends St.Widget {
_getDraggableWindowForPosition(stageX) { _getDraggableWindowForPosition(stageX) {
let workspaceManager = global.workspace_manager; let workspaceManager = global.workspace_manager;
const windows = workspaceManager.get_active_workspace().list_windows(); let workspace = workspaceManager.get_active_workspace();
const allWindowsByStacking = let allWindowsByStacking = global.display.sort_windows_by_stacking(
global.display.sort_windows_by_stacking(windows).reverse(); workspace.list_windows()
).reverse();
return allWindowsByStacking.find(metaWindow => { return allWindowsByStacking.find(metaWindow => {
let rect = metaWindow.get_frame_rect(); let rect = metaWindow.get_frame_rect();

View File

@@ -204,7 +204,7 @@ var RemoteSearchProvider = class {
g_interface_info: proxyInfo, g_interface_info: proxyInfo,
g_interface_name: proxyInfo.name, g_interface_name: proxyInfo.name,
gFlags }); gFlags });
this.proxy.init_async(GLib.PRIORITY_DEFAULT, null); this.proxy.init_async(GLib.PRIORITY_DEFAULT, null, null);
this.appInfo = appInfo; this.appInfo = appInfo;
this.id = appInfo.get_id(); this.id = appInfo.get_id();
@@ -247,7 +247,7 @@ var RemoteSearchProvider = class {
if (error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return; return;
log('Received error from D-Bus search provider %s: %s'.format(this.id, String(error))); log('Received error from DBus search provider %s: %s'.format(this.id, String(error)));
callback([]); callback([]);
return; return;
} }
@@ -274,7 +274,7 @@ var RemoteSearchProvider = class {
_getResultMetasFinished(results, error, callback) { _getResultMetasFinished(results, error, callback) {
if (error) { if (error) {
if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (!error.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
log('Received error from D-Bus search provider %s during GetResultMetas: %s'.format(this.id, String(error))); log('Received error from DBus search provider %s during GetResultMetas: %s'.format(this.id, String(error)));
callback([]); callback([]);
return; return;
} }

View File

@@ -198,7 +198,7 @@ var ScreenShield = class {
let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY); let lockEnabled = this._settings.get_boolean(LOCK_ENABLED_KEY);
let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY); let lockLocked = this._lockSettings.get_boolean(DISABLE_LOCK_KEY);
let inhibit = this._loginSession && this._loginSession.Active && let inhibit = this._loginSession && this._loginSession.Active &&
!this._isActive && lockEnabled && !lockLocked && Main.sessionMode.unlockDialog; !this._isActive && lockEnabled && !lockLocked;
if (inhibit) { if (inhibit) {
this._loginManager.inhibit(_("GNOME needs to lock the screen"), this._loginManager.inhibit(_("GNOME needs to lock the screen"),
inhibitor => { inhibitor => {
@@ -345,7 +345,7 @@ var ScreenShield = class {
this._lockDialogGroup.remove_all_transitions(); this._lockDialogGroup.remove_all_transitions();
if (animate) { if (animate) {
// Animate the lock screen out of screen // Tween the lock screen out of screen
// if velocity is not specified (i.e. we come here from pressing ESC), // if velocity is not specified (i.e. we come here from pressing ESC),
// use the same speed regardless of original position // use the same speed regardless of original position
// if velocity is specified, it's in pixels per milliseconds // if velocity is specified, it's in pixels per milliseconds
@@ -498,8 +498,6 @@ var ScreenShield = class {
if (Main.sessionMode.currentMode == 'unlock-dialog') if (Main.sessionMode.currentMode == 'unlock-dialog')
Main.sessionMode.popMode('unlock-dialog'); Main.sessionMode.popMode('unlock-dialog');
this.emit('wake-up-screen');
if (this._isGreeter) { if (this._isGreeter) {
// We don't want to "deactivate" any more than // We don't want to "deactivate" any more than
// this. In particular, we don't want to drop // this. In particular, we don't want to drop
@@ -521,9 +519,6 @@ var ScreenShield = class {
this._isModal = false; this._isModal = false;
} }
this._longLightbox.lightOff();
this._shortLightbox.lightOff();
this._lockDialogGroup.ease({ this._lockDialogGroup.ease({
translation_y: -global.screen_height, translation_y: -global.screen_height,
duration: Overview.ANIMATION_TIME, duration: Overview.ANIMATION_TIME,
@@ -538,6 +533,8 @@ var ScreenShield = class {
this._dialog = null; this._dialog = null;
} }
this._longLightbox.lightOff();
this._shortLightbox.lightOff();
this.actor.hide(); this.actor.hide();
if (this._becameActiveId != 0) { if (this._becameActiveId != 0) {
@@ -561,8 +558,7 @@ var ScreenShield = class {
if (this._activationTime == 0) if (this._activationTime == 0)
this._activationTime = GLib.get_monotonic_time(); this._activationTime = GLib.get_monotonic_time();
if (!this._ensureUnlockDialog(true)) this._ensureUnlockDialog(true);
return;
this.actor.show(); this.actor.show();

View File

@@ -7,13 +7,6 @@ const GrabHelper = imports.ui.grabHelper;
const Lightbox = imports.ui.lightbox; const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main; const Main = imports.ui.main;
Gio._promisify(Shell.Screenshot.prototype, 'pick_color', 'pick_color_finish');
Gio._promisify(Shell.Screenshot.prototype, 'screenshot', 'screenshot_finish');
Gio._promisify(Shell.Screenshot.prototype,
'screenshot_window', 'screenshot_window_finish');
Gio._promisify(Shell.Screenshot.prototype,
'screenshot_area', 'screenshot_area_finish');
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot'); const ScreenshotIface = loadInterfaceXML('org.gnome.Shell.Screenshot');
@@ -91,7 +84,7 @@ var ScreenshotService = class {
} }
} }
_createStream(filename, invocation) { _createStream(filename) {
if (filename == '') if (filename == '')
return [Gio.MemoryOutputStream.new_resizable(), null]; return [Gio.MemoryOutputStream.new_resizable(), null];
@@ -101,7 +94,6 @@ var ScreenshotService = class {
let stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null); let stream = file.replace(null, false, Gio.FileCreateFlags.NONE, null);
return [stream, file]; return [stream, file];
} catch (e) { } catch (e) {
invocation.return_value(GLib.Variant.new('(bs)', [false, '']));
return [null, null]; return [null, null];
} }
} }
@@ -112,22 +104,23 @@ var ScreenshotService = class {
return [stream, file]; return [stream, file];
} catch (e) { } catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS)) if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.EXISTS))
break; return [null, null];
} }
} }
invocation.return_value(GLib.Variant.new('(bs)', [false, '']));
return [null, null]; return [null, null];
} }
_onScreenshotComplete(area, stream, file, flash, invocation) { _onScreenshotComplete(result, area, stream, file, flash, invocation) {
if (flash) { if (result) {
let flashspot = new Flashspot(area); if (flash) {
flashspot.fire(() => { let flashspot = new Flashspot(area);
flashspot.fire(() => {
this._removeShooterForSender(invocation.get_sender());
});
} else {
this._removeShooterForSender(invocation.get_sender()); this._removeShooterForSender(invocation.get_sender());
}); }
} else {
this._removeShooterForSender(invocation.get_sender());
} }
stream.close(null); stream.close(null);
@@ -141,7 +134,7 @@ var ScreenshotService = class {
clipboard.set_content(St.ClipboardType.CLIPBOARD, 'image/png', bytes); clipboard.set_content(St.ClipboardType.CLIPBOARD, 'image/png', bytes);
} }
let retval = GLib.Variant.new('(bs)', [true, filenameUsed]); let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
invocation.return_value(retval); invocation.return_value(retval);
} }
@@ -163,7 +156,7 @@ var ScreenshotService = class {
return [x, y, width, height]; return [x, y, width, height];
} }
async ScreenshotAreaAsync(params, invocation) { ScreenshotAreaAsync(params, invocation) {
let [x, y, width, height, flash, filename] = params; let [x, y, width, height, flash, filename] = params;
[x, y, width, height] = this._scaleArea(x, y, width, height); [x, y, width, height] = this._scaleArea(x, y, width, height);
if (!this._checkArea(x, y, width, height)) { if (!this._checkArea(x, y, width, height)) {
@@ -176,57 +169,61 @@ var ScreenshotService = class {
if (!screenshot) if (!screenshot)
return; return;
let [stream, file] = this._createStream(filename, invocation); let [stream, file] = this._createStream(filename);
if (!stream)
return;
try { screenshot.screenshot_area(x, y, width, height, stream,
let [area] = (o, res) => {
await screenshot.screenshot_area(x, y, width, height, stream); try {
this._onScreenshotComplete(area, stream, file, flash, invocation); let [result, area] =
} catch (e) { screenshot.screenshot_area_finish(res);
this._removeShooterForSender(invocation.get_sender()); this._onScreenshotComplete(
invocation.return_value(new GLib.Variant('(bs)', [false, ''])); result, area, stream, file, flash, invocation);
} } catch (e) {
invocation.return_gerror(e);
}
});
} }
async ScreenshotWindowAsync(params, invocation) { ScreenshotWindowAsync(params, invocation) {
let [includeFrame, includeCursor, flash, filename] = params; let [includeFrame, includeCursor, flash, filename] = params;
let screenshot = this._createScreenshot(invocation); let screenshot = this._createScreenshot(invocation);
if (!screenshot) if (!screenshot)
return; return;
let [stream, file] = this._createStream(filename, invocation); let [stream, file] = this._createStream(filename);
if (!stream)
return;
try { screenshot.screenshot_window(includeFrame, includeCursor, stream,
let [area] = (o, res) => {
await screenshot.screenshot_window(includeFrame, includeCursor, stream); try {
this._onScreenshotComplete(area, stream, file, flash, invocation); let [result, area] =
} catch (e) { screenshot.screenshot_window_finish(res);
this._removeShooterForSender(invocation.get_sender()); this._onScreenshotComplete(
invocation.return_value(new GLib.Variant('(bs)', [false, ''])); result, area, stream, file, flash, invocation);
} } catch (e) {
invocation.return_gerror(e);
}
});
} }
async ScreenshotAsync(params, invocation) { ScreenshotAsync(params, invocation) {
let [includeCursor, flash, filename] = params; let [includeCursor, flash, filename] = params;
let screenshot = this._createScreenshot(invocation); let screenshot = this._createScreenshot(invocation);
if (!screenshot) if (!screenshot)
return; return;
let [stream, file] = this._createStream(filename, invocation); let [stream, file] = this._createStream(filename);
if (!stream)
return;
try { screenshot.screenshot(includeCursor, stream,
let [area] = await screenshot.screenshot(includeCursor, stream); (o, res) => {
this._onScreenshotComplete(area, stream, file, flash, invocation); try {
} catch (e) { let [result, area] =
this._removeShooterForSender(invocation.get_sender()); screenshot.screenshot_finish(res);
invocation.return_value(new GLib.Variant('(bs)', [false, ''])); this._onScreenshotComplete(
} result, area, stream, file, flash, invocation);
} catch (e) {
invocation.return_gerror(e);
}
});
} }
async SelectAreaAsync(params, invocation) { async SelectAreaAsync(params, invocation) {
@@ -267,17 +264,19 @@ var ScreenshotService = class {
if (!screenshot) if (!screenshot)
return; return;
const [color] = await screenshot.pick_color(coords.x, coords.y); screenshot.pick_color(coords.x, coords.y, (_o, res) => {
const { red, green, blue } = color; let [success_, color] = screenshot.pick_color_finish(res);
const retval = GLib.Variant.new('(a{sv})', [{ let { red, green, blue } = color;
color: GLib.Variant.new('(ddd)', [ let retval = GLib.Variant.new('(a{sv})', [{
red / 255.0, color: GLib.Variant.new('(ddd)', [
green / 255.0, red / 255.0,
blue / 255.0, green / 255.0,
]), blue / 255.0,
}]); ]),
this._removeShooterForSender(invocation.get_sender()); }]);
invocation.return_value(retval); this._removeShooterForSender(invocation.get_sender());
invocation.return_value(retval);
});
} catch (e) { } catch (e) {
invocation.return_error_literal( invocation.return_error_literal(
Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED, Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,

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