Compare commits

..

7 Commits

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

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

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

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

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

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

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

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

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

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/605
2020-02-26 10:36:10 +01:00
315 changed files with 27349 additions and 42845 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/gnome-shell
src/gnome-shell-calendar-server
src/gnome-shell-extension-prefs
src/gnome-shell-extension-tool
src/gnome-shell-hotplug-sniffer
src/gnome-shell-perf-helper

View File

@ -1,13 +1,9 @@
include: 'https://gitlab.gnome.org/GNOME/citemplates/raw/master/flatpak/flatpak_ci_initiative.yml'
stages:
- review
- build
- test
- deploy
variables:
BUNDLE: "extensions-git.flatpak"
JS_LOG: "js-report.txt"
POT_LOG: "pot-update.txt"
@ -18,7 +14,7 @@ variables:
- merge_requests
check_commit_log:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: review
variables:
GIT_DEPTH: "100"
@ -28,10 +24,10 @@ check_commit_log:
- merge_requests
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
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)
<<: *only_default
artifacts:
@ -40,7 +36,7 @@ js_check:
when: on_failure
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
script:
- ./.gitlab-ci/run-eslint.sh
@ -50,22 +46,8 @@ eslint:
- reports
when: always
potfile_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
stage: review
script:
- ./.gitlab-ci/check-potfiles.sh
<<: *only_default
no_template_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v2
stage: review
script:
- ./.gitlab-ci/check-template-strings.sh
<<: *only_default
build:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: build
before_script:
- .gitlab-ci/checkout-mutter.sh
@ -83,7 +65,7 @@ build:
- build
test:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: test
variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
@ -100,7 +82,7 @@ test:
when: on_failure
test-pot:
image: registry.gitlab.gnome.org/gnome/mutter/master:v4
image: registry.gitlab.gnome.org/gnome/mutter/master:v3
stage: test
before_script:
- ninja -C mutter/build install
@ -114,20 +96,3 @@ test-pot:
' | tee $POT_LOG
- (! grep -q . $POT_LOG)
<<: *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

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

View File

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

View File

@ -18,14 +18,12 @@ run_eslint() {
local extra_args=ARGS_$1
local output_var=OUTPUT_$1
local output=${!output_var}
local cache=.eslintcache-${1,,}
# ensure output exists even if eslint doesn't report any errors
mkdir -p $(dirname $output)
touch $output
eslint -f unix --cache --cache-location $cache ${!extra_args} -o $output \
js subprojects/extensions-app/js
eslint -f unix ${!extra_args} -o $output js
}
list_commit_range_additions() {

152
NEWS
View File

@ -1,155 +1,3 @@
3.37.2
======
* Add support for "PrefersNonDefaultGPU" desktop key [Bastien; !1226]
* Only start systemd units when running under systemd
[Carlos, Florian; #2755, !1242, !1252]
* Fix "ghost" media controls [Bryan; #2776]
* Fix zombie sockets from extensions downloader [Michael; #2774]
* Update world clocks offsets when timezone changes [Bryan; #2209]
* Support scrolling anywhere in slider menu items [Peter; #2795]
* Fix "Do Not Disturb" setting getting reset on startup [Florian; #2804]
* Only allow updates for extensions that aren't cached [Florian; !1248]
* Fix matching notifications by PID [Florian; #2592]
* Indicate extension errors in Extensions app [Florian; #2337]
* Add clipboard API for querying supported mimetypes [Andy; #2819]
* Add preview to color picker [Florian; #451]
* Improve world clocks styling [PrOF-kk; #2825]
* Remove Frequent view from app picker [Georges; !880]
* Fix pad OSD glitches [Carlos; !1290]
* Expose actor tree in looking glass [Georges; !1292]
* Fixed crashes [Jonas D., Florian; #2709, #2757]
* Misc. bug fixes and cleanups [Florian, AsciiWolf, Michael, Piotr, Ting-Wei,
Amr, Alexander, Bryan, Georges, Jonas D., Andy, Björn, Koki, Carlos; !1229,
!1231, !1233, !1235, #2578, #2735, #2751, #2602, #2777, !1249, #2796, !1268,
!1269, !1265, !1245, !1273, #2816, !1274, !1263, !1188, !1276, #2652, !1277,
!1281, #2286, !1267, !1286, !1279, !1288, !1293, !1294, !1291]
Contributors:
AsciiWolf, Michael Catanzaro, Björn Daase, Jonas Dreßler, Bryan Dunsmore,
Koki Fukuda, Carlos Garnacho, Andy Holmes, Amr Ibrahim, Soslan Khubulov,
Ting-Wei Lan, Michael Lass, Alexander Mikhaylenko, Florian Müllner,
Georges Basile Stavracas Neto, Bastien Nocera, PrOF-kk, Peter Simonyi
Translators:
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Yuri Chornoivan [uk],
Dušan Kazik [sk], Piotr Drąg [pl], Soslan Khubulov [os],
Daniel Mustieles [es], Nathan Follens [nl], Bruce Cowan [en_GB],
Florentina Mușat [ro], Milo Casagrande [it], Anders Jonsson [sv],
Charles Monzat [fr], Danial Behzadi [fa], sicklylife [ja], Kukuh Syafaat [id],
Jordi Mas [ca], Emin Tufan Çetin [tr], Jiri Grönroos [fi], Марко Костић [sr],
Christian Kirbach [de], Changwoo Ryu [ko], Matej Urbančič [sl]
3.37.1
======
* Improve bluetooth submenu title [Mariana; #2340]
* Add openPrefs() convenience method for extensions [Florian; !1163]
* Bring back support for empty StIcons [Andre, Jonas D.; !1173, !1178]
* Wake up screen when unlocking programmatically [Florian; !1158]
* Improve extensions tool error reporting [Florian; #2391]
* Improve handling of scale-factor changes [Georges; !1176]
* Tone down weekend days with events in calendar [Jakub; #2588]
* Fix showing bluetooth submenu when devices were set up [Florian; !1174]
* Add support for parental controls filtering [Philip W.; !465]
* Provide alternative extension templates [Florian; !812]
* Improve weather section's empty state [Mariana; #2179]
* Fix translations of folder names [Florian; #2623]
* Drop Tweener [Jonas Å.; !1200]
* Match ASCII alternatives of system actions [Will; #2688]
* Fix delay on lock screen after entering wrong password [Jonas D.; #2655]
* Use globalThis instead of window [Andy; #2322]
* Inhibit remote access when disabled by session mode [Jonas Å.; !1210]
* Improve calendar-server performance [Milan; #1875]
* Add gnome-shell-extension-prefs wrapper for compatibility [Florian; !1220]
* Fix stuck lock screen after unlock [Jonas D., Florian; #2446]
* Fixed crashes [Jonas D., Florian, Carlos; #2584, #2625, !1223, !1218]
* Misc. bug fixes and cleanups [Florian, Jonas Å., Marco, Andre, Georges,
Jonas D., Jan, Philip Ch.,, Xiaoguang, Will, Jordan, Matthew, qarmin;
!1126, !1155, !1156, !1165, !1168, !1169, #2551, #2563, !1172, !1175, !1179,
!1160, #2562, #2578, !1184, #2559, !1186, #2607, !1191, !1194, !1199, !1203,
#2649, #2628, !1205, !1206, !1208, !1207, !1211, !1214, !1213, !1192, !1217,
!1219, #1615, #2691, !1094, !1177]
Contributors:
Marco Trevisan (Treviño), Philip Chimento, Milan Crha, Jonas Dreßler,
Carlos Garnacho, Andy Holmes, Matthew Leeds, Andre Moreira Magalhaes,
Florian Müllner, Georges Basile Stavracas Neto, Jordan Petridis,
Mariana Picolo, Jakub Steiner, Will Thompson, Jan Tojnar, Xiaoguang Wang,
Philip Withnall, qarmin, Jonas Ådahl
Translators:
Fabio Tomat [fur], Cheng-Chia Tseng [zh_TW], Danial Behzadi [fa],
Jiri Grönroos [fi], Ibai Oihanguren Sala [eu], Марко Костић [sr],
Rūdolfs Mazurs [lv], Yuri Chornoivan [uk], Carmen Bianca BAKKER [eo],
Dingzhong Chen [zh_CN], Rafael Fontenelle [pt_BR], Petr Kovář [cs],
Asier Sarasua Garmendia [eu], Daniel Mustieles [es], Emin Tufan Çetin [tr]
3.36.0
======
* Fix off-by-1900 error in date conversions [Florian; !1061]
* Fix crash on startup with topIcons* extension enabled [Florian; #2308]
* Don't require gsd-xsettings for X11 support on wayland [Olivier; !1065]
* Fix ibus support in Xorg session [Carlos; #1690]
* Improve Extensions D-Bus API [Florian; !1074]
* Allow session modes to specify alternative resource name [Marco; !1063]
* Fix link to location settings in aggregate menu [Sebastian; #2316]
* Fix illegible app folder titles with light theme [ub; !1059]
* Really fix visual glitch in sliders [Jonas; #1569]
Contributors:
Marco Trevisan (Treviño), Jonas Dreßler, Olivier Fourdan, Carlos Garnacho,
Sebastian Keller, Florian Müllner, ub
Translators:
Aman Alam [pa], Goran Vidović [hr], Aurimas Černius [lt],
Milo Casagrande [it], Daniel Korostil [uk], sicklylife [ja],
Marek Černocký [cs], Nathan Follens [nl]
3.35.92
=======
* Plug a memory leak [Jonas D.; !1015]
* Fix missing "back" button on login screen [Florian; #2228]
* Fix width of window preview titles in overview [Jonas D.; #58]
* Fix looking glass text with light style variant [Feichtmeier; !1023]
* Center unlock entry [Florian; !1021]
* Hide overlay scrollbars in notification popup [Jonas D.; !1013]
* Work around add_actor() slowness in icon spring animation [Daniel; !1002]
* Add disable-animations heuristics [Jonas Å.; !757]
* Fix visual glitches in on-screen keyboard [Carlos; #2214]
* Fix clearing changed textures from cache [Florian; #2244]
* Fix visual glitch in sliders [Daniel; #1569]
* Stop using dedicated lock screen background [Florian; !1001]
* Fix entries disappearing after authentication errors [Florian; #2236]
* Fix crash when animations are disabled [Florian; #2255]
* Fix passing pointer events to clients when magnified [Jonas D.; !993]
* Fix keynav on new lock screen [Florian; #2210]
* Avoid short-lived allocations on actor removal [Christian; #2263]
* Fix super-sized default avatars in user list [Florian, Sam; #2242]
* Leave overview when locking the screen [Jonas D.; !1043]
* Hide message list on login screen [Florian; #2241]
* Avoid IO on the main thread [Christian, Florian; !1050, !1051]
* Fix window animations getting stuck when client doesn't respond [Jonas; !1055]
* Only subscribe to touchpad events for touchpad gestures [Daniel; !925]
* Start X11 session services before Xwayland clients [Carlos; !836, !1056]
* Only show switch-user button with unlock prompt [Florian; !1029]
* Misc. bug fixes and cleanups [Jonas D., Florian, Georges, Jonas Å., Daniel,
Jakub, Philippe; !1018, !1020, !1024, !1027, !1026, !1022, !1031, !1035,
!1032, !1025, !1039, #2157, !1037, !1042, !1047, !1048, #2270, !1046,
!167, !1016]
Contributors:
Jonas Dreßler, Feichtmeier, Carlos Garnacho, Christian Hergert, Sam Hewitt,
Florian Müllner, Georges Basile Stavracas Neto, Jakub Steiner, Philippe Troin,
Daniel van Vugt, Jonas Ådahl
Translators:
Danial Behzadi [fa], Efstathios Iosifidis [el], Daniel Mustieles [es],
Sabri Ünal [tr], sicklylife [ja], Piotr Drąg [pl], Jordi Mas [ca],
Anders Jonsson [sv], Chao-Hsiung Liao [zh_TW], Asier Sarasua Garmendia [eu],
Rafael Fontenelle [pt_BR], Марко Костић [sr], Changwoo Ryu [ko],
Charles Monzat [fr], Jiri Grönroos [fi], Jor Teron [mjw], Bruce Cowan [en_GB],
Emin Tufan Çetin [tr], Alan Mortensen [da], Balázs Úr [hu], Fran Dieguez [gl],
Kukuh Syafaat [id]
3.35.91
=======
* Improve magnifier [Carlos; !984]

View File

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

View File

@ -1,19 +1,12 @@
<node>
<interface name="org.gnome.Shell.CalendarServer">
<method name="SetTimeRange">
<arg type="x" name="since" direction="in"/>
<arg type="x" name="until" direction="in"/>
<arg type="b" name="force_reload" direction="in"/>
<method name="GetEvents">
<arg type="x" direction="in" />
<arg type="x" direction="in" />
<arg type="b" direction="in" />
<arg type="a(sssbxxa{sv})" direction="out" />
</method>
<signal name="EventsAddedOrUpdated">
<arg type="a(ssbxxa{sv})" name="events" direction="out"/>
</signal>
<signal name="EventsRemoved">
<arg type="as" name="ids" direction="out"/>
</signal>
<signal name="ClientDisappeared">
<arg type="s" name="source_uid" direction="out"/>
</signal>
<property name="HasCalendars" type="b" access="read" />
<signal name="Changed" />
</interface>
</node>

View File

@ -199,37 +199,14 @@
<!--
LaunchExtensionPrefs:
Deprecated for OpenExtensionPrefs
@uuid: The UUID of the extension
Launch preferences of an extension.
-->
<method name="LaunchExtensionPrefs">
<arg type="s" direction="in" name="uuid"/>
</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:
Update all extensions for which updates are available
@ -257,11 +234,5 @@
-->
<property name="ShellVersion" type="s" access="read"/>
<!--
UserExtensionsEnabled:
Whether user extensions are enabled
-->
<property name="UserExtensionsEnabled" type="b" access="readwrite"/>
</interface>
</node>

View File

@ -2,6 +2,7 @@
<gresources>
<gresource prefix="/org/gnome/shell/dbus-interfaces">
<file preprocess="xml-stripblanks">net.hadess.SensorProxy.xml</file>
<file preprocess="xml-stripblanks">net.hadess.SwitcherooControl.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.Application.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Device.xml</file>
<file preprocess="xml-stripblanks">org.freedesktop.bolt1.Manager.xml</file>

View File

@ -6,7 +6,6 @@
<file>checkbox-off-focused.svg</file>
<file>checkbox-off.svg</file>
<file>checkbox.svg</file>
<file alias="icons/color-pick.svg">color-pick.svg</file>
<file>dash-placeholder.svg</file>
<file>gnome-shell.css</file>
<file>gnome-shell-high-contrast.css</file>

View File

@ -19,10 +19,6 @@ Before=gnome-session-initialized.target
[Service]
Type=notify
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
SuccessExitStatus=1
# 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,6 @@
desktop_files = [
'org.gnome.Shell.desktop',
'org.gnome.Shell.Extensions.desktop',
'org.gnome.Extensions.desktop',
]
service_files = []

View File

@ -2,9 +2,8 @@
Type=Application
Name=Extensions
# 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
Exec=@bindir@/@prgname@
DBusActivatable=true
Categories=GNOME;GTK;Utility;
Exec=@bindir@/gnome-shell-extension-prefs %u
Categories=GNOME;GTK;
OnlyShowIn=GNOME;

View File

@ -1,10 +0,0 @@
[Desktop Entry]
Type=Application
# Keep in sync with subprojects/extensions-app
Name=Extensions
# Translators: Do NOT translate or transliterate this text (this is an icon file name)!
Icon=org.gnome.Shell.Extensions
# Never launch this, just provide name+icon to portal dialog
Exec=false
OnlyShowIn=GNOME;
NoDisplay=true

View File

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

View File

@ -1,94 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="5.4116011mm"
height="5.1374583mm"
viewBox="0 0 5.4116011 5.1374583"
version="1.1"
id="svg5595"
inkscape:version="0.92.4 (unknown)"
sodipodi:docname="color-pick.svg">
<defs
id="defs5589">
<filter
inkscape:collect="always"
x="-0.10291173"
width="1.2058235"
y="-0.065432459"
height="1.1308649"
id="filter5601"
style="color-interpolation-filters:sRGB">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.610872"
id="feGaussianBlur5603" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="15.839192"
inkscape:cx="39.387731"
inkscape:cy="12.554326"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1016"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<metadata
id="metadata5592">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-103.12753,-146.26461)">
<circle
r="8.4810486"
cy="9.82623"
cx="10.226647"
id="circle7584"
style="color:#000000;display:inline;overflow:visible;opacity:0.6;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;filter:url(#filter5601)"
transform="matrix(0.26458333,0,0,0.26458333,103.12753,146.26461)" />
<path
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.26399338;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
d="m 108.07728,148.64122 c 0,1.2393 -1.00465,2.24394 -2.24395,2.24394 -1.23929,0 -2.24716,-1.00465 -2.25221,-2.24394 l -0.009,-2.24458 2.26136,6.4e-4 c 1.2393,3.4e-4 2.24395,1.00464 2.24395,2.24394 z"
id="path7523-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ssscss" />
<circle
style="color:#000000;display:inline;overflow:visible;opacity:1;vector-effect:none;fill:#50dbb5;fill-opacity:1;stroke:none;stroke-width:0.36885914;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal"
id="path7482-1"
cx="105.83707"
cy="148.64352"
r="1.844296" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -1,15 +1,21 @@
/* App Grid */
$app_icon_size: 96px;
$app_icon_padding: 24px;
// app icons
.icon-grid {
row-spacing: $base_spacing * 6;
column-spacing: $base_spacing * 6;
max-row-spacing: $base_spacing * 12;
max-column-spacing: $base_spacing * 12;
-shell-grid-horizontal-item-size: $app_icon_size + $app_icon_padding * 2;
-shell-grid-vertical-item-size: $app_icon_size + $app_icon_padding * 2;
spacing: $base_spacing * 6;
.overview-icon {
icon-size: $app_icon_size;
}
}
//.app-display { spacing: 20px; }
/* App Icons */
$app_grid_fg_color: #fff;
@ -29,17 +35,17 @@ $app_grid_fg_color: #fff;
}
/* App Folders */
.app-well-app.app-folder {
background-color: transparentize($osd_bg_color, 0.8);
border-radius: $base_border_radius + 4px; // same as %icon_tile
.app-folder {
.overview-icon {
}
}
// expanded folder
.app-folder-dialog {
border-radius: $modal_radius * 1.5;
border: 1px solid $osd_outer_borders_color;
spacing: 12px;
background-color: transparentize(darken($osd_bg_color,10%), 0.05);
padding: 12px;
& .folder-name-container {
padding: 24px 36px 0;
@ -48,13 +54,13 @@ $app_grid_fg_color: #fff;
& .folder-name-label,
& .folder-name-entry {
font-size: 18pt;
font-weight: 800;
font-weight: bold;
}
& .folder-name-entry { width: 300px }
/* 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 {
@extend %button;
@ -68,23 +74,14 @@ $app_grid_fg_color: #fff;
}
}
& .icon-grid {
row-spacing: $base_spacing * 2;
column-spacing: $base_spacing * 5;
}
& .page-indicators {
margin-bottom: 18px;
.page-indicator {
padding: 15px 12px;
}
}
& StButton#vhandle,
& StButton#vhandle:hover,
& StButton#vhandle:active { background-color: transparent; }
}
.app-folder-dialog-container {
padding: 12px;
width: 620px;
height: 620px;
width: 800px;
height: 600px;
}
.app-folder-icon {
@ -130,11 +127,15 @@ $app_grid_fg_color: #fff;
}
// Some hacks I don't even know
.all-apps {
.all-apps,
.frequent-apps > StBoxLayout {
// horizontal padding to make sure scrollbars or dash don't overlap content
padding: 0px 88px 10px 88px;
}
// Label when no frequent apps
.no-frequent-applications-label { @extend %status_text; }
// shutdown and other actions in the grid
.system-action-icon {
background-color: rgba(0,0,0,0.8);
@ -142,3 +143,44 @@ $app_grid_fg_color: #fff;
border-radius: 99px;
icon-size: $app_icon_size * 0.5;
}
/* Frequent | All toggle */
// container
.app-view-controls {
padding-bottom: 32px;
}
// buttons
.app-view-control {
padding: 4px 32px;
margin: 0 4px;
&, &:hover, &:checked {
@include button(undecorated);
color: darken($osd_fg_color, 25%);
}
&:hover {
color: $osd_fg_color;
box-shadow: inset 0 -2px darken($osd_fg_color, 25%);
}
&:active {
box-shadow: inset 0 -2px $osd_fg_color;
}
&:checked {
color: $osd_fg_color;
box-shadow: inset 0 -2px $selected_bg_color;
}
&:first-child {
border-right-width: 0;
border-radius: 0;
}
&:last-child {
border-radius: 0;
}
}

View File

@ -153,11 +153,9 @@
}
.calendar-day-with-events {
color: lighten($fg_color,10%);
font-weight: bold;
background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
&.calendar-work-day {
color: lighten($fg_color,10%);
font-weight: bold;
}
}
.calendar-other-month-day {
@ -177,32 +175,6 @@
}
}
/* Events */
.events-button {
@include notification_bubble;
padding: $base_padding * 2;
.events-box {
spacing: $base_spacing;
}
.events-list {
spacing: 2 * $base_spacing;
}
.events-title {
color: desaturate(darken($fg_color,40%), 10%);
font-weight: bold;
margin-bottom: $base_margin;
}
.event-time {
color: darken($fg_color,20%);
font-feature-settings: "tnum";
@include fontsize($base_font_size - 1);
}
}
/* World clocks */
.world-clocks-button {
@include notification_bubble;
@ -230,7 +202,7 @@
.world-clocks-time {
font-weight: bold;
color: $fg_color;
font-feature-settings: "tnum";
font-feature-settings: "lnum";
@include fontsize($base_font_size);
text-align: right;
}

View File

@ -1,7 +1,5 @@
/* Looking Glass */
$text_fg_color: #ccc;
// Dialog
#LookingGlassDialog {
background-color: $osd_bg_color;
@ -54,11 +52,6 @@ $text_fg_color: #ccc;
&:hover { color: lighten($link_color, 10%); }
&:active { color: darken($link_color, 10%); }
}
.actor-link {
color: $text_fg_color;
&:hover { color: lighten($text_fg_color, 20%); }
&:active { color: darken($text_fg_color, 20%); }
}
}
.lg-completions-text {

View File

@ -54,10 +54,6 @@
@extend %status_text;
}
.grid-search-results {
spacing: $base_spacing * 6;
}
// Search results with icons
.grid-search-result {
@extend %app-well-app;

View File

@ -15,11 +15,13 @@
border: 1px solid transparent;
&: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 {
background-color: transparentize($osd_fg_color, 0.7);
background-color: transparentize($osd_fg_color, 0.9);
color: $osd_fg_color;
}
}

View File

@ -8,7 +8,6 @@ $window_thumbnail_border_color:transparentize($selected_fg_color, 0.65);
$window_close_button_size: 24px;
$window_close_button_padding: 3px;
$window_clone_border_size: 6px;
// Window picker
.window-picker {
@ -23,7 +22,7 @@ $window_clone_border_size: 6px;
// Borders on window thumbnails
.window-clone-border {
border-width: $window_clone_border_size;
border-width: 6px;
border-style: solid;
border-color: $window_thumbnail_border_color;
border-radius: $base_border_radius + 2;
@ -55,6 +54,8 @@ $window_clone_border_size: 6px;
width: $window_close_button_size;
box-shadow: -1px 1px 5px 0px rgba(0,0,0,0.5);
-shell-close-overlap: $window_close_button_size * 0.5;
&:hover {
background-color: lighten($selected_bg_color, 5%);
}

View File

@ -1,9 +1,10 @@
#!/bin/env bash
CLDR_LAYOUTS_TARBALL="http://www.unicode.org/Public/cldr/latest/keyboards.zip"
CLDR2JSON_GIT="git://repo.or.cz/cldr2json.git"
WORKDIR=".osk-layout-workbench"
CLDR2JSON="cldr2json/cldr2json.py"
CLDR2JSON="$WORKDIR/cldr2json/cldr2json.py"
SRCDIR="$WORKDIR/keyboards/android"
DESTDIR="osk-layouts"
GRESOURCE_FILE="gnome-shell-osk-layouts.gresource.xml"
@ -19,6 +20,7 @@ mkdir -p "osk-layouts"
# Download stuff on the work dir
pushd $WORKDIR
gio copy $CLDR_LAYOUTS_TARBALL .
git clone $CLDR2JSON_GIT
unzip keyboards.zip
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,105 +0,0 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NotificationDaemon */
const { Gio, GLib } = imports.gi;
const { loadInterfaceXML } = imports.misc.fileUtils;
const { ServiceImplementation } = imports.dbusService;
const NotificationsIface = loadInterfaceXML('org.freedesktop.Notifications');
const NotificationsProxy = Gio.DBusProxy.makeProxyWrapper(NotificationsIface);
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
var NotificationDaemon = class extends ServiceImplementation {
constructor() {
super(NotificationsIface, '/org/freedesktop/Notifications');
this._autoShutdown = false;
this._proxy = new NotificationsProxy(Gio.DBus.session,
'org.gnome.Shell',
'/org/freedesktop/Notifications',
(proxy, error) => {
if (error)
log(error.message);
});
this._proxy.connectSignal('ActionInvoked',
(proxy, sender, params) => {
this._dbusImpl.emit_signal('ActionInvoked',
new GLib.Variant('(us)', params));
});
this._proxy.connectSignal('NotificationClosed',
(proxy, sender, params) => {
this._dbusImpl.emit_signal('NotificationClosed',
new GLib.Variant('(uu)', params));
});
}
register() {
Gio.DBus.session.own_name(
'org.freedesktop.Notifications',
Gio.BusNameOwnerFlags.REPLACE,
null, null);
}
async NotifyAsync(params, invocation) {
const pid = await this._getSenderPid(invocation.get_sender());
const hints = params[6];
params[6] = {
...hints,
'sender-pid': new GLib.Variant('u', pid),
};
this._proxy.NotifyRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(u)', res));
});
}
CloseNotificationAsync(params, invocation) {
this._proxy.CloseNotificationRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(null);
});
}
GetCapabilitiesAsync(params, invocation) {
this._proxy.GetCapabilitiesRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(as)', res));
});
}
GetServerInformationAsync(params, invocation) {
this._proxy.GetServerInformationRemote(...params, (res, error) => {
if (this._handleError(invocation, error))
return;
invocation.return_value(new GLib.Variant('(ssss)', res));
});
}
async _getSenderPid(sender) {
const res = await Gio.DBus.session.call(
'org.freedesktop.DBus',
'/',
'org.freedesktop.DBus',
'GetConnectionUnixProcessID',
new GLib.Variant('(s)', [sender]),
new GLib.VariantType('(u)'),
Gio.DBusCallFlags.NONE,
-1,
null);
const [pid] = res.deepUnpack();
return pid;
}
};

View File

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

View File

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

View File

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

View File

@ -3,45 +3,34 @@ imports.gi.versions.Gdk = '3.0';
imports.gi.versions.Gtk = '3.0';
const Gettext = imports.gettext;
const Package = imports.package;
const { Gdk, GLib, Gio, GObject, Gtk, Shew } = imports.gi;
const { Gdk, GLib, Gio, GObject, Gtk } = imports.gi;
const Format = imports.format;
Package.initFormat();
const _ = Gettext.gettext;
const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils;
const { loadInterfaceXML } = imports.misc.fileUtils;
const { ExtensionState, ExtensionType } = ExtensionUtils;
const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
Gio._promisify(Gio.DBusConnection.prototype, 'call', 'call_finish');
Gio._promisify(Shew.WindowExporter.prototype, 'export', 'export_finish');
function loadInterfaceXML(iface) {
const uri = 'resource:///org/gnome/Extensions/dbus-interfaces/%s.xml'.format(iface);
const f = Gio.File.new_for_uri(uri);
try {
let [ok_, bytes] = f.load_contents(null);
return imports.byteArray.toString(bytes);
} catch (e) {
log('Failed to load D-Bus interface %s'.format(iface));
}
return null;
}
function toggleState(action) {
let state = action.get_state();
action.change_state(new GLib.Variant('b', !state.get_boolean()));
function stripPrefix(string, prefix) {
if (string.slice(0, prefix.length) == prefix)
return string.slice(prefix.length);
return string;
}
var Application = GObject.registerClass(
class Application extends Gtk.Application {
_init() {
GLib.set_prgname('gnome-extensions-app');
super._init({ application_id: 'org.gnome.Extensions' });
GLib.set_prgname('gnome-shell-extension-prefs');
super._init({
application_id: 'org.gnome.Extensions',
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE,
});
}
get shellProxy() {
@ -57,7 +46,7 @@ class Application extends Gtk.Application {
super.vfunc_startup();
let provider = new Gtk.CssProvider();
let uri = 'resource:///org/gnome/Extensions/css/application.css';
let uri = 'resource:///org/gnome/shell/css/application.css';
try {
provider.load_from_file(Gio.File.new_for_uri(uri));
} catch (e) {
@ -67,19 +56,34 @@ class Application extends Gtk.Application {
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
this._shellProxy = new GnomeShellProxy(Gio.DBus.session,
'org.gnome.Shell.Extensions', '/org/gnome/Shell/Extensions');
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
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({
GTypeName: 'ExtensionsWindow',
Template: 'resource:///org/gnome/Extensions/ui/extensions-window.ui',
Template: 'resource:///org/gnome/shell/ui/extensions-window.ui',
InternalChildren: [
'userList',
'systemList',
'killSwitch',
'mainBox',
'mainStack',
'scrolledWindow',
@ -90,11 +94,11 @@ var ExtensionsWindow = GObject.registerClass({
_init(params) {
super._init(params);
this._startupUuid = null;
this._loaded = false;
this._prefsDialog = null;
this._updatesCheckId = 0;
this._exporter = new Shew.WindowExporter({ window: this });
this._exportedHandle = '';
this._mainBox.set_focus_vadjustment(this._scrolledWindow.vadjustment);
let action;
@ -106,15 +110,10 @@ var ExtensionsWindow = GObject.registerClass({
action.connect('activate', this._logout.bind(this));
this.add_action(action);
action = new Gio.SimpleAction({
name: 'user-extensions-enabled',
state: new GLib.Variant('b', false),
});
action.connect('activate', toggleState);
action.connect('change-state', (a, state) => {
this._shellProxy.UserExtensionsEnabled = state.get_boolean();
});
this.add_action(action);
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
this._settings.bind('disable-user-extensions',
this._killSwitch, 'active',
Gio.SettingsBindFlags.DEFAULT | Gio.SettingsBindFlags.INVERT_BOOLEAN);
this._userList.set_sort_func(this._sortList.bind(this));
this._userList.set_header_func(this._updateHeader.bind(this));
@ -125,10 +124,6 @@ var ExtensionsWindow = GObject.registerClass({
this._shellProxy.connectSignal('ExtensionStateChanged',
this._onExtensionStateChanged.bind(this));
this._shellProxy.connect('g-properties-changed',
this._onUserExtensionsEnabledChanged.bind(this));
this._onUserExtensionsEnabledChanged();
this._scanExtensions();
}
@ -158,18 +153,58 @@ var ExtensionsWindow = GObject.registerClass({
dialog.present();
}
async openPrefs(uuid) {
if (!this._exportedHandle) {
try {
this._exportedHandle = await this._exporter.export();
} catch (e) {
log('Failed to export window: %s'.format(e.message));
}
openPrefs(uuid) {
if (!this._loaded)
this._startupUuid = uuid;
else if (!this._showPrefs(uuid))
this.present();
}
_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._exportedHandle,
{ modal: new GLib.Variant('b', true) });
this._prefsDialog = new Gtk.Window({
application: this.application,
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() {
@ -184,7 +219,7 @@ var ExtensionsWindow = GObject.registerClass({
comments: _('Manage your GNOME Extensions'),
license_type: Gtk.License.GPL_2_0,
logo_icon_name: 'org.gnome.Extensions',
version: imports.package.version,
version: Config.PACKAGE_VERSION,
transient_for: this,
modal: true,
@ -202,7 +237,125 @@ var ExtensionsWindow = GObject.registerClass({
null,
Gio.DBusCallFlags.NONE,
-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) {
@ -224,12 +377,6 @@ var ExtensionsWindow = GObject.registerClass({
].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]) {
let extension = ExtensionUtils.deserializeExtension(newState);
let row = this._findExtensionRow(uuid);
@ -247,11 +394,9 @@ var ExtensionsWindow = GObject.registerClass({
if (row) {
if (extension.state === ExtensionState.UNINSTALLED)
row.destroy();
} else {
this._addExtensionRow(extension);
return; // we only deal with new and deleted extensions here
}
this._syncListVisibility();
this._addExtensionRow(extension);
}
_scanExtensions() {
@ -297,16 +442,6 @@ var ExtensionsWindow = GObject.registerClass({
});
}
_syncListVisibility() {
this._userList.visible = this._userList.get_children().length > 0;
this._systemList.visible = this._systemList.get_children().length > 0;
if (this._userList.visible || this._systemList.visible)
this._mainStack.visible_child_name = 'main';
else
this._mainStack.visible_child_name = 'placeholder';
}
_checkUpdates() {
let nUpdates = this._userList.get_children().filter(c => c.hasUpdate).length;
@ -318,23 +453,131 @@ var ExtensionsWindow = GObject.registerClass({
}
_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();
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({
GTypeName: 'ExtensionRow',
Template: 'resource:///org/gnome/Extensions/ui/extension-row.ui',
Template: 'resource:///org/gnome/shell/ui/extension-row.ui',
InternalChildren: [
'nameLabel',
'descriptionLabel',
'versionLabel',
'authorLabel',
'errorLabel',
'errorIcon',
'updatesIcon',
'switch',
'revealButton',
'revealer',
],
@ -378,7 +621,10 @@ var ExtensionRow = GObject.registerClass({
name: 'enabled',
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) => {
if (state.get_boolean())
this._app.shellProxy.EnableExtensionRemote(this.uuid);
@ -387,7 +633,8 @@ var ExtensionRow = GObject.registerClass({
});
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];
this._descriptionLabel.label = desc;
@ -431,12 +678,6 @@ var ExtensionRow = GObject.registerClass({
return this._extension.hasUpdate || false;
}
get hasError() {
const { state } = this._extension;
return state === ExtensionState.OUT_OF_DATE ||
state === ExtensionState.ERROR;
}
get type() {
return this._extension.type;
}
@ -453,17 +694,6 @@ var ExtensionRow = GObject.registerClass({
return this._extension.metadata.version || '';
}
get error() {
if (!this.hasError)
return '';
if (this._extension.state === ExtensionState.OUT_OF_DATE)
return _('The extension is incompatible with the current GNOME version');
return this._extension.error
? this._extension.error : _('The extension had an error');
}
_updateState() {
let state = this._extension.state === ExtensionState.ENABLED;
@ -471,14 +701,7 @@ var ExtensionRow = GObject.registerClass({
action.set_state(new GLib.Variant('b', state));
action.enabled = this._canToggle();
if (!action.enabled)
this._switch.active = state;
this._updatesIcon.visible = this.hasUpdate;
this._errorIcon.visible = this.hasError;
this._errorLabel.label = this.error;
this._errorLabel.visible = this.error !== '';
this._versionLabel.label = this.version.toString();
this._versionLabel.visible = this.version !== '';
@ -499,12 +722,26 @@ var ExtensionRow = GObject.registerClass({
_canToggle() {
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() {
// Monkey-patch in a "global" object that fakes some Shell utilities
// that ExtensionUtils depends on.
globalThis.global = {
window.global = {
log(...args) {
print(args.join(', '));
},
@ -515,11 +752,12 @@ function initEnvironment() {
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']),
};
String.prototype.format = Format.format;
}
function main(argv) {
initEnvironment();
Package.initGettext();
new Application().run(argv);
}

View File

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

View File

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

View File

@ -120,7 +120,7 @@ var AuthPrompt = GObject.registerClass({
vfunc_key_press_event(keyPressEvent) {
if (keyPressEvent.keyval == Clutter.KEY_Escape)
this.cancel();
return super.vfunc_key_press_event(keyPressEvent);
return Clutter.EVENT_PROPAGATE;
}
_initEntryRow() {
@ -184,7 +184,7 @@ var AuthPrompt = GObject.registerClass({
});
this._defaultButtonWell.add_constraint(new Clutter.BindConstraint({
source: this.cancelButton,
coordinate: Clutter.BindCoordinate.WIDTH,
coordinate: Clutter.BindCoordinate.SIZE,
}));
this._mainBox.add_child(this._defaultButtonWell);
@ -424,13 +424,8 @@ var AuthPrompt = GObject.registerClass({
}
updateSensitivity(sensitive) {
if (this._entry.reactive === sensitive)
return;
this._entry.reactive = sensitive;
if (sensitive)
this._entry.grab_key_focus();
this._entry.clutter_text.editable = sensitive;
}
vfunc_hide() {

View File

@ -35,6 +35,7 @@ const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 250;
const _SCROLL_ANIMATION_TIME = 500;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 48;
var UserListItem = GObject.registerClass({
Signals: { 'activate': {} },
@ -177,7 +178,6 @@ var UserList = GObject.registerClass({
}
vfunc_key_focus_in() {
super.vfunc_key_focus_in();
this._moveFocusToItems();
}
@ -456,6 +456,7 @@ var LoginDialog = GObject.registerClass({
let notListedLabel = new St.Label({
text: _("Not listed?"),
style_class: 'login-dialog-not-listed-label',
x_align: Clutter.ActorAlign.START,
});
this._notListedButton = new St.Button({
style_class: 'login-dialog-not-listed-button',
@ -463,7 +464,6 @@ var LoginDialog = GObject.registerClass({
can_focus: true,
child: notListedLabel,
reactive: true,
x_align: Clutter.ActorAlign.START,
});
this._notListedButton.connect('clicked', this._hideUserListAskForUsernameAndBeginVerification.bind(this));
@ -589,8 +589,8 @@ var LoginDialog = GObject.registerClass({
return actorBox;
}
vfunc_allocate(dialogBox) {
this.set_allocation(dialogBox);
vfunc_allocate(dialogBox, flags) {
this.set_allocation(dialogBox, flags);
let themeNode = this.get_theme_node();
dialogBox = themeNode.get_content_box(dialogBox);
@ -719,19 +719,19 @@ var LoginDialog = GObject.registerClass({
// Finally hand out the allocations
if (bannerAllocation)
this._bannerView.allocate(bannerAllocation);
this._bannerView.allocate(bannerAllocation, flags);
if (authPromptAllocation)
this._authPrompt.allocate(authPromptAllocation);
this._authPrompt.allocate(authPromptAllocation, flags);
if (userSelectionAllocation)
this._userSelectionBox.allocate(userSelectionAllocation);
this._userSelectionBox.allocate(userSelectionAllocation, flags);
if (logoAllocation)
this._logoBin.allocate(logoAllocation);
this._logoBin.allocate(logoAllocation, flags);
if (sessionMenuButtonAllocation)
this._sessionMenuButton.allocate(sessionMenuButtonAllocation);
this._sessionMenuButton.allocate(sessionMenuButtonAllocation, flags);
}
_ensureUserListLoaded() {
@ -810,13 +810,12 @@ var LoginDialog = GObject.registerClass({
return;
this._logoBin.destroy_all_children();
const [valid, resourceScale] = this._logoBin.get_resource_scale();
if (this._logoFile && valid) {
if (this._logoFile && this._logoBin.resource_scale > 0) {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._logoBin.add_child(this._textureCache.load_file_async(this._logoFile,
-1, -1,
-1, _LOGO_ICON_HEIGHT,
scaleFactor,
resourceScale));
this._logoBin.resource_scale));
}
}

View File

@ -2,7 +2,7 @@
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
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 Batch = imports.gdm.batch;
@ -12,15 +12,6 @@ const Main = imports.ui.main;
const Params = imports.misc.params;
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 FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
@ -177,12 +168,14 @@ var ShellUserVerifier = class {
this._checkForFingerprintReader();
// If possible, reauthenticate an already running session,
// so any session specific credentials get updated appropriately
if (userName)
this._openReauthenticationChannel(userName);
else
this._getUserVerifier();
if (userName) {
// If possible, reauthenticate an already running session,
// so any session specific credentials get updated appropriately
this._client.open_reauthentication_channel(userName, this._cancellable,
this._reauthenticationChannelOpened.bind(this));
} else {
this._client.get_user_verifier(this._cancellable, this._userVerifierGot.bind(this));
}
}
cancel() {
@ -346,11 +339,10 @@ var ShellUserVerifier = class {
this._verificationFailed(false);
}
async _openReauthenticationChannel(userName) {
_reauthenticationChannelOpened(client, result) {
try {
this._clearUserVerifier();
this._userVerifier = await this._client.open_reauthentication_channel(
userName, this._cancellable);
this._userVerifier = client.open_reauthentication_channel_finish(result);
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
@ -359,7 +351,8 @@ var ShellUserVerifier = class {
// Gdm emits org.freedesktop.DBus.Error.AccessDenied when there
// is no session to reauthenticate. Fall back to performing
// verification from this login session
this._getUserVerifier();
client.get_user_verifier(this._cancellable,
this._userVerifierGot.bind(this));
return;
}
@ -373,11 +366,10 @@ var ShellUserVerifier = class {
this._hold.release();
}
async _getUserVerifier() {
_userVerifierGot(client, result) {
try {
this._clearUserVerifier();
this._userVerifier =
await this._client.get_user_verifier(this._cancellable);
this._userVerifier = client.get_user_verifier_finish(result);
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
@ -429,25 +421,35 @@ var ShellUserVerifier = class {
}
}
async _startService(serviceName) {
_startService(serviceName) {
this._hold.acquire();
try {
if (this._userName) {
await this._userVerifier.call_begin_verification_for_user(
serviceName, this._userName, this._cancellable);
} else {
await this._userVerifier.call_begin_verification(
serviceName, this._cancellable);
}
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
this._reportInitError(this._userName
? 'Failed to start verification for user'
: 'Failed to start verification', e);
return;
if (this._userName) {
this._userVerifier.call_begin_verification_for_user(serviceName, this._userName, this._cancellable, (obj, result) => {
try {
obj.call_begin_verification_for_user_finish(result);
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
this._reportInitError('Failed to start verification for user', e);
return;
}
this._hold.release();
});
} else {
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() {

View File

@ -23,7 +23,6 @@
<file>misc/modemManager.js</file>
<file>misc/objectManager.js</file>
<file>misc/params.js</file>
<file>misc/parentalControlsManager.js</file>
<file>misc/permissionStore.js</file>
<file>misc/smartcardManager.js</file>
<file>misc/systemActions.js</file>
@ -102,14 +101,15 @@
<file>ui/swipeTracker.js</file>
<file>ui/switcherPopup.js</file>
<file>ui/switchMonitor.js</file>
<file>ui/tweener.js</file>
<file>ui/unlockDialog.js</file>
<file>ui/userWidget.js</file>
<file>ui/viewSelector.js</file>
<file>ui/windowAttentionHandler.js</file>
<file>ui/windowMenu.js</file>
<file>ui/windowManager.js</file>
<file>ui/windowPreview.js</file>
<file>ui/workspace.js</file>
<file>ui/workspaceAnimation.js</file>
<file>ui/workspaceSwitcherPopup.js</file>
<file>ui/workspaceThumbnail.js</file>
<file>ui/workspacesView.js</file>

View File

@ -1,5 +1,4 @@
subdir('misc')
subdir('dbusServices')
js_resources = gnome.compile_resources(
'js-resources', 'js-resources.gresource.xml',
@ -14,3 +13,10 @@ portal_resources = gnome.compile_resources(
c_name: 'portal_js_resources',
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 */
var LIBEXECDIR = '@libexecdir@';
var PKGDATADIR = '@datadir@/@PACKAGE_NAME@';
var VPNDIR = '@vpndir@';
/* g-i package versions */
var LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ExtensionState, ExtensionType, getCurrentExtension,
getSettings, initTranslations, openPrefs, isOutOfDate,
installImporter, serializeExtension, deserializeExtension */
getSettings, initTranslations, isOutOfDate, installImporter,
serializeExtension, deserializeExtension */
// Common utils for the extension system and the extension
// preferences tool
@ -153,27 +153,6 @@ function getSettings(schema) {
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:
* @param {string[]} required - an array of versions we're compatible with

View File

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

View File

@ -4,9 +4,6 @@ const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
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 InputMethod = GObject.registerClass(
@ -49,11 +46,15 @@ class InputMethod extends Clutter.InputMethod {
this._currentSource = this._inputSourceManager.currentSource;
}
async _onConnected() {
_onConnected() {
this._cancellable = new Gio.Cancellable();
this._ibus.create_input_context_async('gnome-shell', -1,
this._cancellable, this._setContext.bind(this));
}
_setContext(bus, res) {
try {
this._context = await this._ibus.create_input_context_async(
'gnome-shell', -1, this._cancellable);
this._context = this._ibus.create_input_context_async_finish(res);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
logError(e);
@ -96,13 +97,8 @@ class InputMethod extends Clutter.InputMethod {
this.commit(text.get_text());
}
_onDeleteSurroundingText(_context, offset, nchars) {
try {
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);
}
_onDeleteSurroundingText() {
this.delete_surrounding();
}
_onUpdatePreeditText(_context, text, pos, visible) {

View File

@ -24,7 +24,8 @@ function getCompletions(text, commandHeader, globalCompletionList) {
[expr_, base, attrHead] = matches;
methods = getPropertyNamesFromExpression(base, commandHeader).filter(
attr => attr.slice(0, attrHead.length) === attrHead);
attr => attr.slice(0, attrHead.length) == attrHead
);
}
// Look for the empty expression or partially entered words
@ -33,7 +34,8 @@ function getCompletions(text, commandHeader, globalCompletionList) {
if (text == '' || matches) {
[expr_, attrHead] = matches;
methods = globalCompletionList.filter(
attr => attr.slice(0, attrHead.length) === attrHead);
attr => attr.slice(0, attrHead.length) == attrHead
);
}
}

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
const { GLib, GnomeDesktop } = imports.gi;
const { GLib, GnomeDesktop, Meta } = imports.gi;
const Main = imports.ui.main;
@ -62,11 +62,11 @@ var KeyboardManager = class {
return;
this._currentKeymap = { layouts, variants, options };
global.backend.set_keymap(layouts, variants, options);
Meta.get_backend().set_keymap(layouts, variants, options);
}
_applyLayoutGroupIndex(idx) {
global.backend.lock_layout_group(idx);
Meta.get_backend().lock_layout_group(idx);
}
apply(id) {

View File

@ -50,22 +50,25 @@ function canLock() {
}
async function registerSessionWithGDM() {
function registerSessionWithGDM() {
log("Registering session with GDM");
try {
await Gio.DBus.system.call(
'org.gnome.DisplayManager',
'/org/gnome/DisplayManager/Manager',
'org.gnome.DisplayManager.Manager',
'RegisterSession',
GLib.Variant.new('(a{sv})', [{}]), null,
Gio.DBusCallFlags.NONE, -1, null);
} catch (e) {
if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
log(`Error registering session with GDM: ${e.message}`);
else
log('Not calling RegisterSession(): method not exported, GDM too old?');
}
Gio.DBus.system.call('org.gnome.DisplayManager',
'/org/gnome/DisplayManager/Manager',
'org.gnome.DisplayManager.Manager',
'RegisterSession',
GLib.Variant.new('(a{sv})', [{}]), null,
Gio.DBusCallFlags.NONE, -1, null,
(source, result) => {
try {
source.call_finish(result);
} catch (e) {
if (!e.matches(Gio.DBusError, Gio.DBusError.UNKNOWN_METHOD))
log(`Error registering session with GDM: ${e.message}`);
else
log("Not calling RegisterSession(): method not exported, GDM too old?");
}
}
);
}
let _loginManager = null;
@ -171,19 +174,24 @@ var LoginManagerSystemd = class {
this._proxy.SuspendRemote(true);
}
async inhibit(reason, callback) {
try {
const inVariant = new GLib.Variant('(ssss)',
['sleep', 'GNOME Shell', reason, 'delay']);
const [outVariant_, fdList] =
await this._proxy.call_with_unix_fd_list('Inhibit',
inVariant, 0, -1, null, null);
const [fd] = fdList.steal_fds();
callback(new Gio.UnixInputStream({ fd }));
} catch (e) {
logError(e, 'Error getting systemd inhibitor');
callback(null);
}
inhibit(reason, callback) {
let inVariant = GLib.Variant.new('(ssss)',
['sleep',
'GNOME Shell',
reason,
'delay']);
this._proxy.call_with_unix_fd_list('Inhibit', inVariant, 0, -1, null, null,
(proxy, result) => {
let fd = -1;
try {
let [outVariant_, fdList] = proxy.call_with_unix_fd_list_finish(result);
fd = fdList.steal_fds()[0];
callback(new Gio.UnixInputStream({ fd }));
} catch (e) {
logError(e, "Error getting systemd inhibitor");
callback(null);
}
});
}
_prepareForSleep(proxy, sender, [aboutToSuspend]) {

View File

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

View File

@ -223,7 +223,7 @@ var BroadbandModem = GObject.registerClass({
}, class BroadbandModem extends ModemBase {
_init(path, 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_cdma = new BroadbandModemCdmaProxy(Gio.DBus.system, 'org.freedesktop.ModemManager1', path);
@ -249,7 +249,7 @@ var BroadbandModem = GObject.registerClass({
}
_reloadSignalQuality() {
let [quality, recent_] = this._proxy.SignalQuality;
let [quality, recent_] = this.SignalQuality;
this._setSignalQuality(quality);
}

View File

@ -57,7 +57,9 @@ var ObjectManager = class {
// Start out inhibiting load until at least the proxy
// manager is loaded and the remote objects are fetched
this._numLoadInhibitors = 1;
this._initManagerProxy();
this._managerProxy.init_async(GLib.PRIORITY_DEFAULT,
this._cancellable,
this._onManagerProxyLoaded.bind(this));
}
_tryToCompleteLoad() {
@ -71,7 +73,7 @@ var ObjectManager = class {
}
}
async _addInterface(objectPath, interfaceName, onFinished) {
_addInterface(objectPath, interfaceName, onFinished) {
let info = this._interfaceInfos[interfaceName];
if (!info) {
@ -87,38 +89,40 @@ var ObjectManager = class {
g_interface_info: info,
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
try {
await proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable);
} catch (e) {
logError(e, `could not initialize proxy for interface ${interfaceName}`);
proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => {
try {
initable.init_finish(result);
} 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)
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) {
@ -147,10 +151,9 @@ var ObjectManager = class {
}
}
async _initManagerProxy() {
_onManagerProxyLoaded(initable, result) {
try {
await this._managerProxy.init_async(
GLib.PRIORITY_DEFAULT, this._cancellable);
initable.init_finish(result);
} catch (e) {
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._canHaveSuspend = true;
function tokenizeKeywords(keywords) {
return keywords.split(';').map(keyword => GLib.str_tokenize_and_fold(keyword, null)).flat(2);
}
this._actions = new Map();
this._actions.set(POWER_OFF_ACTION_ID, {
// Translators: The name of the power-off action in search
name: C_("search-result", "Power Off"),
iconName: 'system-shutdown-symbolic',
// Translators: A list of keywords that match the power-off action, separated by semicolons
keywords: tokenizeKeywords(_('power off;shutdown;reboot;restart;halt;stop')),
keywords: _('power off;shutdown;reboot;restart;halt;stop').split(/[; ]/),
available: false,
});
this._actions.set(LOCK_SCREEN_ACTION_ID, {
@ -101,15 +97,15 @@ const SystemActions = GObject.registerClass({
name: C_("search-result", "Lock Screen"),
iconName: 'system-lock-screen-symbolic',
// Translators: A list of keywords that match the lock screen action, separated by semicolons
keywords: tokenizeKeywords(_('lock screen')),
keywords: _("lock screen").split(/[; ]/),
available: false,
});
this._actions.set(LOGOUT_ACTION_ID, {
// Translators: The name of the logout action in search
name: C_("search-result", "Log Out"),
iconName: 'system-log-out-symbolic',
iconName: 'application-exit-symbolic',
// Translators: A list of keywords that match the logout action, separated by semicolons
keywords: tokenizeKeywords(_('logout;log out;sign off')),
keywords: _("logout;log out;sign off").split(/[; ]/),
available: false,
});
this._actions.set(SUSPEND_ACTION_ID, {
@ -117,7 +113,7 @@ const SystemActions = GObject.registerClass({
name: C_("search-result", "Suspend"),
iconName: 'media-playback-pause-symbolic',
// Translators: A list of keywords that match the suspend action, separated by semicolons
keywords: tokenizeKeywords(_('suspend;sleep')),
keywords: _("suspend;sleep").split(/[; ]/),
available: false,
});
this._actions.set(SWITCH_USER_ACTION_ID, {
@ -125,14 +121,14 @@ const SystemActions = GObject.registerClass({
name: C_("search-result", "Switch User"),
iconName: 'system-switch-user-symbolic',
// Translators: A list of keywords that match the switch user action, separated by semicolons
keywords: tokenizeKeywords(_('switch user')),
keywords: _("switch user").split(/[; ]/),
available: false,
});
this._actions.set(LOCK_ORIENTATION_ACTION_ID, {
name: '',
iconName: '',
// Translators: A list of keywords that match the lock orientation action, separated by semicolons
keywords: tokenizeKeywords(_('lock orientation;unlock orientation;screen;rotation')),
keywords: _("lock orientation;unlock orientation;screen;rotation").split(/[; ]/),
available: false,
});
@ -281,7 +277,7 @@ const SystemActions = GObject.registerClass({
getMatchingActions(terms) {
// 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 = [];

View File

@ -1,9 +1,9 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
formatTime, formatTimeSpan, createTimeLabel, insertSorted,
ensureActorVisibleInScrollView, wiggle */
makeCloseButton, ensureActorVisibleInScrollView, wiggle */
const { Clutter, Gio, GLib, Shell, St, GnomeDesktop } = imports.gi;
const { Clutter, Gio, GLib, GObject, Shell, St, GnomeDesktop } = imports.gi;
const Gettext = imports.gettext;
const Main = imports.ui.main;
@ -363,6 +363,51 @@ function insertSorted(array, val, cmp) {
return pos;
}
var CloseButton = GObject.registerClass(
class CloseButton extends St.Button {
_init(boxpointer) {
super._init({
style_class: 'notification-close',
x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.START,
});
this._boxPointer = boxpointer;
if (boxpointer)
this._boxPointer.connect('arrow-side-changed', this._sync.bind(this));
}
_computeBoxPointerOffset() {
if (!this._boxPointer || !this._boxPointer.get_stage())
return 0;
let side = this._boxPointer.arrowSide;
if (side == St.Side.TOP)
return this._boxPointer.getArrowHeight();
else
return 0;
}
_sync() {
let themeNode = this.get_theme_node();
let offY = this._computeBoxPointerOffset();
this.translation_x = themeNode.get_length('-shell-close-overlap-x');
this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY;
}
vfunc_style_changed() {
this._sync();
super.vfunc_style_changed();
}
});
function makeCloseButton(boxpointer) {
return new CloseButton(boxpointer);
}
function ensureActorVisibleInScrollView(scrollView, actor) {
let adjustment = scrollView.vscroll.adjustment;
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();

View File

@ -7,8 +7,6 @@ const PermissionStore = imports.misc.permissionStore;
const { loadInterfaceXML } = imports.misc.fileUtils;
Gio._promisify(Geoclue.Simple, 'new', 'new_finish');
const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
const WEATHER_BUS_NAME = 'org.gnome.Weather';
@ -81,7 +79,16 @@ var WeatherClient = class {
this._weatherApp = 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({
schema_id: 'org.gnome.shell.weather',
@ -139,17 +146,9 @@ var WeatherClient = class {
(!this._needsAuth || this._weatherAuthorized);
}
async _createWeatherProxy() {
const nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface);
_onWeatherProxyReady(o, res) {
try {
this._weatherProxy = await Gio.DBusProxy.new(
Gio.DBus.session,
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
WEATHER_BUS_NAME,
WEATHER_OBJECT_PATH,
WEATHER_INTEGRATION_IFACE,
null);
this._weatherProxy = Gio.DBusProxy.new_finish(res);
} catch (e) {
log(`Failed to create GNOME Weather proxy: ${e}`);
return;
@ -240,23 +239,25 @@ var WeatherClient = class {
}
}
async _startGClueService() {
_startGClueService() {
if (this._gclueStarting)
return;
this._gclueStarting = true;
try {
this._gclueService = await Geoclue.Simple.new(
'org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null);
} catch (e) {
log(`Failed to connect to Geoclue2 service: ${e.message}`);
this._setLocation(this._mostRecentLocation);
return;
}
this._gclueStarted = true;
this._gclueService.get_client().distance_threshold = 100;
this._updateLocationMonitoring();
Geoclue.Simple.new('org.gnome.Shell', Geoclue.AccuracyLevel.CITY, null,
(o, res) => {
try {
this._gclueService = Geoclue.Simple.new_finish(res);
} catch (e) {
log(`Failed to connect to Geoclue2 service: ${e.message}`);
this._setLocation(this._mostRecentLocation);
return;
}
this._gclueStarted = true;
this._gclueService.get_client().distance_threshold = 100;
this._updateLocationMonitoring();
});
}
_onGClueLocationChanged() {

View File

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

View File

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

View File

@ -68,8 +68,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._items = this._switcherList.icons;
}
vfunc_allocate(box) {
super.vfunc_allocate(box);
vfunc_allocate(box, flags) {
super.vfunc_allocate(box, flags);
// Allocate the thumbnails
// We try to avoid overflowing the screen so we base the resulting size on
@ -102,7 +102,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
childBox.y2 = childBox.y1 + childNaturalHeight;
this._thumbnails.allocate(childBox);
this._thumbnails.allocate(childBox, flags);
}
}
@ -280,10 +280,12 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
}
_onDestroy() {
super._onDestroy();
if (this._thumbnails)
this._destroyThumbnails();
if (this._thumbnailTimeoutId != 0)
GLib.source_remove(this._thumbnailTimeoutId);
super._onDestroy();
}
/**
@ -363,7 +365,8 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
},
});
this._thumbnails = null;
this._switcherList.removeAccessibleState(this._selectedIndex, Atk.StateType.EXPANDED);
if (this._switcherList._items[this._selectedIndex])
this._switcherList._items[this._selectedIndex].remove_accessible_state(Atk.StateType.EXPANDED);
}
_createThumbnails() {
@ -392,7 +395,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
},
});
this._switcherList.addAccessibleState(this._selectedIndex, Atk.StateType.EXPANDED);
this._switcherList._items[this._selectedIndex].add_accessible_state(Atk.StateType.EXPANDED);
}
});
@ -681,7 +684,8 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
// Cache the window list now; we don't handle dynamic changes here,
// and we don't want to be continually retrieving it
appIcon.cachedWindows = allWindows.filter(
w => windowTracker.get_window_app(w) === appIcon.app);
w => windowTracker.get_window_app(w) == appIcon.app
);
if (appIcon.cachedWindows.length > 0)
this._addIcon(appIcon);
}
@ -749,9 +753,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
return super.vfunc_get_preferred_height(forWidth);
}
vfunc_allocate(box) {
vfunc_allocate(box, flags) {
// Allocate the main list items
super.vfunc_allocate(box);
super.vfunc_allocate(box, flags);
let contentBox = this.get_theme_node().get_content_box(box);
@ -766,15 +770,13 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
childBox.x2 = childBox.x1 + arrowWidth;
childBox.y1 = contentBox.y1 + itemBox.y2 + arrowHeight;
childBox.y2 = childBox.y1 + arrowHeight;
this._arrows[i].allocate(childBox);
this._arrows[i].allocate(childBox, flags);
}
}
// We override SwitcherList's _onItemEnter method to delay
// activation when the thumbnail list is open
_onItemEnter(item) {
const index = this._items.indexOf(item);
_onItemEnter(index) {
if (this._mouseTimeOutId != 0)
GLib.source_remove(this._mouseTimeOutId);
if (this._altTabPopup.thumbnailsVisible) {
@ -1056,28 +1058,28 @@ class WindowSwitcher extends SwitcherPopup.SwitcherList {
return [minHeight, natHeight];
}
vfunc_allocate(box) {
vfunc_allocate(box, flags) {
let themeNode = this.get_theme_node();
let contentBox = themeNode.get_content_box(box);
const labelHeight = this._label.height;
const totalLabelHeight =
labelHeight + themeNode.get_padding(St.Side.BOTTOM);
box.y2 -= totalLabelHeight;
super.vfunc_allocate(box);
let childBox = new Clutter.ActorBox();
childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2;
childBox.y1 = childBox.y2 - this._label.height;
this._label.allocate(childBox, flags);
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM);
childBox.x1 = box.x1;
childBox.x2 = box.x2;
childBox.y1 = box.y1;
childBox.y2 = box.y2 - totalLabelHeight;
super.vfunc_allocate(childBox, flags);
// Hooking up the parent vfunc will call this.set_allocation() with
// the height without the label height, so call it again with the
// correct size here.
box.y2 += totalLabelHeight;
this.set_allocation(box);
const childBox = new Clutter.ActorBox();
childBox.x1 = contentBox.x1;
childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2;
childBox.y1 = childBox.y2 - labelHeight;
this._label.allocate(childBox);
this.set_allocation(box, flags);
}
highlight(index, justOutline) {

View File

@ -15,7 +15,8 @@ class Animation extends St.Bin {
const themeContext = St.ThemeContext.get_for_stage(global.stage);
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));

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,6 @@
/* exported getAppFavorites */
const Shell = imports.gi.Shell;
const ParentalControlsManager = imports.misc.parentalControlsManager;
const Signals = imports.signals;
const Main = imports.ui.main;
@ -13,7 +12,6 @@ const RENAMED_DESKTOP_IDS = {
'cheese.desktop': 'org.gnome.Cheese.desktop',
'dconf-editor.desktop': 'ca.desrt.dconf-editor.desktop',
'empathy.desktop': 'org.gnome.Empathy.desktop',
'eog.desktop': 'org.gnome.eog.desktop',
'epiphany.desktop': 'org.gnome.Epiphany.desktop',
'evolution.desktop': 'org.gnome.Evolution.desktop',
'file-roller.desktop': 'org.gnome.FileRoller.desktop',
@ -66,13 +64,6 @@ const RENAMED_DESKTOP_IDS = {
class AppFavorites {
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._favorites = {};
global.settings.connect('changed::%s'.format(this.FAVORITE_APPS_KEY), this._onFavsChanged.bind(this));
@ -104,7 +95,7 @@ class AppFavorites {
global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
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 = {};
for (let i = 0; i < apps.length; i++) {
let app = apps[i];
@ -143,9 +134,6 @@ class AppFavorites {
if (!app)
return false;
if (!this._parentalControlsManager.shouldShowApp(app.app_info))
return false;
let ids = this._getIds();
if (pos == -1)
ids.push(appId);

View File

@ -147,8 +147,9 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
_onDeviceSelected(dialog, device) {
let connection = this._dbusImpl.get_connection();
let info = this._dbusImpl.get_info();
const deviceName = Object.keys(AudioDevice)
.filter(dev => AudioDevice[dev] === device)[0].toLowerCase();
let deviceName = Object.keys(AudioDevice).filter(
dev => AudioDevice[dev] == device
)[0].toLowerCase();
connection.emit_signal(this._audioSelectionDialog._sender,
this._dbusImpl.get_object_path(),
info ? info.name : null,

View File

@ -512,8 +512,8 @@ var SystemBackground = GObject.registerClass({
super._init({
meta_display: global.display,
monitor: 0,
background: _systemBackground,
});
this.content.background = _systemBackground;
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.emit('loaded');
@ -738,8 +738,6 @@ var BackgroundManager = class BackgroundManager {
let backgroundActor = new Meta.BackgroundActor({
meta_display: global.display,
monitor: this._monitorIndex,
});
backgroundActor.content.set({
background,
vignette: this._vignette,
vignette_sharpness: 0.5,

View File

@ -30,8 +30,8 @@ var BarLevel = GObject.registerClass({
accessible_role: Atk.Role.LEVEL_BAR,
};
super._init(Object.assign(defaultParams, params));
this.connect('notify::allocation', () => {
this._barLevelWidth = this.allocation.get_width();
this.connect('allocation-changed', (actor, box) => {
this._barLevelWidth = box.get_width();
});
this._customAccessible = St.GenericAccessible.new_for_actor(this);

View File

@ -196,13 +196,8 @@ var BoxPointer = GObject.registerClass({
return themeNode.adjust_preferred_height(...height);
}
vfunc_allocate(box) {
if (this._sourceActor && this._sourceActor.mapped) {
this._reposition(box);
this._updateFlip(box);
}
this.set_allocation(box);
vfunc_allocate(box, flags) {
this.set_allocation(box, flags);
let themeNode = this.get_theme_node();
let borderWidth = themeNode.get_length('-arrow-border-width');
@ -214,7 +209,7 @@ var BoxPointer = GObject.registerClass({
childBox.y1 = 0;
childBox.x2 = availWidth;
childBox.y2 = availHeight;
this._border.allocate(childBox);
this._border.allocate(childBox, flags);
childBox.x1 = borderWidth;
childBox.y1 = borderWidth;
@ -234,7 +229,13 @@ var BoxPointer = GObject.registerClass({
childBox.x2 -= rise;
break;
}
this.bin.allocate(childBox);
this.bin.allocate(childBox, flags);
if (this._sourceActor && this._sourceActor.mapped) {
this._reposition(box);
this._updateFlip(box);
this.set_allocation(box, flags);
}
}
_drawBorder(area) {

View File

@ -14,6 +14,7 @@ const { loadInterfaceXML } = imports.misc.fileUtils;
var MSECS_IN_DAY = 24 * 60 * 60 * 1000;
var SHOW_WEEKDATE_KEY = 'show-weekdate';
var ELLIPSIS_CHAR = '\u2026';
var MESSAGE_ICON_SIZE = -1; // pick up from CSS
@ -31,6 +32,10 @@ function sameDay(dateA, dateB) {
return sameMonth(dateA, dateB) && (dateA.getDate() == dateB.getDate());
}
function isToday(date) {
return sameDay(new Date(), date);
}
function _isWorkDay(date) {
/* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
let days = C_('calendar-no-work', "06");
@ -194,52 +199,46 @@ class DBusEventSource extends EventSourceBase {
this._initialized = false;
this._dbusProxy = new CalendarServer();
this._initProxy();
}
this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null, (object, result) => {
let loaded = false;
async _initProxy() {
let loaded = false;
try {
await this._dbusProxy.init_async(GLib.PRIORITY_DEFAULT, null);
loaded = true;
} catch (e) {
// Ignore timeouts and install signals as normal, because with high
// 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
// to read it)
if (!e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
log('Error loading calendars: %s'.format(e.message));
return;
try {
this._dbusProxy.init_finish(result);
loaded = true;
} catch (e) {
if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
// Ignore timeouts and install signals as normal, because with high
// 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
// to read it)
} else {
log('Error loading calendars: %s'.format(e.message));
return;
}
}
}
this._dbusProxy.connectSignal('EventsAddedOrUpdated',
this._onEventsAddedOrUpdated.bind(this));
this._dbusProxy.connectSignal('EventsRemoved',
this._onEventsRemoved.bind(this));
this._dbusProxy.connectSignal('ClientDisappeared',
this._onClientDisappeared.bind(this));
this._dbusProxy.connectSignal('Changed', this._onChanged.bind(this));
this._dbusProxy.connect('notify::g-name-owner', () => {
if (this._dbusProxy.g_name_owner)
this._dbusProxy.connect('notify::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();
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() {
@ -258,7 +257,7 @@ class DBusEventSource extends EventSourceBase {
}
_resetCache() {
this._events = new Map();
this._events = [];
this._lastRequestBegin = null;
this._lastRequestEnd = null;
}
@ -274,47 +273,28 @@ class DBusEventSource extends EventSourceBase {
this.emit('changed');
}
_onEventsAddedOrUpdated(dbusProxy, nameOwner, argArray) {
const [appointments = []] = argArray;
let changed = false;
_onChanged() {
this._loadEvents(false);
}
_onEventsReceived(results, _error) {
let newEvents = [];
let appointments = results[0] || [];
for (let n = 0; n < appointments.length; n++) {
const [id, summary, allDay, startTime, endTime] = appointments[n];
const date = new Date(startTime * 1000);
const end = new Date(endTime * 1000);
let a = appointments[n];
let date = new Date(a[4] * 1000);
let end = new Date(a[5] * 1000);
let id = a[0];
let summary = a[1];
let allDay = a[3];
let event = new CalendarEvent(id, date, end, summary, allDay);
this._events.set(event.id, event);
changed = true;
newEvents.push(event);
}
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
if (changed)
this.emit('changed');
}
_onEventsRemoved(dbusProxy, nameOwner, argArray) {
const [ids = []] = argArray;
let changed = false;
for (const id of ids)
changed |= this._events.delete(id);
if (changed)
this.emit('changed');
}
_onClientDisappeared(dbusProxy, nameOwner, argArray) {
let [sourceUid = ''] = argArray;
sourceUid += '\n';
let changed = false;
for (const id of this._events.keys()) {
if (id.startsWith(sourceUid))
changed |= this._events.delete(id);
}
if (changed)
this.emit('changed');
this._events = newEvents;
this._isLoading = false;
this.emit('changed');
}
_loadEvents(forceReload) {
@ -323,38 +303,33 @@ class DBusEventSource extends EventSourceBase {
return;
if (this._curRequestBegin && this._curRequestEnd) {
if (forceReload) {
this._events.clear();
this.emit('changed');
}
this._dbusProxy.SetTimeRangeRemote(
this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000,
forceReload,
Gio.DBusCallFlags.NONE);
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000,
forceReload,
this._onEventsReceived.bind(this),
Gio.DBusCallFlags.NONE);
}
}
requestRange(begin, end) {
if (!(_datesEqual(begin, this._lastRequestBegin) && _datesEqual(end, this._lastRequestEnd))) {
this._isLoading = true;
this._lastRequestBegin = begin;
this._lastRequestEnd = end;
this._curRequestBegin = begin;
this._curRequestEnd = end;
this._loadEvents(true);
}
}
*_getFilteredEvents(begin, end) {
for (const event of this._events.values()) {
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
yield event;
this._loadEvents(false);
}
}
getEvents(begin, end) {
let result = [...this._getFilteredEvents(begin, end)];
let result = [];
for (let n = 0; n < this._events.length; n++) {
let event = this._events[n];
if (_dateIntervalsOverlap(event.date, event.end, begin, end))
result.push(event);
}
result.sort((event1, event2) => {
// sort events by end time on ending day
let d1 = event1.date < begin && event1.end <= end ? event1.end : event1.date;
@ -368,8 +343,12 @@ class DBusEventSource extends EventSourceBase {
let dayBegin = _getBeginningOfDay(day);
let dayEnd = _getEndOfDay(day);
const { done } = this._getFilteredEvents(dayBegin, dayEnd).next();
return !done;
let events = this.getEvents(dayBegin, dayEnd);
if (events.length == 0)
return false;
return true;
}
});
@ -718,6 +697,61 @@ var Calendar = GObject.registerClass({
}
});
var EventMessage = GObject.registerClass(
class EventMessage extends MessageList.Message {
_init(event, date) {
super._init('', event.summary);
this._event = event;
this._date = date;
this.setTitle(this._formatEventTime());
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
this.setIcon(this._icon);
}
vfunc_style_changed() {
let iconVisible = this.get_parent().has_style_pseudo_class('first-child');
this._icon.opacity = iconVisible ? 255 : 0;
super.vfunc_style_changed();
}
_formatEventTime() {
let periodBegin = _getBeginningOfDay(this._date);
let periodEnd = _getEndOfDay(this._date);
let allDay = this._event.allDay || (this._event.date <= periodBegin &&
this._event.end >= periodEnd);
let title;
if (allDay) {
/* Translators: Shown in calendar event list for all day events
* Keep it short, best if you can use less then 10 characters
*/
title = C_("event list time", "All Day");
} else {
let date = this._event.date >= periodBegin
? this._event.date
: this._event.end;
title = Util.formatTime(date, { timeOnly: true });
}
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
if (this._event.date < periodBegin && !this._event.allDay) {
if (rtl)
title = '%s%s'.format(title, ELLIPSIS_CHAR);
else
title = '%s%s'.format(ELLIPSIS_CHAR, title);
}
if (this._event.end > periodEnd && !this._event.allDay) {
if (rtl)
title = '%s%s'.format(ELLIPSIS_CHAR, title);
else
title = '%s%s'.format(title, ELLIPSIS_CHAR);
}
return title;
}
});
var NotificationMessage = GObject.registerClass(
class NotificationMessage extends MessageList.Message {
_init(notification) {
@ -783,6 +817,144 @@ class NotificationMessage extends MessageList.Message {
}
});
var EventsSection = GObject.registerClass(
class EventsSection extends MessageList.MessageListSection {
_init() {
super._init();
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
this._eventSource = new EmptyEventSource();
this._messageById = new Map();
this._title = new St.Button({ style_class: 'events-section-title',
label: '',
can_focus: true });
this._title.child.x_align = Clutter.ActorAlign.START;
this.insert_child_below(this._title, null);
this._title.connect('clicked', this._onTitleClicked.bind(this));
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
Shell.AppSystem.get_default().connect('installed-changed',
this._appInstalledChanged.bind(this));
this._appInstalledChanged();
}
setEventSource(eventSource) {
if (!(eventSource instanceof EventSourceBase))
throw new Error('Event source is not valid type');
this._eventSource = eventSource;
this._eventSource.connect('changed', this._reloadEvents.bind(this));
}
get allowed() {
return Main.sessionMode.showCalendarEvents;
}
_updateTitle() {
this._title.visible = !isToday(this._date);
if (!this._title.visible)
return;
let dayFormat;
let now = new Date();
if (sameYear(this._date, now)) {
/* Translators: Shown on calendar heading when selected day occurs on current year */
dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d"));
} else {
/* Translators: Shown on calendar heading when selected day occurs on different year */
dayFormat = Shell.util_translate_time_string(NC_("calendar heading", "%A, %B %-d, %Y"));
}
this._title.label = this._date.toLocaleFormat(dayFormat);
}
_reloadEvents() {
if (this._eventSource.isLoading)
return;
this._reloading = true;
let periodBegin = _getBeginningOfDay(this._date);
let periodEnd = _getEndOfDay(this._date);
let events = this._eventSource.getEvents(periodBegin, periodEnd);
let ids = events.map(e => e.id);
this._messageById.forEach((message, id) => {
if (ids.includes(id))
return;
this._messageById.delete(id);
this.removeMessage(message);
});
for (let i = 0; i < events.length; i++) {
let event = events[i];
let message = this._messageById.get(event.id);
if (!message) {
message = new EventMessage(event, this._date);
this._messageById.set(event.id, message);
this.addMessage(message, false);
} else {
this.moveMessage(message, i, false);
}
}
this._reloading = false;
this._sync();
}
_appInstalledChanged() {
this._calendarApp = undefined;
this._title.reactive = this._getCalendarApp() != null;
}
_getCalendarApp() {
if (this._calendarApp !== undefined)
return this._calendarApp;
let apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
if (apps && (apps.length > 0)) {
let app = Gio.AppInfo.get_default_for_type('text/calendar', false);
let defaultInRecommended = apps.some(a => a.equal(app));
this._calendarApp = defaultInRecommended ? app : apps[0];
} else {
this._calendarApp = null;
}
return this._calendarApp;
}
_onTitleClicked() {
Main.overview.hide();
Main.panel.closeCalendar();
let app = this._getCalendarApp();
if (app.get_id() == 'evolution.desktop')
app = Gio.DesktopAppInfo.new('evolution-calendar.desktop');
app.launch([], global.create_app_launch_context(0, -1));
}
setDate(date) {
super.setDate(date);
this._updateTitle();
this._reloadEvents();
}
_shouldShow() {
return !this.empty || !isToday(this._date);
}
_sync() {
if (this._reloading)
return;
super._sync();
}
});
var TimeLabel = GObject.registerClass(
class NotificationTimeLabel extends St.Label {
_init(datetime) {
@ -879,6 +1051,10 @@ class NotificationSection extends MessageList.MessageListSection {
});
super.vfunc_map();
}
_shouldShow() {
return !this.empty && isToday(this._date);
}
});
var Placeholder = GObject.registerClass(
@ -887,13 +1063,41 @@ class Placeholder extends St.BoxLayout {
super._init({ style_class: 'message-list-placeholder', vertical: true });
this._date = new Date();
const file = Gio.File.new_for_uri(
'resource:///org/gnome/shell/theme/no-notifications.svg');
this._icon = new St.Icon({ gicon: new Gio.FileIcon({ file }) });
let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
let otherFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-events.svg');
this._todayIcon = new Gio.FileIcon({ file: todayFile });
this._otherIcon = new Gio.FileIcon({ file: otherFile });
this._icon = new St.Icon();
this.add_actor(this._icon);
this._label = new St.Label({ text: _('No Notifications') });
this._label = new St.Label();
this.add_actor(this._label);
this._sync();
}
setDate(date) {
if (sameDay(this._date, date))
return;
this._date = date;
this._sync();
}
_sync() {
let today = isToday(this._date);
if (today && this._icon.gicon == this._todayIcon)
return;
if (!today && this._icon.gicon == this._otherIcon)
return;
if (today) {
this._icon.gicon = this._todayIcon;
this._label.text = _("No Notifications");
} else {
this._icon.gicon = this._otherIcon;
this._label.text = _("No Events");
}
}
});
@ -945,22 +1149,17 @@ class CalendarMessageList extends St.Widget {
let hbox = new St.BoxLayout({ style_class: 'message-list-controls' });
box.add_child(hbox);
const dndLabel = new St.Label({
hbox.add_child(new St.Label({
text: _('Do Not Disturb'),
y_align: Clutter.ActorAlign.CENTER,
});
hbox.add_child(dndLabel);
}));
this._dndSwitch = new DoNotDisturbSwitch();
this._dndButton = new St.Button({
can_focus: true,
toggle_mode: true,
child: this._dndSwitch,
label_actor: dndLabel,
});
this._dndSwitch.bind_property('state',
this._dndButton, 'checked',
GObject.BindingFlags.BIDIRECTIONAL | GObject.BindingFlags.SYNC_CREATE);
this._dndButton.connect('clicked', () => this._dndSwitch.toggle());
hbox.add_child(this._dndButton);
this._clearButton = new St.Button({
@ -994,6 +1193,9 @@ class CalendarMessageList extends St.Widget {
this._notificationSection = new NotificationSection();
this._addSection(this._notificationSection);
this._eventsSection = new EventsSection();
this._addSection(this._eventsSection);
Main.sessionMode.connect('updated', this._sync.bind(this));
}
@ -1029,4 +1231,13 @@ class CalendarMessageList extends St.Widget {
let canClear = sections.some(s => s.canClear && s.visible);
this._clearButton.reactive = canClear;
}
setEventSource(eventSource) {
this._eventsSection.setEventSource(eventSource);
}
setDate(date) {
this._sectionList.get_children().forEach(s => s.setDate(date));
this._placeholder.setDate(date);
}
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -2,19 +2,12 @@
/* exported Component */
const { Clutter, Gio, GLib, GObject, St } = imports.gi;
const Lang = imports.lang;
var Tpl = null;
var Tp = null;
try {
({ 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) {
log('Telepathy is not available, chat integration will be disabled.');
}
@ -47,59 +40,36 @@ var NotificationDirection = {
RECEIVED: 'chat-received',
};
const ChatMessage = HAVE_TP ? GObject.registerClass({
Properties: {
'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,
});
}
function makeMessageFromTpMessage(tpMessage, direction) {
let [text, flags_] = tpMessage.to_text();
static newFromTplTextEvent(tplTextEvent) {
let direction =
tplTextEvent.get_sender().get_entity_type() === Tpl.EntityType.SELF
? NotificationDirection.SENT : NotificationDirection.RECEIVED;
let timestamp = tpMessage.get_sent_timestamp();
if (timestamp == 0)
timestamp = tpMessage.get_received_timestamp();
return new ChatMessage({
'message-type': tplTextEvent.get_message_type(),
'text': tplTextEvent.get_message(),
'sender': tplTextEvent.get_sender().get_alias(),
'timestamp': tplTextEvent.get_timestamp(),
direction,
});
}
}) : null;
return {
messageType: tpMessage.get_message_type(),
text,
sender: tpMessage.sender.alias,
timestamp,
direction,
};
}
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 {
constructor() {
this._client = null;
@ -223,7 +193,7 @@ class TelepathyClient extends Tp.BaseClient {
// We can only handle text channel, so close any other channel
if (!(channel instanceof Tp.TextChannel)) {
channel.close_async();
channel.close_async(null);
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();
if (targetHandleType != Tp.HandleType.CONTACT) {
@ -278,15 +248,17 @@ class TelepathyClient extends Tp.BaseClient {
return;
}
context.accept();
// Approve private text channels right away as we are going to handle it
try {
await dispatchOp.claim_with_async(this);
this._handlingChannels(account, conn, [channel], false);
} catch (err) {
log('Failed to Claim channel: %s'.format(err.toString()));
}
dispatchOp.claim_with_async(this, (o, result) => {
try {
dispatchOp.claim_with_finish(result);
this._handlingChannels(account, conn, [channel], false);
} catch (err) {
log('Failed to Claim channel: %s'.format(err.toString()));
}
});
context.accept();
}
_delegatedChannelsCb(_client, _channels) {
@ -298,12 +270,12 @@ class TelepathyClient extends Tp.BaseClient {
var ChatSource = HAVE_TP ? GObject.registerClass(
class ChatSource extends MessageTray.Source {
_init(account, conn, channel, contact, client) {
super._init(contact.get_alias());
this._account = account;
this._contact = contact;
this._client = client;
super._init(contact.get_alias());
this.isChat = true;
this._pendingMessages = [];
@ -447,16 +419,19 @@ class ChatSource extends MessageTray.Source {
}
}
async _getLogMessages() {
_getLogMessages() {
let logManager = Tpl.LogManager.dup_singleton();
let entity = Tpl.Entity.new_from_tp_contact(this._contact, Tpl.EntityType.CONTACT);
const [events] = await logManager.get_filtered_events_async(
this._account, entity,
Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
null);
logManager.get_filtered_events_async(this._account, entity,
Tpl.EventTypeMask.TEXT, SCROLLBACK_HISTORY_LINES,
null, this._displayPendingMessages.bind(this));
}
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();
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)
continue;
pendingMessages.push(ChatMessage.newFromTpMessage(message,
NotificationDirection.RECEIVED));
pendingMessages.push(makeMessageFromTpMessage(message, NotificationDirection.RECEIVED));
this._pendingMessages.push(message);
}
@ -512,7 +486,9 @@ class ChatSource extends MessageTray.Source {
this._ackMessages();
// The chat box has been destroyed so it can't
// handle the channel any more.
this._channel.close_async();
this._channel.close_async((channel, result) => {
channel.close_finish(result);
});
} else {
// Don't indicate any unread messages when the notification
// that represents them has been destroyed.
@ -565,8 +541,7 @@ class ChatSource extends MessageTray.Source {
this._pendingMessages.push(message);
this.countUpdated();
message = ChatMessage.newFromTpMessage(message,
NotificationDirection.RECEIVED);
message = makeMessageFromTpMessage(message, NotificationDirection.RECEIVED);
this._notification.appendMessage(message);
// 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.
_messageSent(channel, message, _flags, _token) {
this._ensureNotification();
message = ChatMessage.newFromTpMessage(message,
NotificationDirection.SENT);
message = makeMessageFromTpMessage(message, NotificationDirection.SENT);
this._notification.appendMessage(message);
}
@ -610,7 +584,9 @@ class ChatSource extends MessageTray.Source {
}
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) {
@ -654,19 +630,11 @@ class ChatSource extends MessageTray.Source {
}
}) : 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({
Signals: {
'message-removed': { param_types: [ChatNotificationMessage.$gtype] },
'message-added': { param_types: [ChatNotificationMessage.$gtype] },
'timestamp-changed': { param_types: [ChatNotificationMessage.$gtype] },
'message-removed': { param_types: [Tp.Message.$gtype] },
'message-added': { param_types: [Tp.Message.$gtype] },
'timestamp-changed': { param_types: [Tp.Message.$gtype] },
},
}, class ChatNotification extends MessageTray.Notification {
_init(source) {
@ -767,24 +735,21 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
styles: [],
timestamp: currentTime,
noTimestamp: false });
const { noTimestamp } = props;
delete props.noTimestamp;
// Reset the old message timeout
if (this._timestampTimeoutId)
GLib.source_remove(this._timestampTimeoutId);
this._timestampTimeoutId = 0;
let message = new ChatNotificationMessage({
realMessage: props.group !== 'meta',
showTimestamp: false,
...props,
});
let message = { realMessage: props.group != 'meta',
showTimestamp: false };
Lang.copyProperties(props, message);
delete message.noTimestamp;
this.messages.unshift(message);
this.emit('message-added', message);
if (!noTimestamp) {
if (!props.noTimestamp) {
let timestamp = props.timestamp;
if (timestamp < currentTime - SCROLLBACK_IMMEDIATE_TIME) {
this.appendTimestamp();

View File

@ -292,11 +292,11 @@ class DashActor extends St.Widget {
});
}
vfunc_allocate(box) {
vfunc_allocate(box, flags) {
let contentBox = this.get_theme_node().get_content_box(box);
let availWidth = contentBox.x2 - contentBox.x1;
this.set_allocation(box);
this.set_allocation(box, flags);
let [appIcons, showAppsButton] = this.get_children();
let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
@ -306,11 +306,11 @@ class DashActor extends St.Widget {
childBox.y1 = contentBox.y1;
childBox.x2 = contentBox.x2;
childBox.y2 = contentBox.y2 - showAppsNatHeight;
appIcons.allocate(childBox);
appIcons.allocate(childBox, flags);
childBox.y1 = contentBox.y2 - showAppsNatHeight;
childBox.y2 = contentBox.y2;
showAppsButton.allocate(childBox);
showAppsButton.allocate(childBox, flags);
}
vfunc_get_preferred_height(forWidth) {
@ -815,12 +815,7 @@ var Dash = GObject.registerClass({
else
pos = 0; // always insert at the top when dash is empty
// Put the placeholder after the last favorite if we are not
// in the favorites zone
if (pos > numFavorites)
pos = numFavorites;
if (pos !== this._dragPlaceholderPos && this._animatingPlaceholdersCount === 0) {
if (pos != this._dragPlaceholderPos && pos <= numFavorites && this._animatingPlaceholdersCount == 0) {
this._dragPlaceholderPos = pos;
// Don't allow positioning before or after self
@ -848,6 +843,11 @@ var Dash = GObject.registerClass({
this._dragPlaceholder.show(fadeIn);
}
// Remove the drag placeholder if we are not in the
// "favorites zone"
if (pos > numFavorites)
this._clearDragPlaceholder();
if (!this._dragPlaceholder)
return DND.DragMotionResult.NO_DROP;

View File

@ -13,11 +13,7 @@ const System = imports.system;
const { loadInterfaceXML } = imports.misc.fileUtils;
const NC_ = (context, str) => '%s\u0004%s'.format(context, str);
const T_ = Shell.util_translate_time_string;
const MAX_FORECASTS = 5;
const ELLIPSIS_CHAR = '\u2026';
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
@ -88,188 +84,6 @@ class TodayButton extends St.Button {
}
});
var EventsSection = GObject.registerClass(
class EventsSection extends St.Button {
_init() {
super._init({
style_class: 'events-button',
can_focus: true,
x_expand: true,
child: new St.BoxLayout({
style_class: 'events-box',
vertical: true,
x_expand: true,
}),
});
this._startDate = null;
this._endDate = null;
this._eventSource = null;
this._calendarApp = null;
this._title = new St.Label({
style_class: 'events-title',
});
this.child.add_child(this._title);
this._eventsList = new St.BoxLayout({
style_class: 'events-list',
vertical: true,
x_expand: true,
});
this.child.add_child(this._eventsList);
this._appSys = Shell.AppSystem.get_default();
this._appSys.connect('installed-changed',
this._appInstalledChanged.bind(this));
this._appInstalledChanged();
}
setDate(date) {
const day = [date.getFullYear(), date.getMonth(), date.getDate()];
this._startDate = new Date(...day);
this._endDate = new Date(...day, 23, 59, 59, 999);
this._updateTitle();
this._reloadEvents();
}
setEventSource(eventSource) {
if (!(eventSource instanceof Calendar.EventSourceBase))
throw new Error('Event source is not valid type');
this._eventSource = eventSource;
this._eventSource.connect('changed', this._reloadEvents.bind(this));
this._eventSource.connect('notify::has-calendars',
this._sync.bind(this));
this._sync();
}
_updateTitle() {
/* Translators: Shown on calendar heading when selected day occurs on current year */
const sameYearFormat = T_(NC_('calendar heading', '%B %-d'));
/* Translators: Shown on calendar heading when selected day occurs on different year */
const otherYearFormat = T_(NC_('calendar heading', '%B %-d %Y'));
const timeSpanDay = GLib.TIME_SPAN_DAY / 1000;
const now = new Date();
if (this._startDate <= now && now <= this._endDate)
this._title.text = _('Today');
else if (this._endDate < now && now - this._endDate < timeSpanDay)
this._title.text = _('Yesterday');
else if (this._startDate > now && this._startDate - now < timeSpanDay)
this._title.text = _('Tomorrow');
else if (this._startDate.getFullYear() === now.getFullYear())
this._title.text = this._startDate.toLocaleFormat(sameYearFormat);
else
this._title.text = this._startDate.toLocaleFormat(otherYearFormat);
}
_formatEventTime(event) {
const allDay = event.allDay ||
(event.date <= this._startDate && event.end >= this._endDate);
let title;
if (allDay) {
/* Translators: Shown in calendar event list for all day events
* Keep it short, best if you can use less then 10 characters
*/
title = C_('event list time', 'All Day');
} else {
let date = event.date >= this._startDate ? event.date : event.end;
title = Util.formatTime(date, { timeOnly: true });
}
const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL;
if (event.date < this._startDate && !event.allDay) {
if (rtl)
title = '%s%s'.format(title, ELLIPSIS_CHAR);
else
title = '%s%s'.format(ELLIPSIS_CHAR, title);
}
if (event.end > this._endDate && !event.allDay) {
if (rtl)
title = '%s%s'.format(ELLIPSIS_CHAR, title);
else
title = '%s%s'.format(title, ELLIPSIS_CHAR);
}
return title;
}
_reloadEvents() {
if (this._eventSource.isLoading || this._reloading)
return;
this._reloading = true;
[...this._eventsList].forEach(c => c.destroy());
const events =
this._eventSource.getEvents(this._startDate, this._endDate);
for (let event of events) {
const box = new St.BoxLayout({
style_class: 'event-box',
vertical: true,
});
box.add(new St.Label({
text: event.summary,
style_class: 'event-summary',
}));
box.add(new St.Label({
text: this._formatEventTime(event),
style_class: 'event-time',
}));
this._eventsList.add_child(box);
}
if (this._eventsList.get_n_children() === 0) {
const placeholder = new St.Label({
text: _('No Events'),
style_class: 'event-placeholder',
});
this._eventsList.add_child(placeholder);
}
this._reloading = false;
this._sync();
}
vfunc_clicked() {
Main.overview.hide();
Main.panel.closeCalendar();
let appInfo = this._calendarApp;
if (appInfo.get_id() === 'org.gnome.Evolution.desktop') {
const app = this._appSys.lookup_app('evolution-calendar.desktop');
if (app)
appInfo = app.app_info;
}
appInfo.launch([], global.create_app_launch_context(0, -1));
}
_appInstalledChanged() {
const apps = Gio.AppInfo.get_recommended_for_type('text/calendar');
if (apps && (apps.length > 0)) {
const app = Gio.AppInfo.get_default_for_type('text/calendar', false);
const defaultInRecommended = apps.some(a => a.equal(app));
this._calendarApp = defaultInRecommended ? app : apps[0];
} else {
this._calendarApp = null;
}
return this._sync();
}
_sync() {
this.visible = this._eventSource && this._eventSource.hasCalendars;
this.reactive = this._calendarApp !== null;
}
});
var WorldClocksSection = GObject.registerClass(
class WorldClocksSection extends St.Button {
_init() {
@ -280,7 +94,6 @@ class WorldClocksSection extends St.Button {
});
this._clock = new GnomeDesktop.WallClock();
this._clockNotifyId = 0;
this._tzNotifyId = 0;
this._locations = [];
@ -353,6 +166,8 @@ class WorldClocksSection extends St.Button {
layout.attach(header, 0, 0, 2, 1);
this.label_actor = header;
let localOffset = GLib.DateTime.new_now_local().get_utc_offset();
for (let i = 0; i < this._locations.length; i++) {
let l = this._locations[i].location;
@ -365,14 +180,14 @@ class WorldClocksSection extends St.Button {
let time = new St.Label({ style_class: 'world-clocks-time' });
const tz = new St.Label({
style_class: 'world-clocks-timezone',
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER,
});
time.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
tz.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
let otherOffset = this._getTimeAtLocation(l).get_utc_offset();
let offset = (otherOffset - localOffset) / GLib.TIME_SPAN_HOUR;
let fmt = Math.trunc(offset) == offset ? '%s%.0f' : '%s%.1f';
let prefix = offset >= 0 ? '+' : '-';
let tz = new St.Label({ style_class: 'world-clocks-timezone',
text: fmt.format(prefix, Math.abs(offset)),
x_align: Clutter.ActorAlign.END,
y_align: Clutter.ActorAlign.CENTER });
if (this._grid.text_direction == Clutter.TextDirection.RTL) {
layout.attach(tz, 0, i + 1, 1, 1);
@ -384,65 +199,32 @@ class WorldClocksSection extends St.Button {
layout.attach(tz, 2, i + 1, 1, 1);
}
this._locations[i].timeLabel = time;
this._locations[i].tzLabel = tz;
this._locations[i].actor = time;
}
if (this._grid.get_n_children() > 1) {
if (!this._clockNotifyId) {
this._clockNotifyId =
this._clock.connect('notify::clock', this._updateTimeLabels.bind(this));
this._clock.connect('notify::clock', this._updateLabels.bind(this));
}
if (!this._tzNotifyId) {
this._tzNotifyId =
this._clock.connect('notify::timezone', this._updateTimezoneLabels.bind(this));
}
this._updateTimeLabels();
this._updateTimezoneLabels();
this._updateLabels();
} else {
if (this._clockNotifyId)
this._clock.disconnect(this._clockNotifyId);
this._clockNotifyId = 0;
if (this._tzNotifyId)
this._clock.disconnect(this._tzNotifyId);
this._tzNotifyId = 0;
}
}
_getTimezoneOffsetAtLocation(location) {
const localOffset = GLib.DateTime.new_now_local().get_utc_offset();
const utcOffset = this._getTimeAtLocation(location).get_utc_offset();
const offsetCurrentTz = utcOffset - localOffset;
const offsetHours = Math.abs(offsetCurrentTz) / GLib.TIME_SPAN_HOUR;
const offsetMinutes =
(Math.abs(offsetCurrentTz) % GLib.TIME_SPAN_HOUR) /
GLib.TIME_SPAN_MINUTE;
const prefix = offsetCurrentTz >= 0 ? '+' : '-';
const text = offsetMinutes === 0
? '%s%d'.format(prefix, offsetHours)
: '%s%d\u2236%d'.format(prefix, offsetHours, offsetMinutes);
return text;
}
_getTimeAtLocation(location) {
let tz = GLib.TimeZone.new(location.get_timezone().get_tzid());
return GLib.DateTime.new_now(tz);
}
_updateTimeLabels() {
_updateLabels() {
for (let i = 0; i < this._locations.length; i++) {
let l = this._locations[i];
let now = this._getTimeAtLocation(l.location);
l.timeLabel.text = Util.formatTime(now, { timeOnly: true });
}
}
_updateTimezoneLabels() {
for (let i = 0; i < this._locations.length; i++) {
let l = this._locations[i];
l.tzLabel.text = this._getTimezoneOffsetAtLocation(l.location);
l.actor.text = Util.formatTime(now, { timeOnly: true });
}
}
@ -486,13 +268,13 @@ class WeatherSection extends St.Button {
this.child = 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',
x_align: Clutter.ActorAlign.START,
x_expand: true,
y_align: Clutter.ActorAlign.END,
});
titleBox.add_child(this._titleLabel);
text: _('Weather'),
}));
box.add_child(titleBox);
this._titleLocation = new St.Label({
@ -602,28 +384,21 @@ class WeatherSection extends St.Button {
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() {
this._forecastGrid.destroy_all_children();
if (!this._weatherClient.hasLocation)
if (!this._weatherClient.hasLocation) {
this._setStatusLabel(_("Select a location…"));
return;
}
const { info } = this._weatherClient;
this._titleLocation.text = this._findBestLocationName(info.location);
let info = this._weatherClient.info;
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) {
this._setStatusLabel(_("Loading…"));
@ -647,12 +422,6 @@ class WeatherSection extends St.Button {
if (!this.visible)
return;
if (this._weatherClient.hasLocation)
this._titleLabel.text = _('Weather');
else
this._titleLabel.text = _('Select weather location…');
this._forecastGrid.visible = this._weatherClient.hasLocation;
this._titleLocation.visible = this._weatherClient.hasLocation;
this._updateForecasts();
@ -671,6 +440,7 @@ class MessagesIndicator extends St.Icon {
this._sources = [];
this._count = 0;
this._doNotDisturb = false;
this._settings = new Gio.Settings({
schema_id: 'org.gnome.desktop.notifications',
@ -751,8 +521,8 @@ class FreezableBinLayout extends Clutter.BinLayout {
return this._savedHeight;
}
vfunc_allocate(container, allocation) {
super.vfunc_allocate(container, allocation);
vfunc_allocate(container, allocation, flags) {
super.vfunc_allocate(container, allocation, flags);
let [width, height] = allocation.get_size();
this._savedWidth = [width, width];
@ -818,7 +588,7 @@ class DateMenuButton extends PanelMenu.Button {
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
let date = _gDateTimeToDate(datetime);
layout.frozen = !_isToday(date);
this._eventsItem.setDate(date);
this._messageList.setDate(date);
});
this.menu.connect('open-state-changed', (menu, isOpen) => {
@ -827,7 +597,7 @@ class DateMenuButton extends PanelMenu.Button {
let now = new Date();
this._calendar.setDate(now);
this._date.setDate(now);
this._eventsItem.setDate(now);
this._messageList.setDate(now);
}
});
@ -858,9 +628,6 @@ class DateMenuButton extends PanelMenu.Button {
style_class: 'datemenu-displays-box' });
this._displaysSection.add_actor(displaysBox);
this._eventsItem = new EventsSection();
displaysBox.add_child(this._eventsItem);
this._clocksItem = new WorldClocksSection();
displaysBox.add_child(this._clocksItem);
@ -886,7 +653,7 @@ class DateMenuButton extends PanelMenu.Button {
this._eventSource.destroy();
this._calendar.setEventSource(eventSource);
this._eventsItem.setEventSource(eventSource);
this._messageList.setEventSource(eventSource);
this._eventSource = eventSource;
}

View File

@ -375,30 +375,19 @@ var _Draggable = class _Draggable {
this._dragActorSource = undefined;
this._dragOrigParent = this.actor.get_parent();
this._dragActorHadFixedPos = this._dragActor.fixed_position_set;
this._dragOrigX = this._dragActor.allocation.x1;
this._dragOrigY = this._dragActor.allocation.y1;
this._dragOrigWidth = this._dragActor.allocation.get_width();
this._dragOrigHeight = this._dragActor.allocation.get_height();
this._dragOrigX = this._dragActor.x;
this._dragOrigY = this._dragActor.y;
this._dragOrigScale = this._dragActor.scale_x;
// When the actor gets reparented to the uiGroup, it will be
// allocated its preferred size, so use that size instead of the
// current allocation size.
const [, newAllocatedWidth] = this._dragActor.get_preferred_width(-1);
const [, newAllocatedHeight] = this._dragActor.get_preferred_height(-1);
const transformedAllocation =
Shell.util_get_transformed_allocation(this._dragActor);
// Set the actor's scale such that it will keep the same
// transformed size when it's reparented to the uiGroup
this._dragActor.set_scale(
transformedAllocation.get_width() / newAllocatedWidth,
transformedAllocation.get_height() / newAllocatedHeight);
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
this._dragActor.set_scale(scaledWidth / this.actor.width,
scaledHeight / this.actor.height);
this._dragOffsetX = transformedAllocation.x1 - this._dragStartX;
this._dragOffsetY = transformedAllocation.y1 - this._dragStartY;
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
this._dragOffsetX = actorStageX - this._dragStartX;
this._dragOffsetY = actorStageY - this._dragStartY;
this._dragOrigParent.remove_actor(this._dragActor);
Main.uiGroup.add_child(this._dragActor);
@ -428,10 +417,6 @@ var _Draggable = class _Draggable {
this._dragOffsetX -= transX;
this._dragOffsetY -= transY;
this._dragActor.set_position(
this._dragX + this._dragOffsetX,
this._dragY + this._dragOffsetY);
if (this._dragActorMaxSize != undefined) {
let [scaledWidth, scaledHeight] = this._dragActor.get_transformed_size();
let currentSize = Math.max(scaledWidth, scaledHeight);
@ -650,15 +635,9 @@ var _Draggable = class _Draggable {
if (parentWidth != 0)
parentScale = parentScaledWidth / parentWidth;
// Also adjust for the difference in the original actor width
// and the width it is now (children of uiGroup always get
// allocated their preferred size)
const childScaleX =
this._dragOrigWidth / this._dragActor.allocation.get_width();
x = parentX + parentScale * this._dragOrigX;
y = parentY + parentScale * this._dragOrigY;
scale = this._dragOrigScale * parentScale * childScaleX;
scale = this._dragOrigScale * parentScale;
} else {
// Snap back actor to its original stage position
x = this._snapBackX;
@ -739,10 +718,7 @@ var _Draggable = class _Draggable {
Main.uiGroup.remove_child(this._dragActor);
this._dragOrigParent.add_actor(this._dragActor);
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
if (this._dragActorHadFixedPos)
dragActor.set_position(this._dragOrigX, this._dragOrigY);
else
dragActor.fixed_position_set = false;
dragActor.set_position(this._dragOrigX, this._dragOrigY);
} else {
dragActor.destroy();
}

View File

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

View File

@ -10,22 +10,8 @@ imports.gi.versions.Gtk = '3.0';
imports.gi.versions.TelepathyGLib = '0.12';
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 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;
// We can't import shell JS modules yet, because they may have
// variable initializations, etc, that depend on init() already having
@ -245,15 +231,16 @@ function _loggingFunc(...args) {
}
function init() {
// Add some bindings to the global JS namespace
globalThis.global = Shell.Global.get();
// Add some bindings to the global JS namespace; (gjs keeps the web
// browser convention of having that namespace be called 'window'.)
window.global = Shell.Global.get();
globalThis.log = _loggingFunc;
window.log = _loggingFunc;
globalThis._ = Gettext.gettext;
globalThis.C_ = Gettext.pgettext;
globalThis.ngettext = Gettext.ngettext;
globalThis.N_ = s => s;
window._ = Gettext.gettext;
window.C_ = Gettext.pgettext;
window.ngettext = Gettext.ngettext;
window.N_ = s => s;
GObject.gtypeNameBasedOnJSPath = true;
@ -285,11 +272,6 @@ function init() {
_easeActorProperty(this, 'value', target, params);
};
Clutter.Actor.prototype[Symbol.iterator] = function* () {
for (let c = this.get_first_child(); c; c = c.get_next_sibling())
yield c;
};
Clutter.Actor.prototype.toString = function () {
return St.describe_actor(this);
};
@ -303,13 +285,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) {
let { stack } = new Error();
log(`St.set_slow_down_factor() is deprecated, use St.Settings.slow_down_factor\n${stack}`);
@ -329,25 +304,9 @@ function init() {
}
};
// Override to clear our own timezone cache as well
const origClearDateCaches = System.clearDateCaches;
System.clearDateCaches = function () {
_localTimeZone = null;
origClearDateCaches();
};
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=508783
Date.prototype.toLocaleFormat = function (format) {
if (_localTimeZone === null)
_localTimeZone = GLib.TimeZone.new_local();
let dt = GLib.DateTime.new(_localTimeZone,
this.getFullYear(),
this.getMonth() + 1,
this.getDate(),
this.getHours(),
this.getMinutes(),
this.getSeconds());
let dt = GLib.DateTime.new_from_unix_local(this.getTime() / 1000);
return dt ? dt.format(format) : '';
};
@ -360,12 +319,10 @@ function init() {
// OK, now things are initialized enough that we can import shell JS
const Format = imports.format;
const Tweener = imports.ui.tweener;
Tweener.init();
String.prototype.format = Format.format;
Math.clamp = function (x, lower, upper) {
return Math.min(Math.max(x, lower), upper);
};
}
// adjustAnimationTime:

View File

@ -56,15 +56,6 @@ function uninstallExtension(uuid) {
return false;
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;
}
@ -108,9 +99,6 @@ function gotExtensionZipFile(session, message, uuid, dir, callback, errback) {
}
function downloadExtensionUpdate(uuid) {
if (!Main.extensionManager.updatesSupported)
return;
let dir = Gio.File.new_for_path(
GLib.build_filenamev([global.userdatadir, 'extension-updates', uuid]));
@ -129,9 +117,6 @@ function downloadExtensionUpdate(uuid) {
}
function checkForUpdates() {
if (!Main.extensionManager.updatesSupported)
return;
let metadatas = {};
Main.extensionManager.getUuids().forEach(uuid => {
let extension = Main.extensionManager.lookup(uuid);
@ -142,9 +127,6 @@ function checkForUpdates() {
metadatas[uuid] = extension.metadata;
});
if (Object.keys(metadatas).length === 0)
return; // nothing to update
let versionCheck = global.settings.get_boolean(
'disable-extension-version-validation');
let params = {
@ -162,7 +144,9 @@ function checkForUpdates() {
let operations = JSON.parse(message.response_body.data);
for (let uuid in operations) {
let operation = operations[uuid];
if (operation === 'upgrade' || operation === 'downgrade')
if (operation == 'blacklist')
uninstallExtension(uuid);
else if (operation == 'upgrade' || operation == 'downgrade')
downloadExtensionUpdate(uuid);
}
});
@ -238,7 +222,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
});
function init() {
_httpSession = new Soup.Session({ ssl_use_system_ca_file: true });
_httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });
// See: https://bugzilla.gnome.org/show_bug.cgi?id=655189 for context.
// _httpSession.add_feature(new Soup.ProxyResolverDefault());

View File

@ -26,7 +26,6 @@ var ExtensionManager = class {
this._updateNotified = false;
this._extensions = new Map();
this._unloadedExtensions = new Map();
this._enabledExtensions = [];
this._extensionOrder = [];
@ -61,11 +60,6 @@ var ExtensionManager = class {
ExtensionDownloader.checkForUpdates();
}
get updatesSupported() {
const appSys = Shell.AppSystem.get_default();
return appSys.lookup_app('org.gnome.Extensions.desktop') !== null;
}
lookup(uuid) {
return this._extensions.get(uuid);
}
@ -103,18 +97,18 @@ var ExtensionManager = class {
}
}
try {
extension.stateObj.disable();
} catch (e) {
this.logExtensionError(uuid, e);
}
if (extension.stylesheet) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet;
}
try {
extension.stateObj.disable();
} catch (e) {
this.logExtensionError(uuid, e);
}
for (let i = 0; i < order.length; i++) {
let otherUuid = order[i];
try {
@ -216,24 +210,6 @@ var ExtensionManager = class {
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) {
let extension = this.lookup(uuid);
if (!extension)
@ -260,8 +236,7 @@ var ExtensionManager = class {
if (!extension)
return;
const message = error instanceof Error
? error.message : error.toString();
let message = error.toString();
extension.error = message;
extension.state = ExtensionState.ERROR;
@ -270,7 +245,6 @@ var ExtensionManager = class {
extension.errors.push(message);
logError(error, 'Extension %s'.format(uuid));
this._updateCanChange(extension);
this.emit('extension-state-changed', extension);
}
@ -320,14 +294,6 @@ var ExtensionManager = class {
return extension;
}
_canLoad(extension) {
if (!this._unloadedExtensions.has(extension.uuid))
return true;
const version = this._unloadedExtensions.get(extension.uuid);
return extension.metadata.version === version;
}
loadExtension(extension) {
// Default to error, we set success as the last step
extension.state = ExtensionState.ERROR;
@ -336,9 +302,6 @@ var ExtensionManager = class {
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
extension.state = ExtensionState.OUT_OF_DATE;
} else if (!this._canLoad(extension)) {
this.logExtensionError(extension.uuid, new Error(
'A different version was loaded previously. You need to log out for changes to take effect.'));
} else {
let enabled = this._enabledExtensions.includes(extension.uuid);
if (enabled) {
@ -349,8 +312,6 @@ var ExtensionManager = class {
} else {
extension.state = ExtensionState.INITIALIZED;
}
this._unloadedExtensions.delete(extension.uuid);
}
this._updateCanChange(extension);
@ -358,22 +319,15 @@ var ExtensionManager = class {
}
unloadExtension(extension) {
const { uuid, type } = extension;
// Try to disable it -- if it's ERROR'd, we can't guarantee that,
// but it will be removed on next reboot, and hopefully nothing
// broke too much.
this._callExtensionDisable(uuid);
this._callExtensionDisable(extension.uuid);
extension.state = ExtensionState.UNINSTALLED;
this.emit('extension-state-changed', extension);
// If we did install an importer, it is now cached and it's
// impossible to load a different version
if (type === ExtensionType.PER_USER && extension.imports)
this._unloadedExtensions.set(uuid, extension.metadata.version);
this._extensions.delete(uuid);
this._extensions.delete(extension.uuid);
return true;
}
@ -486,15 +440,19 @@ var ExtensionManager = class {
// Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one.
newEnabledExtensions
.filter(uuid => !this._enabledExtensions.includes(uuid))
.forEach(uuid => this._callExtensionEnable(uuid));
newEnabledExtensions.filter(
uuid => !this._enabledExtensions.includes(uuid)
).forEach(uuid => {
this._callExtensionEnable(uuid);
});
// Find and disable all the newly disabled extensions: UUIDs found in the
// old setting, but not in the new one.
this._extensionOrder
.filter(uuid => !newEnabledExtensions.includes(uuid))
.reverse().forEach(uuid => this._callExtensionDisable(uuid));
this._extensionOrder.filter(
uuid => !newEnabledExtensions.includes(uuid)
).reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
this._enabledExtensions = newEnabledExtensions;
}
@ -523,9 +481,6 @@ var ExtensionManager = class {
}
_installExtensionUpdates() {
if (!this.updatesSupported)
return;
FileUtils.collectFromDatadirs('extension-updates', true, (dir, info) => {
let fileType = info.get_file_type();
if (fileType !== Gio.FileType.DIRECTORY)
@ -534,14 +489,9 @@ var ExtensionManager = class {
let extensionDir = Gio.File.new_for_path(
GLib.build_filenamev([global.userdatadir, 'extensions', uuid]));
try {
FileUtils.recursivelyDeleteDir(extensionDir, false);
FileUtils.recursivelyMoveDir(dir, extensionDir);
} catch (e) {
log('Failed to install extension updates for %s'.format(uuid));
} finally {
FileUtils.recursivelyDeleteDir(dir, true);
}
FileUtils.recursivelyDeleteDir(extensionDir, false);
FileUtils.recursivelyMoveDir(dir, extensionDir);
FileUtils.recursivelyDeleteDir(dir, true);
});
}

File diff suppressed because it is too large Load Diff

View File

@ -61,7 +61,7 @@ class AspectContainer extends St.Widget {
this.queue_relayout();
}
vfunc_allocate(box) {
vfunc_allocate(box, flags) {
if (box.get_width() > 0 && box.get_height() > 0) {
let sizeRatio = box.get_width() / box.get_height();
@ -79,7 +79,7 @@ class AspectContainer extends St.Widget {
}
}
super.vfunc_allocate(box);
super.vfunc_allocate(box, flags);
}
});
@ -498,7 +498,7 @@ var Key = GObject.registerClass({
var KeyboardModel = class {
constructor(groupName) {
let names = [groupName];
if (groupName.includes('+'))
if (names.includes('+'))
names.push(groupName.replace(/\+.*/, ''));
names.push('us');
@ -722,7 +722,7 @@ var EmojiPager = GObject.registerClass({
_onPan(action) {
let [dist_, dx, dy_] = action.get_motion_delta(0);
this.delta += dx;
this.delta = this.delta + dx;
if (this._currentKey != null) {
this._currentKey.cancel();
@ -935,7 +935,8 @@ var EmojiSelection = GObject.registerClass({
this.add_child(this._emojiPager);
this._pageIndicator = new PageIndicators.PageIndicators(
Clutter.Orientation.HORIZONTAL);
Clutter.Orientation.HORIZONTAL
);
this.add_child(this._pageIndicator);
this._pageIndicator.setReactive(false);
@ -1118,12 +1119,11 @@ var KeyboardManager = class KeyBoardManager {
this._seat.connect('notify::touch-mode', this._syncEnabled.bind(this));
this._lastDevice = null;
global.backend.connect('last-device-changed', (backend, device) => {
if (device.device_type === Clutter.InputDeviceType.KEYBOARD_DEVICE)
return;
this._lastDevice = device;
this._syncEnabled();
Meta.get_backend().connect('last-device-changed', (backend, device) => {
if (device.get_device_name().indexOf('XTEST') < 0) {
this._lastDevice = device;
this._syncEnabled();
}
});
this._syncEnabled();
}
@ -1148,9 +1148,9 @@ var KeyboardManager = class KeyBoardManager {
this._keyboard = new Keyboard();
} else if (!enabled && this._keyboard) {
this._keyboard.setCursorLocation(null);
Main.layoutManager.hideKeyboard(true);
this._keyboard.destroy();
this._keyboard = null;
Main.layoutManager.hideKeyboard(true);
}
}
@ -1256,10 +1256,6 @@ class Keyboard extends St.BoxLayout {
return this._keyboardVisible && super.visible;
}
set visible(visible) {
super.visible = visible;
}
_onFocusPositionChanged(focusTracker) {
let rect = focusTracker.getCurrentRect();
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
@ -1872,10 +1868,6 @@ var KeyboardController = class {
Main.inputMethod.disconnect(this._notifyContentPurposeId);
Main.inputMethod.disconnect(this._notifyContentHintsId);
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() {

View File

@ -246,7 +246,7 @@ var LayoutManager = GObject.registerClass({
vertical: true });
this.addChrome(this.panelBox, { affectsStruts: true,
trackFullscreen: true });
this.panelBox.connect('notify::allocation',
this.panelBox.connect('allocation-changed',
this._panelBoxChanged.bind(this));
this.modalDialogGroup = new St.Widget({ name: 'modalDialogGroup',
@ -612,20 +612,10 @@ var LayoutManager = GObject.registerClass({
let signalId = this._systemBackground.connect('loaded', () => {
this._systemBackground.disconnect(signalId);
this._systemBackground.show();
global.stage.show();
// 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
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');
this._prepareStartupAnimation();
});
}
@ -682,7 +672,17 @@ var LayoutManager = GObject.registerClass({
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() {
@ -765,7 +765,7 @@ var LayoutManager = GObject.registerClass({
this._keyboardHeightNotifyId = 0;
}
this.keyboardBox.ease({
translation_y: 0,
translation_y: this.keyboardBox.height,
opacity: 0,
duration: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_QUAD,

View File

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

View File

@ -37,9 +37,10 @@ const LG_ANIMATION_TIME = 500;
function _getAutoCompleteGlobalKeywords() {
const keywords = ['true', 'false', 'null', 'new'];
// Don't add the private properties of globalThis (i.e., ones starting with '_')
const windowProperties = Object.getOwnPropertyNames(globalThis).filter(
a => a.charAt(0) !== '_');
// Don't add the private properties of window (i.e., ones starting with '_')
const windowProperties = Object.getOwnPropertyNames(window).filter(
a => a.charAt(0) != '_'
);
const headerProperties = JsParse.getDeclaredConstants(commandHeader);
return keywords.concat(windowProperties).concat(headerProperties);
@ -554,8 +555,8 @@ var Inspector = GObject.registerClass({
this._lookingGlass = lookingGlass;
}
vfunc_allocate(box) {
this.set_allocation(box);
vfunc_allocate(box, flags) {
this.set_allocation(box, flags);
if (!this._eventHandler)
return;
@ -570,7 +571,7 @@ var Inspector = GObject.registerClass({
childBox.x2 = childBox.x1 + natWidth;
childBox.y1 = primary.y + Math.floor((primary.height - natHeight) / 2);
childBox.y2 = childBox.y1 + natHeight;
this._eventHandler.allocate(childBox);
this._eventHandler.allocate(childBox, flags);
}
_close() {
@ -802,191 +803,6 @@ var Extensions = GObject.registerClass({
}
});
var ActorLink = GObject.registerClass({
Signals: {
'inspect-actor': {},
},
}, class ActorLink extends St.Button {
_init(actor) {
this._arrow = new St.Icon({
icon_name: 'pan-end-symbolic',
icon_size: 8,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER,
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
});
const label = new St.Label({
text: actor.toString(),
x_align: Clutter.ActorAlign.START,
});
const inspectButton = new St.Button({
child: new St.Icon({
icon_name: 'insert-object-symbolic',
icon_size: 12,
y_align: Clutter.ActorAlign.CENTER,
}),
reactive: true,
x_expand: true,
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.CENTER,
});
inspectButton.connect('clicked', () => this.emit('inspect-actor'));
const box = new St.BoxLayout();
box.add_child(this._arrow);
box.add_child(label);
box.add_child(inspectButton);
super._init({
reactive: true,
track_hover: true,
toggle_mode: true,
style_class: 'actor-link',
child: box,
x_align: Clutter.ActorAlign.START,
});
this._actor = actor;
}
vfunc_clicked() {
this._arrow.ease({
rotation_angle_z: this.checked ? 90 : 0,
duration: 250,
});
}
});
var ActorTreeViewer = GObject.registerClass(
class ActorTreeViewer extends St.BoxLayout {
_init(lookingGlass) {
super._init();
this._lookingGlass = lookingGlass;
this._actorData = new Map();
}
_showActorChildren(actor) {
const data = this._actorData.get(actor);
if (!data || data.visible)
return;
data.visible = true;
data.actorAddedId = actor.connect('actor-added', (container, child) => {
this._addActor(data.children, child);
});
data.actorRemovedId = actor.connect('actor-removed', (container, child) => {
this._removeActor(child);
});
for (let child of actor)
this._addActor(data.children, child);
}
_hideActorChildren(actor) {
const data = this._actorData.get(actor);
if (!data || !data.visible)
return;
for (let child of actor)
this._removeActor(child);
data.visible = false;
if (data.actorAddedId > 0) {
actor.disconnect(data.actorAddedId);
data.actorAddedId = 0;
}
if (data.actorRemovedId > 0) {
actor.disconnect(data.actorRemovedId);
data.actorRemovedId = 0;
}
data.children.remove_all_children();
}
_addActor(container, actor) {
if (this._actorData.has(actor))
return;
if (actor === this._lookingGlass)
return;
const button = new ActorLink(actor);
button.connect('notify::checked', () => {
this._lookingGlass.setBorderPaintTarget(actor);
if (button.checked)
this._showActorChildren(actor);
else
this._hideActorChildren(actor);
});
button.connect('inspect-actor', () => {
this._lookingGlass.inspectObject(actor, button);
});
const mainContainer = new St.BoxLayout({ vertical: true });
const childrenContainer = new St.BoxLayout({
vertical: true,
style: 'padding: 0 0 0 18px',
});
mainContainer.add_child(button);
mainContainer.add_child(childrenContainer);
this._actorData.set(actor, {
button,
container: mainContainer,
children: childrenContainer,
visible: false,
actorAddedId: 0,
actorRemovedId: 0,
actorDestroyedId: actor.connect('destroy', () => this._removeActor(actor)),
});
let belowChild = null;
const nextSibling = actor.get_next_sibling();
if (nextSibling && this._actorData.has(nextSibling))
belowChild = this._actorData.get(nextSibling).container;
container.insert_child_above(mainContainer, belowChild);
}
_removeActor(actor) {
const data = this._actorData.get(actor);
if (!data)
return;
for (let child of actor)
this._removeActor(child);
if (data.actorAddedId > 0) {
actor.disconnect(data.actorAddedId);
data.actorAddedId = 0;
}
if (data.actorRemovedId > 0) {
actor.disconnect(data.actorRemovedId);
data.actorRemovedId = 0;
}
if (data.actorDestroyedId > 0) {
actor.disconnect(data.actorDestroyedId);
data.actorDestroyedId = 0;
}
data.container.destroy();
this._actorData.delete(actor);
}
vfunc_map() {
super.vfunc_map();
this._addActor(this, global.stage);
}
vfunc_unmap() {
super.vfunc_unmap();
this._removeActor(global.stage);
}
});
var LookingGlass = GObject.registerClass(
class LookingGlass extends St.BoxLayout {
_init() {
@ -1018,9 +834,9 @@ class LookingGlass extends St.BoxLayout {
Main.uiGroup.add_actor(this);
Main.uiGroup.set_child_below_sibling(this,
Main.layoutManager.panelBox);
Main.layoutManager.panelBox.connect('notify::allocation',
Main.layoutManager.panelBox.connect('allocation-changed',
this._queueResize.bind(this));
Main.layoutManager.keyboardBox.connect('notify::allocation',
Main.layoutManager.keyboardBox.connect('allocation-changed',
this._queueResize.bind(this));
this._objInspector = new ObjInspector(this);
@ -1102,9 +918,6 @@ class LookingGlass extends St.BoxLayout {
this._extensions = new Extensions(this);
notebook.appendPage('Extensions', this._extensions);
this._actorTreeViewer = new ActorTreeViewer(this);
notebook.appendPage('Actors', this._actorTreeViewer);
this._entry.clutter_text.connect('activate', (o, _e) => {
// Hide any completions we are currently showing
this._hideCompletions();
@ -1314,7 +1127,7 @@ class LookingGlass extends St.BoxLayout {
else if (symbol == Clutter.KEY_Page_Down)
this._notebook.nextTab();
}
return super.vfunc_key_press_event(keyPressEvent);
return Clutter.EVENT_PROPAGATE;
}
open() {

View File

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

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