Compare commits

..

1 Commits

Author SHA1 Message Date
6393e90a5a theme: sync OSD colors with gtk 2019-04-16 16:47:59 +02:00
311 changed files with 27585 additions and 50080 deletions

View File

@ -1,6 +0,0 @@
{
"extends": [
"./lint/eslintrc-gjs.json",
"./lint/eslintrc-shell.json"
]
}

View File

@ -1,5 +1,6 @@
stages: stages:
- review - review
- source_check
- build - build
- test - test
@ -14,10 +15,8 @@ variables:
- merge_requests - merge_requests
check_commit_log: check_commit_log:
image: registry.gitlab.gnome.org/gnome/mutter/master:v2 image: registry.gitlab.gnome.org/gnome/mutter/master:v1
stage: review stage: review
variables:
GIT_DEPTH: "100"
script: script:
- ./.gitlab-ci/check-commit-log.sh - ./.gitlab-ci/check-commit-log.sh
only: only:
@ -25,36 +24,28 @@ check_commit_log:
js_check: js_check:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1 image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review stage: source_check
script: script:
- find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG - find js -name '*.js' -exec js60 -c -s '{}' ';' 2>&1 | tee $JS_LOG
- (! grep -q . $JS_LOG) - (! grep -q . $JS_LOG)
<<: *only_default <<: *only_default
only:
changes:
- js/**/*
artifacts: artifacts:
paths: paths:
- ${JS_LOG} - ${JS_LOG}
when: on_failure when: on_failure
eslint:
image: registry.gitlab.gnome.org/gnome/gnome-shell/extension-ci:v1
stage: review
script:
- ./.gitlab-ci/run-eslint.sh
<<: *only_default
artifacts:
paths:
- reports
when: always
build: build:
image: registry.gitlab.gnome.org/gnome/mutter/master:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
stage: build stage: build
before_script: before_script:
- .gitlab-ci/checkout-mutter.sh - .gitlab-ci/checkout-mutter.sh
- meson mutter mutter/build --prefix=/usr -Dtests=false - meson mutter mutter/build --prefix=/usr -Dtests=false
- ninja -C mutter/build install - ninja -C mutter/build install
script: script:
- meson . build -Dbuiltype=debugoptimized -Dman=false --werror - meson . build -Dbuiltype=debugoptimized
- ninja -C build - ninja -C build
- ninja -C build install - ninja -C build install
<<: *only_default <<: *only_default
@ -65,10 +56,8 @@ build:
- build - build
test: test:
image: registry.gitlab.gnome.org/gnome/mutter/master:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
stage: test stage: test
variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
before_script: before_script:
- ninja -C mutter/build install - ninja -C mutter/build install
script: script:
@ -81,7 +70,7 @@ test:
when: on_failure when: on_failure
test-pot: test-pot:
image: registry.gitlab.gnome.org/gnome/mutter/master:v2 image: registry.gitlab.gnome.org/gnome/gnome-shell/master:v1
stage: test stage: test
before_script: before_script:
- ninja -C mutter/build install - ninja -C mutter/build install

19
.gitlab-ci/Dockerfile Normal file
View File

@ -0,0 +1,19 @@
FROM registry.gitlab.gnome.org/gnome/mutter/master:v1
RUN dnf -y update && dnf -y upgrade && \
dnf install -y 'dnf-command(copr)' && \
dnf copr enable -y fmuellner/gnome-shell-ci && \
dnf builddep -y gnome-shell --setopt=install_weak_deps=False && \
# bt only exports HAVE_BLUETOOTH to js, rest are outdated build-requires
dnf remove -y gnome-bluetooth-libs-devel dbus-glib-devel \
upower-devel python3-devel && \
# We'll build mutter ourselves
dnf remove -y --noautoremove mutter mutter-devel && \
# Needed for tests
dnf install -y '*/xvfb-run' gdm-lib accountsservice-libs && \
dnf clean all && \
rm -rf /var/cache/dnf

View File

@ -1,7 +1,7 @@
FROM registry.fedoraproject.org/fedora:latest FROM registry.fedoraproject.org/fedora:latest
RUN dnf -y update && dnf -y upgrade && \ RUN dnf -y update && dnf -y upgrade && \
dnf install -y 'dnf-command(copr)' git && \ dnf install -y 'dnf-command(copr)' && \
# For syntax checks with `find . -name '*.js' -exec js60 -c -s '{}' ';'` # For syntax checks with `find . -name '*.js' -exec js60 -c -s '{}' ';'`
dnf install -y findutils mozjs60-devel && \ dnf install -y findutils mozjs60-devel && \

View File

@ -17,19 +17,15 @@ if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
merge_request_branch=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME merge_request_branch=$CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
echo Looking for $merge_request_branch on remote ... echo Looking for $merge_request_branch on remote ...
if git fetch -q $merge_request_remote $merge_request_branch 2>/dev/null; then if git fetch $merge_request_remote $merge_request_branch >/dev/null 2>&1; then
mutter_target=FETCH_HEAD mutter_target=FETCH_HEAD
else
mutter_target=origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
echo Using $mutter_target instead
fi fi
fi fi
if [ -z "$mutter_target" ]; then if [ -z "$mutter_target" ]; then
mutter_target=$(git branch -r -l origin/$shell_branch) mutter_target=$(git branch -r -l $shell_branch)
mutter_target=${mutter_target:-$(git branch -r -l ${shell_branch#remotes/})}
mutter_target=${mutter_target:-origin/master} mutter_target=${mutter_target:-origin/master}
echo Using $mutter_target instead echo Using $mutter_target instead
fi fi
git checkout -q $mutter_target git checkout $mutter_target

View File

@ -1,105 +0,0 @@
#!/usr/bin/env bash
OUTPUT_REGULAR=reports/lint-regular-report.txt
OUTPUT_LEGACY=reports/lint-legacy-report.txt
OUTPUT_FINAL=reports/lint-common-report.txt
OUTPUT_MR=reports/lint-mr-report.txt
LINE_CHANGES=changed-lines.txt
is_empty() {
(! grep -q . $1)
}
run_eslint() {
ARGS_LEGACY='--config lint/eslintrc-legacy.json'
local extra_args=ARGS_$1
local output=OUTPUT_$1
eslint -f unix ${!extra_args} -o ${!output} js
}
list_commit_range_additions() {
# Turn raw context-less git-diff into a list of
# filename:lineno pairs of new (+) lines
git diff -U0 "$@" -- js |
awk '
BEGIN { file=""; }
/^+++ b/ { file=substr($0,7); }
/^@@ / {
len = split($3,a,",")
start=a[1]
count=(len > 1) ? a[2] : 1
for (line=start; line<start+count; line++)
printf "%s/%s:%d:\n",ENVIRON["PWD"],file,line;
}'
}
copy_matched_lines() {
local source=$1
local matches=$2
local target=$3
echo -n > $target
for l in $(<$matches); do
grep $l $source >> $target
done
}
create_common() {
# comm requires sorted input;
# we also strip the error message to make the following a "common" error:
# regular:
# file.js:42:23 Indentation of 55, expected 42
# legacy:
# file.js:42:23 Indentation of 55, extected 24
prepare() {
sed 's: .*::' $1 | sort
}
comm -12 <(prepare $OUTPUT_REGULAR) <(prepare $OUTPUT_LEGACY) >$OUTPUT_FINAL.tmp
# Now add back the stripped error messages
copy_matched_lines $OUTPUT_REGULAR $OUTPUT_FINAL.tmp $OUTPUT_FINAL
rm $OUTPUT_FINAL.tmp
}
# Disable MR handling for now. We aren't ready to enforce
# non-legacy style just yet ...
unset CI_MERGE_REQUEST_TARGET_BRANCH_NAME
if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
git fetch $CI_MERGE_REQUEST_PROJECT_URL.git $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
branch_point=$(git merge-base HEAD FETCH_HEAD)
commit_range=$branch_point...$CI_COMMIT_SHA
list_commit_range_additions $commit_range > $LINE_CHANGES
# Don't bother with running lint when no JS changed
if is_empty $LINE_CHANGES; then
exit 0
fi
fi
echo Generating lint report using regular configuration
run_eslint REGULAR
echo Generating lint report using legacy configuration
run_eslint LEGACY
echo Done.
create_common
if ! is_empty $OUTPUT_FINAL; then
cat $OUTPUT_FINAL
exit 1
fi
# Just show the report and succeed when not testing a MR
if [ -z "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
exit 0
fi
copy_matched_lines $OUTPUT_REGULAR $LINE_CHANGES $OUTPUT_MR
cat $OUTPUT_MR
is_empty $OUTPUT_MR

View File

@ -84,6 +84,7 @@ don't use.
const Main = imports.ui.main; const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util; const Util = imports.misc.util;
``` ```
The alphabetical ordering should be done independently of the location of the The alphabetical ordering should be done independently of the location of the
@ -276,49 +277,34 @@ If your usage of an object is like a hash table (and thus conceptually the keys
can have special chars in them), don't use quotes, but use brackets: `{ bar: 42 can have special chars in them), don't use quotes, but use brackets: `{ bar: 42
}`, `foo['bar']`. }`, `foo['bar']`.
## Animations ## Getters, setters, and Tweener
Most objects that are animated are actors, and most properties used in animations
are animatable, which means they can use implicit animations:
Getters and setters should be used when you are dealing with an API that is
designed around setting properties, like Tweener. If you want to animate an
arbitrary property, create a getter and setter, and use Tweener to animate the
property.
```javascript ```javascript
moveActor(actor, x, y) { var ANIMATION_TIME = 2000;
actor.ease({
x, var MyClass = class {
y, constructor() {
duration: 500, // ms this.actor = new St.BoxLayout();
mode: Clutter.AnimationMode.EASE_OUT_QUAD this._position = 0;
}); }
}
``` get position() {
return this._position;
The above is a convenience wrapper around the actual Clutter API, and should generally }
be preferred over the more verbose:
set position(value) {
```javascript this._position = value;
moveActor(actor, x, y) { this.actor.set_position(value, value);
actor.save_easing_state(); }
};
actor.set_easing_duration(500);
actor.set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD); let myThing = new MyClass();
actor.set({ Tweener.addTween(myThing,
x, { position: 100,
y time: ANIMATION_TIME,
}); transition: 'easeOutQuad' });
actor.restore_easing_state();
}
```
There is a similar convenience API around Clutter.PropertyTransition to animate
actor (or actor meta) properties that cannot use implicit animations:
```javascript
desaturateActor(actor, desaturate) {
let factor = desaturate ? 1.0 : 0.0;
actor.ease_property('@effects.desaturate.factor', factor, {
duration: 500, // ms
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
}
``` ```

255
NEWS
View File

@ -1,258 +1,3 @@
3.35.1
======
* Misc. bug fixes and cleanups [Marco; Matthias; !758, #701212]
Contributors:
Marco Trevisan (Treviño)
3.34.1
======
* Fix "Frequent" view icons disappearing on hover [Jonas D.; #1502]
* Allow editing app folder names [Georges, Marco; !675, !720]
* Skip property transitions while hidden [Florian; !708]
* Make menu animations more consistent [Florian, GB_2; #1595, !717]
* Improve performance when enabling/disabling all extensions [Jonas D.; !96]
* Fix extra icons appearing in "Frequent" view animation [Georges; !696]
* Fix fading out desktop icons [Harshula; #1616]
* Fix box-shadow glitch with prerendered resources [Daniel; #1186]
* Fix accidentally skipped animations [Florian; #1572]
* Fix screenshots and window animations when scaled [Robert; !728]
* Don't leak NOTIFY_SOCKET environment variable to applications [Benjamin; !741]
* Fix lock-up on X11 when ibus is already running on startup [Marco; #1712]
* Fix screen dimming on idle [Marco; #1683]
* Do not notify systemd before initialization is complete [Iain; !750]
* Support SAE secrets in network agent [Lubomir; !751]
* Fix various regressions with dynamic workspaces [Florian; #1497]
* Fixed crashes [Florian, Marco; #1678, !746]
* Misc. bug fixes and cleanups [Marco, Jonas D., Florian, Iain, Georges,
Jonas Å., Martin, Takao, Carlos; !700, !705, !709, !711, !707, #1538, !710,
!713, !699, !715, !718, !716, !719, !721, #1243, !725, !731, #1614, !683,
!732, !121, !735, !736, !740, #573, #1641, #1571]
Contributors:
Marco Trevisan (Treviño), Benjamin Berg, Jonas Dreßler, Takao Fujiwara, GB_2,
Carlos Garnacho, Harshula Jayasuriya, Iain Lane, Robert Mader,
Daniel García Moreno, Florian Müllner, Georges Basile Stavracas Neto,
Lubomir Rintel, Martin Zurowietz, Jonas Ådahl
Translators:
Rafael Fontenelle [pt_BR], Fran Dieguez [gl], Balázs Úr [hu],
Milo Casagrande [it], Daniel Șerbănescu [ro], Kukuh Syafaat [id],
Jiri Grönroos [fi], Daniel Mustieles [es], Piotr Drąg [pl],
Anders Jonsson [sv], Marek Černocký [cs], Jordi Mas [ca],
Aurimas Černius [lt], Christian Kirbach [de], Emin Tufan Çetin [tr],
Enrico Nicoletto [pt_BR], Danial Behzadi [fa], Марко Костић [sr],
Alexandre Franke [fr], Charles Monzat [fr], Kjartan Maraas [nb],
Ryuta Fujii [ja], Nathan Follens [nl], Dušan Kazik [sk], Fabio Tomat [fur],
Matej Urbančič [sl], Ask Hjorth Larsen [da], Alan Mortensen [da]
3.34.0
======
* Handle startup/shutdown of misc X11 services [Carlos; !680]
* Fix sound volume mute/unmute [Iain; #1557]
* Correctly terminate pasted text [Carlos; #1570]
Contributors:
Carlos Garnacho, Iain Lane
Translators:
Tom Tryfonidis [el], Milo Casagrande [it], Ryuta Fujii [ja],
Efstathios Iosifidis [el], Carmen Bianca BAKKER [eo], Sabri Ünal [tr],
Dušan Kazik [sk], Balázs Meskó [hu], Claude Paroz [fr]
3.33.92
=======
* Animate pointer a11y pie timer [Jonas D.; !688]
* Fix restarting shell in systemd user session [Benjamin; !690]
* Misc. bug fixes and cleanups [Florian, Jonas D., Jonas Å., Will;
!691, !689, !692, #1552, !698]
Contributors:
Jonas Ådahl, Benjamin Berg, Piotr Drąg, Jonas Dreßler, Florian Müllner,
Will Thompson
Translators:
Daniel Șerbănescu [ro], Danial Behzadi [fa], Daniel Mustieles [es],
Jiri Grönroos [fi], Asier Sarasua Garmendia [eu], Piotr Drąg [pl],
Rūdolfs Mazurs [lv], Anders Jonsson [sv], Fran Dieguez [gl], Jordi Mas [ca],
Matej Urbančič [sl], Zander Brown [en_GB], Ryuta Fujii [ja], Tim Sabsch [de],
Fabio Tomat [fur], Pawan Chitrakar [ne], A S Alam [pa], Changwoo Ryu [ko],
Aurimas Černius [lt], Daniel Rusek [cs], Marek Černocký [cs],
Kukuh Syafaat [id], Goran Vidović [hr], Rafael Fontenelle [pt_BR]
3.33.91
=======
* Fix regression when adjusting brightness [Florian; #1500]
* Fix pointer a11y timeout animation [Jonas D.; #1533]
* Add new extensions CLI tool [Florian; #1234]
* Only track top-level windows [Carlos; #556]
* Misc. bug fixes and cleanups [Jonas D., Jonas Å., Piotr, Florian;
!678, !682, !686]
Contributors:
Jonas Ådahl, Jonas Dreßler, Carlos Garnacho, Florian Müllner
Translators:
Asier Sarasua Garmendia [eu], Sveinn í Felli [is], Anders Jonsson [sv],
Jordi Mas [ca], Kukuh Syafaat [id], Florentina Mușat [ro], Jiri Grönroos [fi],
Aurimas Černius [lt], Daniel Mustieles [es], Piotr Drąg [pl],
Danial Behzadi [fa]
3.33.90
=======
* Implement DND app picker folder management [Georges; !643, !645, !664, !671]
* Make Clocks/Weather integration work with sandboxed apps [Florian; #1158]
* Support startup via systemd user instance [Benjamin; !507]
* Replace Tweener with Clutter animations [Florian; !663, !22, !666, !668, !669]
* Minimize travel distance in overview animation [Sergey; !267]
* Rescan icon theme when installed apps changed [Georges; !661]
* Consistently animate new window actions [Jonas; !662, !673]
* Misc. bug fixes and cleanups [Florian, Daniel, Ray, Bastien, Jonas, Niels,
Marco, Georges; !635, !636, !637, #1462, !628, !640, !641, !627, !644, !647,
!385, #1474, !651, #1144, !646, !653, !652, !655, #1482, !656, $654, !665,
!667, !670, #1357, !672, !657, #1507, !674, !677]
Contributors:
Benjamin Berg, Sergey Bugaev, Jonas Dreßler, Niels De Graef, Florian Müllner,
Georges Basile Stavracas Neto, Bastien Nocera, Ray Strode,
Marco Trevisan (Treviño), verdre, Daniel van Vugt
Translators:
Asier Sarasua Garmendia [eu], Rafael Fontenelle [pt_BR],
Kristjan SCHMIDT [eo], Jor Teron [mjw], Daniel Mustieles [es],
Kukuh Syafaat [id], Jordi Mas [ca], Fabio Tomat [fur], Daniel Șerbănescu [ro],
Anders Jonsson [sv]
3.33.4
======
* Fix unintentional interference between gestures [Jonas; !598]
* Fix unintentional loop while polkit dialog is active [Ray; !602]
* Fix alt-tab icon size on HiDPI [Jonas; !587]
* Style fixes and improvements [Frederik, Jakub; !610, #1446, #1449]
* Fix style updates for non-background CSS properties [Florian; #1212]
* Fix cursor visibility in screen recordings [Illya; #1208]
* Add option for disabling the hot corner [Florian; #688320]
* Use more fine-grained levels in battery indicator [Florian; !561, #1442]
* Fix the calculation of the maximum number of app search results [Jonas; !110]
* Handle horizontal workspace layout with gestures/animations [Florian; !575]
* Improve handling of session mode extensions [Florian, Didier; #789852]
* Misc. bug fixes and cleanups [Jonas, Florian, Sonny, Carlos, Mario, Benjamin,
Marco, Ting-Wei; !599, !600, !591, !606, !152, !607, !604, !495, !608, !611,
!614, !612, !615, !618, #369, !620, #774, !621, !616, #1065, !609, !626,
!491, !631, !632, !633, #1457]
Contributors:
Benjamin Berg, Jonas Dreßler, Frederik Feichtmeier, Carlos Garnacho,
Illya Klymov, Ting-Wei Lan, Florian Müllner, Sonny Piers, Mario Sanchez Prada,
Didier Roche, Jakub Steiner, Ray Strode, Jor Teron, Marco Trevisan (Treviño)
Translators:
Jordi Mas [ca], Jor Teron [mjw]
3.33.3
======
* Prepare for optional X11 [Carlos; !378]
* Fix opening window menu [Marco; !557]
* Reload search providers when installed applications change [Cosimo; !562]
* Implement locate-pointer accessibility feature [Olivier; #981]
* Allow to disable window menus via session mode [Cosimo; !569]
* Implement mouse accessibility [Olivier; !474]
* Call GDM's RegisterSession() after startup [Iain; !570]
* Fix extended keys popups being hidden by on-screen keyboard [Marco; !583]
* Fix top bar being hidden by lock screen [Jonas; !571]
* Update theme to better match GTK's Adwaita [Frederik; #841]
* Set up GJS profiler when GJS_TRACE_FD is set [Christian; !573]
* Misc. bug fixes and cleanups [Jonas, Cosimo, Robert, Florian, Marco, Simon,
Laurent, Niels, Will; !551, !555, !464, #1333, !565, !572, !568, !558, #1205,
#1336, !579, !576, #1392, !582, !586, #1406, #1351]
Contributors:
Laurent Bigonville, Cosimo Cecchi, Piotr Drąg, Jonas Dreßler,
Frederik Feichtmeier, Olivier Fourdan, Carlos Garnacho, Niels De Graef,
Christian Hergert, Iain Lane, Robert Mader, Florian Müllner, Simon Schampijer,
Jakub Steiner, Will Thompson, Marco Trevisan (Treviño)
Translators:
Kukuh Syafaat [id], Balázs Meskó [hu], Daniel Mustieles [es],
Fabio Tomat [fur], Nathan Follens [nl], Goran Vidović [hr], Jordi Mas [ca]
3.33.2
======
* Fix keeping actors visible in scrollviews [Marco; #1061]
* Move some chrome above popup windows [Jonas D.; !358]
* Include 'sandboxed-app-id' in winodw introspection info [Florian; #1289]
* Port to libecal-2.0 [Milan; !501]
* Support TCRYPT in mount password dialog [segfault; !126]
* Misc. bug fixes and cleanups [Florian, Marco, Veerasamy; !517, #745, !499,
!510, !515, !546, !549]
Contributors:
Cosimo Cecchi, Milan Crha, Jonas Dreßler, Florian Müllner, segfault,
Veerasamy Sevagen, Marco Trevisan (Treviño)
Translators:
Daniel Mustieles [es]
3.33.1
======
* Refine the app menu [Florian; #968]
* Refine window preview style [Feichtmeier; !461]
* Only emit ::style-changed on actual changes [Carlos; #1153]
* Disable emoji on-screen keyboard support on X11 [Florian; #1172]
* Fix tablet button mapping overlay [Carlos; #1220]
* Don't crash for world clock locations with no timezone [Florian; #1062]
* Don't leak old on-screen keyboard layout groups [Carlos; mutter#556]
* Fix ellipsization in dialog subtitles/bodies [Marco; !531]
* Fix glitch of fullscreen window in workspace switch animation [Jonas D.; !322]
* Fix distortion of some image contents [Florian; !525]
* Allow dragging unfocused tiled/maximized windows from top bar [Dylan; #679290]
* Handle network interface name changes [Fabrice; !534]
* Avoid unnecessary style changes when computing :first/:last-child
[Florian; !529]
* Misc. bug fixes and cleanups [Florian, Marco, Robert, Georges, Carlos, Simon,
Jonas D.; !487, !441, !502, !503, !504, !506, #822, !551, !512, !509, !511,
#1054, !524, #1065, !331, !540]
Contributors:
Fabrice Bellet, Jonas Dreßler, Feichtmeier, Carlos Garnacho, Robert Mader,
Dylan McCall, Simon McVittie, Florian Müllner, Georges Basile Stavracas Neto,
Marco Trevisan (Treviño)
Translators:
Daniel Mustieles [es], Kukuh Syafaat [id], Fabio Tomat [fur],
Carmen Bianca BAKKER [eo], Dingzhong Chen [zh_CN], Tim Sabsch [de]
3.32.1
======
* Fix avatar scaling on login screen [Florian; #1024]
* Fix distortion of desktop zoom [Florian; #646]
* Fix mouse cursor visibility when using desktop zoom [Florian, Marco; #1020]
* Fix screen dimming after wake-up on lock screen [Xiaoguang; #900]
* Fix Alt+Esc switcher [Florian; #1064]
* Respect struts for popover placement [Andrea; #1102]
* Fix app icons updates after theme changes [Florian; #1117]
* Fix desktop zoom after resolution changes [Marco; #1120]
* Implement stick-to-finger workspace switch overview gestures [Florian; #516]
* Make World Clocks offsets relative to local time [Florian; #1157]
* Fix top app icon disappearing from dash [Florian; #1053]
* Update switch style to match new Adwaita [Jakub; !496]
* Ensure CSS units are pixel-aligned when scaling is used [Carlos; #91]
* Misc. bug fixes and cleanups [Florian, Jakub, Robert, Alex, Carlos, Phil,
Marco, Benjamin, AsciiWolf, Ray, verdre; !444, #1016, #1018, !449, #1036,
!455, #1094, !440, #1023, #624, #1017, !476, !473, !480, #1130, !485, !481,
!490, !489, #1151, !435, #1160, !482, #1150, #1166, !384]
Contributors:
AsciiWolf, Andrea Azzarone, Benjamin Berg, Carlos Garnacho, Victor Ibragimov,
Robert Mader, Alex Monday, Florian Müllner, Jakub Steiner, Ray Strode,
Marco Trevisan (Treviño), verdre, Xiaoguang Wang, Phil Wyett
Translators:
Victor Ibragimov [tg, af, et, ja], Bruce Cowan [en_GB], Piotr Drąg [tg],
Charles Monzat [fr], Khaled Hosny [ar], Goran Vidović [hr],
Cheng-Chia Tseng [zh_TW], Carmen Bianca BAKKER [eo], Daniel Mustieles [es],
Dušan Kazik [sk]
3.32.0 3.32.0
====== ======
* Fix sizing issues in on-screen-keyboard emoji panel [Carlos; !439] * Fix sizing issues in on-screen-keyboard emoji panel [Carlos; !439]

View File

@ -1,15 +0,0 @@
<node>
<!--
org.gnome.Shell.ClocksIntegration:
@short_description: Clocks integration interface
The interface used for exporting location settings to GNOME Shell's
world clocks integration.
-->
<interface name="org.gnome.Shell.ClocksIntegration">
<property name="Locations" type="av" access="read"/>
</interface>
</node>

View File

@ -173,30 +173,6 @@
<arg type="s" direction="in" name="uuid"/> <arg type="s" direction="in" name="uuid"/>
</method> </method>
<!--
EnableExtension:
@uuid: The UUID of the extension
@success: Whether the operation was successful
Enable an extension.
-->
<method name="EnableExtension"> \
<arg type="s" direction="in" name="uuid"/> \
<arg type="b" direction="out" name="success"/> \
</method> \
<!--
DisableExtension:
@uuid: The UUID of the extension
@success: Whether the operation was successful
Disable an extension.
-->
<method name="DisableExtension"> \
<arg type="s" direction="in" name="uuid"/> \
<arg type="b" direction="out" name="success"/> \
</method> \
<!-- <!--
LaunchExtensionPrefs: LaunchExtensionPrefs:
@uuid: The UUID of the extension @uuid: The UUID of the extension
@ -213,15 +189,6 @@
--> -->
<method name="CheckForUpdates"/> <method name="CheckForUpdates"/>
<signal name="ExtensionStateChanged">
<arg type="s" name="uuid"/>
<arg type="a{sv}" name="state"/>
</signal>
<!--
ExtensionStatusChanged:
Deprecated for ExtensionStateChanged
-->
<signal name="ExtensionStatusChanged"> <signal name="ExtensionStatusChanged">
<arg type="s" name="uuid"/> <arg type="s" name="uuid"/>
<arg type="i" name="state"/> <arg type="i" name="state"/>

View File

@ -1,16 +0,0 @@
<node>
<!--
org.gnome.Shell.WeatherIntegration:
@short_description: Weather integration interface
The interface used for exporting location settings to GNOME Shell's
weather integration.
-->
<interface name="org.gnome.Shell.WeatherIntegration">
<property name="AutomaticLocation" type="b" access="read"/>
<property name="Locations" type="av" access="read"/>
</interface>
</node>

View File

@ -9,7 +9,7 @@
<method name="ShowOSD"> <method name="ShowOSD">
<arg type="a{sv}" direction="in" name="params"/> <arg type="a{sv}" direction="in" name="params"/>
</method> </method>
<method name="ShowMonitorLabels"> <method name="ShowMonitorLabels2">
<arg type="a{sv}" direction="in" name="params"/> <arg type="a{sv}" direction="in" name="params"/>
</method> </method>
<method name="HideMonitorLabels"/> <method name="HideMonitorLabels"/>

View File

@ -40,7 +40,6 @@
<file preprocess="xml-stripblanks">org.gnome.SettingsDaemon.Wacom.xml</file> <file preprocess="xml-stripblanks">org.gnome.SettingsDaemon.Wacom.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.AudioDeviceSelection.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.AudioDeviceSelection.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.CalendarServer.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.CalendarServer.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.ClocksIntegration.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.Extensions.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.Extensions.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.Introspect.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.Introspect.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.HotplugSniffer.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.HotplugSniffer.xml</file>
@ -49,7 +48,6 @@
<file preprocess="xml-stripblanks">org.gnome.Shell.Screencast.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.Screencast.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.Screenshot.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.Screenshot.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.Wacom.PadOsd.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.Wacom.PadOsd.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.WeatherIntegration.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.xml</file>
<file preprocess="xml-stripblanks">org.Gtk.MountOperationHandler.xml</file> <file preprocess="xml-stripblanks">org.Gtk.MountOperationHandler.xml</file>
<file preprocess="xml-stripblanks">org.gtk.Notifications.xml</file> <file preprocess="xml-stripblanks">org.gtk.Notifications.xml</file>

View File

@ -1,14 +0,0 @@
[Unit]
Description=Disable GNOME Shell extensions after failure
DefaultDependencies=no
# Only disable extensions for a short period of time after login.
# This means we err on the side of failing the first login after a broken
# extension was installed.
Requisite=gnome-session-stable.timer
[Service]
Type=simple
# Disable extensions
ExecStart=gsettings set org.gnome.shell disable-user-extensions true
Restart=no

View File

@ -20,16 +20,12 @@
<file>no-notifications.svg</file> <file>no-notifications.svg</file>
<file>noise-texture.png</file> <file>noise-texture.png</file>
<file>pad-osd.css</file> <file>pad-osd.css</file>
<file alias="icons/pointer-double-click-symbolic.svg">pointer-double-click-symbolic.svg</file>
<file alias="icons/pointer-drag-symbolic.svg">pointer-drag-symbolic.svg</file>
<file alias="icons/pointer-primary-click-symbolic.svg">pointer-primary-click-symbolic.svg</file>
<file alias="icons/pointer-secondary-click-symbolic.svg">pointer-secondary-click-symbolic.svg</file>
<file>process-working.svg</file> <file>process-working.svg</file>
<file>toggle-off.svg</file> <file>toggle-off-us.svg</file>
<file>toggle-off-dark.svg</file> <file>toggle-off-intl.svg</file>
<file>toggle-off-hc.svg</file> <file>toggle-off-hc.svg</file>
<file>toggle-on.svg</file> <file>toggle-on-us.svg</file>
<file>toggle-on-dark.svg</file> <file>toggle-on-intl.svg</file>
<file>toggle-on-hc.svg</file> <file>toggle-on-hc.svg</file>
</gresource> </gresource>
</gresources> </gresources>

View File

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

View File

@ -1,10 +1,5 @@
[Unit] [Unit]
Description=GNOME Shell on Wayland Description=GNOME Shell (wayland sync point)
DefaultDependencies=no After=gnome-shell.service
BindsTo=gnome-shell.service
Requisite=gnome-session-initialized.target Conflicts=gnome-shell-x11.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
Requires=gnome-shell-wayland.service
After=gnome-shell-wayland.service

View File

@ -1,33 +0,0 @@
[Unit]
Description=GNOME Shell on X11
# On X11, try to show the GNOME Session Failed screen
OnFailure=gnome-shell-disable-extensions.service gnome-session-failed.target
OnFailureJobMode=replace
CollectMode=inactive-or-failed
RefuseManualStart=on
RefuseManualStop=on
After=gnome-session-manager.target
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
# The units already conflict because they use the same BusName
#Conflicts=gnome-shell-wayland.service
# Limit startup frequency more than the default
StartLimitIntervalSec=15s
StartLimitBurst=3
[Service]
Type=notify
ExecStart=@bindir@/gnome-shell
# Exit code 1 means we are probably *not* dealing with an extension failure
SuccessExitStatus=1
# On X11 we want to restart on-success (Alt+F2 + r) and on-failure.
Restart=always
# Do not wait before restarting the shell
RestartSec=0ms
# Kill any stubborn child processes after this long
TimeoutStopSec=5

View File

@ -1,10 +1,5 @@
[Unit] [Unit]
Description=GNOME Shell on X11 Description=GNOME Shell (x11 sync point)
DefaultDependencies=no After=gnome-shell.service
BindsTo=gnome-shell.service
Requisite=gnome-session-initialized.target Conflicts=gnome-shell-wayland.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
Requires=gnome-shell-x11.service
After=gnome-shell-x11.service

View File

@ -0,0 +1,11 @@
[Unit]
Description=GNOME Shell
Wants=gnome-session.service
After=graphical-session-pre.target gnome-session-bus.target
PartOf=graphical-session.target
[Service]
Type=dbus
ExecStart=@bindir@/gnome-shell
Restart=on-failure
BusName=org.gnome.Shell

View File

@ -14,8 +14,6 @@ desktopconf = configuration_data()
# file when built in a non-system prefix # file when built in a non-system prefix
desktopconf.set('bindir', bindir) desktopconf.set('bindir', bindir)
desktopconf.set('VERSION', meson.project_version()) desktopconf.set('VERSION', meson.project_version())
desktopconf.set('systemd_hidden', have_systemd ? 'true' : 'false')
foreach desktop_file : desktop_files foreach desktop_file : desktop_files
i18n.merge_file('desktop', i18n.merge_file('desktop',
input: configure_file( input: configure_file(
@ -24,7 +22,7 @@ foreach desktop_file : desktop_files
configuration: desktopconf configuration: desktopconf
), ),
output: desktop_file, output: desktop_file,
po_dir: po_dir, po_dir: '../po',
install: true, install: true,
install_dir: desktopdir, install_dir: desktopdir,
type: 'desktop' type: 'desktop'
@ -100,23 +98,15 @@ if have_systemd
unitconf = configuration_data() unitconf = configuration_data()
unitconf.set('bindir', bindir) unitconf.set('bindir', bindir)
configure_file( unit = configure_file(
input: 'gnome-shell-x11.service.in', input: 'gnome-shell.service.in',
output: 'gnome-shell-x11.service', output: 'gnome-shell.service',
configuration: unitconf, configuration: unitconf,
install_dir: systemduserunitdir install_dir: systemduserunitdir
) )
configure_file( units = files('gnome-shell-wayland.target',
input: 'gnome-shell-wayland.service.in', 'gnome-shell-x11.target')
output: 'gnome-shell-wayland.service',
configuration: unitconf,
install_dir: systemduserunitdir
)
units = files('gnome-shell-x11.target',
'gnome-shell-wayland.target',
'gnome-shell-disable-extensions.service')
install_data(units, install_dir: systemduserunitdir) install_data(units, install_dir: systemduserunitdir)
endif endif

View File

@ -14,4 +14,3 @@ X-GNOME-Autostart-Phase=DisplayServer
X-GNOME-Provides=panel;windowmanager; X-GNOME-Provides=panel;windowmanager;
X-GNOME-Autostart-Notify=true X-GNOME-Autostart-Notify=true
X-GNOME-AutoRestart=false X-GNOME-AutoRestart=false
X-GNOME-HiddenUnderSystemd=@systemd_hidden@

View File

@ -21,17 +21,6 @@
EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell. EnableExtension and DisableExtension D-Bus methods on org.gnome.Shell.
</description> </description>
</key> </key>
<key name="disabled-extensions" type="as">
<default>[]</default>
<summary>UUIDs of extensions to force disabling</summary>
<description>
GNOME Shell extensions have a UUID property; this key lists extensions
which should be disabled, even if loaded as part of the current mode.
You can also manipulate this list with the EnableExtension and
DisableExtension D-Bus methods on org.gnome.Shell.
This key takes precedence over the “enabled-extensions” setting.
</description>
</key>
<key name="disable-user-extensions" type="b"> <key name="disable-user-extensions" type="b">
<default>false</default> <default>false</default>
<summary>Disable user extensions</summary> <summary>Disable user extensions</summary>
@ -110,6 +99,7 @@
</description> </description>
</key> </key>
<child name="keybindings" schema="org.gnome.shell.keybindings"/> <child name="keybindings" schema="org.gnome.shell.keybindings"/>
<child name="keyboard" schema="org.gnome.shell.keyboard"/>
</schema> </schema>
<schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/" <schema id="org.gnome.shell.keybindings" path="/org/gnome/shell/keybindings/"
@ -150,6 +140,11 @@
Keybinding to focus the active notification. Keybinding to focus the active notification.
</description> </description>
</key> </key>
<key name="pause-resume-tweens" type="as">
<default>[]</default>
<summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</summary>
<description></description>
</key>
<key name="switch-to-application-1" type="as"> <key name="switch-to-application-1" type="as">
<default>["&lt;Super&gt;1"]</default> <default>["&lt;Super&gt;1"]</default>
<summary>Switch to application 1</summary> <summary>Switch to application 1</summary>
@ -188,6 +183,17 @@
</key> </key>
</schema> </schema>
<schema id="org.gnome.shell.keyboard" path="/org/gnome/shell/keyboard/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="keyboard-type" type="s">
<default>'touch'</default>
<summary>Which keyboard to use</summary>
<description>
The type of keyboard to use.
</description>
</key>
</schema>
<schema id="org.gnome.shell.app-switcher" <schema id="org.gnome.shell.app-switcher"
path="/org/gnome/shell/app-switcher/" path="/org/gnome/shell/app-switcher/"
gettext-domain="@GETTEXT_PACKAGE@"> gettext-domain="@GETTEXT_PACKAGE@">
@ -228,36 +234,6 @@
</key> </key>
</schema> </schema>
<schema id="org.gnome.shell.world-clocks" path="/org/gnome/shell/world-clocks/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="locations" type="av">
<summary>Locations</summary>
<description>
The locations to show in world clocks
</description>
<default>[]</default>
</key>
</schema>
<schema id="org.gnome.shell.weather" path="/org/gnome/shell/weather/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="automatic-location" type="b">
<summary>Automatic location</summary>
<description>
Whether to fetch the current location or not
</description>
<default>false</default>
</key>
<key name="locations" type="av">
<summary>Location</summary>
<description>
The location for which to show a forecast
</description>
<default>[]</default>
</key>
</schema>
<!-- unused, change 00_org.gnome.shell.gschema.override instead --> <!-- unused, change 00_org.gnome.shell.gschema.override instead -->
<schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/" <schema id="org.gnome.shell.overrides" path="/org/gnome/shell/overrides/"
gettext-domain="@GETTEXT_PACKAGE@"> gettext-domain="@GETTEXT_PACKAGE@">

View File

@ -1,5 +1,3 @@
$variant: 'light';
@import "gnome-shell-sass/_high-contrast-colors"; //use gtk colors @import "gnome-shell-sass/_high-contrast-colors"; //use gtk colors
@import "gnome-shell-sass/_drawing"; @import "gnome-shell-sass/_drawing";
@import "gnome-shell-sass/_common"; @import "gnome-shell-sass/_common";

View File

@ -3,11 +3,11 @@
$base_color: if($variant == 'light', #ffffff, lighten(desaturate(#241f31, 20%), 2%)); $base_color: if($variant == 'light', #ffffff, lighten(desaturate(#241f31, 20%), 2%));
$bg_color: if($variant == 'light', #f6f5f4, darken(desaturate(#3d3846, 100%), 4%)); $bg_color: if($variant == 'light', #f6f5f4, desaturate(#3d3846, 10%));
$fg_color: if($variant == 'light', #2e3436, #eeeeec); $fg_color: if($variant == 'light', #2e3436, #eeeeec);
$selected_fg_color: #ffffff; $selected_fg_color: #ffffff;
$selected_bg_color: if($variant == 'light', #3584e4, darken(#3584e4, 10%)); $selected_bg_color: if($variant == 'light', #3584e4, darken(#3584e4, 20%));
$selected_borders_color: if($variant== 'light', darken($selected_bg_color, 15%), darken($selected_bg_color, 30%)); $selected_borders_color: if($variant== 'light', darken($selected_bg_color, 15%), darken($selected_bg_color, 30%));
$borders_color: if($variant == 'light', darken($bg_color, 18%), darken($bg_color, 10%)); $borders_color: if($variant == 'light', darken($bg_color, 18%), darken($bg_color, 10%));
$borders_edge: if($variant == 'light', transparentize(white, 0.2), transparentize($fg_color, 0.93)); $borders_edge: if($variant == 'light', transparentize(white, 0.2), transparentize($fg_color, 0.93));
@ -21,15 +21,11 @@ $success_color: if($variant == 'light', #33d17a, darken(#33d17a, 10%));
$destructive_color: if($variant == 'light', #e01b24, darken(#e01b24, 10%)); $destructive_color: if($variant == 'light', #e01b24, darken(#e01b24, 10%));
$osd_fg_color: #eeeeec; $osd_fg_color: #eeeeec;
$osd_text_color: white; $osd_bg_color: transparentize(darken(desaturate(#3d3846, 100%), 15%),0.3);
$osd_bg_color: transparentize(darken(desaturate(#3d3846, 100%), 12%),0.04);
$osd_insensitive_bg_color: transparentize(mix($osd_fg_color, opacify($osd_bg_color, 1), 10%), 0.5);
$osd_insensitive_fg_color: mix($osd_fg_color, opacify($osd_bg_color, 1), 50%);
$osd_borders_color: transparentize(black, 0.3); $osd_borders_color: transparentize(black, 0.3);
$osd_outer_borders_color: transparentize(white, 0.84); $osd_outer_borders_color: transparentize(white, 0.9);
$tooltip_borders_color: $osd_outer_borders_color; $tooltip_borders_color: $osd_outer_borders_color;
$shadow_color: transparentize(black, 0.9);
//insensitive state derived colors //insensitive state derived colors
$insensitive_fg_color: mix($fg_color, $bg_color, 50%); $insensitive_fg_color: mix($fg_color, $bg_color, 50%);

File diff suppressed because it is too large Load Diff

View File

@ -37,13 +37,16 @@
// possible $t values: // possible $t values:
// normal, focus, insensitive // normal, focus, insensitive
// //
$_inner_shadows: inset 0 2px 4px transparentize(black, 0.6);
@if $t==normal { @if $t==normal {
background-color: $base_color; background-color: $base_color;
border-color: $borders_color; border-color: $borders_color;
@include _shadows($_inner_shadows);
} }
@if $t==focus { @if $t==focus {
@include _shadows($_inner_shadows);
border-color: if($fc==$selected_bg_color, border-color: if($fc==$selected_bg_color,
$selected_borders_color, $selected_borders_color,
darken($fc,35%)); darken($fc,35%));
@ -108,7 +111,7 @@
} }
} }
@mixin button($t, $c:$bg_color, $tc:$fg_color, $edge: $borders_edge) { @mixin button($t, $c:opacify(lighten($osd_bg_color, 5%),1.0), $tc:$fg_color, $edge: $borders_edge) {
// //
// Button drawing function // Button drawing function
// //
@ -127,17 +130,18 @@
$_hilight_color: _button_hilight_color($c); $_hilight_color: _button_hilight_color($c);
$_button_edge: if($edge == none, none, _widget_edge($edge)); $_button_edge: if($edge == none, none, _widget_edge($edge));
$_blank_edge: if($edge == none, none, _widget_edge(transparentize($edge,1))); $_blank_edge: if($edge == none, none, _widget_edge(transparentize($edge,1)));
$_button_shadow: 0 1px 2px transparentize($shadow_color, 0.03);
@if $t==normal { @if $t==normal {
// //
// normal button // normal button
// //
$_bg: $c;
color: $tc; color: $osd_fg_color;
background-color: $c; background-color: $_bg;
border-color: $borders_color; border-color: $osd_borders_color;
box-shadow: $_button_shadow; box-shadow: inset 0 1px lighten($osd_bg_color,10%);
text-shadow: 0 1px black; text-shadow: 0 1px black;
icon-shadow: 0 1px black; icon-shadow: 0 1px black;
} }
@ -145,21 +149,24 @@
// //
// focused button // focused button
// //
color: $tc; $_bg: lighten($c,3%);
color: $osd_fg_color;
text-shadow: 0 1px black; text-shadow: 0 1px black;
icon-shadow: 0 1px black; icon-shadow: 0 1px black;
box-shadow: inset 0px 0px 0px 2px $selected_bg_color; box-shadow: inset 0px 0px 0px 1px $selected_bg_color;
//border-color: $selected_bg_color;
} }
@else if $t==hover { @else if $t==hover {
// //
// active osd button // active osd button
// //
color: $tc; $_bg: lighten($c,3%);
border-color: $borders_color;
background-color: $c; color: white;
box-shadow: $_button_shadow; border-color: $osd_borders_color;
background-color: $_bg;
box-shadow: inset 0 1px lighten($osd_bg_color,20%);
text-shadow: 0 1px black; text-shadow: 0 1px black;
icon-shadow: 0 1px black; icon-shadow: 0 1px black;
@ -168,18 +175,27 @@
// //
// active osd button // active osd button
// //
color: $tc; $_bg: if($c!=$bg_color, $c, $osd_borders_color);
border-color: $borders_color;
background-color: $c; color: white;
border-color: $osd_borders_color;
background-color: $selected_bg_color;
// This should be none, but it's creating some issues with borders, so to
// workaround it for now, use inset wich goes through a different code path.
// see https://bugzilla.gnome.org/show_bug.cgi?id=752934
box-shadow: inset 0 0 black;
text-shadow: none; text-shadow: none;
icon-shadow: none; icon-shadow: none;
box-shadow: none;
} }
@else if $t==insensitive { @else if $t==insensitive {
//
// insensitive osd button
//
$_bg: transparentize(mix($insensitive_fg_color,$osd_bg_color,20%),0.3);
color: $insensitive_fg_color; color: $insensitive_fg_color;
border-color: $insensitive_borders_color; border-color: $osd_borders_color;
background-color: $insensitive_bg_color; background-color: $_bg;
box-shadow: none; box-shadow: none;
text-shadow: none; text-shadow: none;
icon-shadow: none; icon-shadow: none;

View File

@ -26,7 +26,6 @@ $osd_borders_color: transparentize(black, 0.3);
$osd_outer_borders_color: transparentize(white, 0.9); $osd_outer_borders_color: transparentize(white, 0.9);
$tooltip_borders_color: $osd_outer_borders_color; $tooltip_borders_color: $osd_outer_borders_color;
$shadow_color: transparentize(black, 0.9);
//insensitive state derived colors //insensitive state derived colors
$insensitive_fg_color: mix($fg_color, $bg_color, 50%); $insensitive_fg_color: mix($fg_color, $bg_color, 50%);

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="20"
height="20"
id="svg2">
<g
id="layer1"
style="display:inline">
<g
id="id1"
transform="translate(-19,-0.75)">
<path
style="color:#000000;shape-padding:0;clip-rule:nonzero;display:block;overflow:visible;visibility:visible;opacity:1;solid-color:#000000;solid-opacity:1;fill:#464646;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 19.855469,0.45507812 c 0,6.69466128 0,13.38932288 0,20.08398388 1.414713,-1.38151 2.829427,-2.763021 4.24414,-4.144531 0.5882,1.18866 1.158389,2.386561 1.758464,3.569127 1.108631,1.640259 4.157538,0.465128 3.89799,-1.495859 0.01057,-0.470226 -0.405577,-0.908445 -0.434651,-1.313638 0.259401,-0.25321 0.518802,-0.50642 0.778203,-0.75963 0.5882,1.18866 1.158389,2.386561 1.758464,3.569127 1.108631,1.640259 4.157538,0.465128 3.89799,-1.495859 -0.192325,-0.904303 -0.717854,-1.698026 -1.068629,-2.548967 -0.238908,-0.512658 -0.477817,-1.025315 -0.716725,-1.537973 1.755859,0 3.511719,0 5.267578,0 C 34.777352,9.738932 30.31641,5.0970051 25.855469,0.45507812 c 0,2.08138018 0,4.16276048 0,6.24414068 -2,-2.0813802 -4,-4.1627605 -6,-6.24414068 z m 1.5,3.72656248 c 2,2.0813801 4,4.1627603 6,6.2441404 0,-2.0813801 0,-4.1627603 0,-6.2441404 2.786458,2.8997395 5.572917,5.7994789 8.359375,8.6992184 -1.366537,0 -2.733073,0 -4.09961,0 0.883468,1.903435 1.781983,3.800273 2.656081,5.707817 0.0065,0.622781 -1.227555,0.980575 -1.325116,0.207118 -0.80433,-1.640251 -1.608661,-3.280501 -2.412991,-4.920752 -1.020182,0.995443 -2.040365,1.990885 -3.060547,2.986328 0.263642,0.608048 0.596803,1.192457 0.814693,1.816134 -0.182662,0.601037 -1.26833,0.8373 -1.365856,0.06795 -0.796094,-1.623456 -1.592189,-3.246912 -2.388284,-4.870368 -1.059245,1.033854 -2.118489,2.067708 -3.177734,3.101562 -4e-6,-4.265002 -7e-6,-8.5300036 -1.1e-5,-12.7950054 z"
id="path5565" />
</g>
<g
id="id2"
transform="translate(-25,-0.75)" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="20"
height="20"
id="svg2">
<g
id="g835">
<path
style="color:#000000;shape-padding:0;clip-rule:nonzero;display:block;overflow:visible;visibility:visible;opacity:1;solid-color:#000000;solid-opacity:1;fill:#464646;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="M 10.705078 1.671875 C 9.8685536 1.7465699 8.886927 1.5353073 8.2578125 2.2480469 C 8.0785627 2.7511513 7.8667422 2.9777446 7.3125 2.8652344 C 6.5186841 2.8141575 5.6105879 2.9190179 5.125 3.6386719 C 4.5700923 4.4696324 4.8113194 5.4949043 4.7578125 6.4316406 L 4.7578125 7.9335938 C 4.2480917 7.6156216 3.6258927 7.8015358 3.0585938 7.7519531 C 2.6157606 7.7312277 2.1774807 7.7771069 1.7402344 7.84375 C 1.7971654 10.529678 1.813967 13.217089 1.8613281 15.902344 C 1.9550191 17.204635 3.0933719 18.307155 4.40625 18.326172 C 5.0391993 18.341272 5.8885801 18.332951 6.6308594 18.337891 C 9.8526764 18.325821 13.076973 18.38774 16.296875 18.28125 C 17.459088 18.161027 18.510143 17.092798 18.367188 15.884766 L 18.367188 6.4042969 C 17.660379 5.4636119 16.551912 4.623434 15.308594 4.8339844 C 15.009045 4.3804158 14.822476 3.3608651 14.082031 3.0351562 C 13.727176 2.744118 13.242443 2.9253873 12.822266 2.8730469 C 12.524824 2.8003648 11.966366 3.0655864 11.953125 2.6210938 C 11.795774 2.0995736 11.23789 1.7125276 10.705078 1.671875 z M 10.599609 3.1757812 C 10.764131 3.4472414 10.782382 3.9294982 10.818359 4.3007812 C 10.824915 4.3076775 10.838155 4.3066925 10.845703 4.3125 C 10.836598 4.3123268 10.827465 4.3126732 10.818359 4.3125 L 11.3125 10.212891 L 11.976562 4.3710938 L 13.322266 4.375 C 13.858345 4.7645492 13.735252 5.5154752 13.876953 6.0976562 C 13.865826 6.1651282 13.88335 6.1937019 13.892578 6.234375 C 13.891928 6.2343667 13.891276 6.2343833 13.890625 6.234375 L 13.902344 6.3203125 L 14.384766 10.185547 L 15.048828 6.265625 C 15.622863 6.228498 16.206517 6.3041365 16.607422 6.7675781 C 17.017062 6.9844433 16.823063 7.4565491 16.867188 7.8261719 L 16.867188 16.167969 C 16.530129 17.131654 15.267211 16.71624 14.492188 16.828125 C 11.121671 16.841205 7.7500508 16.861953 4.3808594 16.814453 C 3.4051926 16.786173 3.2389196 15.744474 3.3398438 14.972656 C 3.3282027 13.065594 3.2950998 11.158732 3.2617188 9.2519531 C 3.5880829 9.2584131 3.9376766 9.2391948 4.25 9.2617188 C 4.7438842 10.17694 4.7346154 11.262903 4.7578125 12.277344 C 5.2504494 12.270544 5.8011939 12.317174 6.2578125 12.277344 C 6.2669593 9.7577406 6.2393741 7.2373172 6.2714844 4.71875 C 6.3763823 4.198849 7.0022289 4.409587 7.3828125 4.3652344 L 8.0585938 4.3652344 L 8.546875 10.212891 L 9.2167969 4.3359375 L 9.2128906 4.3359375 C 9.2438386 3.9531035 9.0622615 3.4401006 9.4609375 3.2167969 L 10.599609 3.1757812 z "
id="path5630" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="20"
height="20"
id="svg2"
version="1.1">
<g
id="layer1"
style="display:inline">
<g
id="id1"
transform="translate(-22.25,-0.75)">
<path
style="color:#000000;shape-padding:0;clip-rule:nonzero;display:block;overflow:visible;visibility:visible;opacity:1;solid-color:#000000;solid-opacity:1;fill:#464646;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 25.855469,0.45507812 c 0,6.69466128 0,13.38932288 0,20.08398388 1.414713,-1.380859 2.829427,-2.761719 4.24414,-4.142578 0.612408,1.215372 1.173049,2.460221 1.819709,3.656095 1.141947,1.476279 3.975266,0.389006 3.846009,-1.473608 -0.09413,-0.822519 -0.594755,-1.521423 -0.899969,-2.277599 -0.298869,-0.640171 -0.597739,-1.280342 -0.896608,-1.920513 1.75651,0 3.513021,0 5.269531,0 C 34.777344,9.738932 30.316406,5.0970051 25.855469,0.45507812 Z m 1.5,3.72656248 c 2.786458,2.8997395 5.572917,5.7994789 8.359375,8.6992184 -1.367188,0 -2.734375,0 -4.101563,0 0.885072,1.903196 1.781799,3.80152 2.659622,5.707744 0.0349,0.566084 -1.149057,0.988823 -1.282093,0.297971 -0.818567,-1.671162 -1.637133,-3.342323 -2.455699,-5.013485 -1.059896,1.034505 -2.119791,2.06901 -3.179687,3.103515 1.5e-5,-4.264988 3e-5,-8.5299756 4.5e-5,-12.7949634 z"
id="path5565" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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="20"
height="20"
id="svg2">
<g
id="layer1"
style="display:inline;stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke:#000000;stroke-opacity:1">
<g
transform="matrix(-1,0,0,1,42,-0.75)"
id="g5847"
style="stroke-width:1.5;stroke-miterlimit:4;stroke-dasharray:none;stroke:#000000;stroke-opacity:1">
<path
style="color:#000000;shape-padding:0;clip-rule:nonzero;display:block;overflow:visible;visibility:visible;opacity:1;solid-color:#000000;solid-opacity:1;fill:#464646;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
d="m 25.855469,0.45507812 c 0,6.69466128 0,13.38932288 0,20.08398388 1.414713,-1.380859 2.829427,-2.761719 4.24414,-4.142578 0.612408,1.215372 1.173049,2.460221 1.819709,3.656095 1.141947,1.476279 3.975266,0.389006 3.846009,-1.473608 -0.09413,-0.822519 -0.594755,-1.521423 -0.899969,-2.277599 -0.298869,-0.640171 -0.597739,-1.280342 -0.896608,-1.920513 1.75651,0 3.513021,0 5.269531,0 C 34.777344,9.738932 30.316406,5.0970051 25.855469,0.45507812 Z m 1.5,3.72656248 c 2.786458,2.8997395 5.572917,5.7994789 8.359375,8.6992184 -1.367188,0 -2.734375,0 -4.101563,0 0.885072,1.903196 1.781799,3.80152 2.659622,5.707744 0.0349,0.566084 -1.149057,0.988823 -1.282093,0.297971 -0.818567,-1.671162 -1.637133,-3.342323 -2.455699,-5.013485 -1.059896,1.034505 -2.119791,2.06901 -3.179687,3.103515 1.5e-5,-4.264988 3e-5,-8.5299756 4.5e-5,-12.7949634 z"
id="path5851" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="46" height="22"><defs><linearGradient id="a"><stop offset="0" stop-color="#39393a"/><stop offset="1" stop-color="#302f30"/></linearGradient><linearGradient xlink:href="#a" id="b" x1="53" y1="294.429" x2="53" y2="309.804" gradientUnits="userSpaceOnUse" gradientTransform="translate(-42.76)"/></defs><g transform="translate(0 -291.18)" stroke-width="1.085"><rect style="marker:none" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#323233" stroke="#272728"/><rect ry="10.455" rx="10.455" y="291.715" x=".543" height="20.911" width="21.143" style="marker:none" fill="url(#b)" stroke="#151515"/></g></svg>

Before

Width:  |  Height:  |  Size: 725 B

View File

@ -0,0 +1,209 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="65"
height="22"
id="svg2857"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="toggle-off-us.svg">
<defs
id="defs2859">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2865" />
<inkscape:perspective
id="perspective2843"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient76469-7-7-4"
id="linearGradient38024"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0215462,0,0,1.0322581,717.22867,428.68472)"
x1="6"
y1="102.95528"
x2="6"
y2="84.505203" />
<linearGradient
inkscape:collect="always"
id="linearGradient76469-7-7-4">
<stop
style="stop-color:#2e3232;stop-opacity:1"
offset="0"
id="stop76471-7-1-5" />
<stop
style="stop-color:#3e4545;stop-opacity:1"
offset="1"
id="stop76473-9-0-0" />
</linearGradient>
<inkscape:path-effect
effect="spiro"
id="path-effect77541-4"
is_visible="true" />
<inkscape:path-effect
effect="spiro"
id="path-effect77541-4-0"
is_visible="true" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient37802-8"
id="linearGradient12311-3-1-0-5-4"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.071426)"
x1="610.13782"
y1="501.43866"
x2="610.13782"
y2="492.52756" />
<linearGradient
id="linearGradient37802-8"
inkscape:collect="always">
<stop
id="stop37804-1"
offset="0"
style="stop-color:#2c2c2c;stop-opacity:1" />
<stop
id="stop37806-8"
offset="1"
style="stop-color:#16191a;stop-opacity:1" />
</linearGradient>
<linearGradient
y2="492.52756"
x2="610.13782"
y1="501.43866"
x1="610.13782"
gradientTransform="matrix(1.5918367,0,0,0.85714285,-900.56122,-423.92857)"
gradientUnits="userSpaceOnUse"
id="linearGradient13602"
xlink:href="#linearGradient37802-8"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-5.0602834"
inkscape:cy="16.473273"
inkscape:document-units="px"
inkscape:current-layer="g37994"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1375"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="true"
showborder="false">
<inkscape:grid
type="xygrid"
id="grid12954"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2862">
<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(-444.64286,-781.36218)">
<g
transform="matrix(0.6526046,0,0,0.80554422,99.592644,-636.32172)"
id="g37994">
<g
id="g37996"
transform="translate(-115,1277)">
<rect
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964000000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0.19591837"
id="rect13475"
width="98"
height="25"
x="644.5"
y="484.61118"
rx="4.7429576"
ry="3.8424656" />
<rect
ry="3.8424656"
rx="4.7429576"
y="483.5"
x="644.5"
height="25"
width="98"
id="rect38000"
style="color:#000000;fill:url(#linearGradient12311-3-1-0-5-4);fill-opacity:1;fill-rule:nonzero;stroke:#16191a;stroke-width:1.37920942;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
</g>
<g
transform="translate(-49.946213,-1.890275)"
id="g38002">
<g
transform="translate(-115,1247)"
style="display:inline"
id="g38004">
<rect
ry="3.7972314"
rx="4.6871223"
y="515.5"
x="694.53046"
height="25"
width="45.969578"
id="rect38006"
style="color:#000000;fill:url(#linearGradient38024);fill-opacity:1;fill-rule:nonzero;stroke:#1f2020;stroke-width:1.37920964;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
style="opacity:0.1;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 699.09675,516.7365 36.86904,0"
id="path38016"
inkscape:path-effect="#path-effect77541-4"
inkscape:original-d="m 699.09675,516.7365 36.86904,0"
inkscape:connector-curvature="0" />
</g>
</g>
<path
sodipodi:type="arc"
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:2.15627193;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
id="path13479"
sodipodi:cx="16.4375"
sodipodi:cy="10.8125"
sodipodi:rx="4.3125"
sodipodi:ry="4.3125"
d="m 20.75,10.8125 a 4.3125,4.3125 0 1 1 -8.625,0 4.3125,4.3125 0 1 1 8.625,0 z"
transform="matrix(1.4212691,0,0,1.1514287,577.38488,1761.1138)" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.5 KiB

View File

@ -0,0 +1,255 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="65"
height="22"
id="svg2857"
version="1.1"
inkscape:version="0.48.5 r10040"
sodipodi:docname="toggle-on-intl.svg">
<defs
id="defs2859">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2865" />
<inkscape:perspective
id="perspective2843"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient76469-7-7-4"
id="linearGradient38024"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0215462,0,0,1.0322581,717.22867,428.68472)"
x1="6"
y1="102.95528"
x2="6"
y2="84.505203" />
<linearGradient
inkscape:collect="always"
id="linearGradient76469-7-7-4">
<stop
style="stop-color:#2e3232;stop-opacity:1"
offset="0"
id="stop76471-7-1-5" />
<stop
style="stop-color:#3e4545;stop-opacity:1"
offset="1"
id="stop76473-9-0-0" />
</linearGradient>
<inkscape:path-effect
effect="spiro"
id="path-effect77541-4"
is_visible="true" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient37802"
id="linearGradient12311-3-1-0-5"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.071426)"
x1="610.13782"
y1="501.43866"
x2="610.13782"
y2="492.52756" />
<linearGradient
id="linearGradient37802"
inkscape:collect="always">
<stop
id="stop37804"
offset="0"
style="stop-color:#2c2c2c;stop-opacity:1" />
<stop
id="stop37806"
offset="1"
style="stop-color:#16191a;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient76469-7-7-4-3"
id="linearGradient77680"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1,0,0,1.0322581,717.71949,428.68472)"
x1="6"
y1="102.95528"
x2="6"
y2="84.505203" />
<linearGradient
inkscape:collect="always"
id="linearGradient76469-7-7-4-3">
<stop
style="stop-color:#2e3232;stop-opacity:1"
offset="0"
id="stop76471-7-1-5-7" />
<stop
style="stop-color:#3e4545;stop-opacity:1"
offset="1"
id="stop76473-9-0-0-9" />
</linearGradient>
<inkscape:path-effect
effect="spiro"
id="path-effect77541-4-0"
is_visible="true" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient37802-8"
id="linearGradient12311-3-1-0-5-4"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.5918367,0,0,0.85714285,-256.56122,59.071426)"
x1="610.13782"
y1="501.43866"
x2="610.13782"
y2="492.52756" />
<linearGradient
id="linearGradient37802-8"
inkscape:collect="always">
<stop
id="stop37804-1"
offset="0"
style="stop-color:#2c2c2c;stop-opacity:1" />
<stop
id="stop37806-8"
offset="1"
style="stop-color:#16191a;stop-opacity:1" />
</linearGradient>
<linearGradient
y2="492.52756"
x2="610.13782"
y1="501.43866"
x1="610.13782"
gradientTransform="matrix(1.5918367,0,0,0.85714285,-900.56122,-423.92857)"
gradientUnits="userSpaceOnUse"
id="linearGradient13602"
xlink:href="#linearGradient37802-8"
inkscape:collect="always" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="16.760995"
inkscape:cy="21.955673"
inkscape:document-units="px"
inkscape:current-layer="g37994"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1375"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="true"
showborder="false">
<inkscape:grid
type="xygrid"
id="grid12954"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2862">
<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(-444.64286,-781.36218)">
<g
transform="matrix(0.6526046,0,0,0.80554422,99.592644,-636.32172)"
id="g37994">
<g
id="g37996"
transform="translate(-115,1277)">
<rect
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964000000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0.19591837"
id="rect13475"
width="98"
height="25"
x="644.5"
y="484.61118"
rx="4.7429576"
ry="3.8424656" />
<rect
ry="3.8424656"
rx="4.7429576"
y="483.5"
x="644.5"
height="25"
width="98"
id="rect38000"
style="color:#000000;fill:url(#linearGradient12311-3-1-0-5-4);fill-opacity:1;fill-rule:nonzero;stroke:#16191a;stroke-width:1.37920942;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new" />
</g>
<g
transform="translate(-49.946213,-1.890275)"
id="g38002">
<g
transform="translate(-115,1247)"
style="display:inline"
id="g38004">
<rect
ry="3.7972314"
rx="4.6871223"
y="515.5"
x="694.53046"
height="25"
width="45.969578"
id="rect38006"
style="color:#000000;fill:url(#linearGradient38024);fill-opacity:1;fill-rule:nonzero;stroke:#1f2020;stroke-width:1.37920964;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
style="opacity:0.1;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 699.09675,516.7365 36.86904,0"
id="path38016"
inkscape:path-effect="#path-effect77541-4"
inkscape:original-d="m 699.09675,516.7365 36.86904,0"
inkscape:connector-curvature="0" />
</g>
</g>
<text
xml:space="preserve"
style="font-size:13.79166794px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
x="520.29974"
y="1997.0011"
id="text75614"
sodipodi:linespacing="125%"
transform="scale(1.1236771,0.88993537)"><tspan
sodipodi:role="line"
id="tspan75616"
x="520.29974"
y="1997.0011">OFF</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="22"><g transform="translate(0 -291.18)"><rect style="marker:none;font-variant-east_asian:normal" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#e1dedb" stroke="#cdc7c2" stroke-linecap="round" stroke-linejoin="round"/><rect ry="10.455" rx="10.455" y="291.715" x=".543" height="20.911" width="21.143" style="marker:none;font-variant-east_asian:normal" fill="#f8f7f7" stroke="#aa9f98" stroke-linecap="round" stroke-linejoin="round"/><g transform="matrix(.97148 0 0 1 1658.914 -2552.91)" stroke-width="1.015" stroke-linecap="round" stroke-linejoin="round"><rect ry="13.17" rx="13.556" y="1234.681" x="-1242.732" height="26" width="49.409" style="marker:none" fill="#e1dedb" stroke="#cdc7c2"/><rect style="marker:none" width="26.763" height="26" x="-1242.732" y="1234.769" rx="13.511" ry="13.126" fill="#f8f7f7" stroke="#aa9f98"/></g><g transform="matrix(.97148 0 0 1 1658.914 -2512.91)" stroke-width="1.015" stroke="#2b73cc"><rect style="marker:none" width="49.409" height="26" x="-1242.732" y="1234.681" rx="13.556" ry="13.17" fill="#3081e3"/><rect ry="13.126" rx="13.511" y="1234.769" x="-1220.086" height="26" width="26.763" style="marker:none" fill="#f8f7f7" stroke-linecap="round" stroke-linejoin="round"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="46" height="22"><defs><linearGradient id="a"><stop offset="0" stop-color="#39393a"/><stop offset="1" stop-color="#302f30"/></linearGradient><linearGradient xlink:href="#a" id="b" x1="53" y1="294.429" x2="53" y2="309.804" gradientUnits="userSpaceOnUse" gradientTransform="translate(-19)"/></defs><g transform="translate(0 -291.18)" stroke="#030e1b" stroke-width="1.085"><rect style="marker:none" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#15539e"/><rect ry="10.455" rx="10.455" y="291.715" x="24.304" height="20.911" width="21.143" style="marker:none" fill="url(#b)"/></g></svg>

Before

Width:  |  Height:  |  Size: 707 B

View File

@ -0,0 +1,192 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="65"
height="22"
id="svg2857"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="toggle-on-intl.svg">
<defs
id="defs2859">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2865" />
<inkscape:perspective
id="perspective2843"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient77461"
id="linearGradient77551"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3066667,0,0,1,-841.64667,-483)"
x1="1164.7644"
y1="962.93695"
x2="1164.7644"
y2="970.51404" />
<linearGradient
id="linearGradient77461"
inkscape:collect="always">
<stop
id="stop77463"
offset="0"
style="stop-color:#182f4c;stop-opacity:1" />
<stop
id="stop77465"
offset="1"
style="stop-color:#205b9a;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient76469-7-7-4"
id="linearGradient38024"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0215462,0,0,1.0322581,717.22867,428.68472)"
x1="6"
y1="102.95528"
x2="6"
y2="84.505203" />
<linearGradient
inkscape:collect="always"
id="linearGradient76469-7-7-4">
<stop
style="stop-color:#2e3232;stop-opacity:1"
offset="0"
id="stop76471-7-1-5" />
<stop
style="stop-color:#3e4545;stop-opacity:1"
offset="1"
id="stop76473-9-0-0" />
</linearGradient>
<inkscape:path-effect
effect="spiro"
id="path-effect77541-4"
is_visible="true" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="37.410841"
inkscape:cy="16.009314"
inkscape:document-units="px"
inkscape:current-layer="g37994"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1376"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="true"
showborder="false">
<inkscape:grid
type="xygrid"
id="grid12954"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2862">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-444.64286,-781.36218)">
<g
transform="matrix(0.6526046,0,0,0.80554422,99.592644,-636.32172)"
id="g37994">
<g
id="g37996"
transform="translate(-115,1277)">
<rect
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964000000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0.19591837"
id="rect13475"
width="98"
height="25"
x="644.5"
y="484.61118"
rx="4.7429576"
ry="3.8424656" />
<rect
ry="3.8424656"
rx="4.7429576"
y="483.5"
x="644.5"
height="25"
width="98"
id="rect38000"
style="color:#000000;fill:url(#linearGradient77551);fill-opacity:1;fill-rule:nonzero;stroke:#182f4c;stroke-width:1.37920964;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<g
transform="translate(2.0625,-2)"
id="g38002">
<g
transform="translate(-115,1247)"
style="display:inline"
id="g38004">
<rect
ry="3.7972314"
rx="4.6871223"
y="515.5"
x="694.53046"
height="25"
width="45.969578"
id="rect38006"
style="color:#000000;fill:url(#linearGradient38024);fill-opacity:1;fill-rule:nonzero;stroke:#1f2020;stroke-width:1.37920964;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
style="opacity:0.1;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 699.09675,516.7365 36.86904,0"
id="path38016"
inkscape:path-effect="#path-effect77541-4"
inkscape:original-d="m 699.09675,516.7365 36.86904,0"
inkscape:connector-curvature="0" />
</g>
</g>
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.99999994;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new"
id="rect13678"
width="3.0646207"
height="12.414008"
x="554.77728"
y="1767.3566" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

207
data/theme/toggle-on-us.svg Normal file
View File

@ -0,0 +1,207 @@
<?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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="65"
height="22"
id="svg2857"
version="1.1"
inkscape:version="0.91 r13725"
sodipodi:docname="toggle-on-us.svg">
<defs
id="defs2859">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2865" />
<inkscape:perspective
id="perspective2843"
inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
inkscape:vp_z="1 : 0.5 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_x="0 : 0.5 : 1"
sodipodi:type="inkscape:persp3d" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient76469-7-7-4"
id="linearGradient38024"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.0215462,0,0,1.0322581,717.22867,428.68472)"
x1="6"
y1="102.95528"
x2="6"
y2="84.505203" />
<linearGradient
inkscape:collect="always"
id="linearGradient76469-7-7-4">
<stop
style="stop-color:#2e3232;stop-opacity:1"
offset="0"
id="stop76471-7-1-5" />
<stop
style="stop-color:#3e4545;stop-opacity:1"
offset="1"
id="stop76473-9-0-0" />
</linearGradient>
<inkscape:path-effect
effect="spiro"
id="path-effect77541-4"
is_visible="true" />
<linearGradient
id="linearGradient77461-1"
inkscape:collect="always">
<stop
id="stop77463-1"
offset="0"
style="stop-color:#182f4c;stop-opacity:1" />
<stop
id="stop77465-4"
offset="1"
style="stop-color:#205b9a;stop-opacity:1" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient77461-1"
id="linearGradient77551-6-5"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.8527367,0,0,0.80554422,-969.41608,-778.00299)"
x1="1164.7644"
y1="962.93695"
x2="1164.7644"
y2="970.51404" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient77461-1"
id="linearGradient11198"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3066667,0,0,1,-1066.3709,794.25325)"
x1="1322.5831"
y1="-312.51855"
x2="1322.5831"
y2="-306.53461" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="-26.798898"
inkscape:cy="5.3753009"
inkscape:document-units="px"
inkscape:current-layer="g37994"
showgrid="false"
inkscape:window-width="2560"
inkscape:window-height="1376"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
borderlayer="true"
inkscape:showpageshadow="false"
inkscape:snap-nodes="false"
inkscape:snap-bbox="true"
showborder="false">
<inkscape:grid
type="xygrid"
id="grid12954"
empspacing="5"
visible="true"
enabled="true"
snapvisiblegridlinesonly="true" />
</sodipodi:namedview>
<metadata
id="metadata2862">
<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 />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-444.64286,-781.36218)">
<g
transform="matrix(0.6526046,0,0,0.80554422,99.592644,-636.32172)"
id="g37994">
<g
id="g37996"
transform="translate(-115,1277)">
<rect
style="color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964000000001;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0.19591837"
id="rect13475"
width="98"
height="25"
x="644.5"
y="484.61118"
rx="4.7429576"
ry="3.8424656" />
<rect
ry="3.8424656"
rx="4.7429576"
y="483.5"
x="644.5"
height="25"
width="98"
id="rect38000"
style="color:#000000;fill:url(#linearGradient11198);fill-opacity:1;fill-rule:nonzero;stroke:#182f4c;stroke-width:1.37920964;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto" />
</g>
<g
transform="translate(2.0625,-2)"
id="g38002">
<g
transform="translate(-115,1247)"
style="display:inline"
id="g38004">
<rect
ry="3.7972314"
rx="4.6871223"
y="515.5"
x="694.53046"
height="25"
width="45.969578"
id="rect38006"
style="color:#000000;fill:url(#linearGradient38024);fill-opacity:1;fill-rule:nonzero;stroke:#1f2020;stroke-width:1.37920964;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
sodipodi:nodetypes="cc"
style="opacity:0.1;color:#000000;fill:none;stroke:#ffffff;stroke-width:1.37920964px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 699.09675,516.7365 36.86904,0"
id="path38016"
inkscape:path-effect="#path-effect77541-4"
inkscape:original-d="m 699.09675,516.7365 36.86904,0"
inkscape:connector-curvature="0" />
</g>
</g>
<text
transform="scale(1.1000946,0.90901274)"
sodipodi:linespacing="125%"
id="text38018"
y="1955.5205"
x="495.94223"
style="font-size:13.29953671px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
xml:space="preserve"><tspan
y="1955.5205"
x="495.94223"
id="tspan38020"
sodipodi:role="line">ON</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="46" height="22"><g transform="translate(0 -291.18)" stroke="#2b73cc"><rect style="marker:none;font-variant-east_asian:normal" width="44.446" height="20.911" x=".625" y="291.715" rx="10.455" ry="10.073" fill="#3081e3"/><rect ry="10.455" rx="10.455" y="291.715" x="24.304" height="20.911" width="21.143" style="marker:none;font-variant-east_asian:normal" fill="#f8f7f7" stroke-linecap="round" stroke-linejoin="round"/></g></svg>

Before

Width:  |  Height:  |  Size: 473 B

View File

@ -28,7 +28,7 @@ foreach iface : ifaces
output: 'doc-gen-' + iface[1], output: 'doc-gen-' + iface[1],
command: [ command: [
'gdbus-codegen', 'gdbus-codegen',
'--interface-prefix=@0@.'.format(iface[0]), '--interface-prefix=@0@.'.format(iface),
'--generate-docbook', 'doc-gen', '--generate-docbook', 'doc-gen',
'--output-directory', '@OUTDIR@', '--output-directory', '@OUTDIR@',
'@INPUT@' '@INPUT@'

View File

@ -1,7 +1,3 @@
/* exported main */
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.Gtk = '3.0';
const Gettext = imports.gettext; const Gettext = imports.gettext;
const { Gdk, GLib, Gio, GObject, Gtk, Pango } = imports.gi; const { Gdk, GLib, Gio, GObject, Gtk, Pango } = imports.gi;
const Format = imports.format; const Format = imports.format;
@ -12,8 +8,6 @@ const Config = imports.misc.config;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
const { ExtensionState } = ExtensionUtils;
const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions'); const GnomeShellIface = loadInterfaceXML('org.gnome.Shell.Extensions');
const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface); const GnomeShellProxy = Gio.DBusProxy.makeProxyWrapper(GnomeShellIface);
@ -23,54 +17,74 @@ function stripPrefix(string, prefix) {
return string; return string;
} }
var Application = GObject.registerClass({ var Application = class {
GTypeName: 'ExtensionPrefs_Application' constructor() {
}, class Application extends Gtk.Application {
_init() {
GLib.set_prgname('gnome-shell-extension-prefs'); GLib.set_prgname('gnome-shell-extension-prefs');
super._init({ this.application = new Gtk.Application({
application_id: 'org.gnome.shell.ExtensionPrefs', application_id: 'org.gnome.shell.ExtensionPrefs',
flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE flags: Gio.ApplicationFlags.HANDLES_COMMAND_LINE
}); });
this.application.connect('activate', this._onActivate.bind(this));
this.application.connect('command-line', this._onCommandLine.bind(this));
this.application.connect('startup', this._onStartup.bind(this));
this._extensionPrefsModules = {};
this._startupUuid = null; this._startupUuid = null;
this._loaded = false; this._loaded = false;
this._skipMainWindow = false; this._skipMainWindow = false;
this._shellProxy = null;
} }
get shellProxy() { _extensionAvailable(uuid) {
return this._shellProxy; let extension = ExtensionUtils.extensions[uuid];
}
_showPrefs(uuid) { if (!extension)
let row = this._extensionSelector.get_children().find(c => {
return c.uuid === uuid && c.hasPrefs;
});
if (!row)
return false; return false;
if (!extension.dir.get_child('prefs.js').query_exists(null))
return false;
return true;
}
_getExtensionPrefsModule(extension) {
let uuid = extension.metadata.uuid;
if (this._extensionPrefsModules.hasOwnProperty(uuid))
return this._extensionPrefsModules[uuid];
ExtensionUtils.installImporter(extension);
let prefsModule = extension.imports.prefs;
prefsModule.init(extension.metadata);
this._extensionPrefsModules[uuid] = prefsModule;
return prefsModule;
}
_selectExtension(uuid) {
if (!this._extensionAvailable(uuid))
return;
let extension = ExtensionUtils.extensions[uuid];
let widget; let widget;
try { try {
widget = row.prefsModule.buildPrefsWidget(); let prefsModule = this._getExtensionPrefsModule(extension);
widget = prefsModule.buildPrefsWidget();
} catch (e) { } catch (e) {
widget = this._buildErrorUI(row, e); widget = this._buildErrorUI(extension, e);
} }
let dialog = new Gtk.Window({ let dialog = new Gtk.Window({ modal: !this._skipMainWindow,
modal: !this._skipMainWindow, type_hint: Gdk.WindowTypeHint.DIALOG });
type_hint: Gdk.WindowTypeHint.DIALOG dialog.set_titlebar(new Gtk.HeaderBar({ show_close_button: true,
}); title: extension.metadata.name,
dialog.set_titlebar(new Gtk.HeaderBar({ visible: true }));
show_close_button: true,
title: row.name,
visible: true
}));
if (this._skipMainWindow) { if (this._skipMainWindow) {
this.add_window(dialog); this.application.add_window(dialog);
if (this._window) if (this._window)
this._window.destroy(); this._window.destroy();
this._window = dialog; this._window = dialog;
@ -82,11 +96,9 @@ var Application = GObject.registerClass({
dialog.set_default_size(600, 400); dialog.set_default_size(600, 400);
dialog.add(widget); dialog.add(widget);
dialog.show(); dialog.show();
return true;
} }
_buildErrorUI(row, exc) { _buildErrorUI(extension, exc) {
let scroll = new Gtk.ScrolledWindow({ let scroll = new Gtk.ScrolledWindow({
hscrollbar_policy: Gtk.PolicyType.NEVER, hscrollbar_policy: Gtk.PolicyType.NEVER,
propagate_natural_height: true propagate_natural_height: true
@ -156,20 +168,13 @@ var Application = GObject.registerClass({
copyButton.connect('clicked', w => { copyButton.connect('clicked', w => {
let clipboard = Gtk.Clipboard.get_default(w.get_display()); let clipboard = Gtk.Clipboard.get_default(w.get_display());
// markdown for pasting in gitlab issues let backticks = '```';
let lines = [ clipboard.set_text(
`The settings of extension ${row.uuid} had an error:`, // markdown for pasting in gitlab issues
'```', `The settings of extension ${extension.uuid} had an error:\n${
`${exc}`, backticks}\n${exc}\n${backticks}\n\nStack trace:\n${
'```', backticks}\n${exc.stack}${backticks}\n`, -1
'', );
'Stack trace:',
'```',
exc.stack.replace(/\n$/, ''), // stack without trailing newline
'```',
''
];
clipboard.set_text(lines.join('\n'), -1);
}); });
let spacing = new Gtk.SeparatorToolItem({ draw: false }); let spacing = new Gtk.SeparatorToolItem({ draw: false });
@ -180,13 +185,13 @@ var Application = GObject.registerClass({
label: _("Homepage"), label: _("Homepage"),
tooltip_text: _("Visit extension homepage"), tooltip_text: _("Visit extension homepage"),
no_show_all: true, no_show_all: true,
visible: row.url != null visible: extension.metadata.url != null
}); });
toolbar.add(urlButton); toolbar.add(urlButton);
urlButton.connect('clicked', w => { urlButton.connect('clicked', w => {
let context = w.get_display().get_app_launch_context(); let context = w.get_display().get_app_launch_context();
Gio.AppInfo.launch_default_for_uri(row.url, context); Gio.AppInfo.launch_default_for_uri(extension.metadata.url, context);
}); });
let expandedBox = new Gtk.Box({ let expandedBox = new Gtk.Box({
@ -201,8 +206,8 @@ var Application = GObject.registerClass({
return scroll; return scroll;
} }
_buildUI() { _buildUI(app) {
this._window = new Gtk.ApplicationWindow({ application: this, this._window = new Gtk.ApplicationWindow({ application: app,
window_position: Gtk.WindowPosition.CENTER }); window_position: Gtk.WindowPosition.CENTER });
this._window.set_default_size(800, 500); this._window.set_default_size(800, 500);
@ -236,14 +241,18 @@ var Application = GObject.registerClass({
this._mainStack.add_named(new EmptyPlaceholder(), 'placeholder'); this._mainStack.add_named(new EmptyPlaceholder(), 'placeholder');
this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell'); this._shellProxy = new GnomeShellProxy(Gio.DBus.session, 'org.gnome.Shell', '/org/gnome/Shell');
this._shellProxy.connectSignal('ExtensionStateChanged', this._shellProxy.connectSignal('ExtensionStatusChanged', (proxy, senderName, [uuid, state, error]) => {
this._onExtensionStateChanged.bind(this)); if (ExtensionUtils.extensions[uuid] !== undefined)
this._scanExtensions();
});
this._window.show_all(); this._window.show_all();
} }
_sortList(row1, row2) { _sortList(row1, row2) {
return row1.name.localeCompare(row2.name); let name1 = ExtensionUtils.extensions[row1.uuid].metadata.name;
let name2 = ExtensionUtils.extensions[row2.uuid].metadata.name;
return name1.localeCompare(name2);
} }
_updateHeader(row, before) { _updateHeader(row, before) {
@ -254,56 +263,19 @@ var Application = GObject.registerClass({
row.set_header(sep); row.set_header(sep);
} }
_findExtensionRow(uuid) {
return this._extensionSelector.get_children().find(c => c.uuid === uuid);
}
_onExtensionStateChanged(proxy, senderName, [uuid, newState]) {
let row = this._findExtensionRow(uuid);
if (row) {
let { state } = ExtensionUtils.deserializeExtension(newState);
if (state == ExtensionState.UNINSTALLED)
row.destroy();
return; // we only deal with new and deleted extensions here
}
this._shellProxy.GetExtensionInfoRemote(uuid, ([serialized]) => {
let extension = ExtensionUtils.deserializeExtension(serialized);
if (!extension)
return;
// check the extension wasn't added in between
if (this._findExtensionRow(uuid) != null)
return;
this._addExtensionRow(extension);
});
}
_scanExtensions() { _scanExtensions() {
this._shellProxy.ListExtensionsRemote(([extensionsMap], e) => { let finder = new ExtensionUtils.ExtensionFinder();
if (e) { finder.connect('extension-found', this._extensionFound.bind(this));
if (e instanceof Gio.DBusError) { finder.scanExtensions();
log(`Failed to connect to shell proxy: ${e}`); this._extensionsLoaded();
this._mainStack.add_named(new NoShellPlaceholder(), 'noshell');
this._mainStack.visible_child_name = 'noshell';
} else {
throw e;
}
return;
}
for (let uuid in extensionsMap) {
let extension = ExtensionUtils.deserializeExtension(extensionsMap[uuid]);
this._addExtensionRow(extension);
}
this._extensionsLoaded();
});
} }
_addExtensionRow(extension) { _extensionFound(finder, extension) {
let row = new ExtensionRow(extension); let row = new ExtensionRow(extension.uuid);
row.prefsButton.visible = this._extensionAvailable(row.uuid);
row.prefsButton.connect('clicked', () => { row.prefsButton.connect('clicked', () => {
this._showPrefs(row.uuid); this._selectExtension(row.uuid);
}); });
row.show_all(); row.show_all();
@ -316,26 +288,24 @@ var Application = GObject.registerClass({
else else
this._mainStack.visible_child_name = 'placeholder'; this._mainStack.visible_child_name = 'placeholder';
if (this._startupUuid) if (this._startupUuid && this._extensionAvailable(this._startupUuid))
this._showPrefs(this._startupUuid); this._selectExtension(this._startupUuid);
this._startupUuid = null; this._startupUuid = null;
this._skipMainWindow = false; this._skipMainWindow = false;
this._loaded = true; this._loaded = true;
} }
vfunc_activate() { _onActivate() {
this._window.present(); this._window.present();
} }
vfunc_startup() { _onStartup(app) {
super.vfunc_startup(); this._buildUI(app);
this._buildUI();
this._scanExtensions(); this._scanExtensions();
} }
vfunc_command_line(commandLine) { _onCommandLine(app, commandLine) {
this.activate(); app.activate();
let args = commandLine.get_arguments(); let args = commandLine.get_arguments();
if (args.length) { if (args.length) {
@ -346,14 +316,16 @@ var Application = GObject.registerClass({
// Strip off "extension:///" prefix which fakes a URI, if it exists // Strip off "extension:///" prefix which fakes a URI, if it exists
uuid = stripPrefix(uuid, "extension:///"); uuid = stripPrefix(uuid, "extension:///");
if (!this._loaded) if (this._extensionAvailable(uuid))
this._selectExtension(uuid);
else if (!this._loaded)
this._startupUuid = uuid; this._startupUuid = uuid;
else if (!this._showPrefs(uuid)) else
this._skipMainWindow = false; this._skipMainWindow = false;
} }
return 0; return 0;
} }
}); };
var Expander = GObject.registerClass({ var Expander = GObject.registerClass({
Properties: { Properties: {
@ -520,35 +492,6 @@ class EmptyPlaceholder extends Gtk.Box {
} }
}); });
var NoShellPlaceholder = GObject.registerClass(
class NoShellPlaceholder extends Gtk.Box {
_init() {
super._init({
orientation: Gtk.Orientation.VERTICAL,
spacing: 12,
margin: 100,
margin_bottom: 60
});
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);
this.add(label);
label = new Gtk.Label({
label: _("Were very sorry, but it was not possible to get the list of installed extensions. Make sure you are logged into GNOME and try again."),
justify: Gtk.Justification.CENTER,
wrap: true
});
this.add(label);
this.show_all();
}
});
var DescriptionLabel = GObject.registerClass( var DescriptionLabel = GObject.registerClass(
class DescriptionLabel extends Gtk.Label { class DescriptionLabel extends Gtk.Label {
vfunc_get_preferred_height_for_width(width) { vfunc_get_preferred_height_for_width(width) {
@ -561,59 +504,30 @@ class DescriptionLabel extends Gtk.Label {
var ExtensionRow = GObject.registerClass( var ExtensionRow = GObject.registerClass(
class ExtensionRow extends Gtk.ListBoxRow { class ExtensionRow extends Gtk.ListBoxRow {
_init(extension) { _init(uuid) {
super._init(); super._init();
this._app = Gio.Application.get_default(); this.uuid = uuid;
this._extension = extension;
this._prefsModule = null;
this.connect('destroy', this._onDestroy.bind(this)); this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
this._settings.connect('changed::enabled-extensions', () => {
this._switch.state = this._isEnabled();
});
this._settings.connect('changed::disable-extension-version-validation',
() => {
this._switch.sensitive = this._canEnable();
});
this._settings.connect('changed::disable-user-extensions',
() => {
this._switch.sensitive = this._canEnable();
});
this._buildUI(); this._buildUI();
this._extensionStateChangedId = this._app.shellProxy.connectSignal(
'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
if (this.uuid !== uuid)
return;
this._extension = ExtensionUtils.deserializeExtension(newState);
let state = (this._extension.state == ExtensionState.ENABLED);
GObject.signal_handler_block(this._switch, this._notifyActiveId);
this._switch.state = state;
GObject.signal_handler_unblock(this._switch, this._notifyActiveId);
this._switch.sensitive = this._canToggle();
});
}
get uuid() {
return this._extension.uuid;
}
get name() {
return this._extension.metadata.name;
}
get hasPrefs() {
return this._extension.hasPrefs;
}
get url() {
return this._extension.metadata.url;
}
_onDestroy() {
if (!this._app.shellProxy)
return;
if (this._extensionStateChangedId)
this._app.shellProxy.disconnectSignal(this._extensionStateChangedId);
this._extensionStateChangedId = 0;
} }
_buildUI() { _buildUI() {
let extension = ExtensionUtils.extensions[this.uuid];
let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL, let hbox = new Gtk.Box({ orientation: Gtk.Orientation.HORIZONTAL,
hexpand: true, margin_end: 24, spacing: 24, hexpand: true, margin_end: 24, spacing: 24,
margin: 12 }); margin: 12 });
@ -623,20 +537,19 @@ class ExtensionRow extends Gtk.ListBoxRow {
spacing: 6, hexpand: true }); spacing: 6, hexpand: true });
hbox.add(vbox); hbox.add(vbox);
let name = GLib.markup_escape_text(this.name, -1); let name = GLib.markup_escape_text(extension.metadata.name, -1);
let label = new Gtk.Label({ label: '<b>' + name + '</b>', let label = new Gtk.Label({ label: '<b>' + name + '</b>',
use_markup: true, use_markup: true,
halign: Gtk.Align.START }); halign: Gtk.Align.START });
vbox.add(label); vbox.add(label);
let desc = this._extension.metadata.description.split('\n')[0]; let desc = extension.metadata.description.split('\n')[0];
label = new DescriptionLabel({ label: desc, wrap: true, lines: 2, label = new DescriptionLabel({ label: desc, wrap: true, lines: 2,
ellipsize: Pango.EllipsizeMode.END, ellipsize: Pango.EllipsizeMode.END,
xalign: 0, yalign: 0 }); xalign: 0, yalign: 0 });
vbox.add(label); vbox.add(label);
let button = new Gtk.Button({ valign: Gtk.Align.CENTER, let button = new Gtk.Button({ valign: Gtk.Align.CENTER,
visible: this.hasPrefs,
no_show_all: true }); no_show_all: true });
button.set_image(new Gtk.Image({ icon_name: 'emblem-system-symbolic', button.set_image(new Gtk.Image({ icon_name: 'emblem-system-symbolic',
icon_size: Gtk.IconSize.BUTTON, icon_size: Gtk.IconSize.BUTTON,
@ -646,37 +559,51 @@ class ExtensionRow extends Gtk.ListBoxRow {
this.prefsButton = button; this.prefsButton = button;
this._switch = new Gtk.Switch({ this._switch = new Gtk.Switch({ valign: Gtk.Align.CENTER,
valign: Gtk.Align.CENTER, sensitive: this._canEnable(),
sensitive: this._canToggle(), state: this._isEnabled() });
state: this._extension.state === ExtensionState.ENABLED this._switch.connect('notify::active', () => {
});
this._notifyActiveId = this._switch.connect('notify::active', () => {
if (this._switch.active) if (this._switch.active)
this._app.shellProxy.EnableExtensionRemote(this.uuid); this._enable();
else else
this._app.shellProxy.DisableExtensionRemote(this.uuid); this._disable();
}); });
this._switch.connect('state-set', () => true); this._switch.connect('state-set', () => true);
hbox.add(this._switch); hbox.add(this._switch);
} }
_canToggle() { _canEnable() {
return this._extension.canChange; let extension = ExtensionUtils.extensions[this.uuid];
let checkVersion = !this._settings.get_boolean('disable-extension-version-validation');
return !this._settings.get_boolean('disable-user-extensions') &&
!(checkVersion && ExtensionUtils.isOutOfDate(extension));
} }
get prefsModule() { _isEnabled() {
if (!this._prefsModule) { let extensions = this._settings.get_strv('enabled-extensions');
ExtensionUtils.installImporter(this._extension); return extensions.indexOf(this.uuid) != -1;
}
// give extension prefs access to their own extension object _enable() {
ExtensionUtils.getCurrentExtension = () => this._extension; let extensions = this._settings.get_strv('enabled-extensions');
if (extensions.indexOf(this.uuid) != -1)
return;
this._prefsModule = this._extension.imports.prefs; extensions.push(this.uuid);
this._prefsModule.init(this._extension.metadata); this._settings.set_strv('enabled-extensions', extensions);
} }
return this._prefsModule; _disable() {
let extensions = this._settings.get_strv('enabled-extensions');
let pos = extensions.indexOf(this.uuid);
if (pos == -1)
return;
do {
extensions.splice(pos, 1);
pos = extensions.indexOf(this.uuid);
} while (pos != -1);
this._settings.set_strv('enabled-extensions', extensions);
} }
}); });
@ -684,12 +611,12 @@ function initEnvironment() {
// Monkey-patch in a "global" object that fakes some Shell utilities // Monkey-patch in a "global" object that fakes some Shell utilities
// that ExtensionUtils depends on. // that ExtensionUtils depends on.
window.global = { window.global = {
log(...args) { log() {
print(args.join(', ')); print([].join.call(arguments, ', '));
}, },
logError(s) { logError(s) {
log(`ERROR: ${s}`); log('ERROR: ' + s);
}, },
userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell']) userdatadir: GLib.build_filenamev([GLib.get_user_data_dir(), 'gnome-shell'])
@ -704,5 +631,6 @@ function main(argv) {
Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR); Gettext.bindtextdomain(Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
Gettext.textdomain(Config.GETTEXT_PACKAGE); Gettext.textdomain(Config.GETTEXT_PACKAGE);
new Application().run(argv); let app = new Application();
app.application.run(argv);
} }

View File

@ -8,13 +8,14 @@ const Batch = imports.gdm.batch;
const GdmUtil = imports.gdm.util; const GdmUtil = imports.gdm.util;
const Params = imports.misc.params; const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry; const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget; const UserWidget = imports.ui.userWidget;
var DEFAULT_BUTTON_WELL_ICON_SIZE = 16; var DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000; var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300; var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3;
var MESSAGE_FADE_OUT_ANIMATION_TIME = 500; var MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5;
var AuthPromptMode = { var AuthPromptMode = {
UNLOCK_ONLY: 0, UNLOCK_ONLY: 0,
@ -58,23 +59,23 @@ var AuthPrompt = class {
this.smartcardDetected = this._userVerifier.smartcardDetected; this.smartcardDetected = this._userVerifier.smartcardDetected;
this.connect('next', () => { this.connect('next', () => {
this.updateSensitivity(false); this.updateSensitivity(false);
this.startSpinning(); this.startSpinning();
if (this._queryingService) { if (this._queryingService) {
this._userVerifier.answerQuery(this._queryingService, this._entry.text); this._userVerifier.answerQuery(this._queryingService, this._entry.text);
} else { } else {
this._preemptiveAnswer = this._entry.text; this._preemptiveAnswer = this._entry.text;
} }
}); });
this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout', this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
vertical: true }); vertical: true });
this.actor.connect('destroy', this._onDestroy.bind(this)); this.actor.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('key-press-event', (actor, event) => { this.actor.connect('key-press-event', (actor, event) => {
if (event.get_key_symbol() == Clutter.KEY_Escape) if (event.get_key_symbol() == Clutter.KEY_Escape)
this.cancel(); this.cancel();
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
}); });
this._userWell = new St.Bin({ x_fill: true, this._userWell = new St.Bin({ x_fill: true,
x_align: St.Align.START }); x_align: St.Align.START });
@ -111,7 +112,7 @@ var AuthPrompt = class {
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
vertical: false }); vertical: false });
this.actor.add(this._buttonBox, this.actor.add(this._buttonBox,
{ expand: true, { expand: true,
x_align: St.Align.MIDDLE, x_align: St.Align.MIDDLE,
y_align: St.Align.END }); y_align: St.Align.END });
@ -137,7 +138,7 @@ var AuthPrompt = class {
reactive: true, reactive: true,
can_focus: true, can_focus: true,
label: _("Cancel") }); label: _("Cancel") });
this.cancelButton.connect('clicked', () => this.cancel()); this.cancelButton.connect('clicked', () => { this.cancel(); });
this._buttonBox.add(this.cancelButton, this._buttonBox.add(this.cancelButton,
{ expand: false, { expand: false,
x_fill: false, x_fill: false,
@ -156,7 +157,7 @@ var AuthPrompt = class {
reactive: true, reactive: true,
can_focus: true, can_focus: true,
label: _("Next") }); label: _("Next") });
this.nextButton.connect('clicked', () => this.emit('next')); this.nextButton.connect('clicked', () => { this.emit('next'); });
this.nextButton.add_style_pseudo_class('default'); this.nextButton.add_style_pseudo_class('default');
this._buttonBox.add(this.nextButton, this._buttonBox.add(this.nextButton,
{ expand: false, { expand: false,
@ -266,7 +267,7 @@ var AuthPrompt = class {
let oldActor = this._defaultButtonWellActor; let oldActor = this._defaultButtonWellActor;
if (oldActor) if (oldActor)
oldActor.remove_all_transitions(); Tweener.removeTweens(oldActor);
let wasSpinner; let wasSpinner;
if (oldActor == this._spinner.actor) if (oldActor == this._spinner.actor)
@ -289,18 +290,19 @@ var AuthPrompt = class {
this._spinner.stop(); this._spinner.stop();
} }
} else { } else {
oldActor.ease({ Tweener.addTween(oldActor,
opacity: 0, { opacity: 0,
duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME, time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
mode: Clutter.AnimationMode.LINEAR, transition: 'linear',
onComplete: () => { onCompleteScope: this,
if (wasSpinner) { onComplete() {
if (this._spinner) if (wasSpinner) {
this._spinner.stop(); if (this._spinner)
} this._spinner.stop();
} }
}); }
});
} }
} }
@ -311,12 +313,11 @@ var AuthPrompt = class {
if (!animate) if (!animate)
actor.opacity = 255; actor.opacity = 255;
else else
actor.ease({ Tweener.addTween(actor,
opacity: 255, { opacity: 255,
duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME, time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY, delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
mode: Clutter.AnimationMode.LINEAR transition: 'linear' });
});
} }
this._defaultButtonWellActor = actor; this._defaultButtonWellActor = actor;
@ -365,12 +366,12 @@ var AuthPrompt = class {
_fadeOutMessage() { _fadeOutMessage() {
if (this._message.opacity == 0) if (this._message.opacity == 0)
return; return;
this._message.remove_all_transitions(); Tweener.removeTweens(this._message);
this._message.ease({ Tweener.addTween(this._message,
opacity: 0, { opacity: 0,
duration: MESSAGE_FADE_OUT_ANIMATION_TIME, time: MESSAGE_FADE_OUT_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad'
}); });
} }
setMessage(message, type) { setMessage(message, type) {
@ -385,7 +386,7 @@ var AuthPrompt = class {
this._message.remove_style_class_name('login-dialog-message-hint'); this._message.remove_style_class_name('login-dialog-message-hint');
if (message) { if (message) {
this._message.remove_all_transitions(); Tweener.removeTweens(this._message);
this._message.text = message; this._message.text = message;
this._message.opacity = 255; this._message.opacity = 255;
} else { } else {

View File

@ -20,7 +20,7 @@
* In order for transformation animations to look good, they need to be * In order for transformation animations to look good, they need to be
* incremental and have some order to them (e.g., fade out hidden items, * incremental and have some order to them (e.g., fade out hidden items,
* then shrink to close the void left over). Chaining animations in this way can * then shrink to close the void left over). Chaining animations in this way can
* be error-prone and wordy using just ease() callbacks. * be error-prone and wordy using just Tweener callbacks.
* *
* The classes in this file help with this: * The classes in this file help with this:
* *
@ -44,7 +44,6 @@
* replaced by something else. * replaced by something else.
*/ */
const { GObject } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
var Task = class { var Task = class {
@ -125,7 +124,7 @@ var Batch = class extends Task {
} }
process() { process() {
throw new GObject.NotImplementedError(`process in ${this.constructor.name}`); throw new Error('Not implemented');
} }
runTask() { runTask() {
@ -177,35 +176,36 @@ Signals.addSignalMethods(Batch.prototype);
var ConcurrentBatch = class extends Batch { var ConcurrentBatch = class extends Batch {
process() { process() {
let hold = this.runTask(); let hold = this.runTask();
if (hold) { if (hold) {
this.hold.acquireUntilAfter(hold); this.hold.acquireUntilAfter(hold);
} }
// Regardless of the state of the just run task, // Regardless of the state of the just run task,
// fire off the next one, so all the tasks can run // fire off the next one, so all the tasks can run
// concurrently. // concurrently.
this.nextTask(); this.nextTask();
} }
}; };
Signals.addSignalMethods(ConcurrentBatch.prototype); Signals.addSignalMethods(ConcurrentBatch.prototype);
var ConsecutiveBatch = class extends Batch { var ConsecutiveBatch = class extends Batch {
process() { process() {
let hold = this.runTask(); let hold = this.runTask();
if (hold && hold.isAcquired()) { if (hold && hold.isAcquired()) {
// This task is inhibiting the batch. Wait on it // This task is inhibiting the batch. Wait on it
// before processing the next one. // before processing the next one.
let signalId = hold.connect('release', () => { let signalId = hold.connect('release', () => {
hold.disconnect(signalId); hold.disconnect(signalId);
this.nextTask(); this.nextTask();
}); });
} else { return;
// This task finished, process the next one } else {
this.nextTask(); // This task finished, process the next one
} this.nextTask();
}
} }
}; };
Signals.addSignalMethods(ConsecutiveBatch.prototype); Signals.addSignalMethods(ConsecutiveBatch.prototype);

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported FprintManager */
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
@ -24,8 +23,8 @@ function FprintManager() {
try { try {
self.init(null); self.init(null);
} catch (e) { } catch(e) {
log(`Failed to connect to Fprint service: ${e.message}`); log('Failed to connect to Fprint service: ' + e.message);
return null; return null;
} }

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported LoginDialog */
/* /*
* Copyright 2011 Red Hat, Inc * Copyright 2011 Red Hat, Inc
* *
@ -31,10 +30,11 @@ const LoginManager = imports.misc.loginManager;
const Main = imports.ui.main; const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const Realmd = imports.gdm.realmd; const Realmd = imports.gdm.realmd;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget; const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 250; const _FADE_ANIMATION_TIME = 0.25;
const _SCROLL_ANIMATION_TIME = 500; const _SCROLL_ANIMATION_TIME = 0.5;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0; const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 48; const _LOGO_ICON_HEIGHT = 48;
const _MAX_BOTTOM_MENU_ITEMS = 5; const _MAX_BOTTOM_MENU_ITEMS = 5;
@ -43,7 +43,7 @@ var UserListItem = class {
constructor(user) { constructor(user) {
this.user = user; this.user = user;
this._userChangedId = this.user.connect('changed', this._userChangedId = this.user.connect('changed',
this._onUserChanged.bind(this)); this._onUserChanged.bind(this));
let layout = new St.BoxLayout({ vertical: true }); let layout = new St.BoxLayout({ vertical: true });
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item', this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
@ -150,7 +150,7 @@ Signals.addSignalMethods(UserListItem.prototype);
var UserList = class { var UserList = class {
constructor() { constructor() {
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view' }); this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
this.actor.set_policy(St.PolicyType.NEVER, this.actor.set_policy(St.PolicyType.NEVER,
St.PolicyType.AUTOMATIC); St.PolicyType.AUTOMATIC);
@ -187,6 +187,8 @@ var UserList = class {
} }
updateStyle(isExpanded) { updateStyle(isExpanded) {
let tasks = [];
if (isExpanded) if (isExpanded)
this._box.add_style_pseudo_class('expanded'); this._box.add_style_pseudo_class('expanded');
else else
@ -204,10 +206,11 @@ var UserList = class {
let adjustment = this.actor.get_vscroll_bar().get_adjustment(); let adjustment = this.actor.get_vscroll_bar().get_adjustment();
let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0); let value = (box.y1 + adjustment.step_increment / 2.0) - (adjustment.page_size / 2.0);
adjustment.ease(value, { Tweener.removeTweens(adjustment);
mode: Clutter.AnimationMode.EASE_OUT_QUAD, Tweener.addTween (adjustment,
duration: _SCROLL_ANIMATION_TIME { value: value,
}); time: _SCROLL_ANIMATION_TIME,
transition: 'easeOutQuad' });
} }
jumpToItem(item) { jumpToItem(item) {
@ -241,7 +244,7 @@ var UserList = class {
return; return;
if (user.locked) if (user.locked)
return; return;
let userName = user.get_user_name(); let userName = user.get_user_name();
@ -258,7 +261,7 @@ var UserList = class {
item.connect('activate', this._onItemActivated.bind(this)); item.connect('activate', this._onItemActivated.bind(this));
// Try to keep the focused item front-and-center // Try to keep the focused item front-and-center
item.actor.connect('key-focus-in', () => this.scrollToItem(item)); item.actor.connect('key-focus-in', () => { this.scrollToItem(item); });
this._moveFocusToItems(); this._moveFocusToItems();
@ -316,17 +319,17 @@ var SessionMenuButton = class {
this._menu.actor.hide(); this._menu.actor.hide();
this._menu.connect('open-state-changed', (menu, isOpen) => { this._menu.connect('open-state-changed', (menu, isOpen) => {
if (isOpen) if (isOpen)
this._button.add_style_pseudo_class('active'); this._button.add_style_pseudo_class('active');
else else
this._button.remove_style_pseudo_class('active'); this._button.remove_style_pseudo_class('active');
}); });
this._manager = new PopupMenu.PopupMenuManager(this._button, this._manager = new PopupMenu.PopupMenuManager({ actor: this._button },
{ actionMode: Shell.ActionMode.NONE }); { actionMode: Shell.ActionMode.NONE });
this._manager.addMenu(this._menu); this._manager.addMenu(this._menu);
this._button.connect('clicked', () => this._menu.toggle()); this._button.connect('clicked', () => { this._menu.toggle(); });
this._items = {}; this._items = {};
this._activeSessionId = null; this._activeSessionId = null;
@ -350,11 +353,11 @@ var SessionMenuButton = class {
} }
setActiveSession(sessionId) { setActiveSession(sessionId) {
if (sessionId == this._activeSessionId) if (sessionId == this._activeSessionId)
return; return;
this._activeSessionId = sessionId; this._activeSessionId = sessionId;
this._updateOrnament(); this._updateOrnament();
} }
close() { close() {
@ -371,7 +374,7 @@ var SessionMenuButton = class {
} }
for (let i = 0; i < ids.length; i++) { for (let i = 0; i < ids.length; i++) {
let [sessionName, sessionDescription_] = Gdm.get_session_name_and_description(ids[i]); let [sessionName, sessionDescription] = Gdm.get_session_name_and_description(ids[i]);
let id = ids[i]; let id = ids[i];
let item = new PopupMenu.PopupMenuItem(sessionName); let item = new PopupMenu.PopupMenuItem(sessionName);
@ -400,18 +403,18 @@ var LoginDialog = GObject.registerClass({
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
parentActor.add_child(this); parentActor.add_child(this);
this._userManager = AccountsService.UserManager.get_default(); this._userManager = AccountsService.UserManager.get_default()
this._gdmClient = new Gdm.Client(); this._gdmClient = new Gdm.Client();
this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA }); this._settings = new Gio.Settings({ schema_id: GdmUtil.LOGIN_SCREEN_SCHEMA });
this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_KEY}`, this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_KEY,
this._updateBanner.bind(this)); this._updateBanner.bind(this));
this._settings.connect(`changed::${GdmUtil.BANNER_MESSAGE_TEXT_KEY}`, this._settings.connect('changed::' + GdmUtil.BANNER_MESSAGE_TEXT_KEY,
this._updateBanner.bind(this)); this._updateBanner.bind(this));
this._settings.connect(`changed::${GdmUtil.DISABLE_USER_LIST_KEY}`, this._settings.connect('changed::' + GdmUtil.DISABLE_USER_LIST_KEY,
this._updateDisableUserList.bind(this)); this._updateDisableUserList.bind(this));
this._settings.connect(`changed::${GdmUtil.LOGO_KEY}`, this._settings.connect('changed::' + GdmUtil.LOGO_KEY,
this._updateLogo.bind(this)); this._updateLogo.bind(this));
this._textureCache = St.TextureCache.get_default(); this._textureCache = St.TextureCache.get_default();
@ -517,7 +520,7 @@ var LoginDialog = GObject.registerClass({
_getBannerAllocation(dialogBox) { _getBannerAllocation(dialogBox) {
let actorBox = new Clutter.ActorBox(); let actorBox = new Clutter.ActorBox();
let [, , natWidth, natHeight] = this._bannerView.get_preferred_size(); let [minWidth, minHeight, natWidth, natHeight] = this._bannerView.get_preferred_size();
let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2; let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
actorBox.x1 = Math.floor(centerX - natWidth / 2); actorBox.x1 = Math.floor(centerX - natWidth / 2);
@ -531,7 +534,7 @@ var LoginDialog = GObject.registerClass({
_getLogoBinAllocation(dialogBox) { _getLogoBinAllocation(dialogBox) {
let actorBox = new Clutter.ActorBox(); let actorBox = new Clutter.ActorBox();
let [, , natWidth, natHeight] = this._logoBin.get_preferred_size(); let [minWidth, minHeight, natWidth, natHeight] = this._logoBin.get_preferred_size();
let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2; let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
actorBox.x1 = Math.floor(centerX - natWidth / 2); actorBox.x1 = Math.floor(centerX - natWidth / 2);
@ -545,7 +548,7 @@ var LoginDialog = GObject.registerClass({
_getCenterActorAllocation(dialogBox, actor) { _getCenterActorAllocation(dialogBox, actor) {
let actorBox = new Clutter.ActorBox(); let actorBox = new Clutter.ActorBox();
let [, , natWidth, natHeight] = actor.get_preferred_size(); let [minWidth, minHeight, natWidth, natHeight] = actor.get_preferred_size();
let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2; let centerX = dialogBox.x1 + (dialogBox.x2 - dialogBox.x1) / 2;
let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2; let centerY = dialogBox.y1 + (dialogBox.y2 - dialogBox.y1) / 2;
@ -572,15 +575,19 @@ var LoginDialog = GObject.registerClass({
// First find out what space the children require // First find out what space the children require
let bannerAllocation = null; let bannerAllocation = null;
let bannerHeight = 0; let bannerHeight = 0;
let bannerWidth = 0;
if (this._bannerView.visible) { if (this._bannerView.visible) {
bannerAllocation = this._getBannerAllocation(dialogBox, this._bannerView); bannerAllocation = this._getBannerAllocation(dialogBox, this._bannerView);
bannerHeight = bannerAllocation.y2 - bannerAllocation.y1; bannerHeight = bannerAllocation.y2 - bannerAllocation.y1;
bannerWidth = bannerAllocation.x2 - bannerAllocation.x1;
} }
let authPromptAllocation = null; let authPromptAllocation = null;
let authPromptHeight = 0;
let authPromptWidth = 0; let authPromptWidth = 0;
if (this._authPrompt.actor.visible) { if (this._authPrompt.actor.visible) {
authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor); authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor);
authPromptHeight = authPromptAllocation.y2 - authPromptAllocation.y1;
authPromptWidth = authPromptAllocation.x2 - authPromptAllocation.x1; authPromptWidth = authPromptAllocation.x2 - authPromptAllocation.x1;
} }
@ -612,64 +619,64 @@ var LoginDialog = GObject.registerClass({
let leftOverYSpace = bannerSpace - bannerHeight; let leftOverYSpace = bannerSpace - bannerHeight;
if (leftOverYSpace > 0) { if (leftOverYSpace > 0) {
// First figure out how much left over space is up top // First figure out how much left over space is up top
let leftOverTopSpace = leftOverYSpace / 2; let leftOverTopSpace = leftOverYSpace / 2;
// Then, shift the banner into the middle of that extra space // Then, shift the banner into the middle of that extra space
let yShift = Math.floor(leftOverTopSpace / 2); let yShift = Math.floor(leftOverTopSpace / 2);
bannerAllocation.y1 += yShift; bannerAllocation.y1 += yShift;
bannerAllocation.y2 += yShift; bannerAllocation.y2 += yShift;
} else { } else {
// Then figure out how much space there would be if we switched to a // Then figure out how much space there would be if we switched to a
// wide layout with banner on one side and authprompt on the other. // wide layout with banner on one side and authprompt on the other.
let leftOverXSpace = dialogWidth - authPromptWidth; let leftOverXSpace = dialogWidth - authPromptWidth;
// In a wide view, half of the available space goes to the banner, // In a wide view, half of the available space goes to the banner,
// and the other half goes to the margins. // and the other half goes to the margins.
let wideBannerWidth = leftOverXSpace / 2; let wideBannerWidth = leftOverXSpace / 2;
let wideSpacing = leftOverXSpace - wideBannerWidth; let wideSpacing = leftOverXSpace - wideBannerWidth;
// If we do go with a wide layout, we need there to be at least enough // If we do go with a wide layout, we need there to be at least enough
// space for the banner and the auth prompt to be the same width, // space for the banner and the auth prompt to be the same width,
// so it doesn't look unbalanced. // so it doesn't look unbalanced.
if (authPromptWidth > 0 && wideBannerWidth > authPromptWidth) { if (authPromptWidth > 0 && wideBannerWidth > authPromptWidth) {
let centerX = dialogBox.x1 + dialogWidth / 2; let centerX = dialogBox.x1 + dialogWidth / 2;
let centerY = dialogBox.y1 + dialogHeight / 2; let centerY = dialogBox.y1 + dialogHeight / 2;
// A small portion of the spacing goes down the center of the // A small portion of the spacing goes down the center of the
// screen to help delimit the two columns of the wide view // screen to help delimit the two columns of the wide view
let centerGap = wideSpacing / 8; let centerGap = wideSpacing / 8;
// place the banner along the left edge of the center margin // place the banner along the left edge of the center margin
bannerAllocation.x2 = Math.floor(centerX - centerGap / 2); bannerAllocation.x2 = Math.floor(centerX - centerGap / 2);
bannerAllocation.x1 = Math.floor(bannerAllocation.x2 - wideBannerWidth); bannerAllocation.x1 = Math.floor(bannerAllocation.x2 - wideBannerWidth);
// figure out how tall it would like to be and try to accommodate // figure out how tall it would like to be and try to accomodate
// but don't let it get too close to the logo // but don't let it get too close to the logo
let [, wideBannerHeight] = this._bannerView.get_preferred_height(wideBannerWidth); let [wideMinHeight, wideBannerHeight] = this._bannerView.get_preferred_height(wideBannerWidth);
let maxWideHeight = dialogHeight - 3 * logoHeight; let maxWideHeight = dialogHeight - 3 * logoHeight;
wideBannerHeight = Math.min(maxWideHeight, wideBannerHeight); wideBannerHeight = Math.min(maxWideHeight, wideBannerHeight);
bannerAllocation.y1 = Math.floor(centerY - wideBannerHeight / 2); bannerAllocation.y1 = Math.floor(centerY - wideBannerHeight / 2);
bannerAllocation.y2 = bannerAllocation.y1 + wideBannerHeight; bannerAllocation.y2 = bannerAllocation.y1 + wideBannerHeight;
// place the auth prompt along the right edge of the center margin // place the auth prompt along the right edge of the center margin
authPromptAllocation.x1 = Math.floor(centerX + centerGap / 2); authPromptAllocation.x1 = Math.floor(centerX + centerGap / 2);
authPromptAllocation.x2 = authPromptAllocation.x1 + authPromptWidth; authPromptAllocation.x2 = authPromptAllocation.x1 + authPromptWidth;
} else { } else {
// If we aren't going to do a wide view, then we need to limit // If we aren't going to do a wide view, then we need to limit
// the height of the banner so it will present scrollbars // the height of the banner so it will present scrollbars
// First figure out how much space there is without the banner // First figure out how much space there is without the banner
leftOverYSpace += bannerHeight; leftOverYSpace += bannerHeight;
// Then figure out how much of that space is up top // Then figure out how much of that space is up top
let availableTopSpace = Math.floor(leftOverYSpace / 2); let availableTopSpace = Math.floor(leftOverYSpace / 2);
// Then give all of that space to the banner // Then give all of that space to the banner
bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace; bannerAllocation.y2 = bannerAllocation.y1 + availableTopSpace;
} }
} }
} else if (userSelectionAllocation) { } else if (userSelectionAllocation) {
// Grow the user list to fill the space // Grow the user list to fill the space
@ -757,15 +764,14 @@ var LoginDialog = GObject.registerClass({
_fadeInBannerView() { _fadeInBannerView() {
this._bannerView.show(); this._bannerView.show();
this._bannerView.ease({ Tweener.addTween(this._bannerView,
opacity: 255, { opacity: 255,
duration: _FADE_ANIMATION_TIME, time: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad' });
});
} }
_hideBannerView() { _hideBannerView() {
this._bannerView.remove_all_transitions(); Tweener.removeTweens(this._bannerView);
this._bannerView.opacity = 0; this._bannerView.opacity = 0;
this._bannerView.hide(); this._bannerView.hide();
} }
@ -845,10 +851,10 @@ var LoginDialog = GObject.registerClass({
_shouldShowSessionMenuButton() { _shouldShowSessionMenuButton() {
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING && if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFYING &&
this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_FAILED) this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.VERIFICATION_FAILED)
return false; return false;
if (this._user && this._user.is_loaded && this._user.is_logged_in()) if (this._user && this._user.is_loaded && this._user.is_logged_in())
return false; return false;
return true; return true;
} }
@ -858,11 +864,10 @@ var LoginDialog = GObject.registerClass({
return; return;
this._authPrompt.actor.opacity = 0; this._authPrompt.actor.opacity = 0;
this._authPrompt.actor.show(); this._authPrompt.actor.show();
this._authPrompt.actor.ease({ Tweener.addTween(this._authPrompt.actor,
opacity: 255, { opacity: 255,
duration: _FADE_ANIMATION_TIME, time: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad' });
});
this._fadeInBannerView(); this._fadeInBannerView();
} }
@ -906,31 +911,28 @@ var LoginDialog = GObject.registerClass({
this._showPrompt(); this._showPrompt();
} }
_bindOpacity() {
this._bindings = Main.layoutManager.uiGroup.get_children()
.filter(c => c != Main.layoutManager.screenShieldGroup)
.map(c => this.bind_property('opacity', c, 'opacity', 0));
}
_unbindOpacity() {
this._bindings.forEach(b => b.unbind());
}
_loginScreenSessionActivated() { _loginScreenSessionActivated() {
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING) if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
return; return;
this._bindOpacity(); Tweener.addTween(this,
this.ease({ { opacity: 255,
opacity: 255, time: _FADE_ANIMATION_TIME,
duration: _FADE_ANIMATION_TIME, transition: 'easeOutQuad',
mode: Clutter.AnimationMode.EASE_OUT_QUAD, onUpdate() {
onComplete: () => { let children = Main.layoutManager.uiGroup.get_children();
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset(); for (let i = 0; i < children.length; i++) {
this._unbindOpacity(); if (children[i] != Main.layoutManager.screenShieldGroup)
} children[i].opacity = this.opacity;
}); }
},
onUpdateScope: this,
onComplete() {
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset();
},
onCompleteScope: this });
} }
_gotGreeterSessionProxy(proxy) { _gotGreeterSessionProxy(proxy) {
@ -943,27 +945,34 @@ var LoginDialog = GObject.registerClass({
} }
_startSession(serviceName) { _startSession(serviceName) {
this._bindOpacity(); Tweener.addTween(this,
this.ease({ { opacity: 0,
opacity: 0, time: _FADE_ANIMATION_TIME,
duration: _FADE_ANIMATION_TIME, transition: 'easeOutQuad',
mode: Clutter.AnimationMode.EASE_OUT_QUAD, onUpdate() {
onComplete: () => { let children = Main.layoutManager.uiGroup.get_children();
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
this._unbindOpacity(); for (let i = 0; i < children.length; i++) {
} if (children[i] != Main.layoutManager.screenShieldGroup)
}); children[i].opacity = this.opacity;
}
},
onUpdateScope: this,
onComplete() {
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
},
onCompleteScope: this });
} }
_onSessionOpened(client, serviceName) { _onSessionOpened(client, serviceName) {
this._authPrompt.finish(() => this._startSession(serviceName)); this._authPrompt.finish(() => { this._startSession(serviceName); });
} }
_waitForItemForUser(userName) { _waitForItemForUser(userName) {
let item = this._userList.getItemFromUserName(userName); let item = this._userList.getItemFromUserName(userName);
if (item) if (item)
return null; return null;
let hold = new Batch.Hold(); let hold = new Batch.Hold();
let signalId = this._userList.connect('item-added', let signalId = this._userList.connect('item-added',
@ -974,7 +983,7 @@ var LoginDialog = GObject.registerClass({
hold.release(); hold.release();
}); });
hold.connect('release', () => this._userList.disconnect(signalId)); hold.connect('release', () => { this._userList.disconnect(signalId); });
return hold; return hold;
} }
@ -1038,7 +1047,6 @@ var LoginDialog = GObject.registerClass({
return this._blockTimedLoginUntilIdle(); return this._blockTimedLoginUntilIdle();
} else { } else {
animationTime = delay; animationTime = delay;
return null;
} }
}, },
@ -1074,12 +1082,12 @@ var LoginDialog = GObject.registerClass({
// Restart timed login on user interaction // Restart timed login on user interaction
global.stage.connect('captured-event', (actor, event) => { global.stage.connect('captured-event', (actor, event) => {
if (event.type() == Clutter.EventType.KEY_PRESS || if (event.type() == Clutter.EventType.KEY_PRESS ||
event.type() == Clutter.EventType.BUTTON_PRESS) { event.type() == Clutter.EventType.BUTTON_PRESS) {
this._startTimedLogin(userName, seconds); this._startTimedLogin(userName, seconds);
} }
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
}); });
} }
@ -1225,11 +1233,10 @@ var LoginDialog = GObject.registerClass({
Main.pushModal(this, { actionMode: Shell.ActionMode.LOGIN_SCREEN }); Main.pushModal(this, { actionMode: Shell.ActionMode.LOGIN_SCREEN });
this.ease({ Tweener.addTween(this,
opacity: 255, { opacity: 255,
duration: 1000, time: 1,
mode: Clutter.AnimationMode.EASE_IN_QUAD transition: 'easeInQuad' });
});
return true; return true;
} }
@ -1243,7 +1250,7 @@ var LoginDialog = GObject.registerClass({
this._authPrompt.cancel(); this._authPrompt.cancel();
} }
addCharacter(_unichar) { addCharacter(unichar) {
// Don't allow type ahead at the login screen // Don't allow type ahead at the login screen
} }

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getOVirtCredentialsManager */
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Signals = imports.signals; const Signals = imports.signals;

View File

@ -15,13 +15,12 @@ const RealmIface = loadInterfaceXML("org.freedesktop.realmd.Realm");
const Realm = Gio.DBusProxy.makeProxyWrapper(RealmIface); const Realm = Gio.DBusProxy.makeProxyWrapper(RealmIface);
var Manager = class { var Manager = class {
constructor() { constructor(parentActor) {
this._aggregateProvider = Provider(Gio.DBus.system, this._aggregateProvider = Provider(Gio.DBus.system,
'org.freedesktop.realmd', 'org.freedesktop.realmd',
'/org/freedesktop/realmd', '/org/freedesktop/realmd',
this._reloadRealms.bind(this)); this._reloadRealms.bind(this))
this._realms = {}; this._realms = {};
this._loginFormat = null;
this._signalId = this._aggregateProvider.connect('g-properties-changed', this._signalId = this._aggregateProvider.connect('g-properties-changed',
(proxy, properties) => { (proxy, properties) => {
@ -37,10 +36,10 @@ var Manager = class {
return; return;
for (let i = 0; i < realmPaths.length; i++) { for (let i = 0; i < realmPaths.length; i++) {
Realm(Gio.DBus.system, let realm = Realm(Gio.DBus.system,
'org.freedesktop.realmd', 'org.freedesktop.realmd',
realmPaths[i], realmPaths[i],
this._onRealmLoaded.bind(this)); this._onRealmLoaded.bind(this));
} }
} }
@ -87,7 +86,7 @@ var Manager = class {
} }
get loginFormat() { get loginFormat() {
if (this._loginFormat) if (this._loginFormat !== undefined)
return this._loginFormat; return this._loginFormat;
this._updateLoginFormat(); this._updateLoginFormat();
@ -99,10 +98,10 @@ var Manager = class {
Service(Gio.DBus.system, Service(Gio.DBus.system,
'org.freedesktop.realmd', 'org.freedesktop.realmd',
'/org/freedesktop/realmd', '/org/freedesktop/realmd',
service => service.ReleaseRemote()); service => { service.ReleaseRemote(); });
this._aggregateProvider.disconnect(this._signalId); this._aggregateProvider.disconnect(this._signalId);
this._realms = { }; this._realms = { };
this._updateLoginFormat(); this._updateLoginFormat();
} }
}; };
Signals.addSignalMethods(Manager.prototype); Signals.addSignalMethods(Manager.prototype)

View File

@ -1,6 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported BANNER_MESSAGE_KEY, BANNER_MESSAGE_TEXT_KEY, LOGO_KEY,
DISABLE_USER_LIST_KEY, fadeInActor, fadeOutActor, cloneAndFadeOutActor */
const { Clutter, Gio, GLib } = imports.gi; const { Clutter, Gio, GLib } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
@ -11,13 +9,14 @@ const OVirt = imports.gdm.oVirt;
const Main = imports.ui.main; const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const SmartcardManager = imports.misc.smartcardManager; const SmartcardManager = imports.misc.smartcardManager;
const Tweener = imports.ui.tweener;
var PASSWORD_SERVICE_NAME = 'gdm-password'; var PASSWORD_SERVICE_NAME = 'gdm-password';
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint'; var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard'; var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
var OVIRT_SERVICE_NAME = 'gdm-ovirtcred'; var OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
var FADE_ANIMATION_TIME = 160; var FADE_ANIMATION_TIME = 0.16;
var CLONE_FADE_ANIMATION_TIME = 250; var CLONE_FADE_ANIMATION_TIME = 0.25;
var LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen'; var LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
var PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication'; var PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
@ -31,7 +30,7 @@ var LOGO_KEY = 'logo';
var DISABLE_USER_LIST_KEY = 'disable-user-list'; var DISABLE_USER_LIST_KEY = 'disable-user-list';
// Give user 48ms to read each character of a PAM message // Give user 48ms to read each character of a PAM message
var USER_READ_TIME = 48; var USER_READ_TIME = 48
var MessageType = { var MessageType = {
NONE: 0, NONE: 0,
@ -46,20 +45,20 @@ function fadeInActor(actor) {
let hold = new Batch.Hold(); let hold = new Batch.Hold();
actor.show(); actor.show();
let [, naturalHeight] = actor.get_preferred_height(-1); let [minHeight, naturalHeight] = actor.get_preferred_height(-1);
actor.opacity = 0; actor.opacity = 0;
actor.set_height(0); actor.set_height(0);
actor.ease({ Tweener.addTween(actor,
opacity: 255, { opacity: 255,
height: naturalHeight, height: naturalHeight,
duration: FADE_ANIMATION_TIME, time: FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete() {
this.set_height(-1); this.set_height(-1);
hold.release(); hold.release();
} },
}); });
return hold; return hold;
} }
@ -72,17 +71,17 @@ function fadeOutActor(actor) {
} }
let hold = new Batch.Hold(); let hold = new Batch.Hold();
actor.ease({ Tweener.addTween(actor,
opacity: 0, { opacity: 0,
height: 0, height: 0,
duration: FADE_ANIMATION_TIME, time: FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete() {
this.hide(); this.hide();
this.set_height(-1); this.set_height(-1);
hold.release(); hold.release();
} },
}); });
return hold; return hold;
} }
@ -102,15 +101,15 @@ function cloneAndFadeOutActor(actor) {
clone.set_position(x, y); clone.set_position(x, y);
let hold = new Batch.Hold(); let hold = new Batch.Hold();
clone.ease({ Tweener.addTween(clone,
opacity: 0, { opacity: 0,
duration: CLONE_FADE_ANIMATION_TIME, time: CLONE_FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete() {
clone.destroy(); clone.destroy();
hold.release(); hold.release();
} }
}); });
return hold; return hold;
} }
@ -304,7 +303,7 @@ var ShellUserVerifier = class {
}); });
} }
_oVirtUserAuthenticated(_token) { _oVirtUserAuthenticated(token) {
this._preemptingService = OVIRT_SERVICE_NAME; this._preemptingService = OVIRT_SERVICE_NAME;
this.emit('ovirt-user-authenticated'); this.emit('ovirt-user-authenticated');
} }
@ -343,7 +342,7 @@ var ShellUserVerifier = class {
try { try {
this._clearUserVerifier(); this._clearUserVerifier();
this._userVerifier = client.open_reauthentication_channel_finish(result); this._userVerifier = client.open_reauthentication_channel_finish(result);
} catch (e) { } catch(e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return; return;
if (e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) && if (e.matches(Gio.DBusError, Gio.DBusError.ACCESS_DENIED) &&
@ -370,7 +369,7 @@ var ShellUserVerifier = class {
try { try {
this._clearUserVerifier(); this._clearUserVerifier();
this._userVerifier = client.get_user_verifier_finish(result); this._userVerifier = client.get_user_verifier_finish(result);
} catch (e) { } catch(e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return; return;
this._reportInitError('Failed to obtain user verifier', e); this._reportInitError('Failed to obtain user verifier', e);
@ -424,31 +423,36 @@ var ShellUserVerifier = class {
_startService(serviceName) { _startService(serviceName) {
this._hold.acquire(); this._hold.acquire();
if (this._userName) { if (this._userName) {
this._userVerifier.call_begin_verification_for_user(serviceName, this._userName, this._cancellable, (obj, result) => { this._userVerifier.call_begin_verification_for_user(serviceName,
try { this._userName,
obj.call_begin_verification_for_user_finish(result); this._cancellable,
} catch (e) { (obj, result) => {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) try {
return; obj.call_begin_verification_for_user_finish(result);
this._reportInitError('Failed to start verification for user', e); } catch(e) {
return; if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
} return;
this._reportInitError('Failed to start verification for user', e);
return;
}
this._hold.release(); this._hold.release();
}); });
} else { } else {
this._userVerifier.call_begin_verification(serviceName, this._cancellable, (obj, result) => { this._userVerifier.call_begin_verification(serviceName,
try { this._cancellable,
obj.call_begin_verification_finish(result); (obj, result) => {
} catch (e) { try {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) obj.call_begin_verification_finish(result);
return; } catch(e) {
this._reportInitError('Failed to start verification', e); if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return; return;
} this._reportInitError('Failed to start verification', e);
return;
}
this._hold.release(); this._hold.release();
}); });
} }
} }

View File

@ -64,7 +64,6 @@
<file>ui/keyboard.js</file> <file>ui/keyboard.js</file>
<file>ui/layout.js</file> <file>ui/layout.js</file>
<file>ui/lightbox.js</file> <file>ui/lightbox.js</file>
<file>ui/locatePointer.js</file>
<file>ui/lookingGlass.js</file> <file>ui/lookingGlass.js</file>
<file>ui/magnifier.js</file> <file>ui/magnifier.js</file>
<file>ui/magnifierDBus.js</file> <file>ui/magnifierDBus.js</file>
@ -82,11 +81,9 @@
<file>ui/pageIndicators.js</file> <file>ui/pageIndicators.js</file>
<file>ui/panel.js</file> <file>ui/panel.js</file>
<file>ui/panelMenu.js</file> <file>ui/panelMenu.js</file>
<file>ui/pointerA11yTimeout.js</file>
<file>ui/pointerWatcher.js</file> <file>ui/pointerWatcher.js</file>
<file>ui/popupMenu.js</file> <file>ui/popupMenu.js</file>
<file>ui/remoteSearch.js</file> <file>ui/remoteSearch.js</file>
<file>ui/ripples.js</file>
<file>ui/runDialog.js</file> <file>ui/runDialog.js</file>
<file>ui/screenShield.js</file> <file>ui/screenShield.js</file>
<file>ui/screencast.js</file> <file>ui/screencast.js</file>
@ -123,7 +120,6 @@
<file>ui/status/accessibility.js</file> <file>ui/status/accessibility.js</file>
<file>ui/status/brightness.js</file> <file>ui/status/brightness.js</file>
<file>ui/status/dwellClick.js</file>
<file>ui/status/location.js</file> <file>ui/status/location.js</file>
<file>ui/status/keyboard.js</file> <file>ui/status/keyboard.js</file>
<file>ui/status/nightLight.js</file> <file>ui/status/nightLight.js</file>

View File

@ -1,37 +1,23 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ExtensionState, ExtensionType, getCurrentExtension,
getSettings, initTranslations, isOutOfDate, installImporter,
serializeExtension, deserializeExtension */
// Common utils for the extension system and the extension // Common utils for the extension system and the extension
// preferences tool // preferences tool
const { Gio, GLib } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
const Lang = imports.lang; const Signals = imports.signals;
const Gio = imports.gi.Gio;
const Config = imports.misc.config; const Config = imports.misc.config;
const FileUtils = imports.misc.fileUtils;
var ExtensionType = { var ExtensionType = {
SYSTEM: 1, SYSTEM: 1,
PER_USER: 2 PER_USER: 2
}; };
var ExtensionState = { // Maps uuid -> metadata object
ENABLED: 1, var extensions = {};
DISABLED: 2,
ERROR: 3,
OUT_OF_DATE: 4,
DOWNLOADING: 5,
INITIALIZED: 6,
// Used as an error state for operations on unknown extensions,
// should never be in a real extensionMeta object.
UNINSTALLED: 99
};
const SERIALIZED_PROPERTIES = ['type', 'state', 'path', 'error', 'hasPrefs', 'canChange'];
/** /**
* getCurrentExtension: * getCurrentExtension:
@ -45,7 +31,7 @@ function getCurrentExtension() {
// Search for an occurrence of an extension stack frame // Search for an occurrence of an extension stack frame
// Start at 1 because 0 is the stack frame of this function // Start at 1 because 0 is the stack frame of this function
for (let i = 1; i < stack.length; i++) { for (let i = 1; i < stack.length; i++) {
if (stack[i].includes('/gnome-shell/extensions/')) { if (stack[i].indexOf('/gnome-shell/extensions/') > -1) {
extensionStackLine = stack[i]; extensionStackLine = stack[i];
break; break;
} }
@ -63,17 +49,13 @@ function getCurrentExtension() {
if (!match) if (!match)
return null; return null;
// local import, as the module is used from outside the gnome-shell process
// as well (not this function though)
let extensionManager = imports.ui.main.extensionManager;
let path = match[1]; let path = match[1];
let file = Gio.File.new_for_path(path); let file = Gio.File.new_for_path(path);
// Walk up the directory tree, looking for an extension with // Walk up the directory tree, looking for an extension with
// the same UUID as a directory name. // the same UUID as a directory name.
while (file != null) { while (file != null) {
let extension = extensionManager.lookup(file.get_basename()); let extension = extensions[file.get_basename()];
if (extension !== undefined) if (extension !== undefined)
return extension; return extension;
file = file.get_parent(); file = file.get_parent();
@ -165,8 +147,8 @@ function versionCheck(required, current) {
let requiredArray = required[i].split('.'); let requiredArray = required[i].split('.');
if (requiredArray[0] == major && if (requiredArray[0] == major &&
requiredArray[1] == minor && requiredArray[1] == minor &&
((requiredArray[2] === undefined && parseInt(minor) % 2 == 0) || (requiredArray[2] == point ||
requiredArray[2] == point)) (requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
return true; return true;
} }
return false; return false;
@ -179,50 +161,54 @@ function isOutOfDate(extension) {
return false; return false;
} }
function serializeExtension(extension) { function createExtensionObject(uuid, dir, type) {
let obj = {}; let info;
Lang.copyProperties(extension.metadata, obj);
SERIALIZED_PROPERTIES.forEach(prop => { let metadataFile = dir.get_child('metadata.json');
obj[prop] = extension[prop]; if (!metadataFile.query_exists(null)) {
}); throw new Error('Missing metadata.json');
}
let res = {}; let metadataContents, success, tag;
for (let key in obj) { try {
let val = obj[key]; [success, metadataContents, tag] = metadataFile.load_contents(null);
let type; if (metadataContents instanceof Uint8Array)
switch (typeof val) { metadataContents = imports.byteArray.toString(metadataContents);
case 'string': } catch (e) {
type = 's'; throw new Error('Failed to load metadata.json: ' + e);
break; }
case 'number': let meta;
type = 'd'; try {
break; meta = JSON.parse(metadataContents);
case 'boolean': } catch (e) {
type = 'b'; throw new Error('Failed to parse metadata.json: ' + e);
break; }
default:
continue; let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
for (let i = 0; i < requiredProperties.length; i++) {
let prop = requiredProperties[i];
if (!meta[prop]) {
throw new Error('missing "' + prop + '" property in metadata.json');
} }
res[key] = GLib.Variant.new(type, val);
} }
return res; if (uuid != meta.uuid) {
} throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
function deserializeExtension(variant) {
let res = { metadata: {} };
for (let prop in variant) {
let val = variant[prop].unpack();
if (SERIALIZED_PROPERTIES.includes(prop))
res[prop] = val;
else
res.metadata[prop] = val;
} }
// add the 2 additional properties to create a valid extension object, as createExtensionObject()
res.uuid = res.metadata.uuid; let extension = {};
res.dir = Gio.File.new_for_path(res.path);
return res; extension.metadata = meta;
extension.uuid = meta.uuid;
extension.type = type;
extension.dir = dir;
extension.path = dir.get_path();
extension.error = '';
extension.hasPrefs = dir.get_child('prefs.js').query_exists(null);
extensions[uuid] = extension;
return extension;
} }
function installImporter(extension) { function installImporter(extension) {
@ -233,3 +219,36 @@ function installImporter(extension) {
extension.imports = imports[extension.uuid]; extension.imports = imports[extension.uuid];
imports.searchPath = oldSearchPath; imports.searchPath = oldSearchPath;
} }
var ExtensionFinder = class {
_loadExtension(extensionDir, info, perUserDir) {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
return;
let uuid = info.get_name();
let existing = extensions[uuid];
if (existing) {
log('Extension %s already installed in %s. %s will not be loaded'.format(uuid, existing.path, extensionDir.get_path()));
return;
}
let extension;
let type = extensionDir.has_prefix(perUserDir) ? ExtensionType.PER_USER
: ExtensionType.SYSTEM;
try {
extension = createExtensionObject(uuid, extensionDir, type);
} catch(e) {
logError(e, 'Could not load extension %s'.format(uuid));
return;
}
this.emit('extension-found', extension);
}
scanExtensions() {
let perUserDir = Gio.File.new_for_path(global.userdatadir);
FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
this._loadExtension(dir, info, perUserDir);
});
}
};
Signals.addSignalMethods(ExtensionFinder.prototype);

View File

@ -1,6 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported collectFromDatadirs, deleteGFile, recursivelyDeleteDir,
recursivelyMoveDir, loadInterfaceXML */
const { Gio, GLib } = imports.gi; const { Gio, GLib } = imports.gi;
const Config = imports.misc.config; const Config = imports.misc.config;
@ -38,7 +36,7 @@ function recursivelyDeleteDir(dir, deleteParent) {
let children = dir.enumerate_children('standard::name,standard::type', let children = dir.enumerate_children('standard::name,standard::type',
Gio.FileQueryInfoFlags.NONE, null); Gio.FileQueryInfoFlags.NONE, null);
let info; let info, child;
while ((info = children.next_file(null)) != null) { while ((info = children.next_file(null)) != null) {
let type = info.get_file_type(); let type = info.get_file_type();
let child = dir.get_child(info.get_name()); let child = dir.get_child(info.get_name());
@ -59,7 +57,7 @@ function recursivelyMoveDir(srcDir, destDir) {
if (!destDir.query_exists(null)) if (!destDir.query_exists(null))
destDir.make_directory_with_parents(null); destDir.make_directory_with_parents(null);
let info; let info, child;
while ((info = children.next_file(null)) != null) { while ((info = children.next_file(null)) != null) {
let type = info.get_file_type(); let type = info.get_file_type();
let srcChild = srcDir.get_child(info.get_name()); let srcChild = srcDir.get_child(info.get_name());
@ -86,13 +84,13 @@ function loadInterfaceXML(iface) {
let f = Gio.File.new_for_uri(uri); let f = Gio.File.new_for_uri(uri);
try { try {
let [ok_, bytes] = f.load_contents(null); let [ok, bytes] = f.load_contents(null);
if (bytes instanceof Uint8Array) if (bytes instanceof Uint8Array)
xml = imports.byteArray.toString(bytes); xml = imports.byteArray.toString(bytes)
else else
xml = bytes.toString(); xml = bytes.toString();
} catch (e) { } catch (e) {
log(`Failed to load D-Bus interface ${iface}`); log('Failed to load D-Bus interface ' + iface);
} }
return xml; return xml;

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported PresenceStatus, Presence, Inhibitor, SessionManager */
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;

View File

@ -18,7 +18,7 @@ var HistoryManager = class {
this._historyIndex = 0; this._historyIndex = 0;
if (this._key) { if (this._key) {
this._history = global.settings.get_strv(this._key); this._history = global.settings.get_strv(this._key);
global.settings.connect(`changed::${this._key}`, global.settings.connect('changed::' + this._key,
this._historyChanged.bind(this)); this._historyChanged.bind(this));
} else { } else {
@ -66,7 +66,7 @@ var HistoryManager = class {
this._indexChanged(); this._indexChanged();
} }
return this._historyIndex ? this._history[this._historyIndex - 1] : null; return this._historyIndex ? this._history[this._historyIndex -1] : null;
} }
addItem(input) { addItem(input) {

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getIBusManager */
const { Gio, GLib, IBus } = imports.gi; const { Gio, GLib, IBus } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals; const Signals = imports.signals;
const IBusCandidatePopup = imports.ui.ibusCandidatePopup; const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
@ -18,9 +18,9 @@ function _checkIBusVersion(requiredMajor, requiredMinor, requiredMicro) {
IBus.MICRO_VERSION >= requiredMicro)) IBus.MICRO_VERSION >= requiredMicro))
return; return;
throw "Found IBus version %d.%d.%d but required is %d.%d.%d" throw "Found IBus version %d.%d.%d but required is %d.%d.%d".
.format(IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MINOR_VERSION, format(IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MINOR_VERSION,
requiredMajor, requiredMinor, requiredMicro); requiredMajor, requiredMinor, requiredMicro);
} }
function getIBusManager() { function getIBusManager() {
@ -42,7 +42,7 @@ var IBusManager = class {
this._candidatePopup = new IBusCandidatePopup.CandidatePopup(); this._candidatePopup = new IBusCandidatePopup.CandidatePopup();
this._panelService = null; this._panelService = null;
this._engines = new Map(); this._engines = {};
this._ready = false; this._ready = false;
this._registerPropertiesId = 0; this._registerPropertiesId = 0;
this._currentEngineName = null; this._currentEngineName = null;
@ -58,79 +58,54 @@ var IBusManager = class {
this._spawn(); this._spawn();
} }
_spawn(extraArgs = []) { _spawn() {
try { try {
let cmdLine = ['ibus-daemon', '--panel', 'disable', ...extraArgs]; Gio.Subprocess.new(['ibus-daemon', '--xim', '--panel', 'disable'],
Gio.Subprocess.new(cmdLine, Gio.SubprocessFlags.NONE); Gio.SubprocessFlags.NONE);
} catch (e) { } catch(e) {
log(`Failed to launch ibus-daemon: ${e.message}`); log('Failed to launch ibus-daemon: ' + e.message);
} }
} }
restartDaemon(extraArgs = []) {
this._spawn(['-r', ...extraArgs]);
}
_clear() { _clear() {
if (this._cancellable) {
this._cancellable.cancel();
this._cancellable = null;
}
if (this._preloadEnginesId) {
GLib.source_remove(this._preloadEnginesId);
this._preloadEnginesId = 0;
}
if (this._panelService) if (this._panelService)
this._panelService.destroy(); this._panelService.destroy();
this._panelService = null; this._panelService = null;
this._candidatePopup.setPanelService(null); this._candidatePopup.setPanelService(null);
this._engines.clear(); this._engines = {};
this._ready = false; this._ready = false;
this._registerPropertiesId = 0; this._registerPropertiesId = 0;
this._currentEngineName = null; this._currentEngineName = null;
this.emit('ready', false); this.emit('ready', false);
this._spawn();
} }
_onConnected() { _onConnected() {
this._cancellable = new Gio.Cancellable(); this._ibus.list_engines_async(-1, null, this._initEngines.bind(this));
this._ibus.list_engines_async(-1, this._cancellable,
this._initEngines.bind(this));
this._ibus.request_name_async(IBus.SERVICE_PANEL, this._ibus.request_name_async(IBus.SERVICE_PANEL,
IBus.BusNameFlag.REPLACE_EXISTING, -1, this._cancellable, IBus.BusNameFlag.REPLACE_EXISTING,
this._initPanelService.bind(this)); -1, null,
this._initPanelService.bind(this));
} }
_initEngines(ibus, result) { _initEngines(ibus, result) {
try { let enginesList = this._ibus.list_engines_async_finish(result);
let enginesList = this._ibus.list_engines_async_finish(result); if (enginesList) {
for (let i = 0; i < enginesList.length; ++i) { for (let i = 0; i < enginesList.length; ++i) {
let name = enginesList[i].get_name(); let name = enginesList[i].get_name();
this._engines.set(name, enginesList[i]); this._engines[name] = enginesList[i];
} }
this._updateReadiness(); this._updateReadiness();
} catch (e) { } else {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
logError(e);
this._clear(); this._clear();
} }
} }
_initPanelService(ibus, result) { _initPanelService(ibus, result) {
let success = false; let success = this._ibus.request_name_async_finish(result);
try {
success = !!this._ibus.request_name_async_finish(result);
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
logError(e);
}
if (success) { if (success) {
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(), this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL }); object_path: IBus.PATH_PANEL });
@ -144,7 +119,7 @@ var IBusManager = class {
if (!GLib.str_has_suffix(path, '/InputContext_1')) if (!GLib.str_has_suffix(path, '/InputContext_1'))
this.emit ('focus-in'); this.emit ('focus-in');
}); });
this._panelService.connect('focus-out', () => this.emit('focus-out')); this._panelService.connect('focus-out', () => { this.emit('focus-out'); });
try { try {
// IBus versions older than 1.5.10 have a bug which // IBus versions older than 1.5.10 have a bug which
@ -157,13 +132,13 @@ var IBusManager = class {
} catch (e) { } catch (e) {
} }
// If an engine is already active we need to get its properties // If an engine is already active we need to get its properties
this._ibus.get_global_engine_async(-1, this._cancellable, (_bus, result) => { this._ibus.get_global_engine_async(-1, null, (i, result) => {
let engine; let engine;
try { try {
engine = this._ibus.get_global_engine_async_finish(result); engine = this._ibus.get_global_engine_async_finish(result);
if (!engine) if (!engine)
return; return;
} catch (e) { } catch(e) {
return; return;
} }
this._engineChanged(this._ibus, engine.get_name()); this._engineChanged(this._ibus, engine.get_name());
@ -175,7 +150,8 @@ var IBusManager = class {
} }
_updateReadiness() { _updateReadiness() {
this._ready = this._engines.size > 0 && this._panelService != null; this._ready = (Object.keys(this._engines).length > 0 &&
this._panelService != null);
this.emit('ready', this._ready); this.emit('ready', this._ready);
} }
@ -213,10 +189,10 @@ var IBusManager = class {
} }
getEngineDesc(id) { getEngineDesc(id) {
if (!this._ready || !this._engines.has(id)) if (!this._ready || !this._engines.hasOwnProperty(id))
return null; return null;
return this._engines.get(id); return this._engines[id];
} }
setEngine(id, callback) { setEngine(id, callback) {
@ -229,18 +205,8 @@ var IBusManager = class {
return; return;
} }
this._ibus.set_global_engine_async(id, this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
this._MAX_INPUT_SOURCE_ACTIVATION_TIME, null, callback || null);
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) { preloadEngines(ids) {
@ -248,23 +214,21 @@ var IBusManager = class {
return; return;
if (this._preloadEnginesId != 0) { if (this._preloadEnginesId != 0) {
GLib.source_remove(this._preloadEnginesId); Mainloop.source_remove(this._preloadEnginesId);
this._preloadEnginesId = 0; this._preloadEnginesId = 0;
} }
this._preloadEnginesId = this._preloadEnginesId =
GLib.timeout_add_seconds( Mainloop.timeout_add_seconds(this._PRELOAD_ENGINES_DELAY_TIME,
GLib.PRIORITY_DEFAULT, () => {
this._PRELOAD_ENGINES_DELAY_TIME, this._ibus.preload_engines_async(
() => { ids,
this._ibus.preload_engines_async( -1,
ids, null,
-1, null);
this._cancellable, this._preloadEnginesId = 0;
null); return GLib.SOURCE_REMOVE;
this._preloadEnginesId = 0; });
return GLib.SOURCE_REMOVE;
});
} }
}; };
Signals.addSignalMethods(IBusManager.prototype); Signals.addSignalMethods(IBusManager.prototype);

View File

@ -1,6 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported InputMethod */ const { Clutter, GLib, GObject, IBus } = imports.gi;
const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
const Keyboard = imports.ui.status.keyboard; const Keyboard = imports.ui.status.keyboard;
@ -36,7 +35,15 @@ class InputMethod extends Clutter.InputMethod {
} }
_updateCapabilities() { _updateCapabilities() {
let caps = IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.FOCUS | IBus.Capabilite.SURROUNDING_TEXT; let caps = 0;
if (this.can_show_preedit)
caps |= IBus.Capabilite.PREEDIT_TEXT;
if (this._currentFocus)
caps |= IBus.Capabilite.FOCUS | IBus.Capabilite.SURROUNDING_TEXT;
else
caps |= IBus.Capabilite.PREEDIT_TEXT | IBus.Capabilite.AUXILIARY_TEXT | IBus.Capabilite.LOOKUP_TABLE | IBus.Capabilite.PROPERTY;
if (this._context) if (this._context)
this._context.set_capabilities(caps); this._context.set_capabilities(caps);
@ -47,22 +54,12 @@ class InputMethod extends Clutter.InputMethod {
} }
_onConnected() { _onConnected() {
this._cancellable = new Gio.Cancellable(); this._ibus.create_input_context_async ('gnome-shell', -1, null,
this._ibus.create_input_context_async ('gnome-shell', -1, this._setContext.bind(this));
this._cancellable, this._setContext.bind(this));
} }
_setContext(bus, res) { _setContext(bus, res) {
try { this._context = this._ibus.create_input_context_async_finish(res);
this._context = this._ibus.create_input_context_async_finish(res);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) {
logError(e);
this._clear();
}
return;
}
this._context.connect('commit-text', this._onCommitText.bind(this)); this._context.connect('commit-text', this._onCommitText.bind(this));
this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this)); this._context.connect('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this)); this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this));
@ -74,15 +71,10 @@ class InputMethod extends Clutter.InputMethod {
} }
_clear() { _clear() {
if (this._cancellable) {
this._cancellable.cancel();
this._cancellable = null;
}
this._context = null; this._context = null;
this._hints = 0; this._hints = 0;
this._purpose = 0; this._purpose = 0;
this._preeditStr = ''; this._preeditStr = ''
this._preeditPos = 0; this._preeditPos = 0;
this._preeditVisible = false; this._preeditVisible = false;
} }
@ -92,15 +84,15 @@ class InputMethod extends Clutter.InputMethod {
this.emit('request-surrounding'); this.emit('request-surrounding');
} }
_onCommitText(_context, text) { _onCommitText(context, text) {
this.commit(text.get_text()); this.commit(text.get_text());
} }
_onDeleteSurroundingText() { _onDeleteSurroundingText(context) {
this.delete_surrounding(); this.delete_surrounding();
} }
_onUpdatePreeditText(_context, text, pos, visible) { _onUpdatePreeditText(context, text, pos, visible) {
if (text == null) if (text == null)
return; return;
@ -116,17 +108,17 @@ class InputMethod extends Clutter.InputMethod {
this._preeditVisible = visible; this._preeditVisible = visible;
} }
_onShowPreeditText() { _onShowPreeditText(context) {
this._preeditVisible = true; this._preeditVisible = true;
this.set_preedit_text(this._preeditStr, this._preeditPos); this.set_preedit_text(this._preeditStr, this._preeditPos);
} }
_onHidePreeditText() { _onHidePreeditText(context) {
this.set_preedit_text(null, this._preeditPos); this.set_preedit_text(null, this._preeditPos);
this._preeditVisible = false; this._preeditVisible = false;
} }
_onForwardKeyEvent(_context, keyval, keycode, state) { _onForwardKeyEvent(context, keyval, keycode, state) {
let press = (state & IBus.ModifierType.RELEASE_MASK) == 0; let press = (state & IBus.ModifierType.RELEASE_MASK) == 0;
state &= ~(IBus.ModifierType.RELEASE_MASK); state &= ~(IBus.ModifierType.RELEASE_MASK);
@ -144,6 +136,7 @@ class InputMethod extends Clutter.InputMethod {
this._currentFocus = focus; this._currentFocus = focus;
if (this._context) { if (this._context) {
this._context.focus_in(); this._context.focus_in();
this._updateCapabilities();
this._emitRequestSurrounding(); this._emitRequestSurrounding();
} }
@ -155,8 +148,10 @@ class InputMethod extends Clutter.InputMethod {
vfunc_focus_out() { vfunc_focus_out() {
this._currentFocus = null; this._currentFocus = null;
if (this._context) if (this._context) {
this._context.focus_out(); this._context.focus_out();
this._updateCapabilities();
}
if (this._preeditStr) { if (this._preeditStr) {
// Unset any preedit text // Unset any preedit text
@ -259,19 +254,17 @@ class InputMethod extends Clutter.InputMethod {
if (event.type() == Clutter.EventType.KEY_RELEASE) if (event.type() == Clutter.EventType.KEY_RELEASE)
state |= IBus.ModifierType.RELEASE_MASK; state |= IBus.ModifierType.RELEASE_MASK;
this._context.process_key_event_async( this._context.process_key_event_async(event.get_key_symbol(),
event.get_key_symbol(), event.get_key_code() - 8, // Convert XKB keycodes to evcodes
event.get_key_code() - 8, // Convert XKB keycodes to evcodes state, -1, null,
state, -1, this._cancellable, (context, res) => {
(context, res) => { try {
try { let retval = context.process_key_event_async_finish(res);
let retval = context.process_key_event_async_finish(res); this.notify_key_event(event, retval);
this.notify_key_event(event, retval); } catch (e) {
} catch (e) { log('Error processing key on IM: ' + e.message);
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) }
log(`Error processing key on IM: ${e.message}`); });
}
});
return true; return true;
} }
}); });

View File

@ -1,4 +1,3 @@
/* exported IntrospectService */
const { Gio, GLib, Meta, Shell } = imports.gi; const { Gio, GLib, Meta, Shell } = imports.gi;
const INTROSPECT_SCHEMA = 'org.gnome.shell'; const INTROSPECT_SCHEMA = 'org.gnome.shell';
@ -43,20 +42,17 @@ var IntrospectService = class {
} }
_isStandaloneApp(app) { _isStandaloneApp(app) {
let windows = app.get_windows();
return app.get_windows().some(w => w.transient_for == null); return app.get_windows().some(w => w.transient_for == null);
} }
_isIntrospectEnabled() { _isIntrospectEnabled() {
return this._settings.get_boolean(INTROSPECT_KEY); return this._settings.get_boolean(INTROSPECT_KEY);
} }
_isSenderWhitelisted(sender) { _isSenderWhitelisted(sender) {
return APP_WHITELIST.includes(sender); return APP_WHITELIST.includes(sender);
}
_getSandboxedAppId(app) {
let ids = app.get_windows().map(w => w.get_sandboxed_app_id());
return ids.find(id => id != null);
} }
_syncRunningApplications() { _syncRunningApplications() {
@ -80,10 +76,6 @@ var IntrospectService = class {
newActiveApplication = app.get_id(); newActiveApplication = app.get_id();
} }
let sandboxedAppId = this._getSandboxedAppId(app);
if (sandboxedAppId)
appInfo['sandboxed-app-id'] = new GLib.Variant('s', sandboxedAppId);
newRunningApplications[app.get_id()] = appInfo; newRunningApplications[app.get_id()] = appInfo;
} }
@ -127,8 +119,7 @@ var IntrospectService = class {
let apps = this._appSystem.get_running(); let apps = this._appSystem.get_running();
let windowsList = {}; let windowsList = {};
if (!this._isIntrospectEnabled() && if (!this._isIntrospectEnabled()) {
!this._isSenderWhitelisted(invocation.get_sender())) {
invocation.return_error_literal(Gio.DBusError, invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED, Gio.DBusError.ACCESS_DENIED,
'App introspection not allowed'); 'App introspection not allowed');
@ -146,7 +137,6 @@ var IntrospectService = class {
let frameRect = window.get_frame_rect(); let frameRect = window.get_frame_rect();
let title = window.get_title(); let title = window.get_title();
let wmClass = window.get_wm_class(); let wmClass = window.get_wm_class();
let sandboxedAppId = window.get_sandboxed_app_id();
windowsList[windowId] = { windowsList[windowId] = {
'app-id': GLib.Variant.new('s', app.get_id()), 'app-id': GLib.Variant.new('s', app.get_id()),
@ -163,10 +153,6 @@ var IntrospectService = class {
if (wmClass != null) if (wmClass != null)
windowsList[windowId]['wm-class'] = GLib.Variant.new('s', wmClass); windowsList[windowId]['wm-class'] = GLib.Variant.new('s', wmClass);
if (sandboxedAppId != null)
windowsList[windowId]['sandboxed-app-id'] =
GLib.Variant.new('s', sandboxedAppId);
} }
} }
invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList])); invocation.return_value(new GLib.Variant('(a{ta{sv}})', [windowsList]));

View File

@ -1,5 +1,4 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* exported getCompletions, getCommonPrefix, getDeclaredConstants */
// Returns a list of potential completions for text. Completions either // Returns a list of potential completions for text. Completions either
// follow a dot (e.g. foo.ba -> bar) or they are picked from globalCompletionList (e.g. fo -> foo) // follow a dot (e.g. foo.ba -> bar) or they are picked from globalCompletionList (e.g. fo -> foo)
@ -9,7 +8,7 @@
// This function is likely the one you want to call from external modules // This function is likely the one you want to call from external modules
function getCompletions(text, commandHeader, globalCompletionList) { function getCompletions(text, commandHeader, globalCompletionList) {
let methods = []; let methods = [];
let expr_, base; let expr, base;
let attrHead = ''; let attrHead = '';
if (globalCompletionList == null) { if (globalCompletionList == null) {
globalCompletionList = []; globalCompletionList = [];
@ -22,7 +21,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
// Look for expressions like "Main.panel.foo" and match Main.panel and foo // Look for expressions like "Main.panel.foo" and match Main.panel and foo
let matches = text.match(/(.*)\.(.*)/); let matches = text.match(/(.*)\.(.*)/);
if (matches) { if (matches) {
[expr_, base, attrHead] = matches; [expr, base, attrHead] = matches;
methods = getPropertyNamesFromExpression(base, commandHeader).filter( methods = getPropertyNamesFromExpression(base, commandHeader).filter(
attr => attr.slice(0, attrHead.length) == attrHead attr => attr.slice(0, attrHead.length) == attrHead
@ -33,7 +32,7 @@ function getCompletions(text, commandHeader, globalCompletionList) {
// not proceeded by a dot and match them against global constants // not proceeded by a dot and match them against global constants
matches = text.match(/^(\w*)$/); matches = text.match(/^(\w*)$/);
if (text == '' || matches) { if (text == '' || matches) {
[expr_, attrHead] = matches; [expr, attrHead] = matches;
methods = globalCompletionList.filter( methods = globalCompletionList.filter(
attr => attr.slice(0, attrHead.length) == attrHead attr => attr.slice(0, attrHead.length) == attrHead
); );
@ -52,14 +51,14 @@ function getCompletions(text, commandHeader, globalCompletionList) {
// if we encounter anything that isn't a letter, '.', ')', or ']', // if we encounter anything that isn't a letter, '.', ')', or ']',
// we should stop parsing. // we should stop parsing.
function isStopChar(c) { function isStopChar(c) {
return !c.match(/[\w.)\]]/); return !c.match(/[\w\.\)\]]/);
} }
// Given the ending position of a quoted string, find where it starts // Given the ending position of a quoted string, find where it starts
function findMatchingQuote(expr, offset) { function findMatchingQuote(expr, offset) {
let quoteChar = expr.charAt(offset); let quoteChar = expr.charAt(offset);
for (let i = offset - 1; i >= 0; --i) { for (let i = offset - 1; i >= 0; --i) {
if (expr.charAt(i) == quoteChar && expr.charAt(i - 1) != '\\') { if (expr.charAt(i) == quoteChar && expr.charAt(i-1) != '\\'){
return i; return i;
} }
} }
@ -69,7 +68,7 @@ function findMatchingQuote(expr, offset) {
// Given the ending position of a regex, find where it starts // Given the ending position of a regex, find where it starts
function findMatchingSlash(expr, offset) { function findMatchingSlash(expr, offset) {
for (let i = offset - 1; i >= 0; --i) { for (let i = offset - 1; i >= 0; --i) {
if (expr.charAt(i) == '/' && expr.charAt(i - 1) != '\\') { if (expr.charAt(i) == '/' && expr.charAt(i-1) != '\\'){
return i; return i;
} }
} }
@ -82,7 +81,7 @@ function findMatchingSlash(expr, offset) {
// findMatchingBrace("[(])", 3) returns 1. // findMatchingBrace("[(])", 3) returns 1.
function findMatchingBrace(expr, offset) { function findMatchingBrace(expr, offset) {
let closeBrace = expr.charAt(offset); let closeBrace = expr.charAt(offset);
let openBrace = ({ ')': '(', ']': '[' })[closeBrace]; let openBrace = ({')': '(', ']': '['})[closeBrace];
function findTheBrace(expr, offset) { function findTheBrace(expr, offset) {
if (offset < 0) { if (offset < 0) {
@ -118,11 +117,11 @@ function getExpressionOffset(expr, offset) {
while (offset >= 0) { while (offset >= 0) {
let currChar = expr.charAt(offset); let currChar = expr.charAt(offset);
if (isStopChar(currChar)) { if (isStopChar(currChar)){
return offset + 1; return offset + 1;
} }
if (currChar.match(/[)\]]/)) { if (currChar.match(/[\)\]]/)) {
offset = findMatchingBrace(expr, offset); offset = findMatchingBrace(expr, offset);
} }
@ -152,11 +151,15 @@ function getAllProps(obj) {
// e.g., expr="({ foo: null, bar: null, 4: null })" will // e.g., expr="({ foo: null, bar: null, 4: null })" will
// return ["foo", "bar", ...] but the list will not include "4", // return ["foo", "bar", ...] but the list will not include "4",
// since methods accessed with '.' notation must star with a letter or _. // since methods accessed with '.' notation must star with a letter or _.
function getPropertyNamesFromExpression(expr, commandHeader = '') { function getPropertyNamesFromExpression(expr, commandHeader) {
if (commandHeader == null) {
commandHeader = '';
}
let obj = {}; let obj = {};
if (!isUnsafeExpression(expr)) { if (!isUnsafeExpression(expr)) {
try { try {
obj = eval(commandHeader + expr); obj = eval(commandHeader + expr);
} catch (e) { } catch (e) {
return []; return [];
} }
@ -165,14 +168,14 @@ function getPropertyNamesFromExpression(expr, commandHeader = '') {
} }
let propsUnique = {}; let propsUnique = {};
if (typeof obj === 'object') { if (typeof obj === 'object'){
let allProps = getAllProps(obj); let allProps = getAllProps(obj);
// Get only things we are allowed to complete following a '.' // Get only things we are allowed to complete following a '.'
allProps = allProps.filter( isValidPropertyName ); allProps = allProps.filter( isValidPropertyName );
// Make sure propsUnique contains one key for every // Make sure propsUnique contains one key for every
// property so we end up with a unique list of properties // property so we end up with a unique list of properties
allProps.map(p => (propsUnique[p] = null)); allProps.map(p => propsUnique[p] = null);
} }
return Object.keys(propsUnique).sort(); return Object.keys(propsUnique).sort();
} }
@ -217,7 +220,7 @@ function isUnsafeExpression(str) {
prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing
prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing
if (prunedStr.match(/[=]/)) { if (prunedStr.match(/=/)) {
return true; return true;
} else if (prunedStr.match(/;/)) { } else if (prunedStr.match(/;/)) {
// If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well // If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well
@ -231,10 +234,10 @@ function isUnsafeExpression(str) {
function getDeclaredConstants(str) { function getDeclaredConstants(str) {
let ret = []; let ret = [];
str.split(';').forEach(s => { str.split(';').forEach(s => {
let base_, keyword; let base, keyword;
let match = s.match(/const\s+(\w+)\s*=/); let match = s.match(/const\s+(\w+)\s*=/);
if (match) { if (match) {
[base_, keyword] = match; [base, keyword] = match;
ret.push(keyword); ret.push(keyword);
} }
}); });

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getKeyboardManager, holdKeyboard, releaseKeyboard */
const { GLib, GnomeDesktop, Meta } = imports.gi; const { GLib, GnomeDesktop, Meta } = imports.gi;
@ -61,7 +60,7 @@ var KeyboardManager = class {
this._currentKeymap.options == options) this._currentKeymap.options == options)
return; return;
this._currentKeymap = { layouts, variants, options }; this._currentKeymap = {layouts, variants, options};
Meta.get_backend().set_keymap(layouts, variants, options); Meta.get_backend().set_keymap(layouts, variants, options);
} }
@ -126,7 +125,7 @@ var KeyboardManager = class {
_getLocaleLayout() { _getLocaleLayout() {
let locale = GLib.get_language_names()[0]; let locale = GLib.get_language_names()[0];
if (!locale.includes('_')) if (locale.indexOf('_') == -1)
locale = DEFAULT_LOCALE; locale = DEFAULT_LOCALE;
let [found, , id] = GnomeDesktop.get_input_source_from_locale(locale); let [found, , id] = GnomeDesktop.get_input_source_from_locale(locale);

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported canLock, getLoginManager, registerSessionWithGDM */
const { GLib, Gio } = imports.gi; const { GLib, Gio } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
@ -44,33 +43,11 @@ function canLock() {
let version = result.deep_unpack()[0].deep_unpack(); let version = result.deep_unpack()[0].deep_unpack();
return haveSystemd() && versionCompare('3.5.91', version); return haveSystemd() && versionCompare('3.5.91', version);
} catch (e) { } catch(e) {
return false; return false;
} }
} }
function registerSessionWithGDM() {
log("Registering session with GDM");
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; let _loginManager = null;
/** /**
@ -110,7 +87,7 @@ var LoginManagerSystemd = class {
let sessionId = GLib.getenv('XDG_SESSION_ID'); let sessionId = GLib.getenv('XDG_SESSION_ID');
if (!sessionId) { if (!sessionId) {
log('Unset XDG_SESSION_ID, getCurrentSessionProxy() called outside a user session. Asking logind directly.'); log('Unset XDG_SESSION_ID, getCurrentSessionProxy() called outside a user session. Asking logind directly.');
let [session, objectPath_] = this._userProxy.Display; let [session, objectPath] = this._userProxy.Display;
if (session) { if (session) {
log(`Will monitor session ${session}`); log(`Will monitor session ${session}`);
sessionId = session; sessionId = session;
@ -183,10 +160,10 @@ var LoginManagerSystemd = class {
(proxy, result) => { (proxy, result) => {
let fd = -1; let fd = -1;
try { try {
let [outVariant_, fdList] = proxy.call_with_unix_fd_list_finish(result); let [outVariant, fdList] = proxy.call_with_unix_fd_list_finish(result);
fd = fdList.steal_fds()[0]; fd = fdList.steal_fds()[0];
callback(new Gio.UnixInputStream({ fd: fd })); callback(new Gio.UnixInputStream({ fd: fd }));
} catch (e) { } catch(e) {
logError(e, "Error getting systemd inhibitor"); logError(e, "Error getting systemd inhibitor");
callback(null); callback(null);
} }
@ -200,7 +177,7 @@ var LoginManagerSystemd = class {
Signals.addSignalMethods(LoginManagerSystemd.prototype); Signals.addSignalMethods(LoginManagerSystemd.prototype);
var LoginManagerDummy = class { var LoginManagerDummy = class {
getCurrentSessionProxy(_callback) { getCurrentSessionProxy(callback) {
// we could return a DummySession object that fakes whatever callers // we could return a DummySession object that fakes whatever callers
// expect (at the time of writing: connect() and connectSignal() // expect (at the time of writing: connect() and connectSignal()
// methods), but just never calling the callback should be safer // methods), but just never calling the callback should be safer

View File

@ -26,33 +26,33 @@ function _getMobileProvidersDatabase() {
} }
// _findProviderForMccMnc: // _findProviderForMccMnc:
// @operatorName: operator name // @operator_name: operator name
// @operatorCode: operator code // @operator_code: operator code
// //
// Given an operator name string (which may not be a real operator name) and an // Given an operator name string (which may not be a real operator name) and an
// operator code string, tries to find a proper operator name to display. // operator code string, tries to find a proper operator name to display.
// //
function _findProviderForMccMnc(operatorName, operatorCode) { function _findProviderForMccMnc(operator_name, operator_code) {
if (operatorName) { if (operator_name) {
if (operatorName.length != 0 && if (operator_name.length != 0 &&
(operatorName.length > 6 || operatorName.length < 5)) { (operator_name.length > 6 || operator_name.length < 5)) {
// this looks like a valid name, i.e. not an MCCMNC (that some // this looks like a valid name, i.e. not an MCCMNC (that some
// devices return when not yet connected // devices return when not yet connected
return operatorName; return operator_name;
} }
if (isNaN(parseInt(operatorName))) { if (isNaN(parseInt(operator_name))) {
// name is definitely not a MCCMNC, so it may be a name // name is definitely not a MCCMNC, so it may be a name
// after all; return that // after all; return that
return operatorName; return operator_name;
} }
} }
let needle; let needle;
if ((!operatorName || operatorName.length == 0) && operatorCode) if ((!operator_name || operator_name.length == 0) && operator_code)
needle = operatorCode; needle = operator_code;
else if (operatorName && (operatorName.length == 6 || operatorName.length == 5)) else if (operator_name && (operator_name.length == 6 || operator_name.length == 5))
needle = operatorName; needle = operator_name;
else // nothing to search else // nothing to search
return null; return null;
@ -71,7 +71,7 @@ function _findProviderForMccMnc(operatorName, operatorCode) {
// Tries to find the operator name corresponding to the given SID // Tries to find the operator name corresponding to the given SID
// //
function _findProviderForSid(sid) { function _findProviderForSid(sid) {
if (!sid) if (sid == 0)
return null; return null;
let mpd = _getMobileProvidersDatabase(); let mpd = _getMobileProvidersDatabase();
@ -84,9 +84,9 @@ function _findProviderForSid(sid) {
} }
// ----------------------------------------------------- // //------------------------------------------------------------------------------
// Support for the old ModemManager interface (MM < 0.7) // // Support for the old ModemManager interface (MM < 0.7)
// ----------------------------------------------------- // //------------------------------------------------------------------------------
// The following are not the complete interfaces, just the methods we need // The following are not the complete interfaces, just the methods we need
@ -110,7 +110,7 @@ var ModemGsm = class {
this.signal_quality = quality; this.signal_quality = quality;
this.emit('notify::signal-quality'); this.emit('notify::signal-quality');
}); });
this._proxy.connectSignal('RegistrationInfo', (proxy, sender, [_status, code, name]) => { this._proxy.connectSignal('RegistrationInfo', (proxy, sender, [status, code, name]) => {
this.operator_name = _findProviderForMccMnc(name, code); this.operator_name = _findProviderForMccMnc(name, code);
this.emit('notify::operator-name'); this.emit('notify::operator-name');
}); });
@ -120,7 +120,7 @@ var ModemGsm = class {
return; return;
} }
let [status_, code, name] = result; let [status, code, name] = result;
this.operator_name = _findProviderForMccMnc(name, code); this.operator_name = _findProviderForMccMnc(name, code);
this.emit('notify::operator-name'); this.emit('notify::operator-name');
}); });
@ -171,9 +171,9 @@ var ModemCdma = class {
// it will return an error if the device is not connected // it will return an error if the device is not connected
this.operator_name = null; this.operator_name = null;
} else { } else {
let [bandClass_, band_, sid] = result; let [bandClass, band, sid] = result;
this.operator_name = _findProviderForSid(sid); this.operator_name = _findProviderForSid(sid)
} }
this.emit('notify::operator-name'); this.emit('notify::operator-name');
}); });
@ -182,9 +182,9 @@ var ModemCdma = class {
Signals.addSignalMethods(ModemCdma.prototype); Signals.addSignalMethods(ModemCdma.prototype);
// ------------------------------------------------------- // //------------------------------------------------------------------------------
// Support for the new ModemManager1 interface (MM >= 0.7) // // Support for the new ModemManager1 interface (MM >= 0.7)
// ------------------------------------------------------- // //------------------------------------------------------------------------------
const BroadbandModemInterface = loadInterfaceXML('org.freedesktop.ModemManager1.Modem'); const BroadbandModemInterface = loadInterfaceXML('org.freedesktop.ModemManager1.Modem');
const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface); const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface);
@ -224,23 +224,23 @@ var BroadbandModem = class {
} }
_reloadSignalQuality() { _reloadSignalQuality() {
let [quality, recent_] = this._proxy.SignalQuality; let [quality, recent] = this._proxy.SignalQuality;
this.signal_quality = quality; this.signal_quality = quality;
this.emit('notify::signal-quality'); this.emit('notify::signal-quality');
} }
_reloadOperatorName() { _reloadOperatorName() {
let newName = ""; let new_name = "";
if (this.operator_name_3gpp && this.operator_name_3gpp.length > 0) if (this.operator_name_3gpp && this.operator_name_3gpp.length > 0)
newName += this.operator_name_3gpp; new_name += this.operator_name_3gpp;
if (this.operator_name_cdma && this.operator_name_cdma.length > 0) { if (this.operator_name_cdma && this.operator_name_cdma.length > 0) {
if (newName != "") if (new_name != "")
newName += ", "; new_name += ", ";
newName += this.operator_name_cdma; new_name += this.operator_name_cdma;
} }
this.operator_name = newName; this.operator_name = new_name;
this.emit('notify::operator-name'); this.emit('notify::operator-name');
} }

View File

@ -77,51 +77,54 @@ var ObjectManager = class {
let info = this._interfaceInfos[interfaceName]; let info = this._interfaceInfos[interfaceName];
if (!info) { if (!info) {
if (onFinished) if (onFinished)
onFinished(); onFinished();
return; return;
} }
let proxy = new Gio.DBusProxy({ g_connection: this._connection, let proxy = new Gio.DBusProxy({ g_connection: this._connection,
g_name: this._serviceName, g_name: this._serviceName,
g_object_path: objectPath, g_object_path: objectPath,
g_interface_name: interfaceName, g_interface_name: interfaceName,
g_interface_info: info, g_interface_info: info,
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START }); g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => { proxy.init_async(GLib.PRIORITY_DEFAULT,
try { this._cancellable,
initable.init_finish(result); (initable, result) => {
} catch (e) { let error = null;
logError(e, `could not initialize proxy for interface ${interfaceName}`); try {
initable.init_finish(result);
} catch(e) {
logError(e, 'could not initialize proxy for interface ' + interfaceName);
if (onFinished) if (onFinished)
onFinished(); onFinished();
return; return;
} }
let isNewObject; let isNewObject;
if (!this._objects[objectPath]) { if (!this._objects[objectPath]) {
this._objects[objectPath] = {}; this._objects[objectPath] = {};
isNewObject = true; isNewObject = true;
} else { } else {
isNewObject = false; isNewObject = false;
} }
this._objects[objectPath][interfaceName] = proxy; this._objects[objectPath][interfaceName] = proxy;
if (!this._interfaces[interfaceName]) if (!this._interfaces[interfaceName])
this._interfaces[interfaceName] = []; this._interfaces[interfaceName] = [];
this._interfaces[interfaceName].push(proxy); this._interfaces[interfaceName].push(proxy);
if (isNewObject) if (isNewObject)
this.emit('object-added', objectPath); this.emit('object-added', objectPath);
this.emit('interface-added', interfaceName, proxy); this.emit('interface-added', interfaceName, proxy);
if (onFinished) if (onFinished)
onFinished(); onFinished();
}); });
} }
@ -152,10 +155,11 @@ var ObjectManager = class {
} }
_onManagerProxyLoaded(initable, result) { _onManagerProxyLoaded(initable, result) {
let error = null;
try { try {
initable.init_finish(result); initable.init_finish(result);
} catch (e) { } catch(e) {
logError(e, `could not initialize object manager for object ${this._serviceName}`); logError(e, 'could not initialize object manager for object ' + this._serviceName);
this._tryToCompleteLoad(); this._tryToCompleteLoad();
return; return;
@ -193,7 +197,7 @@ var ObjectManager = class {
this._managerProxy.GetManagedObjectsRemote((result, error) => { this._managerProxy.GetManagedObjectsRemote((result, error) => {
if (!result) { if (!result) {
if (error) { if (error) {
logError(error, `could not get remote objects for service ${this._serviceName} path ${this._managerPath}`); logError(error, 'could not get remote objects for service ' + this._serviceName + ' path ' + this._managerPath);
} }
this._tryToCompleteLoad(); this._tryToCompleteLoad();

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported parse */
// parse: // parse:
// @params: caller-provided parameter object, or %null // @params: caller-provided parameter object, or %null
@ -15,13 +14,22 @@
// //
// Return value: a new object, containing the merged parameters from // Return value: a new object, containing the merged parameters from
// @params and @defaults // @params and @defaults
function parse(params = {}, defaults, allowExtras) { function parse(params, defaults, allowExtras) {
if (!allowExtras) { let ret = {}, prop;
for (let prop in params)
if (!(prop in defaults)) if (!params)
throw new Error(`Unrecognized parameter "${prop}"`); params = {};
for (prop in params) {
if (!(prop in defaults) && !allowExtras)
throw new Error('Unrecognized parameter "' + prop + '"');
ret[prop] = params[prop];
} }
let defaultsCopy = Object.assign({}, defaults); for (prop in defaults) {
return Object.assign(defaultsCopy, params); if (!(prop in params))
ret[prop] = defaults[prop];
}
return ret;
} }

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported PermissionStore */
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
@ -13,4 +12,4 @@ function PermissionStore(initCallback, cancellable) {
'org.freedesktop.impl.portal.PermissionStore', 'org.freedesktop.impl.portal.PermissionStore',
'/org/freedesktop/impl/portal/PermissionStore', '/org/freedesktop/impl/portal/PermissionStore',
initCallback, cancellable); initCallback, cancellable);
} };

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getSmartcardManager */
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Signals = imports.signals; const Signals = imports.signals;
@ -30,7 +29,7 @@ var SmartcardManager = class {
this._objectManager = new ObjectManager.ObjectManager({ connection: Gio.DBus.session, this._objectManager = new ObjectManager.ObjectManager({ connection: Gio.DBus.session,
name: "org.gnome.SettingsDaemon.Smartcard", name: "org.gnome.SettingsDaemon.Smartcard",
objectPath: '/org/gnome/SettingsDaemon/Smartcard', objectPath: '/org/gnome/SettingsDaemon/Smartcard',
knownInterfaces: [SmartcardTokenIface], knownInterfaces: [ SmartcardTokenIface ],
onLoaded: this._onLoaded.bind(this) }); onLoaded: this._onLoaded.bind(this) });
this._insertedTokens = {}; this._insertedTokens = {};
this._loginToken = null; this._loginToken = null;

View File

@ -1,4 +1,3 @@
/* exported getDefault */
const { AccountsService, Clutter, Gdm, Gio, GLib, GObject, Meta } = imports.gi; const { AccountsService, Clutter, Gdm, Gio, GLib, GObject, Meta } = imports.gi;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
@ -84,54 +83,48 @@ const SystemActions = GObject.registerClass({
this._canHaveSuspend = true; this._canHaveSuspend = true;
this._actions = new Map(); this._actions = new Map();
this._actions.set(POWER_OFF_ACTION_ID, { this._actions.set(POWER_OFF_ACTION_ID,
// Translators: The name of the power-off action in search { // Translators: The name of the power-off action in search
name: C_("search-result", "Power Off"), name: C_("search-result", "Power Off"),
iconName: 'system-shutdown-symbolic', iconName: 'system-shutdown-symbolic',
// Translators: A list of keywords that match the power-off action, separated by semicolons // Translators: A list of keywords that match the power-off action, separated by semicolons
keywords: _("power off;shutdown;reboot;restart").split(/[; ]/), keywords: _("power off;shutdown;reboot;restart").split(';'),
available: false available: false });
}); this._actions.set(LOCK_SCREEN_ACTION_ID,
this._actions.set(LOCK_SCREEN_ACTION_ID, { { // Translators: The name of the lock screen action in search
// Translators: The name of the lock screen action in search name: C_("search-result", "Lock Screen"),
name: C_("search-result", "Lock Screen"), iconName: 'system-lock-screen-symbolic',
iconName: 'system-lock-screen-symbolic', // Translators: A list of keywords that match the lock screen action, separated by semicolons
// Translators: A list of keywords that match the lock screen action, separated by semicolons keywords: _("lock screen").split(';'),
keywords: _("lock screen").split(/[; ]/), available: false });
available: false this._actions.set(LOGOUT_ACTION_ID,
}); { // Translators: The name of the logout action in search
this._actions.set(LOGOUT_ACTION_ID, { name: C_("search-result", "Log Out"),
// Translators: The name of the logout action in search iconName: 'application-exit-symbolic',
name: C_("search-result", "Log Out"), // Translators: A list of keywords that match the logout action, separated by semicolons
iconName: 'application-exit-symbolic', keywords: _("logout;sign off").split(';'),
// Translators: A list of keywords that match the logout action, separated by semicolons available: false });
keywords: _("logout;log out;sign off").split(/[; ]/), this._actions.set(SUSPEND_ACTION_ID,
available: false { // Translators: The name of the suspend action in search
}); name: C_("search-result", "Suspend"),
this._actions.set(SUSPEND_ACTION_ID, { iconName: 'media-playback-pause-symbolic',
// Translators: The name of the suspend action in search // Translators: A list of keywords that match the suspend action, separated by semicolons
name: C_("search-result", "Suspend"), keywords: _("suspend;sleep").split(';'),
iconName: 'media-playback-pause-symbolic', available: false });
// Translators: A list of keywords that match the suspend action, separated by semicolons this._actions.set(SWITCH_USER_ACTION_ID,
keywords: _("suspend;sleep").split(/[; ]/), { // Translators: The name of the switch user action in search
available: false name: C_("search-result", "Switch User"),
}); iconName: 'system-switch-user-symbolic',
this._actions.set(SWITCH_USER_ACTION_ID, { // Translators: A list of keywords that match the switch user action, separated by semicolons
// Translators: The name of the switch user action in search keywords: _("switch user").split(';'),
name: C_("search-result", "Switch User"), available: false });
iconName: 'system-switch-user-symbolic', this._actions.set(LOCK_ORIENTATION_ACTION_ID,
// Translators: A list of keywords that match the switch user action, separated by semicolons { // Translators: The name of the lock orientation action in search
keywords: _("switch user").split(/[; ]/), name: C_("search-result", "Lock Orientation"),
available: false iconName: '',
}); // Translators: A list of keywords that match the lock orientation action, separated by semicolons
this._actions.set(LOCK_ORIENTATION_ACTION_ID, { keywords: _("lock orientation;screen;rotation").split(';'),
// Translators: The name of the lock orientation action in search available: false });
name: C_("search-result", "Lock Orientation"),
iconName: '',
// Translators: A list of keywords that match the lock orientation action, separated by semicolons
keywords: _("lock orientation;screen;rotation").split(/[; ]/),
available: false
});
this._loginScreenSettings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA }); this._loginScreenSettings = new Gio.Settings({ schema_id: LOGIN_SCREEN_SCHEMA });
this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA }); this._lockdownSettings = new Gio.Settings({ schema_id: LOCKDOWN_SCHEMA });
@ -144,96 +137,92 @@ const SystemActions = GObject.registerClass({
this._userManager = AccountsService.UserManager.get_default(); this._userManager = AccountsService.UserManager.get_default();
this._userManager.connect('notify::is-loaded', this._userManager.connect('notify::is-loaded',
() => this._updateMultiUser()); () => { this._updateMultiUser(); });
this._userManager.connect('notify::has-multiple-users', this._userManager.connect('notify::has-multiple-users',
() => this._updateMultiUser()); () => { this._updateMultiUser(); });
this._userManager.connect('user-added', this._userManager.connect('user-added',
() => this._updateMultiUser()); () => { this._updateMultiUser(); });
this._userManager.connect('user-removed', this._userManager.connect('user-removed',
() => this._updateMultiUser()); () => { this._updateMultiUser(); });
this._lockdownSettings.connect(`changed::${DISABLE_USER_SWITCH_KEY}`, this._lockdownSettings.connect('changed::' + DISABLE_USER_SWITCH_KEY,
() => this._updateSwitchUser()); () => { this._updateSwitchUser(); });
this._lockdownSettings.connect(`changed::${DISABLE_LOG_OUT_KEY}`, this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
() => this._updateLogout()); () => { this._updateLogout(); });
global.settings.connect(`changed::${ALWAYS_SHOW_LOG_OUT_KEY}`, global.settings.connect('changed::' + ALWAYS_SHOW_LOG_OUT_KEY,
() => this._updateLogout()); () => { this._updateLogout(); });
this._lockdownSettings.connect(`changed::${DISABLE_LOCK_SCREEN_KEY}`, this._lockdownSettings.connect('changed::' + DISABLE_LOCK_SCREEN_KEY,
() => this._updateLockScreen()); () => { this._updateLockScreen(); });
this._lockdownSettings.connect(`changed::${DISABLE_LOG_OUT_KEY}`, this._lockdownSettings.connect('changed::' + DISABLE_LOG_OUT_KEY,
() => this._updateHaveShutdown()); () => { this._updateHaveShutdown(); });
this.forceUpdate(); this.forceUpdate();
this._orientationSettings.connect('changed::orientation-lock', this._orientationSettings.connect('changed::orientation-lock',
() => { () => { this._updateOrientationLock();
this._updateOrientationLock(); this._updateOrientationLockIcon(); });
this._updateOrientationLockIcon();
});
Main.layoutManager.connect('monitors-changed', Main.layoutManager.connect('monitors-changed',
() => this._updateOrientationLock()); () => { this._updateOrientationLock(); });
this._sensorProxy = new SensorProxy(Gio.DBus.system, Gio.DBus.system.watch_name(SENSOR_BUS_NAME,
SENSOR_BUS_NAME, Gio.BusNameWatcherFlags.NONE,
SENSOR_OBJECT_PATH, () => { this._sensorProxyAppeared(); },
(proxy, error) => { () => {
if (error) this._sensorProxy = null;
log(error.message); this._updateOrientationLock();
}, });
null,
Gio.DBusProxyFlags.DO_NOT_AUTO_START);
this._sensorProxy.connect('g-properties-changed', () => {
this._updateOrientationLock();
});
this._sensorProxy.connect('notify::g-name-owner', () => {
this._updateOrientationLock();
});
this._updateOrientationLock(); this._updateOrientationLock();
this._updateOrientationLockIcon(); this._updateOrientationLockIcon();
Main.sessionMode.connect('updated', () => this._sessionUpdated()); Main.sessionMode.connect('updated', () => { this._sessionUpdated(); });
this._sessionUpdated(); this._sessionUpdated();
} }
// eslint-disable-next-line camelcase
get can_power_off() { get can_power_off() {
return this._actions.get(POWER_OFF_ACTION_ID).available; return this._actions.get(POWER_OFF_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get can_suspend() { get can_suspend() {
return this._actions.get(SUSPEND_ACTION_ID).available; return this._actions.get(SUSPEND_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get can_lock_screen() { get can_lock_screen() {
return this._actions.get(LOCK_SCREEN_ACTION_ID).available; return this._actions.get(LOCK_SCREEN_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get can_switch_user() { get can_switch_user() {
return this._actions.get(SWITCH_USER_ACTION_ID).available; return this._actions.get(SWITCH_USER_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get can_logout() { get can_logout() {
return this._actions.get(LOGOUT_ACTION_ID).available; return this._actions.get(LOGOUT_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get can_lock_orientation() { get can_lock_orientation() {
return this._actions.get(LOCK_ORIENTATION_ACTION_ID).available; return this._actions.get(LOCK_ORIENTATION_ACTION_ID).available;
} }
// eslint-disable-next-line camelcase
get orientation_lock_icon() { get orientation_lock_icon() {
return this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName; return this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName;
} }
_sensorProxyAppeared() {
this._sensorProxy = new SensorProxy(Gio.DBus.system, SENSOR_BUS_NAME, SENSOR_OBJECT_PATH,
(proxy, error) => {
if (error) {
log(error.message);
return;
}
this._sensorProxy.connect('g-properties-changed',
() => { this._updateOrientationLock(); });
this._updateOrientationLock();
});
}
_updateOrientationLock() { _updateOrientationLock() {
let available = false; let available = false;
if (this._sensorProxy.g_name_owner) if (this._sensorProxy)
available = this._sensorProxy.HasAccelerometer && available = this._sensorProxy.HasAccelerometer &&
this._monitorManager.get_is_builtin_display_on(); this._monitorManager.get_is_builtin_display_on();
@ -244,9 +233,8 @@ const SystemActions = GObject.registerClass({
_updateOrientationLockIcon() { _updateOrientationLockIcon() {
let locked = this._orientationSettings.get_boolean('orientation-lock'); let locked = this._orientationSettings.get_boolean('orientation-lock');
let iconName = locked let iconName = locked ? 'rotation-locked-symbolic'
? 'rotation-locked-symbolic' : 'rotation-allowed-symbolic';
: 'rotation-allowed-symbolic';
this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName = iconName; this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName = iconName;
this.notify('orientation-lock-icon'); this.notify('orientation-lock-icon');
@ -269,12 +257,12 @@ const SystemActions = GObject.registerClass({
getMatchingActions(terms) { getMatchingActions(terms) {
// terms is a list of strings // terms is a list of strings
terms = terms.map(term => term.toLowerCase()); terms = terms.map((term) => { return term.toLowerCase(); });
let results = []; let results = [];
for (let [key, { available, keywords }] of this._actions) for (let [key, {available, keywords}] of this._actions)
if (available && terms.every(t => keywords.some(k => k.startsWith(t)))) if (available && terms.every(t => keywords.some(k => (k.indexOf(t) >= 0))))
results.push(key); results.push(key);
return results; return results;
@ -290,24 +278,24 @@ const SystemActions = GObject.registerClass({
activateAction(id) { activateAction(id) {
switch (id) { switch (id) {
case POWER_OFF_ACTION_ID: case POWER_OFF_ACTION_ID:
this.activatePowerOff(); this.activatePowerOff();
break; break;
case LOCK_SCREEN_ACTION_ID: case LOCK_SCREEN_ACTION_ID:
this.activateLockScreen(); this.activateLockScreen();
break; break;
case LOGOUT_ACTION_ID: case LOGOUT_ACTION_ID:
this.activateLogout(); this.activateLogout();
break; break;
case SUSPEND_ACTION_ID: case SUSPEND_ACTION_ID:
this.activateSuspend(); this.activateSuspend();
break; break;
case SWITCH_USER_ACTION_ID: case SWITCH_USER_ACTION_ID:
this.activateSwitchUser(); this.activateSwitchUser();
break; break;
case LOCK_ORIENTATION_ACTION_ID: case LOCK_ORIENTATION_ACTION_ID:
this.activateLockOrientation(); this.activateLockOrientation();
break; break;
} }
} }

View File

@ -1,23 +1,23 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
formatTime, formatTimeSpan, createTimeLabel, insertSorted,
makeCloseButton, ensureActorVisibleInScrollView */
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Params = imports.misc.params; const Params = imports.misc.params;
var SCROLL_TIME = 100; var SCROLL_TIME = 0.1;
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls // http://daringfireball.net/2010/07/improved_regex_for_matching_urls
const _balancedParens = '\\([^\\s()<>]+\\)'; const _balancedParens = '\\([^\\s()<>]+\\)';
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]'; const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u200E\u200F\u201C\u201D\u2018\u2019\u202A\u202C]'; const _notTrailingJunk = '[^\\s`!()\\[\\]{};:\'\\".,<>?\u00AB\u00BB\u201C\u201D\u2018\u2019]';
const _urlRegexp = new RegExp( const _urlRegexp = new RegExp(
`(^|${_leadingJunk})` + '(^|' + _leadingJunk + ')' +
'(' + '(' +
'(?:' + '(?:' +
'(?:http|https|ftp)://' + // scheme:// '(?:http|https|ftp)://' + // scheme://
@ -29,12 +29,12 @@ const _urlRegexp = new RegExp(
'(?:' + // one or more: '(?:' + // one or more:
'[^\\s()<>]+' + // run of non-space non-() '[^\\s()<>]+' + // run of non-space non-()
'|' + // or '|' + // or
`${_balancedParens}` + // balanced parens _balancedParens + // balanced parens
')+' + ')+' +
'(?:' + // end with: '(?:' + // end with:
`${_balancedParens}` + // balanced parens _balancedParens + // balanced parens
'|' + // or '|' + // or
`${_notTrailingJunk}` + // last non-junk char _notTrailingJunk + // last non-junk char
')' + ')' +
')', 'gi'); ')', 'gi');
@ -69,16 +69,16 @@ function spawn(argv) {
} }
// spawnCommandLine: // spawnCommandLine:
// @commandLine: a command line // @command_line: a command line
// //
// Runs @commandLine in the background, handling any errors that // Runs @command_line in the background, handling any errors that
// occur when trying to parse or start the program. // occur when trying to parse or start the program.
function spawnCommandLine(commandLine) { function spawnCommandLine(command_line) {
try { try {
let [success_, argv] = GLib.shell_parse_argv(commandLine); let [success, argv] = GLib.shell_parse_argv(command_line);
trySpawn(argv); trySpawn(argv);
} catch (err) { } catch (err) {
_handleSpawnError(commandLine, err); _handleSpawnError(command_line, err);
} }
} }
@ -93,7 +93,7 @@ function spawnApp(argv) {
let context = global.create_app_launch_context(0, -1); let context = global.create_app_launch_context(0, -1);
app.launch([], context); app.launch([], context);
} catch (err) { } catch(err) {
_handleSpawnError(argv[0], err); _handleSpawnError(argv[0], err);
} }
} }
@ -103,12 +103,13 @@ function spawnApp(argv) {
// //
// Runs @argv in the background. If launching @argv fails, // Runs @argv in the background. If launching @argv fails,
// this will throw an error. // this will throw an error.
function trySpawn(argv) { function trySpawn(argv)
var success_, pid; {
var success, pid;
try { try {
[success_, pid] = GLib.spawn_async(null, argv, null, [success, pid] = GLib.spawn_async(null, argv, null,
GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD, GLib.SpawnFlags.SEARCH_PATH | GLib.SpawnFlags.DO_NOT_REAP_CHILD,
null); null);
} catch (err) { } catch (err) {
/* Rewrite the error in case of ENOENT */ /* Rewrite the error in case of ENOENT */
if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) { if (err.matches(GLib.SpawnError, GLib.SpawnError.NOENT)) {
@ -134,19 +135,19 @@ function trySpawn(argv) {
} }
// trySpawnCommandLine: // trySpawnCommandLine:
// @commandLine: a command line // @command_line: a command line
// //
// Runs @commandLine in the background. If launching @commandLine // Runs @command_line in the background. If launching @command_line
// fails, this will throw an error. // fails, this will throw an error.
function trySpawnCommandLine(commandLine) { function trySpawnCommandLine(command_line) {
let success_, argv; let success, argv;
try { try {
[success_, argv] = GLib.shell_parse_argv(commandLine); [success, argv] = GLib.shell_parse_argv(command_line);
} catch (err) { } catch (err) {
// Replace "Error invoking GLib.shell_parse_argv: " with // Replace "Error invoking GLib.shell_parse_argv: " with
// something nicer // something nicer
err.message = err.message.replace(/[^:]*: /, `${_("Could not parse command:")}\n`); err.message = err.message.replace(/[^:]*: /, _("Could not parse command:") + "\n");
throw err; throw err;
} }
@ -221,7 +222,7 @@ function formatTime(time, params) {
/* Translators: Time in 24h format */ /* Translators: Time in 24h format */
format = N_("%H\u2236%M"); format = N_("%H\u2236%M");
// Show the word "Yesterday" and time if date is on yesterday // Show the word "Yesterday" and time if date is on yesterday
else if (daysAgo < 2) else if (daysAgo <2)
/* Translators: this is the word "Yesterday" followed by a /* Translators: this is the word "Yesterday" followed by a
time string in 24h format. i.e. "Yesterday, 14:30" */ time string in 24h format. i.e. "Yesterday, 14:30" */
// xgettext:no-c-format // xgettext:no-c-format
@ -250,7 +251,7 @@ function formatTime(time, params) {
/* Translators: Time in 12h format */ /* Translators: Time in 12h format */
format = N_("%l\u2236%M %p"); format = N_("%l\u2236%M %p");
// Show the word "Yesterday" and time if date is on yesterday // Show the word "Yesterday" and time if date is on yesterday
else if (daysAgo < 2) else if (daysAgo <2)
/* Translators: this is the word "Yesterday" followed by a /* Translators: this is the word "Yesterday" followed by a
time string in 12h format. i.e. "Yesterday, 2:30 pm" */ time string in 12h format. i.e. "Yesterday, 2:30 pm" */
// xgettext:no-c-format // xgettext:no-c-format
@ -288,7 +289,7 @@ function createTimeLabel(date, params) {
let id = _desktopSettings.connect('changed::clock-format', () => { let id = _desktopSettings.connect('changed::clock-format', () => {
label.text = formatTime(date, params); label.text = formatTime(date, params);
}); });
label.connect('destroy', () => _desktopSettings.disconnect(id)); label.connect('destroy', () => { _desktopSettings.disconnect(id); });
return label; return label;
} }
@ -313,8 +314,7 @@ function lowerBound(array, val, cmp) {
if (array.length == 0) if (array.length == 0)
return 0; return 0;
min = 0; min = 0; max = array.length;
max = array.length;
while (min < (max - 1)) { while (min < (max - 1)) {
mid = Math.floor((min + max) / 2); mid = Math.floor((min + max) / 2);
v = cmp(array[mid], val); v = cmp(array[mid], val);
@ -346,7 +346,7 @@ function insertSorted(array, val, cmp) {
var CloseButton = GObject.registerClass( var CloseButton = GObject.registerClass(
class CloseButton extends St.Button { class CloseButton extends St.Button {
_init(boxpointer) { _init(boxpointer) {
super._init({ style_class: 'notification-close' }); super._init({ style_class: 'notification-close'});
// This is a bit tricky. St.Bin has its own x-align/y-align properties // This is a bit tricky. St.Bin has its own x-align/y-align properties
// that compete with Clutter's properties. This should be fixed for // that compete with Clutter's properties. This should be fixed for
@ -366,7 +366,7 @@ class CloseButton extends St.Button {
} }
_computeBoxPointerOffset() { _computeBoxPointerOffset() {
if (!this._boxPointer || !this._boxPointer.get_stage()) if (!this._boxPointer || !this._boxPointer.actor.get_stage())
return 0; return 0;
let side = this._boxPointer.arrowSide; let side = this._boxPointer.arrowSide;
@ -380,7 +380,7 @@ class CloseButton extends St.Button {
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
let offY = this._computeBoxPointerOffset(); let offY = this._computeBoxPointerOffset();
this.translation_x = themeNode.get_length('-shell-close-overlap-x'); this.translation_x = themeNode.get_length('-shell-close-overlap-x')
this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY; this.translation_y = themeNode.get_length('-shell-close-overlap-y') + offY;
} }
@ -396,7 +396,7 @@ function makeCloseButton(boxpointer) {
function ensureActorVisibleInScrollView(scrollView, actor) { function ensureActorVisibleInScrollView(scrollView, actor) {
let adjustment = scrollView.vscroll.adjustment; let adjustment = scrollView.vscroll.adjustment;
let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values(); let [value, lower, upper, stepIncrement, pageIncrement, pageSize] = adjustment.get_values();
let offset = 0; let offset = 0;
let vfade = scrollView.get_effect("fade"); let vfade = scrollView.get_effect("fade");
@ -424,8 +424,97 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
else else
return; return;
adjustment.ease(value, { Tweener.addTween(adjustment,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, { value: value,
duration: SCROLL_TIME time: SCROLL_TIME,
}); transition: 'easeOutQuad' });
} }
var AppSettingsMonitor = class {
constructor(appId, schemaId) {
this._appId = appId;
this._schemaId = schemaId;
this._app = null;
this._settings = null;
this._handlers = [];
this._schemaSource = Gio.SettingsSchemaSource.get_default();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed',
this._onInstalledChanged.bind(this));
this._onInstalledChanged();
}
get available() {
return this._app != null && this._settings != null;
}
activateApp() {
if (this._app)
this._app.activate();
}
watchSetting(key, callback) {
let handler = { id: 0, key: key, callback: callback };
this._handlers.push(handler);
this._connectHandler(handler);
}
_connectHandler(handler) {
if (!this._settings || handler.id > 0)
return;
handler.id = this._settings.connect('changed::' + handler.key,
handler.callback);
handler.callback(this._settings, handler.key);
}
_disconnectHandler(handler) {
if (this._settings && handler.id > 0)
this._settings.disconnect(handler.id);
handler.id = 0;
}
_onInstalledChanged() {
let hadApp = (this._app != null);
this._app = this._appSystem.lookup_app(this._appId);
let haveApp = (this._app != null);
if (hadApp == haveApp)
return;
if (haveApp)
this._checkSettings();
else
this._setSettings(null);
}
_setSettings(settings) {
this._handlers.forEach((handler) => { this._disconnectHandler(handler); });
let hadSettings = (this._settings != null);
this._settings = settings;
let haveSettings = (this._settings != null);
this._handlers.forEach((handler) => { this._connectHandler(handler); });
if (hadSettings != haveSettings)
this.emit('available-changed');
}
_checkSettings() {
let schema = this._schemaSource.lookup(this._schemaId, true);
if (schema) {
this._setSettings(new Gio.Settings({ settings_schema: schema }));
} else if (this._app) {
Mainloop.timeout_add_seconds(1, () => {
this._checkSettings();
return GLib.SOURCE_REMOVE;
});
}
}
};
Signals.addSignalMethods(AppSettingsMonitor.prototype);

View File

@ -1,19 +1,10 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { Geoclue, Gio, GLib, GWeather, Shell } = imports.gi; const { Geoclue, Gio, GLib, GWeather } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const PermissionStore = imports.misc.permissionStore; const PermissionStore = imports.misc.permissionStore;
const Util = imports.misc.util;
const { loadInterfaceXML } = imports.misc.fileUtils;
const WeatherIntegrationIface = loadInterfaceXML('org.gnome.Shell.WeatherIntegration');
const WEATHER_BUS_NAME = 'org.gnome.Weather';
const WEATHER_OBJECT_PATH = '/org/gnome/Weather';
const WEATHER_INTEGRATION_IFACE = 'org.gnome.Shell.WeatherIntegration';
const WEATHER_APP_ID = 'org.gnome.Weather.desktop';
// Minimum time between updates to show loading indication // Minimum time between updates to show loading indication
var UPDATE_THRESHOLD = 10 * GLib.TIME_SPAN_MINUTE; var UPDATE_THRESHOLD = 10 * GLib.TIME_SPAN_MINUTE;
@ -35,7 +26,7 @@ var WeatherClient = class {
this._weatherAuthorized = false; this._weatherAuthorized = false;
this._permStore = new PermissionStore.PermissionStore((proxy, error) => { this._permStore = new PermissionStore.PermissionStore((proxy, error) => {
if (error) { if (error) {
log(`Failed to connect to permissionStore: ${error.message}`); log('Failed to connect to permissionStore: ' + error.message);
return; return;
} }
@ -49,7 +40,7 @@ var WeatherClient = class {
this._permStore.LookupRemote('gnome', 'geolocation', (res, error) => { this._permStore.LookupRemote('gnome', 'geolocation', (res, error) => {
if (error) if (error)
log(`Error looking up permission: ${error.message}`); log('Error looking up permission: ' + error.message);
let [perms, data] = error ? [{}, null] : res; let [perms, data] = error ? [{}, null] : res;
let params = ['gnome', 'geolocation', false, data, perms]; let params = ['gnome', 'geolocation', false, data, perms];
@ -75,38 +66,17 @@ var WeatherClient = class {
this.emit('changed'); this.emit('changed');
}); });
this._weatherApp = null; this._weatherAppMon = new Util.AppSettingsMonitor('org.gnome.Weather.desktop',
this._weatherProxy = null; 'org.gnome.Weather');
this._weatherAppMon.connect('available-changed', () => { this.emit('changed'); });
let nodeInfo = Gio.DBusNodeInfo.new_for_xml(WeatherIntegrationIface); this._weatherAppMon.watchSetting('automatic-location',
Gio.DBusProxy.new( this._onAutomaticLocationChanged.bind(this));
Gio.DBus.session, this._weatherAppMon.watchSetting('locations',
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES, this._onLocationsChanged.bind(this));
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'
});
this._settings.connect('changed::automatic-location',
this._onAutomaticLocationChanged.bind(this));
this._onAutomaticLocationChanged();
this._settings.connect('changed::locations',
this._onLocationsChanged.bind(this));
this._onLocationsChanged();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed',
this._onInstalledChanged.bind(this));
this._onInstalledChanged();
} }
get available() { get available() {
return this._weatherApp != null; return this._weatherAppMon.available;
} }
get loading() { get loading() {
@ -122,8 +92,7 @@ var WeatherClient = class {
} }
activateApp() { activateApp() {
if (this._weatherApp) this._weatherAppMon.activateApp();
this._weatherApp.activate();
} }
update() { update() {
@ -145,38 +114,6 @@ var WeatherClient = class {
this._weatherAuthorized; this._weatherAuthorized;
} }
_onWeatherProxyReady(o, res) {
try {
this._weatherProxy = Gio.DBusProxy.new_finish(res);
} catch (e) {
log(`Failed to create GNOME Weather proxy: ${e}`);
return;
}
this._weatherProxy.connect('g-properties-changed',
this._onWeatherPropertiesChanged.bind(this));
this._onWeatherPropertiesChanged();
}
_onWeatherPropertiesChanged() {
if (this._weatherProxy.g_name_owner == null)
return;
this._settings.set_boolean('automatic-location',
this._weatherProxy.AutomaticLocation);
this._settings.set_value('locations',
new GLib.Variant('av', this._weatherProxy.Locations));
}
_onInstalledChanged() {
let hadApp = (this._weatherApp != null);
this._weatherApp = this._appSystem.lookup_app(WEATHER_APP_ID);
let haveApp = (this._weatherApp != null);
if (hadApp !== haveApp)
this.emit('changed');
}
_loadInfo() { _loadInfo() {
let id = this._weatherInfo.connect('updated', () => { let id = this._weatherInfo.connect('updated', () => {
this._weatherInfo.disconnect(id); this._weatherInfo.disconnect(id);
@ -241,8 +178,8 @@ var WeatherClient = class {
(o, res) => { (o, res) => {
try { try {
this._gclueService = Geoclue.Simple.new_finish(res); this._gclueService = Geoclue.Simple.new_finish(res);
} catch (e) { } catch(e) {
log(`Failed to connect to Geoclue2 service: ${e.message}`); log('Failed to connect to Geoclue2 service: ' + e.message);
this._setLocation(this._mostRecentLocation); this._setLocation(this._mostRecentLocation);
return; return;
} }
@ -261,8 +198,8 @@ var WeatherClient = class {
this._setLocation(location); this._setLocation(location);
} }
_onAutomaticLocationChanged() { _onAutomaticLocationChanged(settings, key) {
let useAutoLocation = this._settings.get_boolean('automatic-location'); let useAutoLocation = settings.get_boolean(key);
if (this._autoLocationRequested == useAutoLocation) if (this._autoLocationRequested == useAutoLocation)
return; return;
@ -280,9 +217,8 @@ var WeatherClient = class {
this._setLocation(this._mostRecentLocation); this._setLocation(this._mostRecentLocation);
} }
_onLocationsChanged() { _onLocationsChanged(settings, key) {
let locations = this._settings.get_value('locations').deep_unpack(); let serialized = settings.get_value(key).deep_unpack().shift();
let serialized = locations.shift();
let mostRecentLocation = null; let mostRecentLocation = null;
if (serialized) if (serialized)
@ -298,7 +234,7 @@ var WeatherClient = class {
} }
_onPermStoreChanged(proxy, sender, params) { _onPermStoreChanged(proxy, sender, params) {
let [table, id, deleted_, data_, perms] = params; let [table, id, deleted, data, perms] = params;
if (table != 'gnome' || id != 'geolocation') if (table != 'gnome' || id != 'geolocation')
return; return;

View File

@ -1,9 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported run, script_overviewShowStart, script_overviewShowDone,
script_applicationsShowStart, script_applicationsShowDone,
script_afterShowHide, malloc_usedSize, glx_swapComplete,
clutter_stagePaintDone */
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^malloc", "^glx", "^clutter"] }] */
const System = imports.system; const System = imports.system;
@ -24,7 +19,7 @@ var METRICS = {
units: "frames / s" }, units: "frames / s" },
overviewLatencySubsequent: overviewLatencySubsequent:
{ description: "Time to first frame after triggering overview, second time", { description: "Time to first frame after triggering overview, second time",
units: "us" }, units: "us"},
overviewFpsSubsequent: overviewFpsSubsequent:
{ description: "Frames rate when going to the overview, second time", { description: "Frames rate when going to the overview, second time",
units: "frames / s" }, units: "frames / s" },
@ -57,7 +52,7 @@ var METRICS = {
units: "us" }, units: "us" },
applicationsShowTimeSubsequent: applicationsShowTimeSubsequent:
{ description: "Time to switch to applications view, second time", { description: "Time to switch to applications view, second time",
units: "us" } units: "us"}
}; };
let WINDOW_CONFIGS = [ let WINDOW_CONFIGS = [
@ -126,11 +121,9 @@ function *run() {
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates
Main.overview._dash.showAppsButton.checked = true; Main.overview._dash.showAppsButton.checked = true;
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
// eslint-disable-next-line require-atomic-updates
Main.overview._dash.showAppsButton.checked = false; Main.overview._dash.showAppsButton.checked = false;
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
} }
@ -143,6 +136,7 @@ let overviewFrames;
let overviewLatency; let overviewLatency;
let mallocUsedSize = 0; let mallocUsedSize = 0;
let overviewShowCount = 0; let overviewShowCount = 0;
let firstOverviewUsedSize;
let haveSwapComplete = false; let haveSwapComplete = false;
let applicationsShowStart; let applicationsShowStart;
let applicationsShowCount = 0; let applicationsShowCount = 0;
@ -154,7 +148,7 @@ function script_overviewShowStart(time) {
overviewFrames = 0; overviewFrames = 0;
} }
function script_overviewShowDone(_time) { function script_overviewShowDone(time) {
// We've set up the state at the end of the zoom out, but we // We've set up the state at the end of the zoom out, but we
// need to wait for one more frame to paint before we count // need to wait for one more frame to paint before we count
// ourselves as done. // ourselves as done.
@ -173,7 +167,7 @@ function script_applicationsShowDone(time) {
METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart; METRICS.applicationsShowTimeSubsequent.value = time - applicationsShowStart;
} }
function script_afterShowHide(_time) { function script_afterShowHide(time) {
if (overviewShowCount == 1) { if (overviewShowCount == 1) {
METRICS.usedAfterOverview.value = mallocUsedSize; METRICS.usedAfterOverview.value = mallocUsedSize;
} else { } else {

View File

@ -1,12 +1,3 @@
/* exported run, script_desktopShown, script_overviewShowStart,
script_overviewShowDone, script_applicationsShowStart,
script_applicationsShowDone, script_mainViewDrawStart,
script_mainViewDrawDone, script_overviewDrawStart,
script_overviewDrawDone, script_redrawTestStart,
script_redrawTestDone, script_collectTimings,
script_geditLaunch, script_geditFirstFrame,
clutter_stagePaintStart, clutter_paintCompletedTimestamp */
/* eslint camelcase: ["error", { properties: "never", allow: ["^script_", "^clutter"] }] */
const { Clutter, Gio, Shell } = imports.gi; const { Clutter, Gio, Shell } = imports.gi;
const Main = imports.ui.main; const Main = imports.ui.main;
const Scripting = imports.ui.scripting; const Scripting = imports.ui.scripting;
@ -39,7 +30,7 @@ var METRICS = {
geditStartTime: geditStartTime:
{ description: "Time from gedit launch to window drawn", { description: "Time from gedit launch to window drawn",
units: "us" }, units: "us" },
}; }
function waitAndDraw(milliseconds) { function waitAndDraw(milliseconds) {
let cb; let cb;
@ -47,7 +38,7 @@ function waitAndDraw(milliseconds) {
let timeline = new Clutter.Timeline({ duration: milliseconds }); let timeline = new Clutter.Timeline({ duration: milliseconds });
timeline.start(); timeline.start();
timeline.connect('new-frame', (_timeline, _frame) => { timeline.connect('new-frame', (timeline, frame) => {
global.stage.queue_redraw(); global.stage.queue_redraw();
}); });
@ -57,7 +48,7 @@ function waitAndDraw(milliseconds) {
cb(); cb();
}); });
return callback => (cb = callback); return callback => { cb = callback; };
} }
function waitSignal(object, signal) { function waitSignal(object, signal) {
@ -69,7 +60,7 @@ function waitSignal(object, signal) {
cb(); cb();
}); });
return callback => (cb = callback); return callback => { cb = callback; };
} }
function extractBootTimestamp() { function extractBootTimestamp() {
@ -82,8 +73,8 @@ function extractBootTimestamp() {
let result = null; let result = null;
let datastream = Gio.DataInputStream.new(sp.get_stdout_pipe()); let datastream = Gio.DataInputStream.new(sp.get_stdout_pipe());
while (true) { // eslint-disable-line no-constant-condition while (true) {
let [line, length_] = datastream.read_line_utf8(null); let [line, length] = datastream.read_line_utf8(null);
if (line === null) if (line === null)
break; break;
@ -126,7 +117,6 @@ function *run() {
yield Scripting.sleep(1000); yield Scripting.sleep(1000);
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates
Main.overview._dash.showAppsButton.checked = true; Main.overview._dash.showAppsButton.checked = true;
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
@ -137,9 +127,9 @@ function *run() {
Main.overview.hide(); Main.overview.hide();
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
// --------------------- // ////////////////////////////////////////
// Tests of redraw speed // // Tests of redraw speed
// --------------------- // ////////////////////////////////////////
global.frame_timestamps = true; global.frame_timestamps = true;
global.frame_finish_timestamp = true; global.frame_finish_timestamp = true;
@ -167,7 +157,7 @@ function *run() {
Main.overview.hide(); Main.overview.hide();
yield Scripting.createTestWindow({ maximized: true, yield Scripting.createTestWindow({ maximized: true,
redraws: true }); redraws: true});
yield Scripting.waitTestWindows(); yield Scripting.waitTestWindows();
yield Scripting.sleep(1000); yield Scripting.sleep(1000);
@ -186,6 +176,8 @@ function *run() {
yield Scripting.sleep(1000); yield Scripting.sleep(1000);
////////////////////////////////////////
let appSys = Shell.AppSystem.get_default(); let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('org.gnome.gedit.desktop'); let app = appSys.lookup_app('org.gnome.gedit.desktop');
@ -242,31 +234,31 @@ function script_applicationsShowDone(time) {
METRICS.applicationsShowTime.value = time - applicationsShowStart; METRICS.applicationsShowTime.value = time - applicationsShowStart;
} }
function script_mainViewDrawStart(_time) { function script_mainViewDrawStart(time) {
redrawTiming = 'mainView'; redrawTiming = 'mainView';
} }
function script_mainViewDrawDone(_time) { function script_mainViewDrawDone(time) {
redrawTiming = null; redrawTiming = null;
} }
function script_overviewDrawStart(_time) { function script_overviewDrawStart(time) {
redrawTiming = 'overview'; redrawTiming = 'overview';
} }
function script_overviewDrawDone(_time) { function script_overviewDrawDone(time) {
redrawTiming = null; redrawTiming = null;
} }
function script_redrawTestStart(_time) { function script_redrawTestStart(time) {
redrawTiming = 'application'; redrawTiming = 'application';
} }
function script_redrawTestDone(_time) { function script_redrawTestDone(time) {
redrawTiming = null; redrawTiming = null;
} }
function script_collectTimings(_time) { function script_collectTimings(time) {
for (let timing in redrawTimes) { for (let timing in redrawTimes) {
let times = redrawTimes[timing]; let times = redrawTimes[timing];
times.sort((a, b) => a - b); times.sort((a, b) => a - b);
@ -277,11 +269,11 @@ function script_collectTimings(_time) {
if (len == 0) if (len == 0)
median = -1; median = -1;
else if (len % 2 == 1) else if (len % 2 == 1)
median = times[(len - 1) / 2]; median = times[(len - 1)/ 2];
else else
median = Math.round((times[len / 2 - 1] + times[len / 2]) / 2); median = Math.round((times[len / 2 - 1] + times[len / 2]) / 2);
METRICS[`${timing}RedrawTime`].value = median; METRICS[timing + 'RedrawTime'].value = median;
} }
} }

View File

@ -1,4 +1,3 @@
/* exported main */
const Format = imports.format; const Format = imports.format;
const Gettext = imports.gettext; const Gettext = imports.gettext;
const { Gio, GLib, GObject, Gtk, Pango, Soup, WebKit2: WebKit } = imports.gi; const { Gio, GLib, GObject, Gtk, Pango, Soup, WebKit2: WebKit } = imports.gi;
@ -20,6 +19,7 @@ const PortalHelperSecurityLevel = {
INSECURE: 2 INSECURE: 2
}; };
const INACTIVITY_TIMEOUT = 30000; //ms
const CONNECTIVITY_CHECK_HOST = 'nmcheck.gnome.org'; const CONNECTIVITY_CHECK_HOST = 'nmcheck.gnome.org';
const CONNECTIVITY_CHECK_URI = 'http://' + CONNECTIVITY_CHECK_HOST; const CONNECTIVITY_CHECK_URI = 'http://' + CONNECTIVITY_CHECK_HOST;
const CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT = 30 * GLib.USEC_PER_SEC; const CONNECTIVITY_RECHECK_RATELIMIT_TIMEOUT = 30 * GLib.USEC_PER_SEC;
@ -59,7 +59,7 @@ class PortalHeaderBar extends Gtk.HeaderBar {
single_line_mode: true, single_line_mode: true,
ellipsize: Pango.EllipsizeMode.END, ellipsize: Pango.EllipsizeMode.END,
valign: Gtk.Align.BASELINE, valign: Gtk.Align.BASELINE,
selectable: true }); selectable: true});
this.subtitleLabel.get_style_context().add_class('subtitle'); this.subtitleLabel.get_style_context().add_class('subtitle');
hbox.add(this.subtitleLabel); hbox.add(this.subtitleLabel);
@ -152,7 +152,7 @@ class PortalWindow extends Gtk.ApplicationWindow {
this._webView.load_uri(this._originalUrl); this._webView.load_uri(this._originalUrl);
} }
vfunc_delete_event(_event) { vfunc_delete_event(event) {
if (this._recheckAtExit) if (this._recheckAtExit)
this._doneCallback(PortalHelperResult.RECHECK); this._doneCallback(PortalHelperResult.RECHECK);
else else
@ -178,7 +178,7 @@ class PortalWindow extends Gtk.ApplicationWindow {
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE); this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
} }
_onLoadFailedWithTlsErrors(view, failingURI, certificate, _errors) { _onLoadFailedWithTlsErrors(view, failingURI, certificate, errors) {
this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE); this._headerBar.setSecurityIcon(PortalHelperSecurityLevel.INSECURE);
let uri = new Soup.URI(failingURI); let uri = new Soup.URI(failingURI);
this._webContext.allow_tls_certificate_for_host(certificate, uri.get_host()); this._webContext.allow_tls_certificate_for_host(certificate, uri.get_host());
@ -265,7 +265,7 @@ class WebPortalHelper extends Gtk.Application {
this._queue = []; this._queue = [];
let action = new Gio.SimpleAction({ name: 'quit' }); let action = new Gio.SimpleAction({ name: 'quit' });
action.connect('activate', () => this.active_window.destroyWindow()); action.connect('activate', () => { this.active_window.destroyWindow(); });
this.add_action(action); this.add_action(action);
} }

View File

@ -1,5 +1,4 @@
/* exported AccessDialogDBus */ const { Clutter, Gio, GLib, Shell } = imports.gi;
const { Clutter, Gio, GLib, GObject, Shell } = imports.gi;
const CheckBox = imports.ui.checkBox; const CheckBox = imports.ui.checkBox;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
@ -16,10 +15,9 @@ var DialogResponse = {
CLOSED: 2 CLOSED: 2
}; };
var AccessDialog = GObject.registerClass( var AccessDialog = class extends ModalDialog.ModalDialog {
class AccessDialog extends ModalDialog.ModalDialog { constructor(invocation, handle, title, subtitle, body, options) {
_init(invocation, handle, title, subtitle, body, options) { super({ styleClass: 'access-dialog' });
super._init({ styleClass: 'access-dialog' });
this._invocation = invocation; this._invocation = invocation;
this._handle = handle; this._handle = handle;
@ -70,7 +68,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
this.addButton({ label: grantLabel, this.addButton({ label: grantLabel,
action: () => { action: () => {
this._sendResponse(DialogResponse.OK); this._sendResponse(DialogResponse.OK);
} }); }});
} }
open() { open() {
@ -80,7 +78,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
this._requestExported = this._request.export(connection, this._handle); this._requestExported = this._request.export(connection, this._handle);
} }
CloseAsync(invocation, _params) { CloseAsync(invocation, params) {
if (this._invocation.get_sender() != invocation.get_sender()) { if (this._invocation.get_sender() != invocation.get_sender()) {
invocation.return_error_literal(Gio.DBusError, invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED, Gio.DBusError.ACCESS_DENIED,
@ -111,7 +109,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
}); });
this.close(); this.close();
} }
}); };
var AccessDialogDBus = class { var AccessDialogDBus = class {
constructor() { constructor() {
@ -133,10 +131,10 @@ var AccessDialogDBus = class {
return; return;
} }
let [handle, appId, parentWindow_, title, subtitle, body, options] = params; let [handle, appId, parentWindow, title, subtitle, body, options] = params;
// We probably want to use parentWindow and global.display.focus_window // We probably want to use parentWindow and global.display.focus_window
// for this check in the future // for this check in the future
if (appId && `${appId}.desktop` != this._windowTracker.focus_app.id) { if (appId && appId + '.desktop' != this._windowTracker.focus_app.id) {
invocation.return_error_literal(Gio.DBusError, invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED, Gio.DBusError.ACCESS_DENIED,
'Only the focused app is allowed to show a system access dialog'); 'Only the focused app is allowed to show a system access dialog');
@ -147,7 +145,7 @@ var AccessDialogDBus = class {
subtitle, body, options); subtitle, body, options);
dialog.open(); dialog.open();
dialog.connect('closed', () => (this._accessDialog = null)); dialog.connect('closed', () => { this._accessDialog = null; });
this._accessDialog = dialog; this._accessDialog = dialog;
} }

View File

@ -1,17 +1,17 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported AppSwitcherPopup, GroupCyclerPopup, WindowSwitcherPopup,
WindowCyclerPopup */
const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Main = imports.ui.main; const Main = imports.ui.main;
const SwitcherPopup = imports.ui.switcherPopup; const SwitcherPopup = imports.ui.switcherPopup;
const Tweener = imports.ui.tweener;
var APP_ICON_HOVER_TIMEOUT = 200; // milliseconds var APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
var THUMBNAIL_DEFAULT_SIZE = 256; var THUMBNAIL_DEFAULT_SIZE = 256;
var THUMBNAIL_POPUP_TIME = 500; // milliseconds var THUMBNAIL_POPUP_TIME = 500; // milliseconds
var THUMBNAIL_FADE_TIME = 100; // milliseconds var THUMBNAIL_FADE_TIME = 0.1; // seconds
var WINDOW_PREVIEW_SIZE = 128; var WINDOW_PREVIEW_SIZE = 128;
var APP_ICON_SIZE = 96; var APP_ICON_SIZE = 96;
@ -36,7 +36,7 @@ function _createWindowClone(window, size) {
// usual hack for the usual bug in ClutterBinLayout... // usual hack for the usual bug in ClutterBinLayout...
x_expand: true, x_expand: true,
y_expand: true }); y_expand: true });
} };
function getWindows(workspace) { function getWindows(workspace) {
// We ignore skip-taskbar windows in switchers, but if they are attached // We ignore skip-taskbar windows in switchers, but if they are attached
@ -87,9 +87,9 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
let hPadding = leftPadding + rightPadding; let hPadding = leftPadding + rightPadding;
let icon = this._items[this._selectedIndex]; let icon = this._items[this._selectedIndex];
let [posX] = icon.get_transformed_position(); let [posX, posY] = icon.get_transformed_position();
let thumbnailCenter = posX + icon.width / 2; let thumbnailCenter = posX + icon.width / 2;
let [, childNaturalWidth] = this._thumbnails.get_preferred_width(-1); let [childMinWidth, childNaturalWidth] = this._thumbnails.get_preferred_width(-1);
childBox.x1 = Math.max(primary.x + leftPadding, Math.floor(thumbnailCenter - childNaturalWidth / 2)); childBox.x1 = Math.max(primary.x + leftPadding, Math.floor(thumbnailCenter - childNaturalWidth / 2));
if (childBox.x1 + childNaturalWidth > primary.x + primary.width - hPadding) { if (childBox.x1 + childNaturalWidth > primary.x + primary.width - hPadding) {
let offset = childBox.x1 + childNaturalWidth - primary.width + hPadding; let offset = childBox.x1 + childNaturalWidth - primary.width + hPadding;
@ -103,7 +103,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
childBox.x2 = primary.x + primary.width - rightPadding; childBox.x2 = primary.x + primary.width - rightPadding;
childBox.y1 = this._switcherList.allocation.y2 + spacing; childBox.y1 = this._switcherList.allocation.y2 + spacing;
this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1); this._thumbnails.addClones(primary.y + primary.height - bottomPadding - childBox.y1);
let [, childNaturalHeight] = this._thumbnails.get_preferred_height(-1); let [childMinHeight, childNaturalHeight] = this._thumbnails.get_preferred_height(-1);
childBox.y2 = childBox.y1 + childNaturalHeight; childBox.y2 = childBox.y1 + childNaturalHeight;
this._thumbnails.allocate(childBox, flags); this._thumbnails.allocate(childBox, flags);
} }
@ -291,7 +291,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
if (this._thumbnails) if (this._thumbnails)
this._destroyThumbnails(); this._destroyThumbnails();
if (this._thumbnailTimeoutId != 0) if (this._thumbnailTimeoutId != 0)
GLib.source_remove(this._thumbnailTimeoutId); Mainloop.source_remove(this._thumbnailTimeoutId);
} }
/** /**
@ -326,7 +326,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
} }
if (this._thumbnailTimeoutId != 0) { if (this._thumbnailTimeoutId != 0) {
GLib.source_remove(this._thumbnailTimeoutId); Mainloop.source_remove(this._thumbnailTimeoutId);
this._thumbnailTimeoutId = 0; this._thumbnailTimeoutId = 0;
} }
@ -343,8 +343,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._thumbnails.highlight(window, forceAppFocus); this._thumbnails.highlight(window, forceAppFocus);
} else if (this._items[this._selectedIndex].cachedWindows.length > 1 && } else if (this._items[this._selectedIndex].cachedWindows.length > 1 &&
!forceAppFocus) { !forceAppFocus) {
this._thumbnailTimeoutId = GLib.timeout_add( this._thumbnailTimeoutId = Mainloop.timeout_add (
GLib.PRIORITY_DEFAULT,
THUMBNAIL_POPUP_TIME, THUMBNAIL_POPUP_TIME,
this._timeoutPopupThumbnails.bind(this)); this._timeoutPopupThumbnails.bind(this));
GLib.Source.set_name_by_id(this._thumbnailTimeoutId, '[gnome-shell] this._timeoutPopupThumbnails'); GLib.Source.set_name_by_id(this._thumbnailTimeoutId, '[gnome-shell] this._timeoutPopupThumbnails');
@ -361,15 +360,15 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
_destroyThumbnails() { _destroyThumbnails() {
let thumbnailsActor = this._thumbnails; let thumbnailsActor = this._thumbnails;
this._thumbnails.ease({ Tweener.addTween(thumbnailsActor,
opacity: 0, { opacity: 0,
duration: THUMBNAIL_FADE_TIME, time: THUMBNAIL_FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete: () => {
thumbnailsActor.destroy(); thumbnailsActor.destroy();
this.thumbnailsVisible = false; this.thumbnailsVisible = false;
} }
}); });
this._thumbnails = null; this._thumbnails = null;
if (this._switcherList._items[this._selectedIndex]) if (this._switcherList._items[this._selectedIndex])
this._switcherList._items[this._selectedIndex].remove_accessible_state (Atk.StateType.EXPANDED); this._switcherList._items[this._selectedIndex].remove_accessible_state (Atk.StateType.EXPANDED);
@ -392,14 +391,12 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._thumbnails.get_allocation_box(); this._thumbnails.get_allocation_box();
this._thumbnails.opacity = 0; this._thumbnails.opacity = 0;
this._thumbnails.ease({ Tweener.addTween(this._thumbnails,
opacity: 255, { opacity: 255,
duration: THUMBNAIL_FADE_TIME, time: THUMBNAIL_FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete: () => { this.thumbnailsVisible = true; }
this.thumbnailsVisible = true; });
}
});
this._switcherList._items[this._selectedIndex].add_accessible_state (Atk.StateType.EXPANDED); this._switcherList._items[this._selectedIndex].add_accessible_state (Atk.StateType.EXPANDED);
} }
@ -437,8 +434,8 @@ class CyclerHighlight {
if (this._clone.source) if (this._clone.source)
this._clone.source.sync_visibility(); this._clone.source.sync_visibility();
let windowActor = this._window let windowActor = this._window ? this._window.get_compositor_private()
? this._window.get_compositor_private() : null; : null;
if (windowActor) if (windowActor)
windowActor.hide(); windowActor.hide();
@ -462,7 +459,7 @@ class CyclerHighlight {
_onDestroy() { _onDestroy() {
this.window = null; this.window = null;
} }
} };
// We don't show an actual popup, so just provide what SwitcherPopup // We don't show an actual popup, so just provide what SwitcherPopup
// expects instead of inheriting from SwitcherList // expects instead of inheriting from SwitcherList
@ -472,15 +469,17 @@ var CyclerList = GObject.registerClass({
'item-removed': { param_types: [GObject.TYPE_INT] }, 'item-removed': { param_types: [GObject.TYPE_INT] },
'item-highlighted': { param_types: [GObject.TYPE_INT] } }, 'item-highlighted': { param_types: [GObject.TYPE_INT] } },
}, class CyclerList extends St.Widget { }, class CyclerList extends St.Widget {
highlight(index, _justOutline) { highlight(index, justOutline) {
this.emit('item-highlighted', index); this.emit('item-highlighted', index);
} }
}); });
var CyclerPopup = GObject.registerClass({ var CyclerPopup = GObject.registerClass(
GTypeFlags: GObject.TypeFlags.ABSTRACT class CyclerPopup extends SwitcherPopup.SwitcherPopup {
}, class CyclerPopup extends SwitcherPopup.SwitcherPopup {
_init() { _init() {
if (new.target === CyclerPopup)
throw new TypeError('Cannot instantiate abstract class ' + new.target.name);
super._init(); super._init();
this._items = this._getWindows(); this._items = this._getWindows();
@ -497,7 +496,7 @@ var CyclerPopup = GObject.registerClass({
}); });
} }
_highlightItem(index, _justOutline) { _highlightItem(index, justOutline) {
this._highlight.window = this._items[index]; this._highlight.window = this._items[index];
global.window_group.set_child_above_sibling(this._highlight.actor, null); global.window_group.set_child_above_sibling(this._highlight.actor, null);
} }
@ -648,9 +647,8 @@ class WindowCyclerPopup extends CyclerPopup {
} }
}); });
var AppIcon = GObject.registerClass({ var AppIcon = GObject.registerClass(
GTypeName: 'AltTab_AppIcon' class AppIcon extends St.BoxLayout {
}, class AppIcon extends St.BoxLayout {
_init(app) { _init(app) {
super._init({ style_class: 'alt-tab-app', super._init({ style_class: 'alt-tab-app',
vertical: true }); vertical: true });
@ -664,10 +662,17 @@ var AppIcon = GObject.registerClass({
this.add(this.label, { x_fill: false }); this.add(this.label, { x_fill: false });
} }
// eslint-disable-next-line camelcase
set_size(size) { set_size(size) {
this.icon = this.app.create_icon_texture(size); this.icon = this.app.create_icon_texture(size);
this._iconBin.child = this.icon; this._iconBin.child = this.icon;
this._iconBin.set_size(size, size);
}
vfunc_get_preferred_width(forHeight) {
let [minWidth, ] = super.vfunc_get_preferred_width(forHeight);
minWidth = Math.max(minWidth, forHeight);
return [minWidth, minWidth];
} }
}); });
@ -712,7 +717,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
_onDestroy() { _onDestroy() {
if (this._mouseTimeOutId != 0) if (this._mouseTimeOutId != 0)
GLib.source_remove(this._mouseTimeOutId); Mainloop.source_remove(this._mouseTimeOutId);
this.icons.forEach(icon => { this.icons.forEach(icon => {
icon.app.disconnect(icon._stateChangedId); icon.app.disconnect(icon._stateChangedId);
@ -721,16 +726,15 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
_setIconSize() { _setIconSize() {
let j = 0; let j = 0;
while (this._items.length > 1 && this._items[j].style_class != 'item-box') { while(this._items.length > 1 && this._items[j].style_class != 'item-box') {
j++; j++;
} }
let themeNode = this._items[j].get_theme_node(); let themeNode = this._items[j].get_theme_node();
this._list.ensure_style();
let iconPadding = themeNode.get_horizontal_padding(); let iconPadding = themeNode.get_horizontal_padding();
let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT); let iconBorder = themeNode.get_border_width(St.Side.LEFT) + themeNode.get_border_width(St.Side.RIGHT);
let [, labelNaturalHeight] = this.icons[j].label.get_preferred_height(-1); let [iconMinHeight, iconNaturalHeight] = this.icons[j].label.get_preferred_height(-1);
let iconSpacing = labelNaturalHeight + iconPadding + iconBorder; let iconSpacing = iconNaturalHeight + iconPadding + iconBorder;
let totalSpacing = this._list.spacing * (this._items.length - 1); let totalSpacing = this._list.spacing * (this._items.length - 1);
// We just assume the whole screen here due to weirdness happing with the passed width // We just assume the whole screen here due to weirdness happing with the passed width
@ -743,7 +747,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
let iconSize = baseIconSizes[0]; let iconSize = baseIconSizes[0];
if (this._items.length > 1) { if (this._items.length > 1) {
for (let i = 0; i < baseIconSizes.length; i++) { for(let i = 0; i < baseIconSizes.length; i++) {
iconSize = baseIconSizes[i]; iconSize = baseIconSizes[i];
let height = iconSizes[i] + iconSpacing; let height = iconSizes[i] + iconSpacing;
let w = height * this._items.length + totalSpacing; let w = height * this._items.length + totalSpacing;
@ -754,7 +758,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
this._iconSize = iconSize; this._iconSize = iconSize;
for (let i = 0; i < this.icons.length; i++) { for(let i = 0; i < this.icons.length; i++) {
if (this.icons[i].icon != null) if (this.icons[i].icon != null)
break; break;
this.icons[i].set_size(iconSize); this.icons[i].set_size(iconSize);
@ -791,24 +795,21 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
// activation when the thumbnail list is open // activation when the thumbnail list is open
_onItemEnter(index) { _onItemEnter(index) {
if (this._mouseTimeOutId != 0) if (this._mouseTimeOutId != 0)
GLib.source_remove(this._mouseTimeOutId); Mainloop.source_remove(this._mouseTimeOutId);
if (this._altTabPopup.thumbnailsVisible) { if (this._altTabPopup.thumbnailsVisible) {
this._mouseTimeOutId = GLib.timeout_add( this._mouseTimeOutId = Mainloop.timeout_add(APP_ICON_HOVER_TIMEOUT,
GLib.PRIORITY_DEFAULT, () => {
APP_ICON_HOVER_TIMEOUT, this._enterItem(index);
() => { this._mouseTimeOutId = 0;
this._enterItem(index); return GLib.SOURCE_REMOVE;
this._mouseTimeOutId = 0; });
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._mouseTimeOutId, '[gnome-shell] this._enterItem'); GLib.Source.set_name_by_id(this._mouseTimeOutId, '[gnome-shell] this._enterItem');
} else { } else
this._itemEntered(index); this._itemEntered(index);
}
} }
_enterItem(index) { _enterItem(index) {
let [x, y] = global.get_pointer(); let [x, y, mask] = global.get_pointer();
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y); let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
if (this._items[index].contains(pickedActor)) if (this._items[index].contains(pickedActor))
this._itemEntered(index); this._itemEntered(index);
@ -849,8 +850,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
this._removeIcon(app); this._removeIcon(app);
}); });
let n = this._arrows.length;
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' }); let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
arrow.connect('repaint', () => SwitcherPopup.drawArrow(arrow, St.Side.BOTTOM)); arrow.connect('repaint', () => { SwitcherPopup.drawArrow(arrow, St.Side.BOTTOM); });
this.add_actor(arrow); this.add_actor(arrow);
this._arrows.push(arrow); this._arrows.push(arrow);
@ -877,9 +879,9 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
_init(windows) { _init(windows) {
super._init(false); super._init(false);
this._labels = []; this._labels = new Array();
this._thumbnailBins = []; this._thumbnailBins = new Array();
this._clones = []; this._clones = new Array();
this._windows = windows; this._windows = windows;
for (let i = 0; i < windows.length; i++) { for (let i = 0; i < windows.length; i++) {
@ -915,7 +917,7 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
return; return;
let totalPadding = this._items[0].get_theme_node().get_horizontal_padding() + this._items[0].get_theme_node().get_vertical_padding(); let totalPadding = this._items[0].get_theme_node().get_horizontal_padding() + this._items[0].get_theme_node().get_vertical_padding();
totalPadding += this.get_theme_node().get_horizontal_padding() + this.get_theme_node().get_vertical_padding(); totalPadding += this.get_theme_node().get_horizontal_padding() + this.get_theme_node().get_vertical_padding();
let [, labelNaturalHeight] = this._labels[0].get_preferred_height(-1); let [labelMinHeight, labelNaturalHeight] = this._labels[0].get_preferred_height(-1);
let spacing = this._items[0].child.get_theme_node().get_length('spacing'); let spacing = this._items[0].child.get_theme_node().get_length('spacing');
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
let thumbnailSize = THUMBNAIL_DEFAULT_SIZE * scaleFactor; let thumbnailSize = THUMBNAIL_DEFAULT_SIZE * scaleFactor;
@ -940,7 +942,7 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
} }
// Make sure we only do this once // Make sure we only do this once
this._thumbnailBins = []; this._thumbnailBins = new Array();
} }
_removeThumbnail(source, clone) { _removeThumbnail(source, clone) {
@ -991,32 +993,32 @@ class WindowIcon extends St.BoxLayout {
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
switch (mode) { switch (mode) {
case AppIconMode.THUMBNAIL_ONLY: case AppIconMode.THUMBNAIL_ONLY:
size = WINDOW_PREVIEW_SIZE; size = WINDOW_PREVIEW_SIZE;
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor)); this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
break; break;
case AppIconMode.BOTH: case AppIconMode.BOTH:
size = WINDOW_PREVIEW_SIZE; size = WINDOW_PREVIEW_SIZE;
this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor)); this._icon.add_actor(_createWindowClone(mutterWindow, size * scaleFactor));
if (this.app) if (this.app)
this._icon.add_actor(this._createAppIcon(this.app, this._icon.add_actor(this._createAppIcon(this.app,
APP_ICON_SIZE_SMALL)); APP_ICON_SIZE_SMALL));
break; break;
case AppIconMode.APP_ICON_ONLY: case AppIconMode.APP_ICON_ONLY:
size = APP_ICON_SIZE; size = APP_ICON_SIZE;
this._icon.add_actor(this._createAppIcon(this.app, size)); this._icon.add_actor(this._createAppIcon(this.app, size));
} }
this._icon.set_size(size * scaleFactor, size * scaleFactor); this._icon.set_size(size * scaleFactor, size * scaleFactor);
} }
_createAppIcon(app, size) { _createAppIcon(app, size) {
let appIcon = app let appIcon = app ? app.create_icon_texture(size)
? app.create_icon_texture(size) : new St.Icon({ icon_name: 'icon-missing',
: new St.Icon({ icon_name: 'icon-missing', icon_size: size }); icon_size: size });
appIcon.x_expand = appIcon.y_expand = true; appIcon.x_expand = appIcon.y_expand = true;
appIcon.x_align = appIcon.y_align = Clutter.ActorAlign.END; appIcon.x_align = appIcon.y_align = Clutter.ActorAlign.END;
@ -1043,8 +1045,8 @@ class WindowList extends SwitcherPopup.SwitcherList {
this.addItem(icon, icon.label); this.addItem(icon, icon.label);
this.icons.push(icon); this.icons.push(icon);
icon._unmanagedSignalId = icon.window.connect('unmanaged', window => { icon._unmanagedSignalId = icon.window.connect('unmanaged', (window) => {
this._removeWindow(window); this._removeWindow(window)
}); });
} }
@ -1080,7 +1082,7 @@ class WindowList extends SwitcherPopup.SwitcherList {
childBox.y1 = childBox.y2 - this._label.height; childBox.y1 = childBox.y2 - this._label.height;
this._label.allocate(childBox, flags); this._label.allocate(childBox, flags);
let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM); let totalLabelHeight = this._label.height + themeNode.get_padding(St.Side.BOTTOM)
childBox.x1 = box.x1; childBox.x1 = box.x1;
childBox.x2 = box.x2; childBox.x2 = box.x2;
childBox.y1 = box.y1; childBox.y1 = box.y1;

View File

@ -1,11 +1,13 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Animation, AnimatedIcon, Spinner */
const { Clutter, GLib, Gio, St } = imports.gi; const { GLib, Gio, St } = imports.gi;
const Mainloop = imports.mainloop;
const Tweener = imports.ui.tweener;
var ANIMATED_ICON_UPDATE_TIMEOUT = 16; var ANIMATED_ICON_UPDATE_TIMEOUT = 16;
var SPINNER_ANIMATION_TIME = 300; var SPINNER_ANIMATION_TIME = 0.3;
var SPINNER_ANIMATION_DELAY = 1000; var SPINNER_ANIMATION_DELAY = 1.0;
var Animation = class { var Animation = class {
constructor(file, width, height, speed) { constructor(file, width, height, speed) {
@ -44,7 +46,7 @@ var Animation = class {
stop() { stop() {
if (this._timeoutId > 0) { if (this._timeoutId > 0) {
GLib.source_remove(this._timeoutId); Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0; this._timeoutId = 0;
} }
@ -53,29 +55,19 @@ var Animation = class {
_loadFile(file, width, height) { _loadFile(file, width, height) {
let [validResourceScale, resourceScale] = this.actor.get_resource_scale(); let [validResourceScale, resourceScale] = this.actor.get_resource_scale();
let wasPlaying = this._isPlaying;
if (this._isPlaying)
this.stop();
this._isLoaded = false; this._isLoaded = false;
this.actor.destroy_all_children(); this.actor.destroy_all_children();
if (!validResourceScale) { if (!validResourceScale)
if (wasPlaying)
this.play();
return; return;
}
let textureCache = St.TextureCache.get_default(); let texture_cache = St.TextureCache.get_default();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._animations = textureCache.load_sliced_image(file, width, height, this._animations = texture_cache.load_sliced_image(file, width, height,
scaleFactor, resourceScale, scaleFactor, resourceScale,
this._animationsLoaded.bind(this)); this._animationsLoaded.bind(this));
this.actor.set_child(this._animations); this.actor.set_child(this._animations);
if (wasPlaying)
this.play();
} }
_showFrame(frame) { _showFrame(frame) {
@ -131,7 +123,7 @@ var AnimatedIcon = class extends Animation {
}; };
var Spinner = class extends AnimatedIcon { var Spinner = class extends AnimatedIcon {
constructor(size, animate = false) { constructor(size, animate=false) {
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg'); let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg');
super(file, size); super(file, size);
@ -145,15 +137,15 @@ var Spinner = class extends AnimatedIcon {
} }
play() { play() {
this.actor.remove_all_transitions(); Tweener.removeTweens(this.actor);
if (this._animate) { if (this._animate) {
super.play(); super.play();
this.actor.ease({ Tweener.addTween(this.actor, {
opacity: 255, opacity: 255,
delay: SPINNER_ANIMATION_DELAY, delay: SPINNER_ANIMATION_DELAY,
duration: SPINNER_ANIMATION_TIME, time: SPINNER_ANIMATION_TIME,
mode: Clutter.AnimationMode.LINEAR transition: 'linear'
}); });
} else { } else {
this.actor.opacity = 255; this.actor.opacity = 255;
@ -162,14 +154,16 @@ var Spinner = class extends AnimatedIcon {
} }
stop() { stop() {
this.actor.remove_all_transitions(); Tweener.removeTweens(this.actor);
if (this._animate) { if (this._animate) {
this.actor.ease({ Tweener.addTween(this.actor, {
opacity: 0, opacity: 0,
duration: SPINNER_ANIMATION_TIME, time: SPINNER_ANIMATION_TIME,
mode: Clutter.AnimationMode.LINEAR, transition: 'linear',
onComplete: () => super.stop() onComplete: () => {
this.stop(false);
}
}); });
} else { } else {
this.actor.opacity = 0; this.actor.opacity = 0;

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported getAppFavorites */
const Shell = imports.gi.Shell; const Shell = imports.gi.Shell;
const Signals = imports.signals; const Signals = imports.signals;
@ -64,7 +63,7 @@ class AppFavorites {
constructor() { constructor() {
this.FAVORITE_APPS_KEY = 'favorite-apps'; this.FAVORITE_APPS_KEY = 'favorite-apps';
this._favorites = {}; this._favorites = {};
global.settings.connect(`changed::${this.FAVORITE_APPS_KEY}`, this._onFavsChanged.bind(this)); global.settings.connect('changed::' + this.FAVORITE_APPS_KEY, this._onFavsChanged.bind(this));
this.reload(); this.reload();
} }
@ -147,11 +146,12 @@ class AppFavorites {
let app = Shell.AppSystem.get_default().lookup_app(appId); let app = Shell.AppSystem.get_default().lookup_app(appId);
let msg = _("%s has been added to your favorites.").format(app.get_name()); Main.overview.setMessage(_("%s has been added to your favorites.").format(app.get_name()),
Main.overview.setMessage(msg, { { forFeedback: true,
forFeedback: true, undoCallback: () => {
undoCallback: () => this._removeFavorite(appId), this._removeFavorite(appId);
}); }
});
} }
addFavorite(appId) { addFavorite(appId) {
@ -180,13 +180,14 @@ class AppFavorites {
if (!this._removeFavorite(appId)) if (!this._removeFavorite(appId))
return; return;
let msg = _("%s has been removed from your favorites.").format(app.get_name()); Main.overview.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
Main.overview.setMessage(msg, { { forFeedback: true,
forFeedback: true, undoCallback: () => {
undoCallback: () => this._addFavorite(appId, pos), this._addFavorite(appId, pos);
}); }
});
} }
} };
Signals.addSignalMethods(AppFavorites.prototype); Signals.addSignalMethods(AppFavorites.prototype);
var appFavoritesInstance = null; var appFavoritesInstance = null;

View File

@ -1,5 +1,4 @@
/* exported AudioDeviceSelectionDBus */ const { Clutter, Gio, GLib, Meta, Shell, St } = imports.gi;
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Main = imports.ui.main; const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog; const ModalDialog = imports.ui.modalDialog;
@ -14,11 +13,10 @@ var AudioDevice = {
const AudioDeviceSelectionIface = loadInterfaceXML('org.gnome.Shell.AudioDeviceSelection'); const AudioDeviceSelectionIface = loadInterfaceXML('org.gnome.Shell.AudioDeviceSelection');
var AudioDeviceSelectionDialog = GObject.registerClass({ var AudioDeviceSelectionDialog =
Signals: { 'device-selected': { param_types: [GObject.TYPE_UINT] } } class AudioDeviceSelectionDialog extends ModalDialog.ModalDialog {
}, class AudioDeviceSelectionDialog extends ModalDialog.ModalDialog { constructor(devices) {
_init(devices) { super({ styleClass: 'audio-device-selection-dialog' });
super._init({ styleClass: 'audio-device-selection-dialog' });
this._deviceItems = {}; this._deviceItems = {};
@ -35,7 +33,11 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
throw new Error('Too few devices for a selection'); throw new Error('Too few devices for a selection');
} }
_buildLayout() { destroy() {
super.destroy();
}
_buildLayout(devices) {
let title = new St.Label({ style_class: 'audio-selection-title', let title = new St.Label({ style_class: 'audio-selection-title',
text: _("Select Audio Device"), text: _("Select Audio Device"),
x_align: Clutter.ActorAlign.CENTER }); x_align: Clutter.ActorAlign.CENTER });
@ -55,28 +57,28 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
} }
_getDeviceLabel(device) { _getDeviceLabel(device) {
switch (device) { switch(device) {
case AudioDevice.HEADPHONES: case AudioDevice.HEADPHONES:
return _("Headphones"); return _("Headphones");
case AudioDevice.HEADSET: case AudioDevice.HEADSET:
return _("Headset"); return _("Headset");
case AudioDevice.MICROPHONE: case AudioDevice.MICROPHONE:
return _("Microphone"); return _("Microphone");
default: default:
return null; return null;
} }
} }
_getDeviceIcon(device) { _getDeviceIcon(device) {
switch (device) { switch(device) {
case AudioDevice.HEADPHONES: case AudioDevice.HEADPHONES:
return 'audio-headphones-symbolic'; return 'audio-headphones-symbolic';
case AudioDevice.HEADSET: case AudioDevice.HEADSET:
return 'audio-headset-symbolic'; return 'audio-headset-symbolic';
case AudioDevice.MICROPHONE: case AudioDevice.MICROPHONE:
return 'audio-input-microphone-symbolic'; return 'audio-input-microphone-symbolic';
default: default:
return null; return null;
} }
} }
@ -86,7 +88,6 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
box.connect('notify::height', () => { box.connect('notify::height', () => {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
box.width = box.height; box.width = box.height;
return GLib.SOURCE_REMOVE;
}); });
}); });
@ -112,11 +113,11 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
} }
_openSettings() { _openSettings() {
let desktopFile = 'gnome-sound-panel.desktop'; let desktopFile = 'gnome-sound-panel.desktop'
let app = Shell.AppSystem.get_default().lookup_app(desktopFile); let app = Shell.AppSystem.get_default().lookup_app(desktopFile);
if (!app) { if (!app) {
log(`Settings panel for desktop file ${desktopFile} could not be loaded!`); log('Settings panel for desktop file ' + desktopFile + ' could not be loaded!');
return; return;
} }
@ -124,7 +125,7 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
Main.overview.hide(); Main.overview.hide();
app.activate(); app.activate();
} }
}); };
var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus { var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
constructor() { constructor() {
@ -161,12 +162,12 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
let [deviceNames] = params; let [deviceNames] = params;
let devices = 0; let devices = 0;
deviceNames.forEach(n => (devices |= AudioDevice[n.toUpperCase()])); deviceNames.forEach(n => { devices |= AudioDevice[n.toUpperCase()]; });
let dialog; let dialog;
try { try {
dialog = new AudioDeviceSelectionDialog(devices); dialog = new AudioDeviceSelectionDialog(devices);
} catch (e) { } catch(e) {
invocation.return_value(null); invocation.return_value(null);
return; return;
} }

View File

@ -99,6 +99,7 @@ const Signals = imports.signals;
const LoginManager = imports.misc.loginManager; const LoginManager = imports.misc.loginManager;
const Main = imports.ui.main; const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
var DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff); var DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
@ -107,9 +108,10 @@ const PRIMARY_COLOR_KEY = 'primary-color';
const SECONDARY_COLOR_KEY = 'secondary-color'; const SECONDARY_COLOR_KEY = 'secondary-color';
const COLOR_SHADING_TYPE_KEY = 'color-shading-type'; const COLOR_SHADING_TYPE_KEY = 'color-shading-type';
const BACKGROUND_STYLE_KEY = 'picture-options'; const BACKGROUND_STYLE_KEY = 'picture-options';
const PICTURE_OPACITY_KEY = 'picture-opacity';
const PICTURE_URI_KEY = 'picture-uri'; const PICTURE_URI_KEY = 'picture-uri';
var FADE_ANIMATION_TIME = 1000; var FADE_ANIMATION_TIME = 1.0;
// These parameters affect how often we redraw. // These parameters affect how often we redraw.
// The first is how different (percent crossfaded) the slide show // The first is how different (percent crossfaded) the slide show
@ -255,15 +257,14 @@ var Background = class Background {
this._refreshAnimation(); this._refreshAnimation();
}); });
this._settingsChangedSignalId = this._settingsChangedSignalId = this._settings.connect('changed', () => {
this._settings.connect('changed', this._emitChangedSignal.bind(this)); this.emit('changed');
});
this._load(); this._load();
} }
destroy() { destroy() {
this.background = null;
this._cancellable.cancel(); this._cancellable.cancel();
this._removeAnimationTimeout(); this._removeAnimationTimeout();
@ -287,22 +288,6 @@ var Background = class Background {
if (this._settingsChangedSignalId != 0) if (this._settingsChangedSignalId != 0)
this._settings.disconnect(this._settingsChangedSignalId); this._settings.disconnect(this._settingsChangedSignalId);
this._settingsChangedSignalId = 0; this._settingsChangedSignalId = 0;
if (this._changedIdleId) {
GLib.source_remove(this._changedIdleId);
this._changedIdleId = 0;
}
}
_emitChangedSignal() {
if (this._changedIdleId)
return;
this._changedIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this._changedIdleId = 0;
this.emit('changed');
return GLib.SOURCE_REMOVE;
});
} }
updateResolution() { updateResolution() {
@ -332,12 +317,12 @@ var Background = class Background {
} }
_loadPattern() { _loadPattern() {
let colorString, res_, color, secondColor; let colorString, res, color, secondColor;
colorString = this._settings.get_string(PRIMARY_COLOR_KEY); colorString = this._settings.get_string(PRIMARY_COLOR_KEY);
[res_, color] = Clutter.Color.from_string(colorString); [res, color] = Clutter.Color.from_string(colorString);
colorString = this._settings.get_string(SECONDARY_COLOR_KEY); colorString = this._settings.get_string(SECONDARY_COLOR_KEY);
[res_, secondColor] = Clutter.Color.from_string(colorString); [res, secondColor] = Clutter.Color.from_string(colorString);
let shadingType = this._settings.get_enum(COLOR_SHADING_TYPE_KEY); let shadingType = this._settings.get_enum(COLOR_SHADING_TYPE_KEY);
@ -358,7 +343,7 @@ var Background = class Background {
if (changedFile.equal(file)) { if (changedFile.equal(file)) {
let imageCache = Meta.BackgroundImageCache.get_default(); let imageCache = Meta.BackgroundImageCache.get_default();
imageCache.purge(changedFile); imageCache.purge(changedFile);
this._emitChangedSignal(); this.emit('changed');
} }
}); });
this._fileWatches[key] = signalId; this._fileWatches[key] = signalId;
@ -431,31 +416,30 @@ var Background = class Background {
return; return;
this._updateAnimationTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, this._updateAnimationTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
interval, interval,
() => { () => {
this._updateAnimationTimeoutId = 0; this._updateAnimationTimeoutId = 0;
this._updateAnimation(); this._updateAnimation();
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
GLib.Source.set_name_by_id(this._updateAnimationTimeoutId, '[gnome-shell] this._updateAnimation'); GLib.Source.set_name_by_id(this._updateAnimationTimeoutId, '[gnome-shell] this._updateAnimation');
} }
_loadAnimation(file) { _loadAnimation(file) {
this._cache.getAnimation({ this._cache.getAnimation({ file: file,
file: file, settingsSchema: this._settings.schema_id,
settingsSchema: this._settings.schema_id, onLoaded: animation => {
onLoaded: animation => { this._animation = animation;
this._animation = animation;
if (!this._animation || this._cancellable.is_cancelled()) { if (!this._animation || this._cancellable.is_cancelled()) {
this._setLoaded(); this._setLoaded();
return; return;
} }
this._updateAnimation(); this._updateAnimation();
this._watchFile(file); this._watchFile(file);
} }
}); });
} }
_loadImage(file) { _loadImage(file) {
@ -464,9 +448,9 @@ var Background = class Background {
let cache = Meta.BackgroundImageCache.get_default(); let cache = Meta.BackgroundImageCache.get_default();
let image = cache.load(file); let image = cache.load(file);
if (image.is_loaded()) { if (image.is_loaded())
this._setLoaded(); this._setLoaded();
} else { else {
let id = image.connect('loaded', () => { let id = image.connect('loaded', () => {
this._setLoaded(); this._setLoaded();
image.disconnect(id); image.disconnect(id);
@ -633,9 +617,9 @@ var Animation = class Animation {
} }
load(callback) { load(callback) {
this._show = new GnomeDesktop.BGSlideShow({ file: this.file }); this._show = new GnomeDesktop.BGSlideShow({ filename: this.file.get_path() });
this._show.load_async(null, () => { this._show.load_async(null, (object, result) => {
this.loaded = true; this.loaded = true;
if (callback) if (callback)
callback(); callback();
@ -651,7 +635,7 @@ var Animation = class Animation {
if (this._show.get_num_slides() < 1) if (this._show.get_num_slides() < 1)
return; return;
let [progress, duration, isFixed_, filename1, filename2] = this._show.get_current_slide(monitor.width, monitor.height); let [progress, duration, isFixed, filename1, filename2] = this._show.get_current_slide(monitor.width, monitor.height);
this.transitionDuration = duration; this.transitionDuration = duration;
this.transitionProgress = progress; this.transitionProgress = progress;
@ -710,12 +694,15 @@ var BackgroundManager = class BackgroundManager {
this._newBackgroundActor = null; this._newBackgroundActor = null;
this.emit('changed'); this.emit('changed');
oldBackgroundActor.ease({ Tweener.addTween(oldBackgroundActor,
opacity: 0, { opacity: 0,
duration: FADE_ANIMATION_TIME, time: FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => oldBackgroundActor.destroy() onComplete() {
}); oldBackgroundActor.background.run_dispose();
oldBackgroundActor.destroy();
}
});
} }
_updateBackgroundActor() { _updateBackgroundActor() {
@ -749,14 +736,13 @@ var BackgroundManager = class BackgroundManager {
_createBackgroundActor() { _createBackgroundActor() {
let background = this._backgroundSource.getBackground(this._monitorIndex); let background = this._backgroundSource.getBackground(this._monitorIndex);
let backgroundActor = new Meta.BackgroundActor({ let backgroundActor = new Meta.BackgroundActor({ meta_display: global.display,
meta_display: global.display, monitor: this._monitorIndex,
monitor: this._monitorIndex, background: background.background,
background: background.background, vignette: this._vignette,
vignette: this._vignette, vignette_sharpness: 0.5,
vignette_sharpness: 0.5, brightness: 0.5,
brightness: 0.5, });
});
this._container.add_child(backgroundActor); this._container.add_child(backgroundActor);

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported addBackgroundMenu */
const { Clutter, St } = imports.gi; const { Clutter, St } = imports.gi;
@ -26,12 +25,12 @@ var BackgroundMenu = class BackgroundMenu extends PopupMenu.PopupMenu {
function addBackgroundMenu(actor, layoutManager) { function addBackgroundMenu(actor, layoutManager) {
actor.reactive = true; actor.reactive = true;
actor._backgroundMenu = new BackgroundMenu(layoutManager); actor._backgroundMenu = new BackgroundMenu(layoutManager);
actor._backgroundManager = new PopupMenu.PopupMenuManager(actor); actor._backgroundManager = new PopupMenu.PopupMenuManager({ actor: actor });
actor._backgroundManager.addMenu(actor._backgroundMenu); actor._backgroundManager.addMenu(actor._backgroundMenu);
function openMenu(x, y) { function openMenu(x, y) {
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0); Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
actor._backgroundMenu.open(BoxPointer.PopupAnimation.FULL); actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
} }
let clickAction = new Clutter.ClickAction(); let clickAction = new Clutter.ClickAction();

View File

@ -1,106 +1,74 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */ /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* exported BarLevel */
const { Atk, Clutter, GObject, St } = imports.gi; const { Atk, Clutter, St } = imports.gi;
const Signals = imports.signals;
var BarLevel = GObject.registerClass({ var BarLevel = class {
Properties: { constructor(value, params) {
'value': GObject.ParamSpec.double( if (isNaN(value))
'value', 'value', 'value', // Avoid spreading NaNs around
GObject.ParamFlags.READWRITE, throw TypeError('The bar level value must be a number');
0, 2, 0),
'maximum-value': GObject.ParamSpec.double(
'maximum-value', 'maximum-value', 'maximum-value',
GObject.ParamFlags.READWRITE,
1, 2, 1),
'overdrive-start': GObject.ParamSpec.double(
'overdrive-start', 'overdrive-start', 'overdrive-start',
GObject.ParamFlags.READWRITE,
1, 2, 1)
}
}, class BarLevel extends St.DrawingArea {
_init(params) {
this._maxValue = 1; this._maxValue = 1;
this._value = 0; this._value = Math.max(Math.min(value, this._maxValue), 0);
this._overdriveStart = 1; this._overdriveStart = 1;
this._barLevelWidth = 0; this._barLevelWidth = 0;
let defaultParams = { if (params == undefined)
style_class: 'barlevel', params = {}
accessible_role: Atk.Role.LEVEL_BAR
}; this.actor = new St.DrawingArea({ styleClass: params['styleClass'] || 'barlevel',
super._init(Object.assign(defaultParams, params)); can_focus: params['canFocus'] || false,
this.connect('allocation-changed', (actor, box) => { reactive: params['reactive'] || false,
accessible_role: params['accessibleRole'] || Atk.Role.LEVEL_BAR });
this.actor.connect('repaint', this._barLevelRepaint.bind(this));
this.actor.connect('allocation-changed', (actor, box) => {
this._barLevelWidth = box.get_width(); this._barLevelWidth = box.get_width();
}); });
this._customAccessible = St.GenericAccessible.new_for_actor(this); this._customAccessible = St.GenericAccessible.new_for_actor(this.actor);
this.set_accessible(this._customAccessible); this.actor.set_accessible(this._customAccessible);
this._customAccessible.connect('get-current-value', this._getCurrentValue.bind(this)); this._customAccessible.connect('get-current-value', this._getCurrentValue.bind(this));
this._customAccessible.connect('get-minimum-value', this._getMinimumValue.bind(this)); this._customAccessible.connect('get-minimum-value', this._getMinimumValue.bind(this));
this._customAccessible.connect('get-maximum-value', this._getMaximumValue.bind(this)); this._customAccessible.connect('get-maximum-value', this._getMaximumValue.bind(this));
this._customAccessible.connect('set-current-value', this._setCurrentValue.bind(this)); this._customAccessible.connect('set-current-value', this._setCurrentValue.bind(this));
this.connect('notify::value', this._valueChanged.bind(this)); this.connect('value-changed', this._valueChanged.bind(this));
} }
get value() { setValue(value) {
return this._value; if (isNaN(value))
throw TypeError('The bar level value must be a number');
this._value = Math.max(Math.min(value, this._maxValue), 0);
this.actor.queue_repaint();
} }
set value(value) { setMaximumValue(value) {
value = Math.max(Math.min(value, this._maxValue), 0); if (isNaN(value))
throw TypeError('The bar level max value must be a number');
if (this._value == value) this._maxValue = Math.max(value, 1);
return;
this._value = value;
this.notify('value');
this.queue_repaint();
}
// eslint-disable-next-line camelcase
get maximum_value() {
return this._maxValue;
}
// eslint-disable-next-line camelcase
set maximum_value(value) {
value = Math.max(value, 1);
if (this._maxValue == value)
return;
this._maxValue = value;
this._overdriveStart = Math.min(this._overdriveStart, this._maxValue); this._overdriveStart = Math.min(this._overdriveStart, this._maxValue);
this.notify('maximum-value'); this.actor.queue_repaint();
this.queue_repaint();
} }
// eslint-disable-next-line camelcase setOverdriveStart(value) {
get overdrive_start() { if (isNaN(value))
return this._overdriveStart; throw TypeError('The overdrive limit value must be a number');
}
// eslint-disable-next-line camelcase
set overdrive_start(value) {
if (this._overdriveStart == value)
return;
if (value > this._maxValue) if (value > this._maxValue)
throw new Error(`Tried to set overdrive value to ${value}, ` + throw new Error(`Tried to set overdrive value to ${value}, ` +
`which is a number greater than the maximum allowed value ${this._maxValue}`); `which is a number greater than the maximum allowed value ${this._maxValue}`);
this._overdriveStart = value; this._overdriveStart = value;
this.notify('overdrive-start'); this._value = Math.max(Math.min(value, this._maxValue), 0);
this.queue_repaint(); this.actor.queue_repaint();
} }
vfunc_repaint() { _barLevelRepaint(area) {
let cr = this.get_context(); let cr = area.get_context();
let themeNode = this.get_theme_node(); let themeNode = area.get_theme_node();
let [width, height] = this.get_surface_size(); let [width, height] = area.get_surface_size();
let barLevelHeight = themeNode.get_length('-barlevel-height'); let barLevelHeight = themeNode.get_length('-barlevel-height');
let barLevelBorderRadius = Math.min(width, barLevelHeight) / 2; let barLevelBorderRadius = Math.min(width, barLevelHeight) / 2;
@ -137,7 +105,7 @@ var BarLevel = GObject.registerClass({
overdriveSeparatorWidth = themeNode.get_length('-barlevel-overdrive-separator-width'); overdriveSeparatorWidth = themeNode.get_length('-barlevel-overdrive-separator-width');
/* background bar */ /* background bar */
cr.arc(width - barLevelBorderRadius - barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4)); cr.arc(width - barLevelBorderRadius - barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * 3 / 4, TAU * 1 / 4);
cr.lineTo(endX, (height + barLevelHeight) / 2); cr.lineTo(endX, (height + barLevelHeight) / 2);
cr.lineTo(endX, (height - barLevelHeight) / 2); cr.lineTo(endX, (height - barLevelHeight) / 2);
cr.lineTo(width - barLevelBorderRadius - barLevelBorderWidth, (height - barLevelHeight) / 2); cr.lineTo(width - barLevelBorderRadius - barLevelBorderWidth, (height - barLevelHeight) / 2);
@ -149,12 +117,11 @@ var BarLevel = GObject.registerClass({
/* normal progress bar */ /* normal progress bar */
let x = Math.min(endX, overdriveSeparatorX - overdriveSeparatorWidth / 2); let x = Math.min(endX, overdriveSeparatorX - overdriveSeparatorWidth / 2);
cr.arc(barLevelBorderRadius + barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * (1 / 4), TAU * (3 / 4)); cr.arc(barLevelBorderRadius + barLevelBorderWidth, height / 2, barLevelBorderRadius, TAU * 1 / 4, TAU * 3 / 4);
cr.lineTo(x, (height - barLevelHeight) / 2); cr.lineTo(x, (height - barLevelHeight) / 2);
cr.lineTo(x, (height + barLevelHeight) / 2); cr.lineTo(x, (height + barLevelHeight) / 2);
cr.lineTo(barLevelBorderRadius + barLevelBorderWidth, (height + barLevelHeight) / 2); cr.lineTo(barLevelBorderRadius + barLevelBorderWidth, (height + barLevelHeight) / 2);
if (this._value > 0) Clutter.cairo_set_source_color(cr, barLevelActiveColor);
Clutter.cairo_set_source_color(cr, barLevelActiveColor);
cr.fillPreserve(); cr.fillPreserve();
Clutter.cairo_set_source_color(cr, barLevelActiveBorderColor); Clutter.cairo_set_source_color(cr, barLevelActiveBorderColor);
cr.setLineWidth(barLevelBorderWidth); cr.setLineWidth(barLevelBorderWidth);
@ -176,19 +143,17 @@ var BarLevel = GObject.registerClass({
} }
/* end progress bar arc */ /* end progress bar arc */
if (this._value > 0) { if (this._value <= this._overdriveStart)
if (this._value <= this._overdriveStart) Clutter.cairo_set_source_color(cr, barLevelActiveColor);
Clutter.cairo_set_source_color(cr, barLevelActiveColor); else
else Clutter.cairo_set_source_color(cr, barLevelOverdriveColor);
Clutter.cairo_set_source_color(cr, barLevelOverdriveColor); cr.arc(endX, height / 2, barLevelBorderRadius, TAU * 3 / 4, TAU * 1 / 4);
cr.arc(endX, height / 2, barLevelBorderRadius, TAU * (3 / 4), TAU * (1 / 4)); cr.lineTo(Math.floor(endX), (height + barLevelHeight) / 2);
cr.lineTo(Math.floor(endX), (height + barLevelHeight) / 2); cr.lineTo(Math.floor(endX), (height - barLevelHeight) / 2);
cr.lineTo(Math.floor(endX), (height - barLevelHeight) / 2); cr.lineTo(endX, (height - barLevelHeight) / 2);
cr.lineTo(endX, (height - barLevelHeight) / 2); cr.fillPreserve();
cr.fillPreserve(); cr.setLineWidth(barLevelBorderWidth);
cr.setLineWidth(barLevelBorderWidth); cr.stroke();
cr.stroke();
}
/* draw overdrive separator */ /* draw overdrive separator */
if (overdriveActive) { if (overdriveActive) {
@ -207,27 +172,32 @@ var BarLevel = GObject.registerClass({
cr.$dispose(); cr.$dispose();
} }
_getCurrentValue() { _getCurrentValue(actor) {
return this._value; return this._value;
} }
_getOverdriveStart() { _getOverdriveStart(actor) {
return this._overdriveStart; return this._overdriveStart;
} }
_getMinimumValue() { _getMinimumValue(actor) {
return 0; return 0;
} }
_getMaximumValue() { _getMaximumValue(actor) {
return this._maxValue; return this._maxValue;
} }
_setCurrentValue(_actor, value) { _setCurrentValue(actor, value) {
this._value = value; this._value = value;
} }
_valueChanged() { _valueChanged(barLevel, value, property) {
this._customAccessible.notify("accessible-value"); this._customAccessible.notify("accessible-value");
} }
});
get value() {
return this._value;
}
};
Signals.addSignalMethods(BarLevel.prototype);

View File

@ -1,9 +1,9 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported BoxPointer */
const { Clutter, GObject, Shell, St } = imports.gi; const { Clutter, GObject, Meta, Shell, St } = imports.gi;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var PopupAnimation = { var PopupAnimation = {
NONE: 0, NONE: 0,
@ -12,7 +12,7 @@ var PopupAnimation = {
FULL: ~0, FULL: ~0,
}; };
var POPUP_ANIMATION_TIME = 150; var POPUP_ANIMATION_TIME = 0.15;
/** /**
* BoxPointer: * BoxPointer:
@ -33,6 +33,8 @@ var BoxPointer = GObject.registerClass({
_init(arrowSide, binProperties) { _init(arrowSide, binProperties) {
super._init(); super._init();
this.actor = this;
this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); this.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._arrowSide = arrowSide; this._arrowSide = arrowSide;
@ -48,15 +50,6 @@ var BoxPointer = GObject.registerClass({
this._sourceAlignment = 0.5; this._sourceAlignment = 0.5;
this._capturedEventId = 0; this._capturedEventId = 0;
this._muteInput(); this._muteInput();
this.connect('destroy', this._onDestroy.bind(this));
}
_onDestroy() {
if (this._sourceActorDestroyId) {
this._sourceActor.disconnect(this._sourceActorDestroyId);
delete this._sourceActorDestroyId;
}
} }
get arrowSide() { get arrowSide() {
@ -76,6 +69,36 @@ var BoxPointer = GObject.registerClass({
} }
} }
// BoxPointer.show() and BoxPointer.hide() are here for only compatibility
// purposes, and will be removed in 3.32.
show(animate, onComplete) {
if (animate !== undefined) {
try {
throw new Error('BoxPointer.show() has been moved to BoxPointer.open(), this code will break in the future.');
} catch(e) {
logError(e);
this.open(animate, onComplete);
return;
}
}
this.visible = true;
}
hide(animate, onComplete) {
if (animate !== undefined) {
try {
throw new Error('BoxPointer.hide() has been moved to BoxPointer.close(), this code will break in the future.');
} catch(e) {
logError(e);
this.close(animate, onComplete);
return;
}
}
this.visible = false;
}
open(animate, onComplete) { open(animate, onComplete) {
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
let rise = themeNode.get_length('-arrow-rise'); let rise = themeNode.get_length('-arrow-rise');
@ -90,33 +113,31 @@ var BoxPointer = GObject.registerClass({
if (animate & PopupAnimation.SLIDE) { if (animate & PopupAnimation.SLIDE) {
switch (this._arrowSide) { switch (this._arrowSide) {
case St.Side.TOP: case St.Side.TOP:
this.translation_y = -rise; this.translation_y = -rise;
break; break;
case St.Side.BOTTOM: case St.Side.BOTTOM:
this.translation_y = rise; this.translation_y = rise;
break; break;
case St.Side.LEFT: case St.Side.LEFT:
this.translation_x = -rise; this.translation_x = -rise;
break; break;
case St.Side.RIGHT: case St.Side.RIGHT:
this.translation_x = rise; this.translation_x = rise;
break; break;
} }
} }
this.ease({ Tweener.addTween(this, { opacity: 255,
opacity: 255, translation_x: 0,
translation_x: 0, translation_y: 0,
translation_y: 0, transition: 'linear',
duration: animationTime, onComplete: () => {
mode: Clutter.AnimationMode.LINEAR, this._unmuteInput();
onComplete: () => { if (onComplete)
this._unmuteInput(); onComplete();
if (onComplete) },
onComplete(); time: animationTime });
}
});
} }
close(animate, onComplete) { close(animate, onComplete) {
@ -132,39 +153,38 @@ var BoxPointer = GObject.registerClass({
if (animate & PopupAnimation.SLIDE) { if (animate & PopupAnimation.SLIDE) {
switch (this._arrowSide) { switch (this._arrowSide) {
case St.Side.TOP: case St.Side.TOP:
translationY = rise; translationY = rise;
break; break;
case St.Side.BOTTOM: case St.Side.BOTTOM:
translationY = -rise; translationY = -rise;
break; break;
case St.Side.LEFT: case St.Side.LEFT:
translationX = rise; translationX = rise;
break; break;
case St.Side.RIGHT: case St.Side.RIGHT:
translationX = -rise; translationX = -rise;
break; break;
} }
} }
this._muteInput(); this._muteInput();
this.remove_all_transitions(); Tweener.removeTweens(this);
this.ease({ Tweener.addTween(this, { opacity: fade ? 0 : 255,
opacity: fade ? 0 : 255, translation_x: translationX,
translation_x: translationX, translation_y: translationY,
translation_y: translationY, transition: 'linear',
duration: animationTime, time: animationTime,
mode: Clutter.AnimationMode.LINEAR, onComplete: () => {
onComplete: () => { this.hide();
this.hide(); this.opacity = 0;
this.opacity = 0; this.translation_x = 0;
this.translation_x = 0; this.translation_y = 0;
this.translation_y = 0; if (onComplete)
if (onComplete) onComplete();
onComplete(); }
} });
});
} }
_adjustAllocationForArrow(isWidth, minSize, natSize) { _adjustAllocationForArrow(isWidth, minSize, natSize) {
@ -172,8 +192,8 @@ var BoxPointer = GObject.registerClass({
let borderWidth = themeNode.get_length('-arrow-border-width'); let borderWidth = themeNode.get_length('-arrow-border-width');
minSize += borderWidth * 2; minSize += borderWidth * 2;
natSize += borderWidth * 2; natSize += borderWidth * 2;
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM)) || if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM))
(isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) { || (isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
let rise = themeNode.get_length('-arrow-rise'); let rise = themeNode.get_length('-arrow-rise');
minSize += rise; minSize += rise;
natSize += rise; natSize += rise;
@ -207,10 +227,13 @@ var BoxPointer = GObject.registerClass({
this.set_allocation(box, flags); this.set_allocation(box, flags);
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
box = themeNode.get_content_box(box);
let borderWidth = themeNode.get_length('-arrow-border-width'); let borderWidth = themeNode.get_length('-arrow-border-width');
let rise = themeNode.get_length('-arrow-rise'); let rise = themeNode.get_length('-arrow-rise');
let childBox = new Clutter.ActorBox(); let childBox = new Clutter.ActorBox();
let [availWidth, availHeight] = themeNode.get_content_box(box).get_size(); let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
childBox.x1 = 0; childBox.x1 = 0;
childBox.y1 = 0; childBox.y1 = 0;
@ -223,25 +246,24 @@ var BoxPointer = GObject.registerClass({
childBox.x2 = availWidth - borderWidth; childBox.x2 = availWidth - borderWidth;
childBox.y2 = availHeight - borderWidth; childBox.y2 = availHeight - borderWidth;
switch (this._arrowSide) { switch (this._arrowSide) {
case St.Side.TOP: case St.Side.TOP:
childBox.y1 += rise; childBox.y1 += rise;
break; break;
case St.Side.BOTTOM: case St.Side.BOTTOM:
childBox.y2 -= rise; childBox.y2 -= rise;
break; break;
case St.Side.LEFT: case St.Side.LEFT:
childBox.x1 += rise; childBox.x1 += rise;
break; break;
case St.Side.RIGHT: case St.Side.RIGHT:
childBox.x2 -= rise; childBox.x2 -= rise;
break; break;
} }
this.bin.allocate(childBox, flags); this.bin.allocate(childBox, flags);
if (this._sourceActor && this._sourceActor.mapped) { if (this._sourceActor && this._sourceActor.mapped) {
this._reposition(box); this._reposition();
this._updateFlip(box); this._updateFlip();
this.set_allocation(box, flags);
} }
} }
@ -267,7 +289,7 @@ var BoxPointer = GObject.registerClass({
let borderRadius = themeNode.get_length('-arrow-border-radius'); let borderRadius = themeNode.get_length('-arrow-border-radius');
let halfBorder = borderWidth / 2; let halfBorder = borderWidth / 2;
let halfBase = Math.floor(base / 2); let halfBase = Math.floor(base/2);
let backgroundColor = themeNode.get_color('-arrow-background-color'); let backgroundColor = themeNode.get_color('-arrow-background-color');
@ -348,7 +370,7 @@ var BoxPointer = GObject.registerClass({
if (!skipTopRight) { if (!skipTopRight) {
cr.lineTo(x2 - borderRadius, y1); cr.lineTo(x2 - borderRadius, y1);
cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius, cr.arc(x2 - borderRadius, y1 + borderRadius, borderRadius,
3 * Math.PI / 2, Math.PI * 2); 3*Math.PI/2, Math.PI*2);
} }
if (this._arrowSide == St.Side.RIGHT && rise) { if (this._arrowSide == St.Side.RIGHT && rise) {
@ -369,7 +391,7 @@ var BoxPointer = GObject.registerClass({
if (!skipBottomRight) { if (!skipBottomRight) {
cr.lineTo(x2, y2 - borderRadius); cr.lineTo(x2, y2 - borderRadius);
cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius, cr.arc(x2 - borderRadius, y2 - borderRadius, borderRadius,
0, Math.PI / 2); 0, Math.PI/2);
} }
if (this._arrowSide == St.Side.BOTTOM && rise) { if (this._arrowSide == St.Side.BOTTOM && rise) {
@ -390,7 +412,7 @@ var BoxPointer = GObject.registerClass({
if (!skipBottomLeft) { if (!skipBottomLeft) {
cr.lineTo(x1 + borderRadius, y2); cr.lineTo(x1 + borderRadius, y2);
cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius, cr.arc(x1 + borderRadius, y2 - borderRadius, borderRadius,
Math.PI / 2, Math.PI); Math.PI/2, Math.PI);
} }
if (this._arrowSide == St.Side.LEFT && rise) { if (this._arrowSide == St.Side.LEFT && rise) {
@ -399,7 +421,7 @@ var BoxPointer = GObject.registerClass({
cr.lineTo(x1 - rise, y1); cr.lineTo(x1 - rise, y1);
cr.lineTo(x1 + borderRadius, y1); cr.lineTo(x1 + borderRadius, y1);
} else if (skipBottomLeft) { } else if (skipBottomLeft) {
cr.lineTo(x1 - rise, y2); cr.lineTo(x1 - rise, y2)
cr.lineTo(x1 - rise, y2 - halfBase); cr.lineTo(x1 - rise, y2 - halfBase);
} else { } else {
cr.lineTo(x1, this._arrowOrigin + halfBase); cr.lineTo(x1, this._arrowOrigin + halfBase);
@ -411,7 +433,7 @@ var BoxPointer = GObject.registerClass({
if (!skipTopLeft) { if (!skipTopLeft) {
cr.lineTo(x1, y1 + borderRadius); cr.lineTo(x1, y1 + borderRadius);
cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius, cr.arc(x1 + borderRadius, y1 + borderRadius, borderRadius,
Math.PI, 3 * Math.PI / 2); Math.PI, 3*Math.PI/2);
} }
Clutter.cairo_set_source_color(cr, backgroundColor); Clutter.cairo_set_source_color(cr, backgroundColor);
@ -428,25 +450,15 @@ var BoxPointer = GObject.registerClass({
} }
setPosition(sourceActor, alignment) { setPosition(sourceActor, alignment) {
if (!this._sourceActor || sourceActor != this._sourceActor) { // We need to show it now to force an allocation,
if (this._sourceActorDestroyId) { // so that we can query the correct size.
this._sourceActor.disconnect(this._sourceActorDestroyId); this.show();
delete this._sourceActorDestroyId;
}
this._sourceActor = sourceActor;
if (this._sourceActor) {
this._sourceActorDestroyId = this._sourceActor.connect('destroy', () => {
this._sourceActor = null;
delete this._sourceActorDestroyId;
});
}
}
this._sourceActor = sourceActor;
this._arrowAlignment = alignment; this._arrowAlignment = alignment;
this.queue_relayout(); this._reposition();
this._updateFlip();
} }
setSourceAlignment(alignment) { setSourceAlignment(alignment) {
@ -458,7 +470,7 @@ var BoxPointer = GObject.registerClass({
this.setPosition(this._sourceActor, this._arrowAlignment); this.setPosition(this._sourceActor, this._arrowAlignment);
} }
_reposition(allocationBox) { _reposition() {
let sourceActor = this._sourceActor; let sourceActor = this._sourceActor;
let alignment = this._arrowAlignment; let alignment = this._arrowAlignment;
let monitorIndex = Main.layoutManager.findIndexForActor(sourceActor); let monitorIndex = Main.layoutManager.findIndexForActor(sourceActor);
@ -472,7 +484,7 @@ var BoxPointer = GObject.registerClass({
let sourceAllocation = this._sourceAllocation; let sourceAllocation = this._sourceAllocation;
let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment; let sourceCenterX = sourceAllocation.x1 + sourceContentBox.x1 + (sourceContentBox.x2 - sourceContentBox.x1) * this._sourceAlignment;
let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment; let sourceCenterY = sourceAllocation.y1 + sourceContentBox.y1 + (sourceContentBox.y2 - sourceContentBox.y1) * this._sourceAlignment;
let [, , natWidth, natHeight] = this.get_preferred_size(); let [minWidth, minHeight, natWidth, natHeight] = this.get_preferred_size();
// We also want to keep it onscreen, and separated from the // We also want to keep it onscreen, and separated from the
// edge by the same distance as the main part of the box is // edge by the same distance as the main part of the box is
@ -516,7 +528,7 @@ var BoxPointer = GObject.registerClass({
// of the box to maintain the arrow's accuracy. // of the box to maintain the arrow's accuracy.
let arrowOrigin; let arrowOrigin;
let halfBase = Math.floor(arrowBase / 2); let halfBase = Math.floor(arrowBase/2);
let halfBorder = borderWidth / 2; let halfBorder = borderWidth / 2;
let halfMargin = margin / 2; let halfMargin = margin / 2;
let [x1, y1] = [halfBorder, halfBorder]; let [x1, y1] = [halfBorder, halfBorder];
@ -572,7 +584,8 @@ var BoxPointer = GObject.registerClass({
} }
// Actually set the position // Actually set the position
allocationBox.set_origin(Math.floor(x), Math.floor(y)); this.x = Math.floor(x);
this.y = Math.floor(y);
} }
// @origin: Coordinate specifying middle of the arrow, along // @origin: Coordinate specifying middle of the arrow, along
@ -597,7 +610,7 @@ var BoxPointer = GObject.registerClass({
_calculateArrowSide(arrowSide) { _calculateArrowSide(arrowSide) {
let sourceAllocation = this._sourceAllocation; let sourceAllocation = this._sourceAllocation;
let [, , boxWidth, boxHeight] = this.get_preferred_size(); let [minWidth, minHeight, boxWidth, boxHeight] = this.get_preferred_size();
let workarea = this._workArea; let workarea = this._workArea;
switch (arrowSide) { switch (arrowSide) {
@ -626,11 +639,15 @@ var BoxPointer = GObject.registerClass({
return arrowSide; return arrowSide;
} }
_updateFlip(allocationBox) { _updateFlip() {
let arrowSide = this._calculateArrowSide(this._userArrowSide); let arrowSide = this._calculateArrowSide(this._userArrowSide);
if (this._arrowSide != arrowSide) { if (this._arrowSide != arrowSide) {
this._arrowSide = arrowSide; this._arrowSide = arrowSide;
this._reposition(allocationBox); this._reposition();
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this.queue_relayout();
return false;
});
this.emit('arrow-side-changed'); this.emit('arrow-side-changed');
} }

View File

@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Calendar, CalendarMessageList */
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi; const { Clutter, Gio, GLib, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -18,7 +17,7 @@ var ELLIPSIS_CHAR = '\u2026';
var MESSAGE_ICON_SIZE = -1; // pick up from CSS var MESSAGE_ICON_SIZE = -1; // pick up from CSS
var NC_ = (context, str) => `${context}\u0004${str}`; var NC_ = (context, str) => context + '\u0004' + str;
function sameYear(dateA, dateB) { function sameYear(dateA, dateB) {
return (dateA.getYear() == dateB.getYear()); return (dateA.getYear() == dateB.getYear());
@ -39,7 +38,7 @@ function isToday(date) {
function _isWorkDay(date) { function _isWorkDay(date) {
/* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */ /* Translators: Enter 0-6 (Sunday-Saturday) for non-work days. Examples: "0" (Sunday) "6" (Saturday) "06" (Sunday and Saturday). */
let days = C_('calendar-no-work', "06"); let days = C_('calendar-no-work', "06");
return !days.includes(date.getDay().toString()); return days.indexOf(date.getDay().toString()) == -1;
} }
function _getBeginningOfDay(date) { function _getBeginningOfDay(date) {
@ -110,15 +109,15 @@ var EmptyEventSource = class EmptyEventSource {
destroy() { destroy() {
} }
requestRange(_begin, _end) { requestRange(begin, end) {
} }
getEvents(_begin, _end) { getEvents(begin, end) {
let result = []; let result = [];
return result; return result;
} }
hasEvents(_day) { hasEvents(day) {
return false; return false;
} }
}; };
@ -144,7 +143,8 @@ function _datesEqual(a, b) {
return true; return true;
} }
function _dateIntervalsOverlap(a0, a1, b0, b1) { function _dateIntervalsOverlap(a0, a1, b0, b1)
{
if (a1 <= b0) if (a1 <= b0)
return false; return false;
else if (b1 <= a0) else if (b1 <= a0)
@ -168,7 +168,7 @@ var DBusEventSource = class DBusEventSource {
try { try {
this._dbusProxy.init_finish(result); this._dbusProxy.init_finish(result);
loaded = true; loaded = true;
} catch (e) { } catch(e) {
if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) { if (e.matches(Gio.DBusError, Gio.DBusError.TIMED_OUT)) {
// Ignore timeouts and install signals as normal, because with high // Ignore timeouts and install signals as normal, because with high
// probability the service will appear later on, and we will get a // probability the service will appear later on, and we will get a
@ -178,7 +178,7 @@ var DBusEventSource = class DBusEventSource {
// about the HasCalendars property and would cause an exception trying // about the HasCalendars property and would cause an exception trying
// to read it) // to read it)
} else { } else {
log(`Error loading calendars: ${e.message}`); log('Error loading calendars: ' + e.message);
return; return;
} }
} }
@ -221,13 +221,13 @@ var DBusEventSource = class DBusEventSource {
this._lastRequestEnd = null; this._lastRequestEnd = null;
} }
_onNameAppeared() { _onNameAppeared(owner) {
this._initialized = true; this._initialized = true;
this._resetCache(); this._resetCache();
this._loadEvents(true); this._loadEvents(true);
} }
_onNameVanished() { _onNameVanished(oldOwner) {
this._resetCache(); this._resetCache();
this.emit('changed'); this.emit('changed');
} }
@ -236,20 +236,22 @@ var DBusEventSource = class DBusEventSource {
this._loadEvents(false); this._loadEvents(false);
} }
_onEventsReceived(results, _error) { _onEventsReceived(results, error) {
let newEvents = []; let newEvents = [];
let appointments = results[0] || []; let appointments = results ? results[0] : null;
for (let n = 0; n < appointments.length; n++) { if (appointments != null) {
let a = appointments[n]; for (let n = 0; n < appointments.length; n++) {
let date = new Date(a[4] * 1000); let a = appointments[n];
let end = new Date(a[5] * 1000); let date = new Date(a[4] * 1000);
let id = a[0]; let end = new Date(a[5] * 1000);
let summary = a[1]; let id = a[0];
let allDay = a[3]; let summary = a[1];
let event = new CalendarEvent(id, date, end, summary, allDay); let allDay = a[3];
newEvents.push(event); let event = new CalendarEvent(id, date, end, summary, allDay);
newEvents.push(event);
}
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
} }
newEvents.sort((ev1, ev2) => ev1.date.getTime() - ev2.date.getTime());
this._events = newEvents; this._events = newEvents;
this.isLoading = false; this.isLoading = false;
@ -261,7 +263,7 @@ var DBusEventSource = class DBusEventSource {
if (!this._initialized) if (!this._initialized)
return; return;
if (this._curRequestBegin && this._curRequestEnd) { if (this._curRequestBegin && this._curRequestEnd){
this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000, this._dbusProxy.GetEventsRemote(this._curRequestBegin.getTime() / 1000,
this._curRequestEnd.getTime() / 1000, this._curRequestEnd.getTime() / 1000,
forceReload, forceReload,
@ -283,7 +285,7 @@ var DBusEventSource = class DBusEventSource {
getEvents(begin, end) { getEvents(begin, end) {
let result = []; let result = [];
for (let n = 0; n < this._events.length; n++) { for(let n = 0; n < this._events.length; n++) {
let event = this._events[n]; let event = this._events[n];
if (_dateIntervalsOverlap (event.date, event.end, begin, end)) { if (_dateIntervalsOverlap (event.date, event.end, begin, end)) {
@ -318,7 +320,7 @@ var Calendar = class Calendar {
this._weekStart = Shell.util_get_week_start(); this._weekStart = Shell.util_get_week_start();
this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.calendar' }); this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.calendar' });
this._settings.connect(`changed::${SHOW_WEEKDATE_KEY}`, this._onSettingsChange.bind(this)); this._settings.connect('changed::' + SHOW_WEEKDATE_KEY, this._onSettingsChange.bind(this));
this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY); this._useWeekdate = this._settings.get_boolean(SHOW_WEEKDATE_KEY);
/** /**
@ -400,8 +402,8 @@ var Calendar = class Calendar {
this._topBox.add(this._backButton); this._topBox.add(this._backButton);
this._backButton.connect('clicked', this._onPrevMonthButtonClicked.bind(this)); this._backButton.connect('clicked', this._onPrevMonthButtonClicked.bind(this));
this._monthLabel = new St.Label({ style_class: 'calendar-month-label', this._monthLabel = new St.Label({style_class: 'calendar-month-label',
can_focus: true }); can_focus: true });
this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE }); this._topBox.add(this._monthLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
this._forwardButton = new St.Button({ style_class: 'calendar-change-month-forward pager-button', this._forwardButton = new St.Button({ style_class: 'calendar-change-month-forward pager-button',
@ -464,7 +466,8 @@ var Calendar = class Calendar {
let day = 32 - new Date(newDate.getFullYear() - 1, 11, 32).getDate(); let day = 32 - new Date(newDate.getFullYear() - 1, 11, 32).getDate();
newDate = new Date(newDate.getFullYear() - 1, 11, day); newDate = new Date(newDate.getFullYear() - 1, 11, day);
} }
} else { }
else {
newDate.setMonth(oldMonth - 1); newDate.setMonth(oldMonth - 1);
if (newDate.getMonth() != oldMonth - 1) { if (newDate.getMonth() != oldMonth - 1) {
let day = 32 - new Date(newDate.getFullYear(), oldMonth - 1, 32).getDate(); let day = 32 - new Date(newDate.getFullYear(), oldMonth - 1, 32).getDate();
@ -487,7 +490,8 @@ var Calendar = class Calendar {
let day = 32 - new Date(newDate.getFullYear() + 1, 0, 32).getDate(); let day = 32 - new Date(newDate.getFullYear() + 1, 0, 32).getDate();
newDate = new Date(newDate.getFullYear() + 1, 0, day); newDate = new Date(newDate.getFullYear() + 1, 0, day);
} }
} else { }
else {
newDate.setMonth(oldMonth + 1); newDate.setMonth(oldMonth + 1);
if (newDate.getMonth() != oldMonth + 1) { if (newDate.getMonth() != oldMonth + 1) {
let day = 32 - new Date(newDate.getFullYear(), oldMonth + 1, 32).getDate(); let day = 32 - new Date(newDate.getFullYear(), oldMonth + 1, 32).getDate();
@ -542,6 +546,8 @@ var Calendar = class Calendar {
this._calendarBegin = new Date(beginDate); this._calendarBegin = new Date(beginDate);
this._markedAsToday = now; this._markedAsToday = now;
let year = beginDate.getYear();
let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7; let daysToWeekStart = (7 + beginDate.getDay() - this._weekStart) % 7;
let startsOnWeekStart = daysToWeekStart == 0; let startsOnWeekStart = daysToWeekStart == 0;
let weekPadding = startsOnWeekStart ? 7 : 0; let weekPadding = startsOnWeekStart ? 7 : 0;
@ -553,7 +559,7 @@ var Calendar = class Calendar {
let row = 2; let row = 2;
// nRows here means 6 weeks + one header + one navbar // nRows here means 6 weeks + one header + one navbar
let nRows = 8; let nRows = 8;
while (row < nRows) { while (row < 8) {
// xgettext:no-javascript-format // xgettext:no-javascript-format
let button = new St.Button({ label: iter.toLocaleFormat(C_("date day number format", "%d")), let button = new St.Button({ label: iter.toLocaleFormat(C_("date day number format", "%d")),
can_focus: true }); can_focus: true });
@ -579,13 +585,12 @@ var Calendar = class Calendar {
// Hack used in lieu of border-collapse - see gnome-shell.css // Hack used in lieu of border-collapse - see gnome-shell.css
if (row == 2) if (row == 2)
styleClass = `calendar-day-top ${styleClass}`; styleClass = 'calendar-day-top ' + styleClass;
let leftMost = rtl let leftMost = rtl ? iter.getDay() == (this._weekStart + 6) % 7
? iter.getDay() == (this._weekStart + 6) % 7 : iter.getDay() == this._weekStart;
: iter.getDay() == this._weekStart;
if (leftMost) if (leftMost)
styleClass = `calendar-day-left ${styleClass}`; styleClass = 'calendar-day-left ' + styleClass;
if (sameDay(now, iter)) if (sameDay(now, iter))
styleClass += ' calendar-today'; styleClass += ' calendar-today';
@ -643,9 +648,9 @@ var Calendar = class Calendar {
button.add_style_pseudo_class('selected'); button.add_style_pseudo_class('selected');
if (this._shouldDateGrabFocus) if (this._shouldDateGrabFocus)
button.grab_key_focus(); button.grab_key_focus();
} else {
button.remove_style_pseudo_class('selected');
} }
else
button.remove_style_pseudo_class('selected');
}); });
} }
}; };
@ -681,24 +686,23 @@ var EventMessage = class EventMessage extends MessageList.Message {
*/ */
title = C_("event list time", "All Day"); title = C_("event list time", "All Day");
} else { } else {
let date = this._event.date >= periodBegin let date = this._event.date >= periodBegin ? this._event.date
? this._event.date : this._event.end;
: this._event.end;
title = Util.formatTime(date, { timeOnly: true }); title = Util.formatTime(date, { timeOnly: true });
} }
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL; let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
if (this._event.date < periodBegin && !this._event.allDay) { if (this._event.date < periodBegin && !this._event.allDay) {
if (rtl) if (rtl)
title = `${title}${ELLIPSIS_CHAR}`; title = title + ELLIPSIS_CHAR;
else else
title = `${ELLIPSIS_CHAR}${title}`; title = ELLIPSIS_CHAR + title;
} }
if (this._event.end > periodEnd && !this._event.allDay) { if (this._event.end > periodEnd && !this._event.allDay) {
if (rtl) if (rtl)
title = `${ELLIPSIS_CHAR}${title}`; title = ELLIPSIS_CHAR + title;
else else
title = `${title}${ELLIPSIS_CHAR}`; title = title + ELLIPSIS_CHAR;
} }
return title; return title;
} }
@ -737,7 +741,7 @@ class NotificationMessage extends MessageList.Message {
return this.notification.source.createIcon(MESSAGE_ICON_SIZE); return this.notification.source.createIcon(MESSAGE_ICON_SIZE);
} }
_onUpdated(n, _clear) { _onUpdated(n, clear) {
this.setIcon(this._getIcon()); this.setIcon(this._getIcon());
this.setTitle(n.title); this.setTitle(n.title);
this.setBody(n.bannerBodyText); this.setBody(n.bannerBodyText);
@ -1073,14 +1077,10 @@ var CalendarMessageList = class CalendarMessageList {
this._clearButton.set_x_align(Clutter.ActorAlign.END); this._clearButton.set_x_align(Clutter.ActorAlign.END);
this._clearButton.connect('clicked', () => { this._clearButton.connect('clicked', () => {
let sections = [...this._sections.keys()]; let sections = [...this._sections.keys()];
sections.forEach(s => s.clear()); sections.forEach((s) => { s.clear(); });
}); });
box.add_actor(this._clearButton); box.add_actor(this._clearButton);
this._placeholder.actor.bind_property('visible',
this._clearButton, 'visible',
GObject.BindingFlags.INVERT_BOOLEAN);
this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections', this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections',
vertical: true, vertical: true,
y_expand: true, y_expand: true,
@ -1103,7 +1103,7 @@ var CalendarMessageList = class CalendarMessageList {
_addSection(section) { _addSection(section) {
let obj = { let obj = {
destroyId: 0, destroyId: 0,
visibleId: 0, visibleId: 0,
emptyChangedId: 0, emptyChangedId: 0,
canClearChangedId: 0, canClearChangedId: 0,
keyFocusId: 0 keyFocusId: 0
@ -1151,6 +1151,7 @@ var CalendarMessageList = class CalendarMessageList {
let empty = sections.every(s => s.empty || !s.actor.visible); let empty = sections.every(s => s.empty || !s.actor.visible);
this._placeholder.actor.visible = empty; this._placeholder.actor.visible = empty;
this._clearButton.visible = !empty;
let canClear = sections.some(s => s.canClear && s.actor.visible); let canClear = sections.some(s => s.canClear && s.actor.visible);
this._clearButton.reactive = canClear; this._clearButton.reactive = canClear;

View File

@ -1,4 +1,3 @@
/* exported CheckBox */
const { Clutter, Pango, St } = imports.gi; const { Clutter, Pango, St } = imports.gi;
var CheckBox = class CheckBox { var CheckBox = class CheckBox {

View File

@ -1,17 +1,17 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported CloseDialog */
const { Clutter, Gio, GLib, GObject, Meta, Shell } = imports.gi; const { Clutter, Gio, GLib, GObject, Meta, Shell } = imports.gi;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var FROZEN_WINDOW_BRIGHTNESS = -0.3; var FROZEN_WINDOW_BRIGHTNESS = -0.3
var DIALOG_TRANSITION_TIME = 150; var DIALOG_TRANSITION_TIME = 0.15
var ALIVE_TIMEOUT = 5000; var ALIVE_TIMEOUT = 5000;
var CloseDialog = GObject.registerClass({ var CloseDialog = GObject.registerClass({
Implements: [Meta.CloseDialog], Implements: [ Meta.CloseDialog ],
Properties: { Properties: {
'window': GObject.ParamSpec.override('window', Meta.CloseDialog) 'window': GObject.ParamSpec.override('window', Meta.CloseDialog)
}, },
@ -56,12 +56,12 @@ var CloseDialog = GObject.registerClass({
this._dialog.height = windowActor.height; this._dialog.height = windowActor.height;
this._dialog.addContent(this._createDialogContent()); this._dialog.addContent(this._createDialogContent());
this._dialog.addButton({ label: _('Force Quit'), this._dialog.addButton({ label: _('Force Quit'),
action: this._onClose.bind(this), action: this._onClose.bind(this),
default: true }); default: true });
this._dialog.addButton({ label: _('Wait'), this._dialog.addButton({ label: _('Wait'),
action: this._onWait.bind(this), action: this._onWait.bind(this),
key: Clutter.Escape }); key: Clutter.Escape });
global.focus_manager.add_group(this._dialog); global.focus_manager.add_group(this._dialog);
} }
@ -148,12 +148,12 @@ var CloseDialog = GObject.registerClass({
this._dialog.scale_y = 0; this._dialog.scale_y = 0;
this._dialog.set_pivot_point(0.5, 0.5); this._dialog.set_pivot_point(0.5, 0.5);
this._dialog.ease({ Tweener.addTween(this._dialog,
scale_y: 1, { scale_y: 1,
mode: Clutter.AnimationMode.LINEAR, transition: 'linear',
duration: DIALOG_TRANSITION_TIME, time: DIALOG_TRANSITION_TIME,
onComplete: this._onFocusChanged.bind(this) onComplete: this._onFocusChanged.bind(this)
}); });
} }
vfunc_hide() { vfunc_hide() {
@ -165,7 +165,7 @@ var CloseDialog = GObject.registerClass({
GLib.source_remove(this._timeoutId); GLib.source_remove(this._timeoutId);
this._timeoutId = 0; this._timeoutId = 0;
global.display.disconnect(this._windowFocusChangedId); global.display.disconnect(this._windowFocusChangedId)
this._windowFocusChangedId = 0; this._windowFocusChangedId = 0;
global.stage.disconnect(this._keyFocusChangedId); global.stage.disconnect(this._keyFocusChangedId);
@ -175,12 +175,14 @@ var CloseDialog = GObject.registerClass({
this._dialog = null; this._dialog = null;
this._removeWindowEffect(); this._removeWindowEffect();
dialog.ease({ Tweener.addTween(dialog,
scale_y: 0, { scale_y: 0,
mode: Clutter.AnimationMode.LINEAR, transition: 'linear',
duration: DIALOG_TRANSITION_TIME, time: DIALOG_TRANSITION_TIME,
onComplete: () => dialog.destroy() onComplete: () => {
}); dialog.destroy();
}
});
} }
vfunc_focus() { vfunc_focus() {

View File

@ -1,4 +1,3 @@
/* exported ComponentManager */
const Main = imports.ui.main; const Main = imports.ui.main;
var ComponentManager = class { var ComponentManager = class {
@ -14,13 +13,13 @@ var ComponentManager = class {
let newEnabledComponents = Main.sessionMode.components; let newEnabledComponents = Main.sessionMode.components;
newEnabledComponents.filter( newEnabledComponents.filter(
name => !this._enabledComponents.includes(name) name => this._enabledComponents.indexOf(name) == -1
).forEach(name => { ).forEach(name => {
this._enableComponent(name); this._enableComponent(name);
}); });
this._enabledComponents.filter( this._enabledComponents.filter(
name => !newEnabledComponents.includes(name) name => newEnabledComponents.indexOf(name) == -1
).forEach(name => { ).forEach(name => {
this._disableComponent(name); this._disableComponent(name);
}); });
@ -38,8 +37,8 @@ var ComponentManager = class {
if (component) if (component)
return component; return component;
if (Main.sessionMode.isLocked) if (Main.sessionMode.isLocked)
return null; return null;
let constructor = this._importComponent(name); let constructor = this._importComponent(name);
component = new constructor(); component = new constructor();
@ -49,7 +48,7 @@ var ComponentManager = class {
_enableComponent(name) { _enableComponent(name) {
let component = this._ensureComponent(name); let component = this._ensureComponent(name);
if (component) if (component)
component.enable(); component.enable();
} }

View File

@ -1,11 +1,10 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */
const { Gio, GLib } = imports.gi; const { Gio, GLib } = imports.gi;
const Mainloop = imports.mainloop;
const Params = imports.misc.params; const Params = imports.misc.params;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main;
const ShellMountOperation = imports.ui.shellMountOperation; const ShellMountOperation = imports.ui.shellMountOperation;
var GNOME_SESSION_AUTOMOUNT_INHIBIT = 16; var GNOME_SESSION_AUTOMOUNT_INHIBIT = 16;
@ -38,7 +37,7 @@ var AutomountManager = class {
this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', this._onDriveDisconnected.bind(this)); this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', this._onDriveDisconnected.bind(this));
this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', this._onDriveEjectButton.bind(this)); this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', this._onDriveEjectButton.bind(this));
this._mountAllId = GLib.idle_add(GLib.PRIORITY_DEFAULT, this._startupMountAll.bind(this)); this._mountAllId = Mainloop.idle_add(this._startupMountAll.bind(this));
GLib.Source.set_name_by_id(this._mountAllId, '[gnome-shell] this._startupMountAll'); GLib.Source.set_name_by_id(this._mountAllId, '[gnome-shell] this._startupMountAll');
} }
@ -50,12 +49,12 @@ var AutomountManager = class {
this._volumeMonitor.disconnect(this._driveEjectButtonId); this._volumeMonitor.disconnect(this._driveEjectButtonId);
if (this._mountAllId > 0) { if (this._mountAllId > 0) {
GLib.source_remove(this._mountAllId); Mainloop.source_remove(this._mountAllId);
this._mountAllId = 0; this._mountAllId = 0;
} }
} }
_InhibitorsChanged(_object, _senderName, [_inhibitor]) { _InhibitorsChanged(object, senderName, [inhibtor]) {
this._session.IsInhibitedRemote(GNOME_SESSION_AUTOMOUNT_INHIBIT, this._session.IsInhibitedRemote(GNOME_SESSION_AUTOMOUNT_INHIBIT,
(result, error) => { (result, error) => {
if (!error) { if (!error) {
@ -109,23 +108,25 @@ var AutomountManager = class {
// we force stop/eject in this case, so we don't have to pass a // we force stop/eject in this case, so we don't have to pass a
// mount operation object // mount operation object
if (drive.can_stop()) { if (drive.can_stop()) {
drive.stop(Gio.MountUnmountFlags.FORCE, null, null, drive.stop
(drive, res) => { (Gio.MountUnmountFlags.FORCE, null, null,
try { (drive, res) => {
drive.stop_finish(res); try {
} catch (e) { drive.stop_finish(res);
log(`Unable to stop the drive after drive-eject-button ${e.toString()}`); } catch (e) {
} log("Unable to stop the drive after drive-eject-button " + e.toString());
}); }
});
} else if (drive.can_eject()) { } else if (drive.can_eject()) {
drive.eject_with_operation(Gio.MountUnmountFlags.FORCE, null, null, drive.eject_with_operation
(drive, res) => { (Gio.MountUnmountFlags.FORCE, null, null,
try { (drive, res) => {
drive.eject_with_operation_finish(res); try {
} catch (e) { drive.eject_with_operation_finish(res);
log(`Unable to eject the drive after drive-eject-button ${e.toString()}`); } catch (e) {
} log("Unable to eject the drive after drive-eject-button " + e.toString());
}); }
});
} }
} }
@ -198,20 +199,12 @@ var AutomountManager = class {
// error strings are not unique for the cases in the comments below. // error strings are not unique for the cases in the comments below.
if (e.message.includes('No key available with this passphrase') || // cryptsetup if (e.message.includes('No key available with this passphrase') || // cryptsetup
e.message.includes('No key available to unlock device') || // udisks (no password) e.message.includes('No key available to unlock device') || // udisks (no password)
// libblockdev wrong password opening LUKS device e.message.includes('Error unlocking')) { // udisks (wrong password)
e.message.includes('Failed to activate device: Incorrect passphrase') ||
// cryptsetup returns EINVAL in many cases, including wrong TCRYPT password/parameters
e.message.includes('Failed to load device\'s parameters: Invalid argument')) {
this._reaskPassword(volume); this._reaskPassword(volume);
} else { } else {
if (e.message.includes('Compiled against a version of libcryptsetup that does not support the VeraCrypt PIM setting')) {
Main.notifyError(_("Unable to unlock volume"),
_("The installed udisks version does not support the PIM setting"));
}
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED)) if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED))
log(`Unable to mount volume ${volume.get_name()}: ${e.toString()}`); log('Unable to mount volume ' + volume.get_name() + ': ' + e.toString());
this._closeOperation(volume); this._closeOperation(volume);
} }
} }
@ -219,7 +212,7 @@ var AutomountManager = class {
_onVolumeRemoved(monitor, volume) { _onVolumeRemoved(monitor, volume) {
if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) { if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) {
GLib.source_remove(volume._allowAutorunExpireId); Mainloop.source_remove(volume._allowAutorunExpireId);
delete volume._allowAutorunExpireId; delete volume._allowAutorunExpireId;
} }
this._volumeQueue = this._volumeQueue =
@ -248,7 +241,7 @@ var AutomountManager = class {
} }
_allowAutorunExpire(volume) { _allowAutorunExpire(volume) {
let id = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, AUTORUN_EXPIRE_TIMEOUT_SECS, () => { let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => {
volume.allowAutorun = false; volume.allowAutorun = false;
delete volume._allowAutorunExpireId; delete volume._allowAutorunExpireId;
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */
const { Gio, St } = imports.gi; const { Gio, St } = imports.gi;
@ -41,7 +40,7 @@ function isMountRootHidden(root) {
let path = root.get_path(); let path = root.get_path();
// skip any mounts in hidden directory hierarchies // skip any mounts in hidden directory hierarchies
return (path.includes('/.')); return (path.indexOf('/.') != -1);
} }
function isMountNonLocal(mount) { function isMountNonLocal(mount) {
@ -66,12 +65,15 @@ function startAppForMount(app, mount) {
retval = app.launch(files, retval = app.launch(files,
global.create_app_launch_context(0, -1)); global.create_app_launch_context(0, -1));
} catch (e) { } catch (e) {
log(`Unable to launch the application ${app.get_name()}: ${e}`); log('Unable to launch the application ' + app.get_name()
+ ': ' + e.toString());
} }
return retval; return retval;
} }
/******************************************/
const HotplugSnifferIface = loadInterfaceXML('org.gnome.Shell.HotplugSniffer'); const HotplugSnifferIface = loadInterfaceXML('org.gnome.Shell.HotplugSniffer');
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface); const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
function HotplugSniffer() { function HotplugSniffer() {
@ -105,7 +107,8 @@ var ContentTypeDiscoverer = class {
try { try {
contentTypes = mount.guess_content_type_finish(res); contentTypes = mount.guess_content_type_finish(res);
} catch (e) { } catch (e) {
log(`Unable to guess content types on added mount ${mount.get_name()}: ${e}`); log('Unable to guess content types on added mount ' + mount.get_name()
+ ': ' + e.toString());
} }
if (contentTypes.length) { if (contentTypes.length) {
@ -115,13 +118,16 @@ var ContentTypeDiscoverer = class {
let hotplugSniffer = new HotplugSniffer(); let hotplugSniffer = new HotplugSniffer();
hotplugSniffer.SniffURIRemote(root.get_uri(), hotplugSniffer.SniffURIRemote(root.get_uri(),
([contentTypes]) => { ([contentTypes]) => {
this._emitCallback(mount, contentTypes); this._emitCallback(mount, contentTypes);
}); });
} }
} }
_emitCallback(mount, contentTypes = []) { _emitCallback(mount, contentTypes) {
if (!contentTypes)
contentTypes = [];
// we're not interested in win32 software content types here // we're not interested in win32 software content types here
contentTypes = contentTypes.filter( contentTypes = contentTypes.filter(
type => (type != 'x-content/win32-software') type => (type != 'x-content/win32-software')
@ -186,15 +192,15 @@ var AutorunDispatcher = class {
_getAutorunSettingForType(contentType) { _getAutorunSettingForType(contentType) {
let runApp = this._settings.get_strv(SETTING_START_APP); let runApp = this._settings.get_strv(SETTING_START_APP);
if (runApp.includes(contentType)) if (runApp.indexOf(contentType) != -1)
return AutorunSetting.RUN; return AutorunSetting.RUN;
let ignore = this._settings.get_strv(SETTING_IGNORE); let ignore = this._settings.get_strv(SETTING_IGNORE);
if (ignore.includes(contentType)) if (ignore.indexOf(contentType) != -1)
return AutorunSetting.IGNORE; return AutorunSetting.IGNORE;
let openFiles = this._settings.get_strv(SETTING_OPEN_FOLDER); let openFiles = this._settings.get_strv(SETTING_OPEN_FOLDER);
if (openFiles.includes(contentType)) if (openFiles.indexOf(contentType) != -1)
return AutorunSetting.FILES; return AutorunSetting.FILES;
return AutorunSetting.ASK; return AutorunSetting.ASK;
@ -323,10 +329,10 @@ var AutorunNotification = class extends MessageTray.Notification {
style_class: 'hotplug-notification-item-icon' }); style_class: 'hotplug-notification-item-icon' });
box.add(icon); box.add(icon);
let label = new St.Bin({ let label = new St.Bin({ y_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE, child: new St.Label
child: new St.Label({ text: _("Open with %s").format(app.get_name()) }), ({ text: _("Open with %s").format(app.get_name()) })
}); });
box.add(label); box.add(label);
let button = new St.Button({ child: box, let button = new St.Button({ child: box,

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */
const { Clutter, Gcr, Gio, GObject, Pango, Shell, St } = imports.gi; const { Clutter, Gcr, Gio, GObject, Pango, Shell, St } = imports.gi;
@ -11,10 +10,9 @@ const CheckBox = imports.ui.checkBox;
var WORK_SPINNER_ICON_SIZE = 16; var WORK_SPINNER_ICON_SIZE = 16;
var KeyringDialog = GObject.registerClass( var KeyringDialog = class extends ModalDialog.ModalDialog {
class KeyringDialog extends ModalDialog.ModalDialog { constructor() {
_init() { super({ styleClass: 'prompt-dialog' });
super._init({ styleClass: 'prompt-dialog' });
this.prompt = new Shell.KeyringPrompt(); this.prompt = new Shell.KeyringPrompt();
this.prompt.connect('show-password', this._onShowPassword.bind(this)); this.prompt.connect('show-password', this._onShowPassword.bind(this));
@ -25,8 +23,20 @@ class KeyringDialog extends ModalDialog.ModalDialog {
this._content = new Dialog.MessageDialogContent({ icon }); this._content = new Dialog.MessageDialogContent({ icon });
this.contentLayout.add(this._content); this.contentLayout.add(this._content);
// FIXME: Why does this break now?
/*
this.prompt.bind_property('message', this._content, 'title', GObject.BindingFlags.SYNC_CREATE); this.prompt.bind_property('message', this._content, 'title', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('description', this._content, 'body', GObject.BindingFlags.SYNC_CREATE); this.prompt.bind_property('description', this._content, 'body', GObject.BindingFlags.SYNC_CREATE);
*/
this.prompt.connect('notify::message', () => {
this._content.title = this.prompt.message;
});
this._content.title = this.prompt.message;
this.prompt.connect('notify::description', () => {
this._content.body = this.prompt.description;
});
this._content.body = this.prompt.description;
this._workSpinner = null; this._workSpinner = null;
this._controlTable = null; this._controlTable = null;
@ -163,7 +173,7 @@ class KeyringDialog extends ModalDialog.ModalDialog {
// NOTE: ModalDialog.open() is safe to call if the dialog is // NOTE: ModalDialog.open() is safe to call if the dialog is
// already open - it just returns true without side-effects // already open - it just returns true without side-effects
if (this.open()) if (this.open())
return true; return true;
// The above fail if e.g. unable to get input grab // The above fail if e.g. unable to get input grab
// //
@ -173,25 +183,25 @@ class KeyringDialog extends ModalDialog.ModalDialog {
log('keyringPrompt: Failed to show modal dialog.' + log('keyringPrompt: Failed to show modal dialog.' +
' Dismissing prompt request'); ' Dismissing prompt request');
this.prompt.cancel(); this.prompt.cancel()
return false; return false;
} }
_onShowPassword() { _onShowPassword(prompt) {
this._buildControlTable(); this._buildControlTable();
this._ensureOpen(); this._ensureOpen();
this._updateSensitivity(true); this._updateSensitivity(true);
this._passwordEntry.grab_key_focus(); this._passwordEntry.grab_key_focus();
} }
_onShowConfirm() { _onShowConfirm(prompt) {
this._buildControlTable(); this._buildControlTable();
this._ensureOpen(); this._ensureOpen();
this._updateSensitivity(true); this._updateSensitivity(true);
this._continueButton.grab_key_focus(); this._continueButton.grab_key_focus();
} }
_onHidePrompt() { _onHidePrompt(prompt) {
this.close(); this.close();
} }
@ -214,7 +224,7 @@ class KeyringDialog extends ModalDialog.ModalDialog {
_onCancelButton() { _onCancelButton() {
this.prompt.cancel(); this.prompt.cancel();
} }
}); };
var KeyringDummyDialog = class { var KeyringDummyDialog = class {
constructor() { constructor() {
@ -232,9 +242,8 @@ var KeyringPrompter = class {
constructor() { constructor() {
this._prompter = new Gcr.SystemPrompter(); this._prompter = new Gcr.SystemPrompter();
this._prompter.connect('new-prompt', () => { this._prompter.connect('new-prompt', () => {
let dialog = this._enabled let dialog = this._enabled ? new KeyringDialog()
? new KeyringDialog() : new KeyringDummyDialog();
: new KeyringDummyDialog();
this._currentPrompt = dialog.prompt; this._currentPrompt = dialog.prompt;
return this._currentPrompt; return this._currentPrompt;
}); });

View File

@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */
const { Clutter, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi; const { Clutter, Gio, GLib, NM, Pango, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Config = imports.misc.config; const Config = imports.misc.config;
@ -13,10 +12,9 @@ const ShellEntry = imports.ui.shellEntry;
const VPN_UI_GROUP = 'VPN Plugin UI'; const VPN_UI_GROUP = 'VPN Plugin UI';
var NetworkSecretDialog = GObject.registerClass( var NetworkSecretDialog = class extends ModalDialog.ModalDialog {
class NetworkSecretDialog extends ModalDialog.ModalDialog { constructor(agent, requestId, connection, settingName, hints, flags, contentOverride) {
_init(agent, requestId, connection, settingName, hints, flags, contentOverride) { super({ styleClass: 'prompt-dialog' });
super._init({ styleClass: 'prompt-dialog' });
this._agent = agent; this._agent = agent;
this._requestId = requestId; this._requestId = requestId;
@ -81,9 +79,8 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
secret.valid = secret.value.length > 0; secret.valid = secret.value.length > 0;
this._updateOkButton(); this._updateOkButton();
}); });
} else { } else
secret.valid = true; secret.valid = true;
}
if (rtl) { if (rtl) {
layout.attach(secret.entry, 0, pos, 1, 1); layout.attach(secret.entry, 0, pos, 1, 1);
@ -107,22 +104,21 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; descriptionLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
contentBox.messageBox.add(descriptionLabel, contentBox.messageBox.add(descriptionLabel,
{ y_fill: true, { y_fill: true,
y_align: St.Align.START, y_align: St.Align.START,
expand: true }); expand: true });
} }
this._okButton = { this._okButton = { label: _("Connect"),
label: _("Connect"), action: this._onOk.bind(this),
action: this._onOk.bind(this), default: true
default: true, };
};
this.setButtons([{ this.setButtons([{ label: _("Cancel"),
label: _("Cancel"), action: this.cancel.bind(this),
action: this.cancel.bind(this), key: Clutter.KEY_Escape,
key: Clutter.KEY_Escape, },
}, this._okButton]); this._okButton]);
this._updateOkButton(); this._updateOkButton();
} }
@ -164,9 +160,9 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
if (value.length == 64) { if (value.length == 64) {
// must be composed of hexadecimal digits only // must be composed of hexadecimal digits only
for (let i = 0; i < 64; i++) { for (let i = 0; i < 64; i++) {
if (!((value[i] >= 'a' && value[i] <= 'f') || if (!((value[i] >= 'a' && value[i] <= 'f')
(value[i] >= 'A' && value[i] <= 'F') || || (value[i] >= 'A' && value[i] <= 'F')
(value[i] >= '0' && value[i] <= '9'))) || (value[i] >= '0' && value[i] <= '9')))
return false; return false;
} }
return true; return true;
@ -179,29 +175,28 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
let value = secret.value; let value = secret.value;
if (secret.wep_key_type == NM.WepKeyType.KEY) { if (secret.wep_key_type == NM.WepKeyType.KEY) {
if (value.length == 10 || value.length == 26) { if (value.length == 10 || value.length == 26) {
for (let i = 0; i < value.length; i++) { for (let i = 0; i < value.length; i++) {
if (!((value[i] >= 'a' && value[i] <= 'f') || if (!((value[i] >= 'a' && value[i] <= 'f')
(value[i] >= 'A' && value[i] <= 'F') || || (value[i] >= 'A' && value[i] <= 'F')
(value[i] >= '0' && value[i] <= '9'))) || (value[i] >= '0' && value[i] <= '9')))
return false;
}
} else if (value.length == 5 || value.length == 13) {
for (let i = 0; i < value.length; i++) {
if (!((value[i] >= 'a' && value[i] <= 'z')
|| (value[i] >= 'A' && value[i] <= 'Z')))
return false; return false;
} }
} else if (value.length == 5 || value.length == 13) { } else
for (let i = 0; i < value.length; i++) {
if (!((value[i] >= 'a' && value[i] <= 'z') ||
(value[i] >= 'A' && value[i] <= 'Z')))
return false;
}
} else {
return false; return false;
} } else if (secret.wep_key_type == NM.WepKeyType.PASSPHRASE) {
} else if (secret.wep_key_type == NM.WepKeyType.PASSPHRASE) { if (value.length < 0 || value.length > 64)
if (value.length < 0 || value.length > 64) return false;
return false; }
}
return true; return true;
} }
_getWirelessSecrets(secrets, _wirelessSetting) { _getWirelessSecrets(secrets, wirelessSetting) {
let wirelessSecuritySetting = this._connection.get_setting_wireless_security(); let wirelessSecuritySetting = this._connection.get_setting_wireless_security();
if (this._settingName == '802-1x') { if (this._settingName == '802-1x') {
@ -213,13 +208,12 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
// First the easy ones // First the easy ones
case 'wpa-none': case 'wpa-none':
case 'wpa-psk': case 'wpa-psk':
case 'sae':
secrets.push({ label: _("Password: "), key: 'psk', secrets.push({ label: _("Password: "), key: 'psk',
value: wirelessSecuritySetting.psk || '', value: wirelessSecuritySetting.psk || '',
validate: this._validateWpaPsk, password: true }); validate: this._validateWpaPsk, password: true });
break; break;
case 'none': // static WEP case 'none': // static WEP
secrets.push({ label: _("Key: "), key: `wep-key${wirelessSecuritySetting.wep_tx_keyidx}`, secrets.push({ label: _("Key: "), key: 'wep-key' + wirelessSecuritySetting.wep_tx_keyidx,
value: wirelessSecuritySetting.get_wep_key(wirelessSecuritySetting.wep_tx_keyidx) || '', value: wirelessSecuritySetting.get_wep_key(wirelessSecuritySetting.wep_tx_keyidx) || '',
wep_key_type: wirelessSecuritySetting.wep_key_type, wep_key_type: wirelessSecuritySetting.wep_key_type,
validate: this._validateStaticWep, password: true }); validate: this._validateStaticWep, password: true });
@ -235,12 +229,13 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
this._get8021xSecrets(secrets); this._get8021xSecrets(secrets);
break; break;
default: default:
log(`Invalid wireless key management: ${wirelessSecuritySetting.key_mgmt}`); log('Invalid wireless key management: ' + wirelessSecuritySetting.key_mgmt);
} }
} }
_get8021xSecrets(secrets) { _get8021xSecrets(secrets) {
let ieee8021xSetting = this._connection.get_setting_802_1x(); let ieee8021xSetting = this._connection.get_setting_802_1x();
let phase2method;
/* If hints were given we know exactly what we need to ask */ /* If hints were given we know exactly what we need to ask */
if (this._settingName == "802-1x" && this._hints.length) { if (this._settingName == "802-1x" && this._hints.length) {
@ -277,7 +272,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
value: ieee8021xSetting.private_key_password || '', password: true }); value: ieee8021xSetting.private_key_password || '', password: true });
break; break;
default: default:
log(`Invalid EAP/IEEE802.1x method: ${ieee8021xSetting.get_eap_method(0)}`); log('Invalid EAP/IEEE802.1x method: ' + ieee8021xSetting.get_eap_method(0));
} }
} }
@ -308,7 +303,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
let ssid; let ssid;
let content = { }; let content = { };
content.secrets = []; content.secrets = [ ];
switch (connectionType) { switch (connectionType) {
case '802-11-wireless': case '802-11-wireless':
@ -331,7 +326,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
this._getPPPoESecrets(content.secrets); this._getPPPoESecrets(content.secrets);
break; break;
case 'gsm': case 'gsm':
if (this._hints.includes('pin')) { if (this._hints.indexOf('pin') != -1) {
let gsmSetting = this._connection.get_setting_gsm(); let gsmSetting = this._connection.get_setting_gsm();
content.title = _("PIN code required"); content.title = _("PIN code required");
content.message = _("PIN code is needed for the mobile broadband device"); content.message = _("PIN code is needed for the mobile broadband device");
@ -347,12 +342,12 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
this._getMobileSecrets(content.secrets, connectionType); this._getMobileSecrets(content.secrets, connectionType);
break; break;
default: default:
log(`Invalid connection type: ${connectionType}`); log('Invalid connection type: ' + connectionType);
} };
return content; return content;
} }
}); };
var VPNRequestHandler = class { var VPNRequestHandler = class {
constructor(agent, requestId, authHelper, serviceType, connection, hints, flags) { constructor(agent, requestId, authHelper, serviceType, connection, hints, flags) {
@ -363,15 +358,16 @@ var VPNRequestHandler = class {
this._pluginOutBuffer = []; this._pluginOutBuffer = [];
this._title = null; this._title = null;
this._description = null; this._description = null;
this._content = []; this._content = [ ];
this._shellDialog = null; this._shellDialog = null;
let connectionSetting = connection.get_setting_connection(); let connectionSetting = connection.get_setting_connection();
let argv = [authHelper.fileName, let argv = [ authHelper.fileName,
'-u', connectionSetting.uuid, '-u', connectionSetting.uuid,
'-n', connectionSetting.id, '-n', connectionSetting.id,
'-s', serviceType]; '-s', serviceType
];
if (authHelper.externalUIMode) if (authHelper.externalUIMode)
argv.push('--external-ui-mode'); argv.push('--external-ui-mode');
if (flags & NM.SecretAgentGetSecretsFlags.ALLOW_INTERACTION) if (flags & NM.SecretAgentGetSecretsFlags.ALLOW_INTERACTION)
@ -388,7 +384,7 @@ var VPNRequestHandler = class {
this._newStylePlugin = authHelper.externalUIMode; this._newStylePlugin = authHelper.externalUIMode;
try { try {
let [success_, pid, stdin, stdout, stderr] = let [success, pid, stdin, stdout, stderr] =
GLib.spawn_async_with_pipes(null, /* pwd */ GLib.spawn_async_with_pipes(null, /* pwd */
argv, argv,
null, /* envp */ null, /* envp */
@ -410,7 +406,7 @@ var VPNRequestHandler = class {
this._vpnChildFinished.bind(this)); this._vpnChildFinished.bind(this));
this._writeConnection(); this._writeConnection();
} catch (e) { } catch(e) {
logError(e, 'error while spawning VPN auth helper'); logError(e, 'error while spawning VPN auth helper');
this._agent.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR); this._agent.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
@ -427,7 +423,7 @@ var VPNRequestHandler = class {
} else { } else {
try { try {
this._stdin.write('QUIT\n\n', null); this._stdin.write('QUIT\n\n', null);
} catch (e) { /* ignore broken pipe errors */ } } catch(e) { /* ignore broken pipe errors */ }
} }
this.destroy(); this.destroy();
@ -447,7 +443,7 @@ var VPNRequestHandler = class {
this._destroyed = true; this._destroyed = true;
} }
_vpnChildFinished(pid, status, _requestObj) { _vpnChildFinished(pid, status, requestObj) {
this._childWatch = 0; this._childWatch = 0;
if (this._newStylePlugin) { if (this._newStylePlugin) {
// For new style plugin, all work is done in the async reading functions // For new style plugin, all work is done in the async reading functions
@ -462,9 +458,8 @@ var VPNRequestHandler = class {
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED); this._agent.respond(this._requestId, Shell.NetworkAgentResponse.USER_CANCELED);
else else
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED); this._agent.respond(this._requestId, Shell.NetworkAgentResponse.CONFIRMED);
} else { } else
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR); this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
}
this.destroy(); this.destroy();
} }
@ -477,7 +472,7 @@ var VPNRequestHandler = class {
if (line == '' && this._previousLine == '') { if (line == '' && this._previousLine == '') {
try { try {
this._stdin.write('QUIT\n\n', null); this._stdin.write('QUIT\n\n', null);
} catch (e) { /* ignore broken pipe errors */ } } catch(e) { /* ignore broken pipe errors */ }
} else { } else {
this._agent.set_password(this._requestId, this._previousLine, line); this._agent.set_password(this._requestId, this._previousLine, line);
this._previousLine = undefined; this._previousLine = undefined;
@ -489,7 +484,7 @@ var VPNRequestHandler = class {
_readStdoutOldStyle() { _readStdoutOldStyle() {
this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, (stream, result) => { this._dataStdout.read_line_async(GLib.PRIORITY_DEFAULT, null, (stream, result) => {
let [line, len_] = this._dataStdout.read_line_finish_utf8(result); let [line, len] = this._dataStdout.read_line_finish_utf8(result);
if (line == null) { if (line == null) {
// end of file // end of file
@ -544,7 +539,7 @@ var VPNRequestHandler = class {
message: keyfile.get_string(VPN_UI_GROUP, 'Description'), message: keyfile.get_string(VPN_UI_GROUP, 'Description'),
secrets: [] }; secrets: [] };
let [groups, len_] = keyfile.get_groups(); let [groups, len] = keyfile.get_groups();
for (let i = 0; i < groups.length; i++) { for (let i = 0; i < groups.length; i++) {
if (groups[i] == VPN_UI_GROUP) if (groups[i] == VPN_UI_GROUP)
continue; continue;
@ -553,12 +548,11 @@ var VPNRequestHandler = class {
let shouldAsk = keyfile.get_boolean(groups[i], 'ShouldAsk'); let shouldAsk = keyfile.get_boolean(groups[i], 'ShouldAsk');
if (shouldAsk) { if (shouldAsk) {
contentOverride.secrets.push({ contentOverride.secrets.push({ label: keyfile.get_string(groups[i], 'Label'),
label: keyfile.get_string(groups[i], 'Label'), key: groups[i],
key: groups[i], value: value,
value: value, password: keyfile.get_boolean(groups[i], 'IsSecret')
password: keyfile.get_boolean(groups[i], 'IsSecret'), });
});
} else { } else {
if (!value.length) // Ignore empty secrets if (!value.length) // Ignore empty secrets
continue; continue;
@ -566,7 +560,7 @@ var VPNRequestHandler = class {
this._agent.set_password(this._requestId, groups[i], value); this._agent.set_password(this._requestId, groups[i], value);
} }
} }
} catch (e) { } catch(e) {
// No output is a valid case it means "both secrets are stored" // No output is a valid case it means "both secrets are stored"
if (data.length > 0) { if (data.length > 0) {
logError(e, 'error while reading VPN plugin output keyfile'); logError(e, 'error while reading VPN plugin output keyfile');
@ -592,15 +586,15 @@ var VPNRequestHandler = class {
try { try {
vpnSetting.foreach_data_item((key, value) => { vpnSetting.foreach_data_item((key, value) => {
this._stdin.write(`DATA_KEY=${key}\n`, null); this._stdin.write('DATA_KEY=' + key + '\n', null);
this._stdin.write(`DATA_VAL=${value || ''}\n\n`, null); this._stdin.write('DATA_VAL=' + (value || '') + '\n\n', null);
}); });
vpnSetting.foreach_secret((key, value) => { vpnSetting.foreach_secret((key, value) => {
this._stdin.write(`SECRET_KEY=${key}\n`, null); this._stdin.write('SECRET_KEY=' + key + '\n', null);
this._stdin.write(`SECRET_VAL=${value || ''}\n\n`, null); this._stdin.write('SECRET_VAL=' + (value || '') + '\n\n', null);
}); });
this._stdin.write('DONE\n\n', null); this._stdin.write('DONE\n\n', null);
} catch (e) { } catch(e) {
logError(e, 'internal error while writing connection to helper'); logError(e, 'internal error while writing connection to helper');
this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR); this._agent.respond(this._requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
@ -612,11 +606,10 @@ Signals.addSignalMethods(VPNRequestHandler.prototype);
var NetworkAgent = class { var NetworkAgent = class {
constructor() { constructor() {
this._native = new Shell.NetworkAgent({ this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent',
identifier: 'org.gnome.Shell.NetworkAgent', capabilities: NM.SecretAgentCapabilities.VPN_HINTS,
capabilities: NM.SecretAgentCapabilities.VPN_HINTS, auto_register: false
auto_register: false, });
});
this._dialogs = { }; this._dialogs = { };
this._vpnRequests = { }; this._vpnRequests = { };
@ -625,9 +618,9 @@ var NetworkAgent = class {
this._pluginDir = Gio.file_new_for_path(Config.VPNDIR); this._pluginDir = Gio.file_new_for_path(Config.VPNDIR);
try { try {
let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null); let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null);
monitor.connect('changed', () => (this._vpnCacheBuilt = false)); monitor.connect('changed', () => { this._vpnCacheBuilt = false; });
} catch (e) { } catch(e) {
log(`Failed to create monitor for VPN plugin dir: ${e.message}`); log('Failed to create monitor for VPN plugin dir: ' + e.message);
} }
this._native.connect('new-request', this._newRequest.bind(this)); this._native.connect('new-request', this._newRequest.bind(this));
@ -638,7 +631,7 @@ var NetworkAgent = class {
try { try {
this._native.init_finish(res); this._native.init_finish(res);
this._initialized = true; this._initialized = true;
} catch (e) { } catch(e) {
this._native = null; this._native = null;
logError(e, 'error initializing the NetworkManager Agent'); logError(e, 'error initializing the NetworkManager Agent');
} }
@ -686,13 +679,12 @@ var NetworkAgent = class {
let connectionSetting = connection.get_setting_connection(); let connectionSetting = connection.get_setting_connection();
let connectionType = connectionSetting.get_connection_type(); let connectionType = connectionSetting.get_connection_type();
switch (connectionType) { switch (connectionType) {
case '802-11-wireless': { case '802-11-wireless':
let wirelessSetting = connection.get_setting_wireless(); let wirelessSetting = connection.get_setting_wireless();
let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data()); let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data());
title = _("Authentication required by wireless network"); title = _("Authentication required by wireless network");
body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid); body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
break; break;
}
case '802-3-ethernet': case '802-3-ethernet':
title = _("Wired 802.1X authentication"); title = _("Wired 802.1X authentication");
body = _("A password is required to connect to “%s”.".format(connection.get_id())); body = _("A password is required to connect to “%s”.".format(connection.get_id()));
@ -702,7 +694,8 @@ var NetworkAgent = class {
body = _("A password is required to connect to “%s”.".format(connection.get_id())); body = _("A password is required to connect to “%s”.".format(connection.get_id()));
break; break;
case 'gsm': case 'gsm':
if (hints.includes('pin')) { if (hints.indexOf('pin') != -1) {
let gsmSetting = connection.get_setting_gsm();
title = _("PIN code required"); title = _("PIN code required");
body = _("PIN code is needed for the mobile broadband device"); body = _("PIN code is needed for the mobile broadband device");
break; break;
@ -714,7 +707,7 @@ var NetworkAgent = class {
body = _("A password is required to connect to “%s”.").format(connectionSetting.get_id()); body = _("A password is required to connect to “%s”.").format(connectionSetting.get_id());
break; break;
default: default:
log(`Invalid connection type: ${connectionType}`); log('Invalid connection type: ' + connectionType);
this._native.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR); this._native.respond(requestId, Shell.NetworkAgentResponse.INTERNAL_ERROR);
return; return;
} }

View File

@ -1,8 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */
const { AccountsService, Clutter, Gio, GLib, const { AccountsService, Clutter, Gio, GLib,
GObject, Pango, PolkitAgent, Polkit, Shell, St } = imports.gi; Pango, PolkitAgent, Polkit, Shell, St } = imports.gi;
const Signals = imports.signals;
const Animation = imports.ui.animation; const Animation = imports.ui.animation;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
@ -15,11 +15,9 @@ var DIALOG_ICON_SIZE = 48;
var WORK_SPINNER_ICON_SIZE = 16; var WORK_SPINNER_ICON_SIZE = 16;
var AuthenticationDialog = GObject.registerClass({ var AuthenticationDialog = class extends ModalDialog.ModalDialog {
Signals: { 'done': { param_types: [GObject.TYPE_BOOLEAN] } } constructor(actionId, body, cookie, userNames) {
}, class AuthenticationDialog extends ModalDialog.ModalDialog { super({ styleClass: 'prompt-dialog' });
_init(actionId, body, cookie, userNames) {
super._init({ styleClass: 'prompt-dialog' });
this.actionId = actionId; this.actionId = actionId;
this.message = body; this.message = body;
@ -27,7 +25,7 @@ var AuthenticationDialog = GObject.registerClass({
this._wasDismissed = false; this._wasDismissed = false;
this._sessionUpdatedId = Main.sessionMode.connect('updated', () => { this._sessionUpdatedId = Main.sessionMode.connect('updated', () => {
this.visible = !Main.sessionMode.isLocked; this._group.visible = !Main.sessionMode.isLocked;
}); });
this.connect('closed', this._onDialogClosed.bind(this)); this.connect('closed', this._onDialogClosed.bind(this));
@ -39,19 +37,19 @@ var AuthenticationDialog = GObject.registerClass({
this.contentLayout.add_actor(content); this.contentLayout.add_actor(content);
if (userNames.length > 1) { if (userNames.length > 1) {
log(`polkitAuthenticationAgent: Received ${userNames.length} ` + log('polkitAuthenticationAgent: Received ' + userNames.length +
'identities that can be used for authentication. Only ' + ' identities that can be used for authentication. Only ' +
'considering one.'); 'considering one.');
} }
let userName = GLib.get_user_name(); let userName = GLib.get_user_name();
if (!userNames.includes(userName)) if (userNames.indexOf(userName) < 0)
userName = 'root'; userName = 'root';
if (!userNames.includes(userName)) if (userNames.indexOf(userName) < 0)
userName = userNames[0]; userName = userNames[0];
this._user = AccountsService.UserManager.get_default().get_user(userName); this._user = AccountsService.UserManager.get_default().get_user(userName);
let userRealName = this._user.get_real_name(); let userRealName = this._user.get_real_name()
this._userLoadedId = this._user.connect('notify::is_loaded', this._userLoadedId = this._user.connect('notify::is_loaded',
this._onUserChanged.bind(this)); this._onUserChanged.bind(this));
this._userChangedId = this._user.connect('changed', this._userChangedId = this._user.connect('changed',
@ -78,15 +76,15 @@ var AuthenticationDialog = GObject.registerClass({
styleClass: 'polkit-dialog-user-icon' }); styleClass: 'polkit-dialog-user-icon' });
this._userAvatar.actor.hide(); this._userAvatar.actor.hide();
userBox.add(this._userAvatar.actor, userBox.add(this._userAvatar.actor,
{ x_fill: true, { x_fill: true,
y_fill: false, y_fill: false,
x_align: St.Align.END, x_align: St.Align.END,
y_align: St.Align.START }); y_align: St.Align.START });
let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label', let userLabel = new St.Label(({ style_class: 'polkit-dialog-user-label',
text: userRealName })); text: userRealName }));
userBox.add(userLabel, userBox.add(userLabel,
{ x_fill: true, { x_fill: true,
y_fill: false, y_fill: false,
x_align: St.Align.END, x_align: St.Align.END,
y_align: St.Align.MIDDLE }); y_align: St.Align.MIDDLE });
} }
@ -99,7 +97,7 @@ var AuthenticationDialog = GObject.registerClass({
this._passwordBox.add(this._passwordLabel, { y_fill: false, y_align: St.Align.MIDDLE }); this._passwordBox.add(this._passwordLabel, { y_fill: false, y_align: St.Align.MIDDLE });
this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry', this._passwordEntry = new St.Entry({ style_class: 'prompt-dialog-password-entry',
text: "", text: "",
can_focus: true }); can_focus: true});
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true }); ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this)); this._passwordEntry.clutter_text.connect('activate', this._onEntryActivate.bind(this));
this._passwordBox.add(this._passwordEntry, this._passwordBox.add(this._passwordEntry,
@ -128,7 +126,7 @@ var AuthenticationDialog = GObject.registerClass({
* gnome-shell.css sets the color to be transparent * gnome-shell.css sets the color to be transparent
*/ */
this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label', this._nullMessageLabel = new St.Label({ style_class: 'prompt-dialog-null-label',
text: 'abc' }); text: 'abc'});
this._nullMessageLabel.add_style_class_name('hidden'); this._nullMessageLabel.add_style_class_name('hidden');
this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._nullMessageLabel.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this._nullMessageLabel.clutter_text.line_wrap = true; this._nullMessageLabel.clutter_text.line_wrap = true;
@ -138,7 +136,7 @@ var AuthenticationDialog = GObject.registerClass({
this._cancelButton = this.addButton({ label: _("Cancel"), this._cancelButton = this.addButton({ label: _("Cancel"),
action: this.cancel.bind(this), action: this.cancel.bind(this),
key: Clutter.Escape }); key: Clutter.Escape });
this._okButton = this.addButton({ label: _("Authenticate"), this._okButton = this.addButton({ label: _("Authenticate"),
action: this._onAuthenticateButtonPressed.bind(this), action: this._onAuthenticateButtonPressed.bind(this),
default: true }); default: true });
@ -181,9 +179,9 @@ var AuthenticationDialog = GObject.registerClass({
// //
// We could add retrying if this turns out to be a problem // We could add retrying if this turns out to be a problem
log('polkitAuthenticationAgent: Failed to show modal dialog. ' + log('polkitAuthenticationAgent: Failed to show modal dialog.' +
`Dismissing authentication request for action-id ${this.actionId} ` + ' Dismissing authentication request for action-id ' + this.actionId +
`cookie ${this._cookie}`); ' cookie ' + this._cookie);
this._emitDone(true); this._emitDone(true);
} }
} }
@ -251,14 +249,14 @@ var AuthenticationDialog = GObject.registerClass({
} }
} }
_onSessionRequest(session, request, echoOn) { _onSessionRequest(session, request, echo_on) {
// Cheap localization trick // Cheap localization trick
if (request == 'Password:' || request == 'Password: ') if (request == 'Password:' || request == 'Password: ')
this._passwordLabel.set_text(_("Password:")); this._passwordLabel.set_text(_("Password:"));
else else
this._passwordLabel.set_text(request); this._passwordLabel.set_text(request);
if (echoOn) if (echo_on)
this._passwordEntry.clutter_text.set_password_char(''); this._passwordEntry.clutter_text.set_password_char('');
else else
this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE this._passwordEntry.clutter_text.set_password_char('\u25cf'); // ● U+25CF BLACK CIRCLE
@ -328,7 +326,8 @@ var AuthenticationDialog = GObject.registerClass({
this._destroySession(); this._destroySession();
} }
}); };
Signals.addSignalMethods(AuthenticationDialog.prototype);
var AuthenticationAgent = class { var AuthenticationAgent = class {
constructor() { constructor() {
@ -343,7 +342,7 @@ var AuthenticationAgent = class {
enable() { enable() {
try { try {
this._native.register(); this._native.register();
} catch (e) { } catch(e) {
log('Failed to register AuthenticationAgent'); log('Failed to register AuthenticationAgent');
} }
} }
@ -351,7 +350,7 @@ var AuthenticationAgent = class {
disable() { disable() {
try { try {
this._native.unregister(); this._native.unregister();
} catch (e) { } catch(e) {
log('Failed to unregister AuthenticationAgent'); log('Failed to unregister AuthenticationAgent');
} }
} }
@ -384,11 +383,11 @@ var AuthenticationAgent = class {
this._currentDialog.performAuthentication(); this._currentDialog.performAuthentication();
} }
_onCancel(_nativeAgent) { _onCancel(nativeAgent) {
this._completeRequest(false); this._completeRequest(false);
} }
_onDialogDone(_dialog, dismissed) { _onDialogDone(dialog, dismissed) {
this._completeRequest(dismissed); this._completeRequest(dismissed);
} }

View File

@ -1,14 +1,14 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */
const { Clutter, Gio, GLib, GObject, St } = imports.gi; const { Clutter, Gio, GLib, GObject, St } = imports.gi;
const Lang = imports.lang; const Lang = imports.lang;
const Mainloop = imports.mainloop;
var Tpl = null; var Tpl = null;
var Tp = null; var Tp = null;
try { try {
({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi); ({ TelepathyGLib: Tp, TelepathyLogger: Tpl } = imports.gi);
} catch (e) { } catch(e) {
log('Telepathy is not available, chat integration will be disabled.'); log('Telepathy is not available, chat integration will be disabled.');
} }
@ -40,8 +40,10 @@ var NotificationDirection = {
RECEIVED: 'chat-received' RECEIVED: 'chat-received'
}; };
var N_ = s => s;
function makeMessageFromTpMessage(tpMessage, direction) { function makeMessageFromTpMessage(tpMessage, direction) {
let [text, flags_] = tpMessage.to_text(); let [text, flags] = tpMessage.to_text();
let timestamp = tpMessage.get_sent_timestamp(); let timestamp = tpMessage.get_sent_timestamp();
if (timestamp == 0) if (timestamp == 0)
@ -87,7 +89,7 @@ var TelepathyComponent = class {
try { try {
this._client.register(); this._client.register();
} catch (e) { } catch (e) {
throw new Error(`Could not register Telepathy client. Error: ${e}`); throw new Error('Couldn\'t register Telepathy client. Error: \n' + e);
} }
if (!this._client.account_manager.is_prepared(Tp.AccountManager.get_feature_quark_core())) if (!this._client.account_manager.is_prepared(Tp.AccountManager.get_feature_quark_core()))
@ -147,20 +149,20 @@ class TelepathyClient extends Tp.BaseClient {
this._delegatedChannelsCb.bind(this)); this._delegatedChannelsCb.bind(this));
} }
vfunc_observe_channels(...args) { vfunc_observe_channels(account, conn, channels,
let [account, conn, channels, dispatchOp_, requests_, context] = args; dispatchOp, requests, context) {
let len = channels.length; let len = channels.length;
for (let i = 0; i < len; i++) { for (let i = 0; i < len; i++) {
let channel = channels[i]; let channel = channels[i];
let [targetHandle_, targetHandleType] = channel.get_handle(); let [targetHandle, targetHandleType] = channel.get_handle();
if (channel.get_invalidated()) if (channel.get_invalidated())
continue; continue;
/* Only observe contact text channels */ /* Only observe contact text channels */
if ((!(channel instanceof Tp.TextChannel)) || if ((!(channel instanceof Tp.TextChannel)) ||
targetHandleType != Tp.HandleType.CONTACT) targetHandleType != Tp.HandleType.CONTACT)
continue; continue;
this._createChatSource(account, conn, channel, channel.get_target_contact()); this._createChatSource(account, conn, channel, channel.get_target_contact());
} }
@ -180,8 +182,8 @@ class TelepathyClient extends Tp.BaseClient {
}); });
} }
vfunc_handle_channels(...args) { vfunc_handle_channels(account, conn, channels, requests,
let [account, conn, channels, requests_, userActionTime_, context] = args; user_action_time, context) {
this._handlingChannels(account, conn, channels, true); this._handlingChannels(account, conn, channels, true);
context.accept(); context.accept();
} }
@ -198,7 +200,7 @@ class TelepathyClient extends Tp.BaseClient {
} }
if (channel.get_invalidated()) if (channel.get_invalidated())
continue; continue;
// 'notify' will be true when coming from an actual HandleChannels // 'notify' will be true when coming from an actual HandleChannels
// call, and not when from a successful Claim call. The point is // call, and not when from a successful Claim call. The point is
@ -220,8 +222,8 @@ class TelepathyClient extends Tp.BaseClient {
} }
} }
vfunc_add_dispatch_operation(...args) { vfunc_add_dispatch_operation(account, conn, channels,
let [account, conn, channels, dispatchOp, context] = args; dispatchOp, context) {
let channel = channels[0]; let channel = channels[0];
let chanType = channel.get_channel_type(); let chanType = channel.get_channel_type();
@ -239,7 +241,7 @@ class TelepathyClient extends Tp.BaseClient {
} }
_approveTextChannel(account, conn, channel, dispatchOp, context) { _approveTextChannel(account, conn, channel, dispatchOp, context) {
let [targetHandle_, targetHandleType] = channel.get_handle(); let [targetHandle, targetHandleType] = channel.get_handle();
if (targetHandleType != Tp.HandleType.CONTACT) { if (targetHandleType != Tp.HandleType.CONTACT) {
context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT, context.fail(new Tp.Error({ code: Tp.Error.INVALID_ARGUMENT,
@ -253,14 +255,14 @@ class TelepathyClient extends Tp.BaseClient {
dispatchOp.claim_with_finish(result); dispatchOp.claim_with_finish(result);
this._handlingChannels(account, conn, [channel], false); this._handlingChannels(account, conn, [channel], false);
} catch (err) { } catch (err) {
log(`Failed to Claim channel: ${err}`); log('Failed to Claim channel: ' + err);
} }
}); });
context.accept(); context.accept();
} }
_delegatedChannelsCb(_client, _channels) { _delegatedChannelsCb(client, channels) {
// Nothing to do as we don't make a distinction between observed and // Nothing to do as we don't make a distinction between observed and
// handled channels. // handled channels.
} }
@ -360,28 +362,28 @@ var ChatSource = class extends MessageTray.Source {
let presenceType = this._contact.get_presence_type(); let presenceType = this._contact.get_presence_type();
switch (presenceType) { switch (presenceType) {
case Tp.ConnectionPresenceType.AVAILABLE: case Tp.ConnectionPresenceType.AVAILABLE:
iconName = 'user-available'; iconName = 'user-available';
break; break;
case Tp.ConnectionPresenceType.BUSY: case Tp.ConnectionPresenceType.BUSY:
iconName = 'user-busy'; iconName = 'user-busy';
break; break;
case Tp.ConnectionPresenceType.OFFLINE: case Tp.ConnectionPresenceType.OFFLINE:
iconName = 'user-offline'; iconName = 'user-offline';
break; break;
case Tp.ConnectionPresenceType.HIDDEN: case Tp.ConnectionPresenceType.HIDDEN:
iconName = 'user-invisible'; iconName = 'user-invisible';
break; break;
case Tp.ConnectionPresenceType.AWAY: case Tp.ConnectionPresenceType.AWAY:
iconName = 'user-away'; iconName = 'user-away';
break; break;
case Tp.ConnectionPresenceType.EXTENDED_AWAY: case Tp.ConnectionPresenceType.EXTENDED_AWAY:
iconName = 'user-idle'; iconName = 'user-idle';
break; break;
default: default:
iconName = 'user-offline'; iconName = 'user-offline';
} }
return new Gio.ThemedIcon({ name: iconName }); return new Gio.ThemedIcon({ name: iconName });
} }
_updateAvatarIcon() { _updateAvatarIcon() {
@ -399,7 +401,7 @@ var ChatSource = class extends MessageTray.Source {
if (this._client.is_handling_channel(this._channel)) { if (this._client.is_handling_channel(this._channel)) {
// We are handling the channel, try to pass it to Empathy or Polari // We are handling the channel, try to pass it to Empathy or Polari
// (depending on the channel type) // (depending on the channel type)
// We don't check if either app is available - mission control will // We don't check if either app is availble - mission control will
// fallback to something else if activation fails // fallback to something else if activation fails
let target; let target;
@ -427,7 +429,7 @@ var ChatSource = class extends MessageTray.Source {
} }
_displayPendingMessages(logManager, result) { _displayPendingMessages(logManager, result) {
let [success_, events] = logManager.get_filtered_events_finish(result); let [success, events] = logManager.get_filtered_events_finish(result);
let logMessages = events.map(makeMessageFromTplEvent); let logMessages = events.map(makeMessageFromTplEvent);
this._ensureNotification(); this._ensureNotification();
@ -545,8 +547,8 @@ var ChatSource = class extends MessageTray.Source {
// Wait a bit before notifying for the received message, a handler // Wait a bit before notifying for the received message, a handler
// could ack it in the meantime. // could ack it in the meantime.
if (this._notifyTimeoutId != 0) if (this._notifyTimeoutId != 0)
GLib.source_remove(this._notifyTimeoutId); Mainloop.source_remove(this._notifyTimeoutId);
this._notifyTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, this._notifyTimeoutId = Mainloop.timeout_add(500,
this._notifyTimeout.bind(this)); this._notifyTimeout.bind(this));
GLib.Source.set_name_by_id(this._notifyTimeoutId, '[gnome-shell] this._notifyTimeout'); GLib.Source.set_name_by_id(this._notifyTimeoutId, '[gnome-shell] this._notifyTimeout');
} }
@ -562,7 +564,7 @@ var ChatSource = class extends MessageTray.Source {
// This is called for both messages we send from // This is called for both messages we send from
// our client and other clients as well. // our client and other clients as well.
_messageSent(channel, message, _flags, _token) { _messageSent(channel, message, flags, token) {
this._ensureNotification(); this._ensureNotification();
message = makeMessageFromTpMessage(message, NotificationDirection.SENT); message = makeMessageFromTpMessage(message, NotificationDirection.SENT);
this._notification.appendMessage(message); this._notification.appendMessage(message);
@ -595,12 +597,12 @@ var ChatSource = class extends MessageTray.Source {
// keep track of it with the ChatStateChanged signal but it is good // keep track of it with the ChatStateChanged signal but it is good
// enough right now. // enough right now.
if (state != this._chatState) { if (state != this._chatState) {
this._chatState = state; this._chatState = state;
this._channel.set_chat_state_async(state, null); this._channel.set_chat_state_async(state, null);
} }
} }
_presenceChanged(_contact, _presence, _status, _message) { _presenceChanged(contact, presence, status, message) {
if (this._notification) if (this._notification)
this._notification.update(this._notification.title, this._notification.update(this._notification.title,
this._notification.bannerBodyText, this._notification.bannerBodyText,
@ -640,7 +642,7 @@ var ChatNotification = class extends MessageTray.Notification {
destroy(reason) { destroy(reason) {
if (this._timestampTimeoutId) if (this._timestampTimeoutId)
GLib.source_remove(this._timestampTimeoutId); Mainloop.source_remove(this._timestampTimeoutId);
this._timestampTimeoutId = 0; this._timestampTimeoutId = 0;
super.destroy(reason); super.destroy(reason);
} }
@ -673,8 +675,8 @@ var ChatNotification = class extends MessageTray.Notification {
{ datetime: GLib.DateTime.new_from_unix_local (message.timestamp), { datetime: GLib.DateTime.new_from_unix_local (message.timestamp),
bannerMarkup: true }); bannerMarkup: true });
let group = (message.direction == NotificationDirection.RECEIVED let group = (message.direction == NotificationDirection.RECEIVED ?
? 'received' : 'sent'); 'received' : 'sent');
this._append({ body: messageBody, this._append({ body: messageBody,
group: group, group: group,
@ -696,8 +698,8 @@ var ChatNotification = class extends MessageTray.Notification {
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise // SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
// we'll keep SCROLLBACK_IDLE_LENGTH messages. // we'll keep SCROLLBACK_IDLE_LENGTH messages.
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
? SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH; SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
let filteredHistory = this.messages.filter(item => item.realMessage); let filteredHistory = this.messages.filter(item => item.realMessage);
if (filteredHistory.length > maxLength) { if (filteredHistory.length > maxLength) {
@ -728,7 +730,7 @@ var ChatNotification = class extends MessageTray.Notification {
// Reset the old message timeout // Reset the old message timeout
if (this._timestampTimeoutId) if (this._timestampTimeoutId)
GLib.source_remove(this._timestampTimeoutId); Mainloop.source_remove(this._timestampTimeoutId);
this._timestampTimeoutId = 0; this._timestampTimeoutId = 0;
let message = { realMessage: props.group != 'meta', let message = { realMessage: props.group != 'meta',
@ -746,8 +748,7 @@ var ChatNotification = class extends MessageTray.Notification {
} else { } else {
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME // Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
// from the timestamp of the message. // from the timestamp of the message.
this._timestampTimeoutId = GLib.timeout_add_seconds( this._timestampTimeoutId = Mainloop.timeout_add_seconds(
GLib.PRIORITY_DEFAULT,
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp), SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
this.appendTimestamp.bind(this)); this.appendTimestamp.bind(this));
GLib.Source.set_name_by_id(this._timestampTimeoutId, '[gnome-shell] this.appendTimestamp'); GLib.Source.set_name_by_id(this._timestampTimeoutId, '[gnome-shell] this.appendTimestamp');
@ -952,15 +953,14 @@ var ChatNotificationBanner = class extends MessageTray.NotificationBanner {
// Remove composing timeout. // Remove composing timeout.
if (this._composingTimeoutId > 0) { if (this._composingTimeoutId > 0) {
GLib.source_remove(this._composingTimeoutId); Mainloop.source_remove(this._composingTimeoutId);
this._composingTimeoutId = 0; this._composingTimeoutId = 0;
} }
if (text != '') { if (text != '') {
this.notification.source.setChatState(Tp.ChannelChatState.COMPOSING); this.notification.source.setChatState(Tp.ChannelChatState.COMPOSING);
this._composingTimeoutId = GLib.timeout_add_seconds( this._composingTimeoutId = Mainloop.timeout_add_seconds(
GLib.PRIORITY_DEFAULT,
COMPOSING_STOP_TIMEOUT, COMPOSING_STOP_TIMEOUT,
this._composingStopTimeout.bind(this)); this._composingStopTimeout.bind(this));
GLib.Source.set_name_by_id(this._composingTimeoutId, '[gnome-shell] this._composingStopTimeout'); GLib.Source.set_name_by_id(this._composingTimeoutId, '[gnome-shell] this._composingStopTimeout');

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported CtrlAltTabManager */
const { Clutter, GObject, Meta, Shell, St } = imports.gi; const { Clutter, GObject, Meta, Shell, St } = imports.gi;
@ -8,6 +7,7 @@ const SwitcherPopup = imports.ui.switcherPopup;
const Params = imports.misc.params; const Params = imports.misc.params;
var POPUP_APPICON_SIZE = 96; var POPUP_APPICON_SIZE = 96;
var POPUP_FADE_TIME = 0.1; // seconds
var SortGroup = { var SortGroup = {
TOP: 0, TOP: 0,
@ -33,7 +33,7 @@ var CtrlAltTabManager = class CtrlAltTabManager {
item.iconName = icon; item.iconName = icon;
this._items.push(item); this._items.push(item);
root.connect('destroy', () => this.removeGroup(root)); root.connect('destroy', () => { this.removeGroup(root); });
if (root instanceof St.Widget) if (root instanceof St.Widget)
global.focus_manager.add_group(root); global.focus_manager.add_group(root);
} }
@ -64,8 +64,9 @@ var CtrlAltTabManager = class CtrlAltTabManager {
if (a.sortGroup != b.sortGroup) if (a.sortGroup != b.sortGroup)
return a.sortGroup - b.sortGroup; return a.sortGroup - b.sortGroup;
let [ax] = a.proxy.get_transformed_position(); let ax, bx, y;
let [bx] = b.proxy.get_transformed_position(); [ax, y] = a.proxy.get_transformed_position();
[bx, y] = b.proxy.get_transformed_position();
return ax - bx; return ax - bx;
} }

View File

@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Dash */
const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi; const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals; const Signals = imports.signals;
const AppDisplay = imports.ui.appDisplay; const AppDisplay = imports.ui.appDisplay;
@ -9,10 +9,11 @@ const AppFavorites = imports.ui.appFavorites;
const DND = imports.ui.dnd; const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid; const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var DASH_ANIMATION_TIME = 200; var DASH_ANIMATION_TIME = 0.2;
var DASH_ITEM_LABEL_SHOW_TIME = 150; var DASH_ITEM_LABEL_SHOW_TIME = 0.15;
var DASH_ITEM_LABEL_HIDE_TIME = 100; var DASH_ITEM_LABEL_HIDE_TIME = 0.1;
var DASH_ITEM_HOVER_TIMEOUT = 300; var DASH_ITEM_HOVER_TIMEOUT = 300;
function getAppFromSource(source) { function getAppFromSource(source) {
@ -23,30 +24,6 @@ function getAppFromSource(source) {
} }
} }
var DashIcon = class DashIcon extends AppDisplay.AppIcon {
constructor(app) {
super(app, {
setSizeManually: true,
showLabel: false
});
}
// Disable all DnD methods
_onDragBegin() {
}
_onDragEnd() {
}
handleDragOver() {
return DND.DragMotionResult.CONTINUE;
}
acceptDrop() {
return false;
}
};
// A container like StBin, but taking the child's scale into account // A container like StBin, but taking the child's scale into account
// when requesting a size // when requesting a size
var DashItemContainer = GObject.registerClass( var DashItemContainer = GObject.registerClass(
@ -54,24 +31,20 @@ class DashItemContainer extends St.Widget {
_init() { _init() {
super._init({ style_class: 'dash-item-container', super._init({ style_class: 'dash-item-container',
pivot_point: new Clutter.Point({ x: .5, y: .5 }), pivot_point: new Clutter.Point({ x: .5, y: .5 }),
scale_x: 0,
scale_y: 0,
opacity: 0,
x_expand: true, x_expand: true,
x_align: Clutter.ActorAlign.CENTER }); x_align: Clutter.ActorAlign.CENTER });
this._labelText = ""; this._labelText = "";
this.label = new St.Label({ style_class: 'dash-label' }); this.label = new St.Label({ style_class: 'dash-label'});
this.label.hide(); this.label.hide();
Main.layoutManager.addChrome(this.label); Main.layoutManager.addChrome(this.label);
this.label_actor = this.label; this.label_actor = this.label;
this.child = null; this.child = null;
this._childScale = 0;
this._childOpacity = 0;
this.animatingOut = false; this.animatingOut = false;
this.connect('notify::scale-x', () => this.queue_relayout());
this.connect('notify::scale-y', () => this.queue_relayout());
this.connect('destroy', () => { this.connect('destroy', () => {
if (this.child != null) if (this.child != null)
this.child.destroy(); this.child.destroy();
@ -108,7 +81,7 @@ class DashItemContainer extends St.Widget {
let itemHeight = this.allocation.y2 - this.allocation.y1; let itemHeight = this.allocation.y2 - this.allocation.y1;
let labelHeight = this.label.get_height(); let labelHeight = this.label.get_height();
let yOffset = Math.floor((itemHeight - labelHeight) / 2); let yOffset = Math.floor((itemHeight - labelHeight) / 2)
let y = stageY + yOffset; let y = stageY + yOffset;
@ -122,11 +95,11 @@ class DashItemContainer extends St.Widget {
x = stageX + this.get_width() + xOffset; x = stageX + this.get_width() + xOffset;
this.label.set_position(x, y); this.label.set_position(x, y);
this.label.ease({ Tweener.addTween(this.label,
opacity: 255, { opacity: 255,
duration: DASH_ITEM_LABEL_SHOW_TIME, time: DASH_ITEM_LABEL_SHOW_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad',
}); });
} }
setLabelText(text) { setLabelText(text) {
@ -135,12 +108,14 @@ class DashItemContainer extends St.Widget {
} }
hideLabel() { hideLabel() {
this.label.ease({ Tweener.addTween(this.label,
opacity: 0, { opacity: 0,
duration: DASH_ITEM_LABEL_HIDE_TIME, time: DASH_ITEM_LABEL_HIDE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => this.label.hide() onComplete: () => {
}); this.label.hide();
}
});
} }
setChild(actor) { setChild(actor) {
@ -151,6 +126,9 @@ class DashItemContainer extends St.Widget {
this.child = actor; this.child = actor;
this.add_actor(this.child); this.add_actor(this.child);
this.set_scale(this._childScale, this._childScale);
this.set_opacity(this._childOpacity);
} }
show(animate) { show(animate) {
@ -158,13 +136,12 @@ class DashItemContainer extends St.Widget {
return; return;
let time = animate ? DASH_ANIMATION_TIME : 0; let time = animate ? DASH_ANIMATION_TIME : 0;
this.ease({ Tweener.addTween(this,
scale_x: 1, { childScale: 1.0,
scale_y: 1, childOpacity: 255,
opacity: 255, time: time,
duration: time, transition: 'easeOutQuad'
mode: Clutter.AnimationMode.EASE_OUT_QUAD });
});
} }
animateOutAndDestroy() { animateOutAndDestroy() {
@ -176,14 +153,37 @@ class DashItemContainer extends St.Widget {
} }
this.animatingOut = true; this.animatingOut = true;
this.ease({ Tweener.addTween(this,
scale_x: 0, { childScale: 0.0,
scale_y: 0, childOpacity: 0,
opacity: 0, time: DASH_ANIMATION_TIME,
duration: DASH_ANIMATION_TIME, transition: 'easeOutQuad',
mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => {
onComplete: () => this.destroy() this.destroy();
}); }
});
}
set childScale(scale) {
this._childScale = scale;
this.set_scale(scale, scale);
this.queue_relayout();
}
get childScale() {
return this._childScale;
}
set childOpacity(opacity) {
this._childOpacity = opacity;
this.set_opacity(opacity);
this.queue_redraw();
}
get childOpacity() {
return this._childOpacity;
} }
}); });
@ -198,9 +198,9 @@ class ShowAppsIcon extends DashItemContainer {
toggle_mode: true }); toggle_mode: true });
this._iconActor = null; this._iconActor = null;
this.icon = new IconGrid.BaseIcon(_("Show Applications"), this.icon = new IconGrid.BaseIcon(_("Show Applications"),
{ setSizeManually: true, { setSizeManually: true,
showLabel: false, showLabel: false,
createIcon: this._createIcon.bind(this) }); createIcon: this._createIcon.bind(this) });
this.toggleButton.add_actor(this.icon); this.toggleButton.add_actor(this.icon);
this.toggleButton._delegate = this; this.toggleButton._delegate = this;
@ -241,14 +241,14 @@ class ShowAppsIcon extends DashItemContainer {
this.setLabelText(_("Show Applications")); this.setLabelText(_("Show Applications"));
} }
handleDragOver(source, _actor, _x, _y, _time) { handleDragOver(source, actor, x, y, time) {
if (!this._canRemoveApp(getAppFromSource(source))) if (!this._canRemoveApp(getAppFromSource(source)))
return DND.DragMotionResult.NO_DROP; return DND.DragMotionResult.NO_DROP;
return DND.DragMotionResult.MOVE_DROP; return DND.DragMotionResult.MOVE_DROP;
} }
acceptDrop(source, _actor, _x, _y, _time) { acceptDrop(source, actor, x, y, time) {
let app = getAppFromSource(source); let app = getAppFromSource(source);
if (!this._canRemoveApp(app)) if (!this._canRemoveApp(app))
return false; return false;
@ -296,7 +296,7 @@ class DashActor extends St.Widget {
this.set_allocation(box, flags); this.set_allocation(box, flags);
let [appIcons, showAppsButton] = this.get_children(); let [appIcons, showAppsButton] = this.get_children();
let [, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth); let [showAppsMinHeight, showAppsNatHeight] = showAppsButton.get_preferred_height(availWidth);
let childBox = new Clutter.ActorBox(); let childBox = new Clutter.ActorBox();
childBox.x1 = contentBox.x1; childBox.x1 = contentBox.x1;
@ -321,14 +321,14 @@ class DashActor extends St.Widget {
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
let adjustedForWidth = themeNode.adjust_for_width(forWidth); let adjustedForWidth = themeNode.adjust_for_width(forWidth);
let [, showAppsButton] = this.get_children(); let [, showAppsButton] = this.get_children();
let [minHeight] = showAppsButton.get_preferred_height(adjustedForWidth); let [minHeight, ] = showAppsButton.get_preferred_height(adjustedForWidth);
[minHeight] = themeNode.adjust_preferred_height(minHeight, natHeight); [minHeight, ] = themeNode.adjust_preferred_height(minHeight, natHeight);
return [minHeight, natHeight]; return [minHeight, natHeight];
} }
}); });
const baseIconSizes = [16, 22, 24, 32, 48, 64]; const baseIconSizes = [ 16, 22, 24, 32, 48, 64 ];
var Dash = class Dash { var Dash = class Dash {
constructor() { constructor() {
@ -351,7 +351,8 @@ var Dash = class Dash {
this._container.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); this._container.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._showAppsIcon = new ShowAppsIcon(); this._showAppsIcon = new ShowAppsIcon();
this._showAppsIcon.show(false); this._showAppsIcon.childScale = 1;
this._showAppsIcon.childOpacity = 255;
this._showAppsIcon.icon.setIconSize(this.iconSize); this._showAppsIcon.icon.setIconSize(this.iconSize);
this._hookUpLabel(this._showAppsIcon); this._hookUpLabel(this._showAppsIcon);
@ -473,7 +474,19 @@ var Dash = class Dash {
} }
_createAppItem(app) { _createAppItem(app) {
let appIcon = new DashIcon(app); let appIcon = new AppDisplay.AppIcon(app,
{ setSizeManually: true,
showLabel: false });
if (appIcon._draggable) {
appIcon._draggable.connect('drag-begin',
() => {
appIcon.actor.opacity = 50;
});
appIcon._draggable.connect('drag-end',
() => {
appIcon.actor.opacity = 255;
});
}
appIcon.connect('menu-state-changed', appIcon.connect('menu-state-changed',
(appIcon, opened) => { (appIcon, opened) => {
@ -499,7 +512,7 @@ var Dash = class Dash {
// that the notify::hover handler does everything we need to. // that the notify::hover handler does everything we need to.
if (opened) { if (opened) {
if (this._showLabelTimeoutId > 0) { if (this._showLabelTimeoutId > 0) {
GLib.source_remove(this._showLabelTimeoutId); Mainloop.source_remove(this._showLabelTimeoutId);
this._showLabelTimeoutId = 0; this._showLabelTimeoutId = 0;
} }
@ -513,7 +526,7 @@ var Dash = class Dash {
if (shouldShow) { if (shouldShow) {
if (this._showLabelTimeoutId == 0) { if (this._showLabelTimeoutId == 0) {
let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT; let timeout = this._labelShowing ? 0 : DASH_ITEM_HOVER_TIMEOUT;
this._showLabelTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
() => { () => {
this._labelShowing = true; this._labelShowing = true;
item.showLabel(); item.showLabel();
@ -522,17 +535,17 @@ var Dash = class Dash {
}); });
GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel'); GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel');
if (this._resetHoverTimeoutId > 0) { if (this._resetHoverTimeoutId > 0) {
GLib.source_remove(this._resetHoverTimeoutId); Mainloop.source_remove(this._resetHoverTimeoutId);
this._resetHoverTimeoutId = 0; this._resetHoverTimeoutId = 0;
} }
} }
} else { } else {
if (this._showLabelTimeoutId > 0) if (this._showLabelTimeoutId > 0)
GLib.source_remove(this._showLabelTimeoutId); Mainloop.source_remove(this._showLabelTimeoutId);
this._showLabelTimeoutId = 0; this._showLabelTimeoutId = 0;
item.hideLabel(); item.hideLabel();
if (this._labelShowing) { if (this._labelShowing) {
this._resetHoverTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, DASH_ITEM_HOVER_TIMEOUT, this._resetHoverTimeoutId = Mainloop.timeout_add(DASH_ITEM_HOVER_TIMEOUT,
() => { () => {
this._labelShowing = false; this._labelShowing = false;
this._resetHoverTimeoutId = 0; this._resetHoverTimeoutId = 0;
@ -620,12 +633,12 @@ var Dash = class Dash {
icon.icon.set_size(icon.icon.width * scale, icon.icon.set_size(icon.icon.width * scale,
icon.icon.height * scale); icon.icon.height * scale);
icon.icon.ease({ Tweener.addTween(icon.icon,
width: targetWidth, { width: targetWidth,
height: targetHeight, height: targetHeight,
duration: DASH_ANIMATION_TIME, time: DASH_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad',
}); });
} }
} }
@ -635,10 +648,10 @@ var Dash = class Dash {
let running = this._appSystem.get_running(); let running = this._appSystem.get_running();
let children = this._box.get_children().filter(actor => { let children = this._box.get_children().filter(actor => {
return actor.child && return actor.child &&
actor.child._delegate && actor.child._delegate &&
actor.child._delegate.app; actor.child._delegate.app;
}); });
// Apps currently in the dash // Apps currently in the dash
let oldApps = children.map(actor => actor.child._delegate.app); let oldApps = children.map(actor => actor.child._delegate.app);
// Apps supposed to be in the dash // Apps supposed to be in the dash
@ -687,14 +700,14 @@ var Dash = class Dash {
} }
// App removed at oldIndex // App removed at oldIndex
if (oldApp && !newApps.includes(oldApp)) { if (oldApp && newApps.indexOf(oldApp) == -1) {
removedActors.push(children[oldIndex]); removedActors.push(children[oldIndex]);
oldIndex++; oldIndex++;
continue; continue;
} }
// App added at newIndex // App added at newIndex
if (newApp && !oldApps.includes(newApp)) { if (newApp && oldApps.indexOf(newApp) == -1) {
addedItems.push({ app: newApp, addedItems.push({ app: newApp,
item: this._createAppItem(newApp), item: this._createAppItem(newApp),
pos: newIndex }); pos: newIndex });
@ -703,8 +716,8 @@ var Dash = class Dash {
} }
// App moved // App moved
let nextApp = newApps.length > newIndex + 1 let nextApp = newApps.length > newIndex + 1 ? newApps[newIndex + 1]
? newApps[newIndex + 1] : null; : null;
let insertHere = nextApp && nextApp == oldApp; let insertHere = nextApp && nextApp == oldApp;
let alreadyRemoved = removedActors.reduce((result, actor) => { let alreadyRemoved = removedActors.reduce((result, actor) => {
let removedApp = actor.child._delegate.app; let removedApp = actor.child._delegate.app;
@ -777,7 +790,7 @@ var Dash = class Dash {
} }
} }
handleDragOver(source, actor, x, y, _time) { handleDragOver(source, actor, x, y, time) {
let app = getAppFromSource(source); let app = getAppFromSource(source);
// Don't allow favoriting of transient apps // Don't allow favoriting of transient apps
@ -855,7 +868,7 @@ var Dash = class Dash {
} }
// Draggable target interface // Draggable target interface
acceptDrop(source, _actor, _x, _y, _time) { acceptDrop(source, actor, x, y, time) {
let app = getAppFromSource(source); let app = getAppFromSource(source);
// Don't allow favoriting of transient apps // Don't allow favoriting of transient apps
@ -886,7 +899,7 @@ var Dash = class Dash {
favPos++; favPos++;
} }
// No drag placeholder means we don't want to favorite the app // No drag placeholder means we don't wan't to favorite the app
// and we are dragging it to its original position // and we are dragging it to its original position
if (!this._dragPlaceholder) if (!this._dragPlaceholder)
return true; return true;

View File

@ -1,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported DateMenuButton */
const { Clutter, Gio, GLib, GnomeDesktop, const { Clutter, GLib, GnomeDesktop,
GObject, GWeather, Shell, St } = imports.gi; GObject, GWeather, Shell, St } = imports.gi;
const Util = imports.misc.util; const Util = imports.misc.util;
@ -11,13 +10,8 @@ const Calendar = imports.ui.calendar;
const Weather = imports.misc.weather; const Weather = imports.misc.weather;
const System = imports.system; const System = imports.system;
const { loadInterfaceXML } = imports.misc.fileUtils;
const MAX_FORECASTS = 5; const MAX_FORECASTS = 5;
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
function _isToday(date) { function _isToday(date) {
let now = new Date(); let now = new Date();
return now.getYear() == date.getYear() && return now.getYear() == date.getYear() &&
@ -30,13 +24,11 @@ var TodayButton = class TodayButton {
// Having the ability to go to the current date if the user is already // Having the ability to go to the current date if the user is already
// on the current date can be confusing. So don't make the button reactive // on the current date can be confusing. So don't make the button reactive
// until the selected date changes. // until the selected date changes.
this.actor = new St.Button({ this.actor = new St.Button({ style_class: 'datemenu-today-button',
style_class: 'datemenu-today-button', x_expand: true, x_align: St.Align.START,
x_align: St.Align.START, can_focus: true,
x_expand: true, reactive: false
can_focus: true, });
reactive: false,
});
this.actor.connect('clicked', () => { this.actor.connect('clicked', () => {
this._calendar.setDate(new Date(), false); this._calendar.setDate(new Date(), false);
}); });
@ -55,7 +47,7 @@ var TodayButton = class TodayButton {
this._calendar.connect('selected-date-changed', (calendar, date) => { this._calendar.connect('selected-date-changed', (calendar, date) => {
// Make the button reactive only if the selected date is not the // Make the button reactive only if the selected date is not the
// current date. // current date.
this.actor.reactive = !_isToday(date); this.actor.reactive = !_isToday(date)
}); });
} }
@ -90,8 +82,7 @@ var WorldClocksSection = class WorldClocksSection {
x_fill: true, x_fill: true,
can_focus: true }); can_focus: true });
this.actor.connect('clicked', () => { this.actor.connect('clicked', () => {
if (this._clocksApp) this._clockAppMon.activateApp();
this._clocksApp.activate();
Main.overview.hide(); Main.overview.hide();
Main.panel.closeCalendar(); Main.panel.closeCalendar();
@ -104,41 +95,30 @@ var WorldClocksSection = class WorldClocksSection {
this.actor.child = this._grid; this.actor.child = this._grid;
this._clocksApp = null; this._clockAppMon = new Util.AppSettingsMonitor('org.gnome.clocks.desktop',
this._clocksProxy = new ClocksProxy( 'org.gnome.clocks');
Gio.DBus.session, this._clockAppMon.connect('available-changed',
'org.gnome.clocks', this._sync.bind(this));
'/org/gnome/clocks', this._clockAppMon.watchSetting('world-clocks',
this._onProxyReady.bind(this), this._clocksChanged.bind(this));
null /* cancellable */,
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES);
this._settings = new Gio.Settings({
schema_id: 'org.gnome.shell.world-clocks'
});
this._settings.connect('changed', this._clocksChanged.bind(this));
this._clocksChanged();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed',
this._sync.bind(this));
this._sync(); this._sync();
} }
_sync() { _sync() {
this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop'); this.actor.visible = this._clockAppMon.available;
this.actor.visible = this._clocksApp != null;
} }
_clocksChanged() { _clocksChanged(settings) {
this._grid.destroy_all_children(); this._grid.destroy_all_children();
this._locations = []; this._locations = [];
let world = GWeather.Location.get_world(); let world = GWeather.Location.get_world();
let clocks = this._settings.get_value('locations').deep_unpack(); let clocks = settings.get_value('world-clocks').deep_unpack();
for (let i = 0; i < clocks.length; i++) { for (let i = 0; i < clocks.length; i++) {
let l = world.deserialize(clocks[i]); if (!clocks[i].location)
if (l && l.get_timezone() != null) continue;
let l = world.deserialize(clocks[i].location);
if (l)
this._locations.push({ location: l }); this._locations.push({ location: l });
} }
@ -148,9 +128,8 @@ var WorldClocksSection = class WorldClocksSection {
}); });
let layout = this._grid.layout_manager; let layout = this._grid.layout_manager;
let title = (this._locations.length == 0) let title = (this._locations.length == 0) ? _("Add world clocks…")
? _("Add world clocks") : _("World Clocks");
: _("World Clocks");
let header = new St.Label({ style_class: 'world-clocks-header', let header = new St.Label({ style_class: 'world-clocks-header',
x_align: Clutter.ActorAlign.START, x_align: Clutter.ActorAlign.START,
text: title }); text: title });
@ -217,25 +196,6 @@ var WorldClocksSection = class WorldClocksSection {
l.actor.text = Util.formatTime(now, { timeOnly: true }); l.actor.text = Util.formatTime(now, { timeOnly: true });
} }
} }
_onProxyReady(proxy, error) {
if (error) {
log(`Failed to create GNOME Clocks proxy: ${error}`);
return;
}
this._clocksProxy.connect('g-properties-changed',
this._onClocksPropertiesChanged.bind(this));
this._onClocksPropertiesChanged();
}
_onClocksPropertiesChanged() {
if (this._clocksProxy.g_name_owner == null)
return;
this._settings.set_value('locations',
new GLib.Variant('av', this._clocksProxy.Locations));
}
}; };
var WeatherSection = class WeatherSection { var WeatherSection = class WeatherSection {
@ -257,7 +217,7 @@ var WeatherSection = class WeatherSection {
}); });
let box = new St.BoxLayout({ style_class: 'weather-box', let box = new St.BoxLayout({ style_class: 'weather-box',
vertical: true }); vertical: true });
this.actor.child = box; this.actor.child = box;
@ -289,12 +249,12 @@ var WeatherSection = class WeatherSection {
let current = info; let current = info;
let infos = [info]; let infos = [info];
for (let i = 0; i < forecasts.length; i++) { for (let i = 0; i < forecasts.length; i++) {
let [ok_, timestamp] = forecasts[i].get_value_update(); let [ok, timestamp] = forecasts[i].get_value_update();
let datetime = new Date(timestamp * 1000); let datetime = new Date(timestamp * 1000);
if (!_isToday(datetime)) if (!_isToday(datetime))
continue; // Ignore forecasts from other days continue; // Ignore forecasts from other days
[ok_, timestamp] = current.get_value_update(); [ok, timestamp] = current.get_value_update();
let currenttime = new Date(timestamp * 1000); let currenttime = new Date(timestamp * 1000);
if (currenttime.getHours() == datetime.getHours()) if (currenttime.getHours() == datetime.getHours())
continue; // Enforce a minimum interval of 1h continue; // Enforce a minimum interval of 1h
@ -315,7 +275,7 @@ var WeatherSection = class WeatherSection {
let col = 0; let col = 0;
infos.forEach(fc => { infos.forEach(fc => {
let [ok_, timestamp] = fc.get_value_update(); let [ok, timestamp] = fc.get_value_update();
let timeStr = Util.formatTime(new Date(timestamp * 1000), { let timeStr = Util.formatTime(new Date(timestamp * 1000), {
timeOnly: true timeOnly: true
}); });
@ -397,7 +357,7 @@ var MessagesIndicator = class MessagesIndicator {
Main.messageTray.connect('queue-changed', this._updateCount.bind(this)); Main.messageTray.connect('queue-changed', this._updateCount.bind(this));
let sources = Main.messageTray.getSources(); let sources = Main.messageTray.getSources();
sources.forEach(source => this._onSourceAdded(null, source)); sources.forEach(source => { this._onSourceAdded(null, source); });
} }
_onSourceAdded(tray, source) { _onSourceAdded(tray, source) {
@ -413,7 +373,7 @@ var MessagesIndicator = class MessagesIndicator {
_updateCount() { _updateCount() {
let count = 0; let count = 0;
this._sources.forEach(source => (count += source.unseenCount)); this._sources.forEach(source => { count += source.unseenCount; });
count -= Main.messageTray.queueCount; count -= Main.messageTray.queueCount;
this.actor.visible = (count > 0); this.actor.visible = (count > 0);
@ -424,8 +384,8 @@ var IndicatorPad = GObject.registerClass(
class IndicatorPad extends St.Widget { class IndicatorPad extends St.Widget {
_init(actor) { _init(actor) {
this._source = actor; this._source = actor;
this._source.connect('notify::visible', () => this.queue_relayout()); this._source.connect('notify::visible', () => { this.queue_relayout(); });
this._source.connect('notify::size', () => this.queue_relayout()); this._source.connect('notify::size', () => { this.queue_relayout(); });
super._init(); super._init();
} }
@ -499,6 +459,7 @@ class CalendarColumnLayout extends Clutter.BoxLayout {
var DateMenuButton = GObject.registerClass( var DateMenuButton = GObject.registerClass(
class DateMenuButton extends PanelMenu.Button { class DateMenuButton extends PanelMenu.Button {
_init() { _init() {
let item;
let hbox; let hbox;
let vbox; let vbox;
@ -515,9 +476,10 @@ class DateMenuButton extends PanelMenu.Button {
box.add_actor(this._clockDisplay); box.add_actor(this._clockDisplay);
box.add_actor(this._indicator.actor); box.add_actor(this._indicator.actor);
this.label_actor = this._clockDisplay; this.actor.label_actor = this._clockDisplay;
this.add_actor(box); this.actor.add_actor(box);
this.add_style_class_name ('clock-display'); this.actor.add_style_class_name ('clock-display');
let layout = new FreezableBinLayout(); let layout = new FreezableBinLayout();
let bin = new St.Widget({ layout_manager: layout }); let bin = new St.Widget({ layout_manager: layout });

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Dialog, MessageDialogContent */
const { Clutter, Gio, GObject, Pango, St } = imports.gi; const { Clutter, Gio, GObject, Pango, St } = imports.gi;
@ -26,9 +25,9 @@ class Dialog extends St.Widget {
_createDialog() { _createDialog() {
this._dialog = new St.BoxLayout({ style_class: 'modal-dialog', this._dialog = new St.BoxLayout({ style_class: 'modal-dialog',
x_align: Clutter.ActorAlign.CENTER, x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER, y_align: Clutter.ActorAlign.CENTER,
vertical: true }); vertical: true });
// modal dialogs are fixed width and grow vertically; set the request // modal dialogs are fixed width and grow vertically; set the request
// mode accordingly so wrapped labels are handled correctly during // mode accordingly so wrapped labels are handled correctly during
@ -39,13 +38,13 @@ class Dialog extends St.Widget {
this.contentLayout = new St.BoxLayout({ vertical: true, this.contentLayout = new St.BoxLayout({ vertical: true,
style_class: "modal-dialog-content-box" }); style_class: "modal-dialog-content-box" });
this._dialog.add(this.contentLayout, this._dialog.add(this.contentLayout,
{ expand: true, { expand: true,
x_fill: true, x_fill: true,
y_fill: true, y_fill: true,
x_align: St.Align.MIDDLE, x_align: St.Align.MIDDLE,
y_align: St.Align.START }); y_align: St.Align.START });
this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout({ homogeneous: true }) }); this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout({ homogeneous:true }) });
this._dialog.add(this.buttonLayout, this._dialog.add(this.buttonLayout,
{ x_align: St.Align.MIDDLE, { x_align: St.Align.MIDDLE,
y_align: St.Align.START }); y_align: St.Align.START });
@ -117,11 +116,11 @@ class Dialog extends St.Widget {
let button = new St.Button({ style_class: 'modal-dialog-linked-button', let button = new St.Button({ style_class: 'modal-dialog-linked-button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true, reactive: true,
can_focus: true, can_focus: true,
x_expand: true, x_expand: true,
y_expand: true, y_expand: true,
label: label }); label: label });
button.connect('clicked', action); button.connect('clicked', action);
buttonInfo['button'] = button; buttonInfo['button'] = button;
@ -176,13 +175,15 @@ var MessageDialogContent = GObject.registerClass({
this[`_${prop}`].add_style_class_name(`message-dialog-${prop}`); this[`_${prop}`].add_style_class_name(`message-dialog-${prop}`);
}); });
let textProps = { ellipsize: Pango.EllipsizeMode.NONE, let textProps = { ellipsize_mode: Pango.EllipsizeMode.NONE,
line_wrap: true }; line_wrap: true };
this._subtitle.clutter_text.set(textProps); Object.assign(this._subtitle.clutter_text, textProps);
this._body.clutter_text.set(textProps); Object.assign(this._body.clutter_text, textProps);
let defaultParams = { style_class: 'message-dialog-main-layout' }; if (!params.hasOwnProperty('style_class'))
super._init(Object.assign(defaultParams, params)); params.style_class = 'message-dialog-main-layout';
super._init(params);
this.messageBox = new St.BoxLayout({ style_class: 'message-dialog-content', this.messageBox = new St.BoxLayout({ style_class: 'message-dialog-content',
x_expand: true, x_expand: true,
@ -213,10 +214,7 @@ var MessageDialogContent = GObject.registerClass({
} }
set icon(icon) { set icon(icon) {
this._icon.set({ Object.assign(this._icon, { gicon: icon, visible: icon != null });
gicon: icon,
visible: icon != null
});
this.notify('icon'); this.notify('icon');
} }
@ -233,10 +231,7 @@ var MessageDialogContent = GObject.registerClass({
} }
_setLabel(label, prop, value) { _setLabel(label, prop, value) {
label.set({ Object.assign(label, { text: value || '', visible: value != null });
text: value || '',
visible: value != null
});
this.notify(prop); this.notify(prop);
} }

View File

@ -1,18 +1,18 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported addDragMonitor, removeDragMonitor, makeDraggable */
const { Clutter, GLib, Meta, Shell, St } = imports.gi; const { Clutter, GLib, Meta, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Main = imports.ui.main; const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
// Time to scale down to maxDragActorSize // Time to scale down to maxDragActorSize
var SCALE_ANIMATION_TIME = 250; var SCALE_ANIMATION_TIME = 0.25;
// Time to animate to original position on cancel // Time to animate to original position on cancel
var SNAP_BACK_ANIMATION_TIME = 250; var SNAP_BACK_ANIMATION_TIME = 0.25;
// Time to animate to original position on success // Time to animate to original position on success
var REVERT_ANIMATION_TIME = 750; var REVERT_ANIMATION_TIME = 0.75;
var DragMotionResult = { var DragMotionResult = {
NO_DROP: 0, NO_DROP: 0,
@ -111,6 +111,9 @@ var _Draggable = class _Draggable {
if (event.get_button() != 1) if (event.get_button() != 1)
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
if (Tweener.getTweenCount(actor))
return Clutter.EVENT_PROPAGATE;
this._buttonDown = true; this._buttonDown = true;
this._grabActor(event.get_device()); this._grabActor(event.get_device());
@ -136,6 +139,9 @@ var _Draggable = class _Draggable {
!global.display.is_pointer_emulating_sequence(event.get_event_sequence())) !global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
if (Tweener.getTweenCount(actor))
return Clutter.EVENT_PROPAGATE;
this._buttonDown = true; this._buttonDown = true;
this._grabActor(event.get_device(), event.get_event_sequence()); this._grabActor(event.get_device(), event.get_event_sequence());
@ -422,22 +428,20 @@ var _Draggable = class _Draggable {
// to the final position because that tween would // to the final position because that tween would
// fight with updates as the user continues dragging // fight with updates as the user continues dragging
// the mouse; instead we do the position computations in // the mouse; instead we do the position computations in
// a ::new-frame handler. // an onUpdate() function.
this._dragActor.ease({ Tweener.addTween(this._dragActor,
scale_x: scale * origScale, { scale_x: scale * origScale,
scale_y: scale * origScale, scale_y: scale * origScale,
duration: SCALE_ANIMATION_TIME, time: SCALE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad',
}); onUpdate() {
let currentScale = this._dragActor.scale_x / origScale;
this._dragActor.get_transition('scale-x').connect('new-frame', () => { this._dragOffsetX = currentScale * origDragOffsetX;
let currentScale = this._dragActor.scale_x / origScale; this._dragOffsetY = currentScale * origDragOffsetY;
this._dragOffsetX = currentScale * origDragOffsetX; this._dragActor.set_position(this._dragX + this._dragOffsetX,
this._dragOffsetY = currentScale * origDragOffsetY; this._dragY + this._dragOffsetY);
this._dragActor.set_position( },
this._dragX + this._dragOffsetX, onUpdateScope: this });
this._dragY + this._dragOffsetY);
});
} }
} }
} }
@ -500,7 +504,7 @@ var _Draggable = class _Draggable {
while (target) { while (target) {
if (target._delegate && target._delegate.handleDragOver) { if (target._delegate && target._delegate.handleDragOver) {
let [r_, targX, targY] = target.transform_stage_point(this._dragX, this._dragY); let [r, targX, targY] = target.transform_stage_point(this._dragX, this._dragY);
// We currently loop through all parents on drag-over even if one of the children has handled it. // We currently loop through all parents on drag-over even if one of the children has handled it.
// We can check the return value of the function and break the loop if it's true if we don't want // We can check the return value of the function and break the loop if it's true if we don't want
// to continue checking the parents. // to continue checking the parents.
@ -557,11 +561,11 @@ var _Draggable = class _Draggable {
let dropFunc = dragMonitors[i].dragDrop; let dropFunc = dragMonitors[i].dragDrop;
if (dropFunc) if (dropFunc)
switch (dropFunc(dropEvent)) { switch (dropFunc(dropEvent)) {
case DragDropResult.FAILURE: case DragDropResult.FAILURE:
case DragDropResult.SUCCESS: case DragDropResult.SUCCESS:
return true; return true;
case DragDropResult.CONTINUE: case DragDropResult.CONTINUE:
continue; continue;
} }
} }
@ -572,7 +576,7 @@ var _Draggable = class _Draggable {
while (target) { while (target) {
if (target._delegate && target._delegate.acceptDrop) { if (target._delegate && target._delegate.acceptDrop) {
let [r_, targX, targY] = target.transform_stage_point(dropX, dropY); let [r, targX, targY] = target.transform_stage_point(dropX, dropY);
if (target._delegate.acceptDrop(this.actor._delegate, if (target._delegate.acceptDrop(this.actor._delegate,
this._dragActor, this._dragActor,
targX, targX,
@ -584,9 +588,8 @@ var _Draggable = class _Draggable {
if (this._restoreOnSuccess) { if (this._restoreOnSuccess) {
this._restoreDragActor(event.get_time()); this._restoreDragActor(event.get_time());
return true; return true;
} else { } else
this._dragActor.destroy(); this._dragActor.destroy();
}
} }
this._dragState = DragState.INIT; this._dragState = DragState.INIT;
@ -610,15 +613,15 @@ var _Draggable = class _Draggable {
if (this._dragActorSource && this._dragActorSource.visible) { if (this._dragActorSource && this._dragActorSource.visible) {
// Snap the clone back to its source // Snap the clone back to its source
[x, y] = this._dragActorSource.get_transformed_position(); [x, y] = this._dragActorSource.get_transformed_position();
let [sourceScaledWidth] = this._dragActorSource.get_transformed_size(); let [sourceScaledWidth, sourceScaledHeight] = this._dragActorSource.get_transformed_size();
scale = sourceScaledWidth ? sourceScaledWidth / this._dragActor.width : 0; scale = sourceScaledWidth ? this._dragActor.width / sourceScaledWidth : 0;
} else if (this._dragOrigParent) { } else if (this._dragOrigParent) {
// Snap the actor back to its original position within // Snap the actor back to its original position within
// its parent, adjusting for the fact that the parent // its parent, adjusting for the fact that the parent
// may have been moved or scaled // may have been moved or scaled
let [parentX, parentY] = this._dragOrigParent.get_transformed_position(); let [parentX, parentY] = this._dragOrigParent.get_transformed_position();
let [parentWidth] = this._dragOrigParent.get_size(); let [parentWidth, parentHeight] = this._dragOrigParent.get_size();
let [parentScaledWidth] = this._dragOrigParent.get_transformed_size(); let [parentScaledWidth, parentScaledHeight] = this._dragOrigParent.get_transformed_size();
let parentScale = 1.0; let parentScale = 1.0;
if (parentWidth != 0) if (parentWidth != 0)
parentScale = parentScaledWidth / parentWidth; parentScale = parentScaledWidth / parentWidth;
@ -654,13 +657,13 @@ var _Draggable = class _Draggable {
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation(); let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
this._animateDragEnd(eventTime, { this._animateDragEnd(eventTime,
x: snapBackX, { x: snapBackX,
y: snapBackY, y: snapBackY,
scale_x: snapBackScale, scale_x: snapBackScale,
scale_y: snapBackScale, scale_y: snapBackScale,
duration: SNAP_BACK_ANIMATION_TIME time: SNAP_BACK_ANIMATION_TIME,
}); });
} }
_restoreDragActor(eventTime) { _restoreDragActor(eventTime) {
@ -672,27 +675,26 @@ var _Draggable = class _Draggable {
this._dragActor.set_scale(restoreScale, restoreScale); this._dragActor.set_scale(restoreScale, restoreScale);
this._dragActor.opacity = 0; this._dragActor.opacity = 0;
this._animateDragEnd(eventTime, { this._animateDragEnd(eventTime,
duration: REVERT_ANIMATION_TIME { time: REVERT_ANIMATION_TIME });
});
} }
_animateDragEnd(eventTime, params) { _animateDragEnd(eventTime, params) {
this._animationInProgress = true; this._animationInProgress = true;
params['opacity'] = this._dragOrigOpacity;
params['transition'] = 'easeOutQuad';
params['onComplete'] = this._onAnimationComplete;
params['onCompleteScope'] = this;
params['onCompleteParams'] = [this._dragActor, eventTime];
// start the animation // start the animation
this._dragActor.ease(Object.assign(params, { Tweener.addTween(this._dragActor, params)
opacity: this._dragOrigOpacity,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._onAnimationComplete(this._dragActor, eventTime);
}
}));
} }
_finishAnimation() { _finishAnimation() {
if (!this._animationInProgress) if (!this._animationInProgress)
return; return
this._animationInProgress = false; this._animationInProgress = false;
if (!this._buttonDown) if (!this._buttonDown)

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported EdgeDragAction */
const { Clutter, GObject, Meta, St } = imports.gi; const { Clutter, GObject, Meta, St } = imports.gi;
@ -17,7 +16,7 @@ var EdgeDragAction = GObject.registerClass({
this._allowedModes = allowedModes; this._allowedModes = allowedModes;
this.set_n_touch_points(1); this.set_n_touch_points(1);
global.display.connect('grab-op-begin', () => this.cancel()); global.display.connect('grab-op-begin', () => { this.cancel(); });
} }
_getMonitorRect(x, y) { _getMonitorRect(x, y) {
@ -27,7 +26,7 @@ var EdgeDragAction = GObject.registerClass({
return global.display.get_monitor_geometry(monitorIndex); return global.display.get_monitor_geometry(monitorIndex);
} }
vfunc_gesture_prepare(_actor) { vfunc_gesture_prepare(actor) {
if (this.get_n_current_points() == 0) if (this.get_n_current_points() == 0)
return false; return false;
@ -43,7 +42,7 @@ var EdgeDragAction = GObject.registerClass({
(this._side == St.Side.BOTTOM && y > monitorRect.y + monitorRect.height - EDGE_THRESHOLD)); (this._side == St.Side.BOTTOM && y > monitorRect.y + monitorRect.height - EDGE_THRESHOLD));
} }
vfunc_gesture_progress(_actor) { vfunc_gesture_progress(actor) {
let [startX, startY] = this.get_press_coords(0); let [startX, startY] = this.get_press_coords(0);
let [x, y] = this.get_motion_coords(0); let [x, y] = this.get_motion_coords(0);
let offsetX = Math.abs (x - startX); let offsetX = Math.abs (x - startX);
@ -63,7 +62,7 @@ var EdgeDragAction = GObject.registerClass({
return true; return true;
} }
vfunc_gesture_end(_actor) { vfunc_gesture_end(actor) {
let [startX, startY] = this.get_press_coords(0); let [startX, startY] = this.get_press_coords(0);
let [x, y] = this.get_motion_coords(0); let [x, y] = this.get_motion_coords(0);
let monitorRect = this._getMonitorRect(startX, startY); let monitorRect = this._getMonitorRect(startX, startY);

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported init, EndSessionDialog */
/* /*
* Copyright 2010-2016 Red Hat, Inc * Copyright 2010-2016 Red Hat, Inc
* *
@ -17,8 +16,10 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>. * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/ */
const Mainloop = imports.mainloop;
const { AccountsService, Clutter, Gio, const { AccountsService, Clutter, Gio,
GLib, GObject, Pango, Polkit, Shell, St } = imports.gi; GLib, Pango, Polkit, Shell, St } = imports.gi;
const CheckBox = imports.ui.checkBox; const CheckBox = imports.ui.checkBox;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
@ -28,9 +29,13 @@ const UserWidget = imports.ui.userWidget;
const { loadInterfaceXML } = imports.misc.fileUtils; const { loadInterfaceXML } = imports.misc.fileUtils;
let _endSessionDialog = null;
const _ITEM_ICON_SIZE = 48; const _ITEM_ICON_SIZE = 48;
const _DIALOG_ICON_SIZE = 48; const _DIALOG_ICON_SIZE = 48;
var GSM_SESSION_MANAGER_LOGOUT_FORCE = 2;
const EndSessionDialogIface = loadInterfaceXML('org.gnome.SessionManager.EndSessionDialog'); const EndSessionDialogIface = loadInterfaceXML('org.gnome.SessionManager.EndSessionDialog');
const logoutDialogContent = { const logoutDialogContent = {
@ -48,7 +53,7 @@ const logoutDialogContent = {
}, },
showBatteryWarning: false, showBatteryWarning: false,
confirmButtons: [{ signal: 'ConfirmedLogout', confirmButtons: [{ signal: 'ConfirmedLogout',
label: C_("button", "Log Out") }], label: C_("button", "Log Out") }],
iconStyleClass: 'end-session-dialog-logout-icon', iconStyleClass: 'end-session-dialog-logout-icon',
showOtherSessions: false, showOtherSessions: false,
}; };
@ -64,9 +69,9 @@ const shutdownDialogContent = {
checkBoxText: C_("checkbox", "Install pending software updates"), checkBoxText: C_("checkbox", "Install pending software updates"),
showBatteryWarning: true, showBatteryWarning: true,
confirmButtons: [{ signal: 'ConfirmedReboot', confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart") }, label: C_("button", "Restart") },
{ signal: 'ConfirmedShutdown', { signal: 'ConfirmedShutdown',
label: C_("button", "Power Off") }], label: C_("button", "Power Off") }],
iconName: 'system-shutdown-symbolic', iconName: 'system-shutdown-symbolic',
iconStyleClass: 'end-session-dialog-shutdown-icon', iconStyleClass: 'end-session-dialog-shutdown-icon',
showOtherSessions: true, showOtherSessions: true,
@ -81,7 +86,7 @@ const restartDialogContent = {
}, },
showBatteryWarning: false, showBatteryWarning: false,
confirmButtons: [{ signal: 'ConfirmedReboot', confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart") }], label: C_("button", "Restart") }],
iconName: 'view-refresh-symbolic', iconName: 'view-refresh-symbolic',
iconStyleClass: 'end-session-dialog-shutdown-icon', iconStyleClass: 'end-session-dialog-shutdown-icon',
showOtherSessions: true, showOtherSessions: true,
@ -97,7 +102,7 @@ const restartUpdateDialogContent = {
}, },
showBatteryWarning: true, showBatteryWarning: true,
confirmButtons: [{ signal: 'ConfirmedReboot', confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart &amp; Install") }], label: C_("button", "Restart &amp; Install") }],
unusedFutureButtonForTranslation: C_("button", "Install &amp; Power Off"), unusedFutureButtonForTranslation: C_("button", "Install &amp; Power Off"),
unusedFutureCheckBoxForTranslation: C_("checkbox", "Power off after updates are installed"), unusedFutureCheckBoxForTranslation: C_("checkbox", "Power off after updates are installed"),
iconName: 'view-refresh-symbolic', iconName: 'view-refresh-symbolic',
@ -117,18 +122,18 @@ const restartUpgradeDialogContent = {
disableTimer: true, disableTimer: true,
showBatteryWarning: false, showBatteryWarning: false,
confirmButtons: [{ signal: 'ConfirmedReboot', confirmButtons: [{ signal: 'ConfirmedReboot',
label: C_("button", "Restart &amp; Install") }], label: C_("button", "Restart &amp; Install") }],
iconName: 'view-refresh-symbolic', iconName: 'view-refresh-symbolic',
iconStyleClass: 'end-session-dialog-shutdown-icon', iconStyleClass: 'end-session-dialog-shutdown-icon',
showOtherSessions: true, showOtherSessions: true,
}; };
const DialogType = { const DialogType = {
LOGOUT: 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */, LOGOUT: 0 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_LOGOUT */,
SHUTDOWN: 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */, SHUTDOWN: 1 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_SHUTDOWN */,
RESTART: 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */, RESTART: 2 /* GSM_SHELL_END_SESSION_DIALOG_TYPE_RESTART */,
UPDATE_RESTART: 3, UPDATE_RESTART: 3,
UPGRADE_RESTART: 4 UPGRADE_RESTART: 4
}; };
const DialogContent = { const DialogContent = {
@ -154,7 +159,7 @@ function findAppFromInhibitor(inhibitor) {
let desktopFile; let desktopFile;
try { try {
[desktopFile] = inhibitor.GetAppIdSync(); [desktopFile] = inhibitor.GetAppIdSync();
} catch (e) { } catch(e) {
// XXX -- sometimes JIT inhibitors generated by gnome-session // XXX -- sometimes JIT inhibitors generated by gnome-session
// get removed too soon. Don't fail in this case. // get removed too soon. Don't fail in this case.
log('gnome-session gave us a dead inhibitor: %s'.format(inhibitor.get_object_path())); log('gnome-session gave us a dead inhibitor: %s'.format(inhibitor.get_object_path()));
@ -218,25 +223,25 @@ function init() {
// This always returns the same singleton object // This always returns the same singleton object
// By instantiating it initially, we register the // By instantiating it initially, we register the
// bus object, etc. // bus object, etc.
(new EndSessionDialog()); _endSessionDialog = new EndSessionDialog();
} }
var EndSessionDialog = GObject.registerClass( var EndSessionDialog = class EndSessionDialog extends ModalDialog.ModalDialog {
class EndSessionDialog extends ModalDialog.ModalDialog { constructor() {
_init() { super({ styleClass: 'end-session-dialog',
super._init({ styleClass: 'end-session-dialog', destroyOnClose: false });
destroyOnClose: false });
this._loginManager = LoginManager.getLoginManager(); this._loginManager = LoginManager.getLoginManager();
this._userManager = AccountsService.UserManager.get_default(); this._userManager = AccountsService.UserManager.get_default();
this._user = this._userManager.get_user(GLib.get_user_name()); this._user = this._userManager.get_user(GLib.get_user_name());
this._updatesPermission = null;
this._pkOfflineProxy = new PkOfflineProxy(Gio.DBus.system, this._pkOfflineProxy = new PkOfflineProxy(Gio.DBus.system,
'org.freedesktop.PackageKit', 'org.freedesktop.PackageKit',
'/org/freedesktop/PackageKit', '/org/freedesktop/PackageKit',
this._onPkOfflineProxyCreated.bind(this)); (proxy, error) => {
if (error)
log(error.message);
});
this._powerProxy = new UPowerProxy(Gio.DBus.system, this._powerProxy = new UPowerProxy(Gio.DBus.system,
'org.freedesktop.UPower', 'org.freedesktop.UPower',
'/org/freedesktop/UPower', '/org/freedesktop/UPower',
@ -270,8 +275,8 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._iconBin = new St.Bin(); this._iconBin = new St.Bin();
mainContentLayout.add(this._iconBin, mainContentLayout.add(this._iconBin,
{ x_fill: true, { x_fill: true,
y_fill: false, y_fill: false,
x_align: St.Align.END, x_align: St.Align.END,
y_align: St.Align.START }); y_align: St.Align.START });
@ -284,7 +289,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
messageLayout.add(this._subjectLabel, messageLayout.add(this._subjectLabel,
{ x_fill: false, { x_fill: false,
y_fill: false, y_fill: false,
x_align: St.Align.START, x_align: St.Align.START,
y_align: St.Align.START }); y_align: St.Align.START });
@ -293,7 +298,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._descriptionLabel.clutter_text.line_wrap = true; this._descriptionLabel.clutter_text.line_wrap = true;
messageLayout.add(this._descriptionLabel, messageLayout.add(this._descriptionLabel,
{ y_fill: true, { y_fill: true,
y_align: St.Align.START }); y_align: St.Align.START });
this._checkBox = new CheckBox.CheckBox(); this._checkBox = new CheckBox.CheckBox();
@ -331,36 +336,16 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._inhibitorSection.add_actor(this._sessionHeader); this._inhibitorSection.add_actor(this._sessionHeader);
this._inhibitorSection.add_actor(this._sessionList); this._inhibitorSection.add_actor(this._sessionList);
try {
this._updatesPermission = Polkit.Permission.new_sync("org.freedesktop.packagekit.trigger-offline-update", null, null);
} catch(e) {
log('No permission to trigger offline updates: %s'.format(e.toString()));
}
this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this); this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(EndSessionDialogIface, this);
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog'); this._dbusImpl.export(Gio.DBus.session, '/org/gnome/SessionManager/EndSessionDialog');
} }
_onPkOfflineProxyCreated(proxy, error) {
if (error) {
log(error.message);
return;
}
// Creating a D-Bus proxy won't propagate SERVICE_UNKNOWN or NAME_HAS_NO_OWNER
// errors if PackageKit is not available, but the GIO implementation will make
// sure in that case that the proxy's g-name-owner is set to null, so check that.
if (this._pkOfflineProxy.g_name_owner === null) {
this._pkOfflineProxy = null;
return;
}
// It only makes sense to check for this permission if PackageKit is available.
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: ${e}`);
}
});
}
_onDestroy() { _onDestroy() {
this._user.disconnect(this._userLoadedId); this._user.disconnect(this._userLoadedId);
this._user.disconnect(this._userChangedId); this._user.disconnect(this._userChangedId);
@ -405,8 +390,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
} }
// Use a different description when we are installing a system upgrade // Use a different description when we are installing a system upgrade
// if the PackageKit proxy is available (i.e. PackageKit is available). if (dialogContent.upgradeDescription) {
if (this._pkOfflineProxy && dialogContent.upgradeDescription) {
let name = this._pkOfflineProxy.PreparedUpgrade['name'].deep_unpack(); let name = this._pkOfflineProxy.PreparedUpgrade['name'].deep_unpack();
let version = this._pkOfflineProxy.PreparedUpgrade['version'].deep_unpack(); let version = this._pkOfflineProxy.PreparedUpgrade['version'].deep_unpack();
@ -443,22 +427,20 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
_updateButtons() { _updateButtons() {
let dialogContent = DialogContent[this._type]; let dialogContent = DialogContent[this._type];
let buttons = [{ action: this.cancel.bind(this), let buttons = [{ action: this.cancel.bind(this),
label: _("Cancel"), label: _("Cancel"),
key: Clutter.Escape }]; key: Clutter.Escape }];
for (let i = 0; i < dialogContent.confirmButtons.length; i++) { for (let i = 0; i < dialogContent.confirmButtons.length; i++) {
let signal = dialogContent.confirmButtons[i].signal; let signal = dialogContent.confirmButtons[i].signal;
let label = dialogContent.confirmButtons[i].label; let label = dialogContent.confirmButtons[i].label;
buttons.push({ buttons.push({ action: () => {
action: () => { this.close(true);
this.close(true); let signalId = this.connect('closed', () => {
let signalId = this.connect('closed', () => { this.disconnect(signalId);
this.disconnect(signalId); this._confirm(signal);
this._confirm(signal); });
}); },
}, label: label });
label: label,
});
} }
this.setButtons(buttons); this.setButtons(buttons);
@ -493,19 +475,19 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
// Trigger the offline update as requested // Trigger the offline update as requested
if (this._checkBox.actor.checked) { if (this._checkBox.actor.checked) {
switch (signal) { switch (signal) {
case "ConfirmedReboot": case "ConfirmedReboot":
this._triggerOfflineUpdateReboot(callback); this._triggerOfflineUpdateReboot(callback);
break; break;
case "ConfirmedShutdown": case "ConfirmedShutdown":
// To actually trigger the offline update, we need to // To actually trigger the offline update, we need to
// reboot to do the upgrade. When the upgrade is complete, // reboot to do the upgrade. When the upgrade is complete,
// the computer will shut down automatically. // the computer will shut down automatically.
signal = "ConfirmedReboot"; signal = "ConfirmedReboot";
this._triggerOfflineUpdateShutdown(callback); this._triggerOfflineUpdateShutdown(callback);
break; break;
default: default:
callback(); callback();
break; break;
} }
} else { } else {
this._triggerOfflineUpdateCancel(callback); this._triggerOfflineUpdateCancel(callback);
@ -517,12 +499,6 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
} }
_triggerOfflineUpdateReboot(callback) { _triggerOfflineUpdateReboot(callback) {
// Handle this gracefully if PackageKit is not available.
if (!this._pkOfflineProxy) {
callback();
return;
}
this._pkOfflineProxy.TriggerRemote('reboot', (result, error) => { this._pkOfflineProxy.TriggerRemote('reboot', (result, error) => {
if (error) if (error)
log(error.message); log(error.message);
@ -532,12 +508,6 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
} }
_triggerOfflineUpdateShutdown(callback) { _triggerOfflineUpdateShutdown(callback) {
// Handle this gracefully if PackageKit is not available.
if (!this._pkOfflineProxy) {
callback();
return;
}
this._pkOfflineProxy.TriggerRemote('power-off', (result, error) => { this._pkOfflineProxy.TriggerRemote('power-off', (result, error) => {
if (error) if (error)
log(error.message); log(error.message);
@ -547,12 +517,6 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
} }
_triggerOfflineUpdateCancel(callback) { _triggerOfflineUpdateCancel(callback) {
// Handle this gracefully if PackageKit is not available.
if (!this._pkOfflineProxy) {
callback();
return;
}
this._pkOfflineProxy.CancelRemote((result, error) => { this._pkOfflineProxy.CancelRemote((result, error) => {
if (error) if (error)
log(error.message); log(error.message);
@ -565,7 +529,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let startTime = GLib.get_monotonic_time(); let startTime = GLib.get_monotonic_time();
this._secondsLeft = this._totalSecondsToStayOpen; this._secondsLeft = this._totalSecondsToStayOpen;
this._timerId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, () => { this._timerId = Mainloop.timeout_add_seconds(1, () => {
let currentTime = GLib.get_monotonic_time(); let currentTime = GLib.get_monotonic_time();
let secondsElapsed = ((currentTime - startTime) / 1000000); let secondsElapsed = ((currentTime - startTime) / 1000000);
@ -587,7 +551,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
_stopTimer() { _stopTimer() {
if (this._timerId > 0) { if (this._timerId > 0) {
GLib.source_remove(this._timerId); Mainloop.source_remove(this._timerId);
this._timerId = 0; this._timerId = 0;
} }
@ -620,7 +584,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
} }
_onInhibitorLoaded(inhibitor) { _onInhibitorLoaded(inhibitor) {
if (!this._applications.includes(inhibitor)) { if (this._applications.indexOf(inhibitor) < 0) {
// Stale inhibitor // Stale inhibitor
return; return;
} }
@ -672,7 +636,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._loginManager.listSessions(result => { this._loginManager.listSessions(result => {
let n = 0; let n = 0;
for (let i = 0; i < result.length; i++) { for (let i = 0; i < result.length; i++) {
let [id_, uid_, userName, seat_, sessionPath] = result[i]; let[id, uid, userName, seat, sessionPath] = result[i];
let proxy = new LogindSession(Gio.DBus.system, 'org.freedesktop.login1', sessionPath); let proxy = new LogindSession(Gio.DBus.system, 'org.freedesktop.login1', sessionPath);
if (proxy.Class != 'user') if (proxy.Class != 'user')
@ -715,8 +679,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
this._totalSecondsToStayOpen = totalSecondsToStayOpen; this._totalSecondsToStayOpen = totalSecondsToStayOpen;
this._type = type; this._type = type;
// Only consider updates and upgrades if PackageKit is available. if (this._type == DialogType.RESTART) {
if (this._pkOfflineProxy && this._type == DialogType.RESTART) {
if (this._pkOfflineProxy.UpdateTriggered) if (this._pkOfflineProxy.UpdateTriggered)
this._type = DialogType.UPDATE_RESTART; this._type = DialogType.UPDATE_RESTART;
else if (this._pkOfflineProxy.UpgradeTriggered) else if (this._pkOfflineProxy.UpgradeTriggered)
@ -738,7 +701,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let dialogContent = DialogContent[this._type]; let dialogContent = DialogContent[this._type];
for (let i = 0; i < inhibitorObjectPaths.length; i++) { for (let i = 0; i < inhibitorObjectPaths.length; i++) {
let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], proxy => { let inhibitor = new GnomeSession.Inhibitor(inhibitorObjectPaths[i], (proxy, error) => {
this._onInhibitorLoaded(proxy); this._onInhibitorLoaded(proxy);
}); });
@ -748,9 +711,8 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
if (dialogContent.showOtherSessions) if (dialogContent.showOtherSessions)
this._loadSessions(); this._loadSessions();
// Only consider updates and upgrades if PackageKit is available. let updateTriggered = this._pkOfflineProxy.UpdateTriggered;
let updateTriggered = this._pkOfflineProxy ? this._pkOfflineProxy.UpdateTriggered : false; let updatePrepared = this._pkOfflineProxy.UpdatePrepared;
let updatePrepared = this._pkOfflineProxy ? this._pkOfflineProxy.UpdatePrepared : false;
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed; let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || ''); _setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || '');
@ -782,7 +744,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
}); });
} }
Close(_parameters, _invocation) { Close(parameters, invocation) {
this.close(); this.close();
} }
}); };

View File

@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported init */
const Config = imports.misc.config; const Config = imports.misc.config;
@ -10,7 +9,7 @@ imports.gi.versions.Gtk = '3.0';
imports.gi.versions.TelepathyGLib = '0.12'; imports.gi.versions.TelepathyGLib = '0.12';
imports.gi.versions.TelepathyLogger = '0.2'; imports.gi.versions.TelepathyLogger = '0.2';
const { Clutter, GLib, Meta, Shell, St } = imports.gi; const { Clutter, GLib, Shell, St } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
// We can't import shell JS modules yet, because they may have // We can't import shell JS modules yet, because they may have
@ -58,125 +57,8 @@ function _patchLayoutClass(layoutClass, styleProps) {
}; };
} }
function _makeEaseCallback(params, cleanup) { function _loggingFunc() {
let onComplete = params.onComplete; let fields = {'MESSAGE': [].join.call(arguments, ', ')};
delete params.onComplete;
let onStopped = params.onStopped;
delete params.onStopped;
return isFinished => {
cleanup();
if (onStopped)
onStopped(isFinished);
if (onComplete && isFinished)
onComplete();
};
}
function _getPropertyTarget(actor, propName) {
if (!propName.startsWith('@'))
return [actor, propName];
let [type, name, prop] = propName.split('.');
switch (type) {
case '@layout':
return [actor.layout_manager, name];
case '@actions':
return [actor.get_action(name), prop];
case '@constraints':
return [actor.get_constraint(name), prop];
case '@effects':
return [actor.get_effect(name), prop];
}
throw new Error(`Invalid property name ${propName}`);
}
function _easeActor(actor, params) {
actor.save_easing_state();
if (params.duration != undefined)
actor.set_easing_duration(params.duration);
delete params.duration;
if (params.delay != undefined)
actor.set_easing_delay(params.delay);
delete params.delay;
if (params.mode != undefined)
actor.set_easing_mode(params.mode);
delete params.mode;
Meta.disable_unredirect_for_display(global.display);
let cleanup = () => Meta.enable_unredirect_for_display(global.display);
let callback = _makeEaseCallback(params, cleanup);
// cancel overwritten transitions
let animatedProps = Object.keys(params).map(p => p.replace('_', '-', 'g'));
animatedProps.forEach(p => actor.remove_transition(p));
actor.set(params);
actor.restore_easing_state();
let transition = animatedProps.map(p => actor.get_transition(p))
.find(t => t !== null);
if (transition)
transition.connect('stopped', (t, finished) => callback(finished));
else
callback(true);
}
function _easeActorProperty(actor, propName, target, params) {
// Avoid pointless difference with ease()
if (params.mode)
params.progress_mode = params.mode;
delete params.mode;
if (params.duration)
params.duration = adjustAnimationTime(params.duration);
let duration = Math.floor(params.duration || 0);
// Copy Clutter's behavior for implicit animations, see
// should_skip_implicit_transition()
if (actor instanceof Clutter.Actor && !actor.mapped)
duration = 0;
Meta.disable_unredirect_for_display(global.display);
let cleanup = () => Meta.enable_unredirect_for_display(global.display);
let callback = _makeEaseCallback(params, cleanup);
// cancel overwritten transition
actor.remove_transition(propName);
if (duration == 0) {
let [obj, prop] = _getPropertyTarget(actor, propName);
obj[prop] = target;
callback(true);
return;
}
let pspec = actor.find_property(propName);
let transition = new Clutter.PropertyTransition(Object.assign({
property_name: propName,
interval: new Clutter.Interval({ value_type: pspec.value_type }),
remove_on_complete: true
}, params));
actor.add_transition(propName, transition);
transition.set_to(target);
transition.connect('stopped', (t, finished) => callback(finished));
}
function _loggingFunc(...args) {
let fields = { 'MESSAGE': args.join(', ') };
let domain = "GNOME Shell"; let domain = "GNOME Shell";
// If the caller is an extension, add it as metadata // If the caller is an extension, add it as metadata
@ -211,55 +93,19 @@ function init() {
column_spacing: 'spacing-columns' }); column_spacing: 'spacing-columns' });
_patchLayoutClass(Clutter.BoxLayout, { spacing: 'spacing' }); _patchLayoutClass(Clutter.BoxLayout, { spacing: 'spacing' });
let origSetEasingDuration = Clutter.Actor.prototype.set_easing_duration;
Clutter.Actor.prototype.set_easing_duration = function(msecs) {
origSetEasingDuration.call(this, adjustAnimationTime(msecs));
};
let origSetEasingDelay = Clutter.Actor.prototype.set_easing_delay;
Clutter.Actor.prototype.set_easing_delay = function(msecs) {
origSetEasingDelay.call(this, adjustAnimationTime(msecs));
};
Clutter.Actor.prototype.ease = function(props, easingParams) {
_easeActor(this, props, easingParams);
};
Clutter.Actor.prototype.ease_property = function(propName, target, params) {
_easeActorProperty(this, propName, target, params);
};
St.Adjustment.prototype.ease = function(target, params) {
// we're not an actor of course, but we implement the same
// transition API as Clutter.Actor, so this works anyway
_easeActorProperty(this, 'value', target, params);
};
Clutter.Actor.prototype.toString = function() { Clutter.Actor.prototype.toString = function() {
return St.describe_actor(this); return St.describe_actor(this);
}; };
// Deprecation warning for former JS classes turned into an actor subclass
Object.defineProperty(Clutter.Actor.prototype, 'actor', {
get() {
let klass = this.constructor.name;
let { stack } = new Error();
log(`Usage of object.actor is deprecated for ${klass}\n${stack}`);
return this;
}
});
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}`);
St.Settings.get().slow_down_factor = factor;
};
let origToString = Object.prototype.toString; let origToString = Object.prototype.toString;
Object.prototype.toString = function() { Object.prototype.toString = function() {
let base = origToString.call(this); let base = origToString.call(this);
try { try {
if ('actor' in this && this.actor instanceof Clutter.Actor) if ('actor' in this && this.actor instanceof Clutter.Actor)
return base.replace(/\]$/, ` delegate for ${this.actor.toString().substring(1)}`); return base.replace(/\]$/, ' delegate for ' + this.actor.toString().substring(1));
else else
return base; return base;
} catch (e) { } catch(e) {
return base; return base;
} }
}; };
@ -273,7 +119,7 @@ function init() {
if (slowdownEnv) { if (slowdownEnv) {
let factor = parseFloat(slowdownEnv); let factor = parseFloat(slowdownEnv);
if (!isNaN(factor) && factor > 0.0) if (!isNaN(factor) && factor > 0.0)
St.Settings.get().slow_down_factor = factor; St.set_slow_down_factor(factor);
} }
// OK, now things are initialized enough that we can import shell JS // OK, now things are initialized enough that we can import shell JS
@ -283,17 +129,3 @@ function init() {
Tweener.init(); Tweener.init();
String.prototype.format = Format.format; String.prototype.format = Format.format;
} }
// adjustAnimationTime:
// @msecs: time in milliseconds
//
// Adjust @msecs to account for St's enable-animations
// and slow-down-factor settings
function adjustAnimationTime(msecs) {
let settings = St.Settings.get();
if (!settings.enable_animations)
return 1;
return settings.slow_down_factor * msecs;
}

View File

@ -1,20 +1,19 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported init, installExtension, uninstallExtension,
checkForUpdates, updateExtension */
const { Clutter, Gio, GLib, GObject, Soup } = imports.gi; const { Clutter, Gio, GLib, Soup, St } = imports.gi;
const Config = imports.misc.config; const Config = imports.misc.config;
const Dialog = imports.ui.dialog;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const ExtensionSystem = imports.ui.extensionSystem;
const FileUtils = imports.misc.fileUtils; const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog; const ModalDialog = imports.ui.modalDialog;
const _signals = ExtensionSystem._signals;
var REPOSITORY_URL_BASE = 'https://extensions.gnome.org'; var REPOSITORY_URL_BASE = 'https://extensions.gnome.org';
var REPOSITORY_URL_DOWNLOAD = `${REPOSITORY_URL_BASE}/download-extension/%s.shell-extension.zip`; var REPOSITORY_URL_DOWNLOAD = REPOSITORY_URL_BASE + '/download-extension/%s.shell-extension.zip';
var REPOSITORY_URL_INFO = `${REPOSITORY_URL_BASE}/extension-info/`; var REPOSITORY_URL_INFO = REPOSITORY_URL_BASE + '/extension-info/';
var REPOSITORY_URL_UPDATE = `${REPOSITORY_URL_BASE}/update-info/`; var REPOSITORY_URL_UPDATE = REPOSITORY_URL_BASE + '/update-info/';
let _httpSession; let _httpSession;
@ -26,7 +25,7 @@ function installExtension(uuid, invocation) {
_httpSession.queue_message(message, (session, message) => { _httpSession.queue_message(message, (session, message) => {
if (message.status_code != Soup.KnownStatusCode.OK) { if (message.status_code != Soup.KnownStatusCode.OK) {
Main.extensionManager.logExtensionError(uuid, `downloading info: ${message.status_code}`); ExtensionSystem.logExtensionError(uuid, 'downloading info: ' + message.status_code);
invocation.return_dbus_error('org.gnome.Shell.DownloadInfoError', message.status_code.toString()); invocation.return_dbus_error('org.gnome.Shell.DownloadInfoError', message.status_code.toString());
return; return;
} }
@ -35,7 +34,7 @@ function installExtension(uuid, invocation) {
try { try {
info = JSON.parse(message.response_body.data); info = JSON.parse(message.response_body.data);
} catch (e) { } catch (e) {
Main.extensionManager.logExtensionError(uuid, `parsing info: ${e}`); ExtensionSystem.logExtensionError(uuid, 'parsing info: ' + e);
invocation.return_dbus_error('org.gnome.Shell.ParseInfoError', e.toString()); invocation.return_dbus_error('org.gnome.Shell.ParseInfoError', e.toString());
return; return;
} }
@ -46,7 +45,7 @@ function installExtension(uuid, invocation) {
} }
function uninstallExtension(uuid) { function uninstallExtension(uuid) {
let extension = Main.extensionManager.lookup(uuid); let extension = ExtensionUtils.extensions[uuid];
if (!extension) if (!extension)
return false; return false;
@ -54,7 +53,7 @@ function uninstallExtension(uuid) {
if (extension.type != ExtensionUtils.ExtensionType.PER_USER) if (extension.type != ExtensionUtils.ExtensionType.PER_USER)
return false; return false;
if (!Main.extensionManager.unloadExtension(extension)) if (!ExtensionSystem.unloadExtension(extension))
return false; return false;
FileUtils.recursivelyDeleteDir(extension.dir, true); FileUtils.recursivelyDeleteDir(extension.dir, true);
@ -115,10 +114,10 @@ function updateExtension(uuid) {
_httpSession.queue_message(message, (session, message) => { _httpSession.queue_message(message, (session, message) => {
gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => { gotExtensionZipFile(session, message, uuid, newExtensionTmpDir, () => {
let oldExtension = Main.extensionManager.lookup(uuid); let oldExtension = ExtensionUtils.extensions[uuid];
let extensionDir = oldExtension.dir; let extensionDir = oldExtension.dir;
if (!Main.extensionManager.unloadExtension(oldExtension)) if (!ExtensionSystem.unloadExtension(oldExtension))
return; return;
FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir); FileUtils.recursivelyMoveDir(extensionDir, oldExtensionTmpDir);
@ -127,11 +126,11 @@ function updateExtension(uuid) {
let extension = null; let extension = null;
try { try {
extension = Main.extensionManager.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER); extension = ExtensionUtils.createExtensionObject(uuid, extensionDir, ExtensionUtils.ExtensionType.PER_USER);
Main.extensionManager.loadExtension(extension); ExtensionSystem.loadExtension(extension);
} catch (e) { } catch(e) {
if (extension) if (extension)
Main.extensionManager.unloadExtension(extension); ExtensionSystem.unloadExtension(extension);
logError(e, 'Error loading extension %s'.format(uuid)); logError(e, 'Error loading extension %s'.format(uuid));
@ -140,7 +139,7 @@ function updateExtension(uuid) {
// Restore what was there before. We can't do much if we // Restore what was there before. We can't do much if we
// fail here. // fail here.
Main.extensionManager.loadExtension(oldExtension); ExtensionSystem.loadExtension(oldExtension);
return; return;
} }
@ -153,9 +152,9 @@ function updateExtension(uuid) {
function checkForUpdates() { function checkForUpdates() {
let metadatas = {}; let metadatas = {};
Main.extensionManager.getUuids().forEach(uuid => { for (let uuid in ExtensionUtils.extensions) {
metadatas[uuid] = Main.extensionManager.extensions[uuid].metadata; metadatas[uuid] = ExtensionUtils.extensions[uuid].metadata;
}); }
let params = { shell_version: Config.PACKAGE_VERSION, let params = { shell_version: Config.PACKAGE_VERSION,
installed: JSON.stringify(metadatas) }; installed: JSON.stringify(metadatas) };
@ -177,41 +176,45 @@ function checkForUpdates() {
}); });
} }
var InstallExtensionDialog = GObject.registerClass( var InstallExtensionDialog =
class InstallExtensionDialog extends ModalDialog.ModalDialog { class InstallExtensionDialog extends ModalDialog.ModalDialog {
_init(uuid, info, invocation) { constructor(uuid, info, invocation) {
super._init({ styleClass: 'extension-dialog' }); super({ styleClass: 'extension-dialog' });
this._uuid = uuid; this._uuid = uuid;
this._info = info; this._info = info;
this._invocation = invocation; this._invocation = invocation;
this.setButtons([{ this.setButtons([{ label: _("Cancel"),
label: _("Cancel"), action: this._onCancelButtonPressed.bind(this),
action: this._onCancelButtonPressed.bind(this), key: Clutter.Escape
key: Clutter.Escape, },
}, { { label: _("Install"),
label: _("Install"), action: this._onInstallButtonPressed.bind(this),
action: this._onInstallButtonPressed.bind(this), default: true
default: true, }]);
}]);
let content = new Dialog.MessageDialogContent({ let message = _("Download and install “%s” from extensions.gnome.org?").format(info.name);
title: _("Download and install “%s” from extensions.gnome.org?").format(info.name),
icon: new Gio.FileIcon({
file: Gio.File.new_for_uri(`${REPOSITORY_URL_BASE}${info.icon}`)
})
});
this.contentLayout.add(content); let box = new St.BoxLayout({ style_class: 'message-dialog-main-layout',
vertical: false });
this.contentLayout.add(box);
let gicon = new Gio.FileIcon({ file: Gio.File.new_for_uri(REPOSITORY_URL_BASE + info.icon) })
let icon = new St.Icon({ gicon: gicon });
box.add(icon);
let label = new St.Label({ style_class: 'message-dialog-title headline',
text: message });
box.add(label);
} }
_onCancelButtonPressed() { _onCancelButtonPressed(button, event) {
this.close(); this.close();
this._invocation.return_value(GLib.Variant.new('(s)', ['cancelled'])); this._invocation.return_value(GLib.Variant.new('(s)', ['cancelled']));
} }
_onInstallButtonPressed() { _onInstallButtonPressed(button, event) {
let params = { shell_version: Config.PACKAGE_VERSION }; let params = { shell_version: Config.PACKAGE_VERSION };
let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid); let url = REPOSITORY_URL_DOWNLOAD.format(this._uuid);
@ -223,16 +226,21 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
function errback(code, message) { function errback(code, message) {
let msg = message ? message.toString() : ''; let msg = message ? message.toString() : '';
log('Error while installing %s: %s (%s)'.format(uuid, code, msg)); log('Error while installing %s: %s (%s)'.format(uuid, code, msg));
invocation.return_dbus_error(`org.gnome.Shell.${code}`, msg); invocation.return_dbus_error('org.gnome.Shell.' + code, msg);
} }
function callback() { function callback() {
// Add extension to 'enabled-extensions' for the user, always...
let enabledExtensions = global.settings.get_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY);
if (enabledExtensions.indexOf(uuid) == -1) {
enabledExtensions.push(uuid);
global.settings.set_strv(ExtensionSystem.ENABLED_EXTENSIONS_KEY, enabledExtensions);
}
try { try {
let extension = Main.extensionManager.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER); let extension = ExtensionUtils.createExtensionObject(uuid, dir, ExtensionUtils.ExtensionType.PER_USER);
Main.extensionManager.loadExtension(extension); ExtensionSystem.loadExtension(extension);
if (!Main.extensionManager.enableExtension(uuid)) } catch(e) {
throw new Error(`Cannot add ${uuid} to enabled extensions gsettings key`);
} catch (e) {
uninstallExtension(uuid); uninstallExtension(uuid);
errback('LoadExtensionError', e); errback('LoadExtensionError', e);
return; return;
@ -247,7 +255,7 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
this.close(); this.close();
} }
}); };
function init() { function init() {
_httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true }); _httpSession = new Soup.SessionAsync({ ssl_use_system_ca_file: true });

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