Compare commits

..

1 Commits

Author SHA1 Message Date
Allan Day
1b4062c931 theme: Standardise text styles
Initial attempt to use standard text styles, in line with what's
being done for GTK (https://gitlab.gnome.org/GNOME/gtk/issues/1808).

This is just changing the sizes and weights for now. Spacing
adjustments will be required further down the line.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/594
2019-06-25 14:28:49 +02:00
282 changed files with 24781 additions and 46646 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
@@ -25,27 +26,19 @@ 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/mutter/master:v2
stage: build stage: build
@@ -54,7 +47,7 @@ build:
- 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
@@ -67,8 +60,6 @@ build:
test: test:
image: registry.gitlab.gnome.org/gnome/mutter/master:v2 image: registry.gitlab.gnome.org/gnome/mutter/master:v2
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:

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

@@ -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;
});
} }
```
The above is a convenience wrapper around the actual Clutter API, and should generally get position() {
be preferred over the more verbose: return this._position;
```javascript
moveActor(actor, x, y) {
actor.save_easing_state();
actor.set_easing_duration(500);
actor.set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD);
actor.set({
x,
y
});
actor.restore_easing_state();
} }
```
There is a similar convenience API around Clutter.PropertyTransition to animate set position(value) {
actor (or actor meta) properties that cannot use implicit animations: this._position = value;
this.actor.set_position(value, value);
```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
});
} }
};
let myThing = new MyClass();
Tweener.addTween(myThing,
{ position: 100,
time: ANIMATION_TIME,
transition: 'easeOutQuad' });
``` ```

151
NEWS
View File

@@ -1,154 +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 3.33.3
====== ======
* Prepare for optional X11 [Carlos; !378] * Prepare for optional X11 [Carlos; !378]

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

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

@@ -25,10 +25,8 @@ $cakeisalie: "This stylesheet is generated, DO NOT EDIT";
/* GLOBALS */ /* GLOBALS */
$panel-corner-radius: 6px;
$modal_radius: 9px; $medium_radius: 9px;
$button_radius: 5px;
$panel-corner-radius: $button_radius + 1;
$_trough_color: transparentize($fg_color, 0.9); $_trough_color: transparentize($fg_color, 0.9);
$_bubble_borders_color: lighten($borders_color, if($variant=='light', 0%, 5%)); $_bubble_borders_color: lighten($borders_color, if($variant=='light', 0%, 5%));
@@ -48,7 +46,7 @@ stage {
/* Buttons */ /* Buttons */
.button, %button { .button, %button {
border-radius: $button_radius; border-radius: 5px;
border-width: 1px; border-width: 1px;
min-height: 22px; min-height: 22px;
padding: 4px 32px; padding: 4px 32px;
@@ -70,21 +68,21 @@ stage {
border-top: 1px solid $_bubble_borders_color; border-top: 1px solid $_bubble_borders_color;
&:first-child { &:first-child {
border-radius: 0px 0px 0px $modal_radius; border-radius: 0px 0px 0px $medium_radius;
} }
&:last-child { &:last-child {
border-right-width: 0px; border-right-width: 0px;
border-radius: 0px 0px $modal_radius 0px; border-radius: 0px 0px $medium_radius 0px;
} }
&:first-child:last-child { &:first-child:last-child {
border-right-width: 0px; border-right-width: 0px;
border-radius: 0px 0px $modal_radius $modal_radius; border-radius: 0px 0px $medium_radius $medium_radius;
} }
} }
/* Entries */ /* Entries */
StEntry { StEntry {
border-radius: $button_radius; border-radius: 5px;
padding: 4px; padding: 4px;
border-width: 1px; border-width: 1px;
color: $fg_color; color: $fg_color;
@@ -148,7 +146,8 @@ StScrollBar {
-slider-handle-radius: 8px; -slider-handle-radius: 8px;
-slider-handle-border-width: 1px; -slider-handle-border-width: 1px;
-slider-handle-border-color: $borders_color; -slider-handle-border-color: $borders_color;
color: if($variant == 'light', lighten($bg_color, 10%), darken($bg_color,4%)); color: $bg_color; /* FIXME to match gtk, we'd need to style the border of the slider, not
the whole widget */
&:hover { color: $_hover_bg_color; } &:hover { color: $_hover_bg_color; }
&:active { color: $_active_bg_color; } &:active { color: $_active_bg_color; }
} }
@@ -189,12 +188,12 @@ StScrollBar {
/* Modal Dialogs */ /* Modal Dialogs */
.headline { font-size: 110%; } .headline { @extend %heading; }
.lightbox { background-color: black; } .lightbox { background-color: black; }
.flashspot { background-color: white; } .flashspot { background-color: white; }
.modal-dialog { .modal-dialog {
border-radius: $modal_radius; border-radius: 9px;
@extend %bubble-panel; @extend %bubble-panel;
.modal-dialog-content-box { .modal-dialog-content-box {
padding: 24px; padding: 24px;
@@ -206,8 +205,7 @@ StScrollBar {
} }
.run-dialog-button-box { padding-top: 1em; } .run-dialog-button-box { padding-top: 1em; }
.run-dialog-label { .run-dialog-label {
@include fontsize($font-size + 1.1); @extend %title-4;
font-weight: normal;
color: $fg_color; color: $fg_color;
padding-bottom: .4em; padding-bottom: .4em;
} }
@@ -215,8 +213,8 @@ StScrollBar {
} }
.mount-dialog-subject, .mount-dialog-subject,
.end-session-dialog-subject { //this should be a generic header class .end-session-dialog-subject {
@include fontsize($font-size * 1.3); @extend %title-2;
} }
/* Message Dialog */ /* Message Dialog */
@@ -236,12 +234,12 @@ StScrollBar {
} }
.message-dialog-title { .message-dialog-title {
font-weight: bold; @extend %title-2;
} }
.message-dialog-subtitle { .message-dialog-subtitle {
@extend %heading;
color: $fg_color; color: $fg_color;
font-weight: bold;
} }
/* End Session Dialog */ /* End Session Dialog */
@@ -302,7 +300,7 @@ StScrollBar {
} }
.end-session-dialog-list-header { .end-session-dialog-list-header {
font-weight: bold; @extend %heading;
&:rtl { text-align: right; } &:rtl { text-align: right; }
} }
@@ -313,12 +311,11 @@ StScrollBar {
.end-session-dialog-app-list-item-name, .end-session-dialog-app-list-item-name,
.end-session-dialog-session-list-item-name { .end-session-dialog-session-list-item-name {
font-weight: bold; @extend %heading;
} }
.end-session-dialog-app-list-item-description { .end-session-dialog-app-list-item-description {
color: darken($fg_color,5%); color: darken($fg_color,5%);
font-size: 10pt;
} }
/* ShellMountOperation Dialogs */ /* ShellMountOperation Dialogs */
@@ -374,11 +371,6 @@ StScrollBar {
&:rtl { padding-left: 17px; } &:rtl { padding-left: 17px; }
} }
.mount-dialog-app-list-item-name {
font-size: 10pt;
}
/* Password or Authentication Dialog */ /* Password or Authentication Dialog */
.prompt-dialog { .prompt-dialog {
@@ -401,13 +393,11 @@ StScrollBar {
} }
.prompt-dialog-error-label { .prompt-dialog-error-label {
font-size: 10pt;
color: $warning_color; color: $warning_color;
padding-bottom: 8px; padding-bottom: 8px;
} }
.prompt-dialog-info-label { .prompt-dialog-info-label {
font-size: 10pt;
padding-bottom: 8px; padding-bottom: 8px;
} }
@@ -416,7 +406,6 @@ StScrollBar {
} }
.prompt-dialog-null-label { .prompt-dialog-null-label {
font-size: 10pt;
padding-bottom: 8px; padding-bottom: 8px;
} }
@@ -472,7 +461,7 @@ StScrollBar {
} }
.audio-selection-title { .audio-selection-title {
font-weight: bold; @extend %heading;
text-align: center; text-align: center;
} }
@@ -556,9 +545,9 @@ StScrollBar {
&:ltr { padding: .4em 1.75em .4em 0em; } &:ltr { padding: .4em 1.75em .4em 0em; }
&:rtl { padding: .4em 0em .4em 1.75em; } &:rtl { padding: .4em 0em .4em 1.75em; }
&:checked { &:checked {
@extend %heading;
background-color: $bg_color; background-color: $bg_color;
box-shadow: inset 0 -1px 0px $_bubble_borders_color; box-shadow: inset 0 -1px 0px $_bubble_borders_color;
font-weight: bold;
} }
&.selected { &.selected {
background-color: transparentize(white, if($variant=='light', 0.2, 0.9)); background-color: transparentize(white, if($variant=='light', 0.2, 0.9));
@@ -591,7 +580,7 @@ StScrollBar {
} }
.popup-menu-boxpointer, .popup-menu-boxpointer,
.candidate-popup-boxpointer { .candidate-popup-boxpointer {
-arrow-border-radius: $button_radius+4; -arrow-border-radius: $medium_radius;
-arrow-background-color: $bg_color; -arrow-background-color: $bg_color;
-arrow-border-width: 1px; -arrow-border-width: 1px;
-arrow-border-color: if($variant=='light', transparentize(black, 0.6), $borders_color); -arrow-border-color: if($variant=='light', transparentize(black, 0.6), $borders_color);
@@ -610,13 +599,6 @@ StScrollBar {
border-bottom-style: solid; border-bottom-style: solid;
} }
// Rename popup
.rename-folder-popup {
.rename-folder-popup-item {
spacing: 6px;
&:ltr, &:rtl { padding: 0, 12px; }
}
}
// Background menu // Background menu
.background-menu { -boxpointer-gap: 4px; -arrow-rise: 0px; } .background-menu { -boxpointer-gap: 4px; -arrow-rise: 0px; }
@@ -626,18 +608,6 @@ StScrollBar {
app menu inside the main app window itself rather than the top bar app menu inside the main app window itself rather than the top bar
*/ */
/*************
* App Icons *
*************/
/* Outline for low res icons */
.lowres-icon {
icon-shadow: 0 1px 2px rgba(0,0,0,0.3);
}
/* Drapshadow for large icons */
.icon-dropshadow {
icon-shadow: 0 1px 2px rgba(0,0,0,0.4);
}
/* OSD */ /* OSD */
.osd-window { .osd-window {
@@ -648,7 +618,7 @@ StScrollBar {
min-width: 64px; min-width: 64px;
min-height: 64px; min-height: 64px;
.osd-monitor-label { font-size: 3em; } .osd-monitor-label { @extend %title-1; }
.level { .level {
height: 0.6em; height: 0.6em;
-barlevel-height: 0.6em; -barlevel-height: 0.6em;
@@ -747,9 +717,8 @@ StScrollBar {
spacing: 8px; spacing: 8px;
} }
.ws-switcher-active-up, .ws-switcher-active-down, .ws-switcher-active-up, .ws-switcher-active-down {
.ws-switcher-active-left, .ws-switcher-active-right { height: 50px;
height: 52px;
background-color: $selected_bg_color; background-color: $selected_bg_color;
color: $selected_fg_color; color: $selected_fg_color;
background-size: 32px; background-size: 32px;
@@ -822,8 +791,8 @@ StScrollBar {
/* TOP BAR */ /* TOP BAR */
#panel { #panel {
@extend %heading;
background-color: black; background-color: black;
font-weight: bold;
height: 1.86em; height: 1.86em;
font-feature-settings: "tnum"; font-feature-settings: "tnum";
@@ -855,9 +824,9 @@ StScrollBar {
} }
.panel-button { .panel-button {
@extend %heading;
-natural-hpadding: 12px; -natural-hpadding: 12px;
-minimum-hpadding: 6px; -minimum-hpadding: 6px;
font-weight: bold;
color: #ccc; color: #ccc;
.app-menu-icon { .app-menu-icon {
@@ -949,33 +918,33 @@ StScrollBar {
.world-clocks-button, .world-clocks-button,
.weather-button, .weather-button,
.events-section-title { .events-section-title {
&:hover, &:focus { background-color: $_hover_bg_color } &:hover, focus { background-color: $_hover_bg_color }
&:active { background-color: $_active_bg_color } &:active { background-color: $_active_bg_color }
} }
.datemenu-today-button .day-label { .datemenu-today-button .day-label {
@extend %heading;
} }
.datemenu-today-button .date-label { .datemenu-today-button .date-label {
font-size: 1.5em; @extend %large-title;
font-weight: 300;
} }
.world-clocks-header, .world-clocks-header,
.weather-header, .weather-header,
.events-section-title { .events-section-title,
.calendar-month-label {
@extend %heading;
color: darken($fg_color,40%); color: darken($fg_color,40%);
font-weight: bold;
} }
.weather-header.location { .weather-header.location {
font-weight: normal; @extend %caption;
font-size: 0.9em;
} }
.world-clocks-grid, .world-clocks-grid,
.weather-grid { .weather-grid {
spacing-rows: 0.4em; spacing-rows: 0.8em;
spacing-columns: 0.8em; spacing-columns: 0.8em;
} }
@@ -983,35 +952,26 @@ StScrollBar {
spacing: 0.4em; spacing: 0.4em;
} }
.world-clocks-city {
font-weight: bold;
font-size: 0.9em;
}
.world-clocks-time { .world-clocks-time {
color: darken($fg_color,20%);
font-feature-settings: "tnum"; font-feature-settings: "tnum";
font-size: 1.2em;
} }
.world-clocks-timezone { .world-clocks-timezone {
color: $fg_color; color: darken($fg_color,40%);
font-feature-settings: "tnum"; font-feature-settings: "tnum";
font-size: 0.9em; @extend %caption;
} }
.weather-forecast-icon { .weather-forecast-icon {
icon-size: 2.18em; icon-size: 32px;
} }
.weather-forecast-time { .weather-forecast-time {
@extend %caption;
color: darken($fg_color,40%); color: darken($fg_color,40%);
font-size: 0.8em;
} }
.calendar-month-label { .calendar-month-label {
color: lighten($fg_color,5%);
font-weight: bold;
padding: 8px 0; padding: 8px 0;
&:focus {} &:focus {}
} }
@@ -1020,7 +980,7 @@ StScrollBar {
background-color: transparent; background-color: transparent;
width: 32px; width: 32px;
border-radius: 4px; border-radius: 4px;
&:hover, &:focus { background-color: $_hover_bg_color; } &:hover, focus { background-color: $_hover_bg_color; }
&:active { background-color: transparentize($fg_color, 0.84); } &:active { background-color: transparentize($fg_color, 0.84); }
} }
@@ -1029,23 +989,22 @@ StScrollBar {
} }
.calendar-day-base { .calendar-day-base {
font-size: 80%; @extend %caption;
text-align: center; text-align: center;
width: 2.4em; height: 2.4em; width: 2.4em; height: 2.4em;
padding: 0.1em; padding: 0.1em;
margin: 2px; margin: 2px;
border-radius: 1.4em; border-radius: 1.4em;
font-feature-settings: "tnum"; font-feature-settings: "tnum";
&:hover, &:focus { background-color: $_hover_bg_color; } &:hover, focus { background-color: $_hover_bg_color; }
&:active,&:selected { &:active,&:selected {
color: lighten($selected_fg_color,5%); color: lighten($selected_fg_color,5%);
background-color: $selected_bg_color; background-color: $selected_bg_color;
border-color: transparent; //avoid jumparound due to today border-color: transparent; //avoid jumparound due to today
} }
&.calendar-day-heading { //day of week heading &.calendar-day-heading { //day of week heading
color: lighten($fg_color,5%); color: darken($fg_color,40%);
margin-top: 1em; // margin-top: 1em;
font-size: 70%;
} }
} }
.calendar-day { //border collapse hack - see calendar.js .calendar-day { //border collapse hack - see calendar.js
@@ -1060,14 +1019,15 @@ StScrollBar {
color: $insensitive_fg_color; color: $insensitive_fg_color;
} }
.calendar-today { .calendar-today {
font-weight: bold; @extend %caption-heading;
//color: lighten($fg_color,10%); //color: lighten($fg_color,10%);
//background-color: darken($bg_color,5%); //background-color: darken($bg_color,5%);
border: 1px solid $_bubble_borders_color; border: 1px solid $_bubble_borders_color;
} }
.calendar-day-with-events { .calendar-day-with-events {
@extend %caption-heading;
color: lighten($fg_color,10%); color: lighten($fg_color,10%);
font-weight: bold;
background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg"); background-image: url("resource:///org/gnome/shell/theme/calendar-today.svg");
} }
.calendar-other-month-day { .calendar-other-month-day {
@@ -1075,8 +1035,7 @@ StScrollBar {
opacity: 0.5; opacity: 0.5;
} }
.calendar-week-number { .calendar-week-number {
font-size: 70%; @extend %caption-heading;
font-weight: bold;
width: 2.3em; height: 1.8em; width: 2.3em; height: 1.8em;
border-radius: 2px; border-radius: 2px;
padding: 0.5em 0 0; padding: 0.5em 0 0;
@@ -1133,8 +1092,8 @@ StScrollBar {
} }
.message-secondary-bin > .event-time { .message-secondary-bin > .event-time {
@extend %caption;
color: $fg_color; color: $fg_color;
font-size: 0.7em;
/* HACK: the label should be baseline-aligned with a 1em label, /* HACK: the label should be baseline-aligned with a 1em label,
fake this with some bottom padding */ fake this with some bottom padding */
padding-bottom: 0.13em; padding-bottom: 0.13em;
@@ -1177,7 +1136,13 @@ StScrollBar {
// a little unstructured mess: // a little unstructured mess:
.system-switch-user-submenu-icon {
icon-size: 16px;
padding: 0 4px;
}
#appMenu { #appMenu {
spinner-image: url("resource:///org/gnome/shell/theme/process-working.svg");
spacing: 4px; spacing: 4px;
.label-shadow { color: transparent; } .label-shadow { color: transparent; }
@@ -1299,17 +1264,16 @@ StScrollBar {
.nm-dialog-airplane-box { spacing: 12px; } .nm-dialog-airplane-box { spacing: 12px; }
.nm-dialog-airplane-headline { .nm-dialog-airplane-headline {
font-weight: bold; @extend %heading;
text-align: center; text-align: center;
} }
.nm-dialog-airplane-text { color: $fg_color; } .nm-dialog-airplane-text { color: $fg_color; }
.nm-dialog-header-icon { icon-size: 32px; } .nm-dialog-header-icon { icon-size: 32px; }
.nm-dialog-scroll-view { border: 2px solid $borders_color; } .nm-dialog-scroll-view { border: 2px solid $borders_color; }
.nm-dialog-header { font-weight: bold; } .nm-dialog-header { @extend %title-2; }
.nm-dialog-item { .nm-dialog-item {
font-size: 110%;
border-bottom: 1px solid $borders_color; border-bottom: 1px solid $borders_color;
padding: 12px; padding: 12px;
spacing: 20px; spacing: 20px;
@@ -1345,8 +1309,8 @@ StScrollBar {
.window-clone-border { .window-clone-border {
$_bg: transparentize(white, 0.65); $_bg: transparentize(white, 0.65);
border: 7px solid $_bg; border: 5px solid $_bg;
border-radius: $modal_radius; border-radius: 6px;
// For window decorations with round corners we can't match // For window decorations with round corners we can't match
// the exact shape when the window is scaled. So apply a shadow // the exact shape when the window is scaled. So apply a shadow
// to fix that case // to fix that case
@@ -1383,8 +1347,11 @@ StScrollBar {
//search results //search results
#searchResultsContent { #searchResultsBin {
max-width: 1000px; max-width: 1000px;
}
#searchResultsContent {
padding-left: 20px; padding-left: 20px;
padding-right: 20px; padding-right: 20px;
spacing: 16px; spacing: 16px;
@@ -1413,7 +1380,7 @@ StScrollBar {
#dash { #dash {
@extend %overview-panel; @extend %overview-panel;
font-size: 9pt; @extend %caption;
padding: 4px 0; padding: 4px 0;
border-radius: 0px 9px 9px 0px; border-radius: 0px 9px 9px 0px;
@@ -1500,11 +1467,11 @@ StScrollBar {
.search-provider-icon, .search-provider-icon,
.list-search-result { .list-search-result {
@extend %icon_tile; @extend %icon_tile;
&:active, &:checked { background-color: transparentize(darken($osd_bg_color,10%),.1); }
&:focus, &:selected, &:hover { &:focus, &:selected, &:hover {
background-color: transparentize($osd_fg_color,.9); background-color: transparentize($osd_fg_color,.9);
transition-duration: 200ms; transition-duration: 200ms;
} }
&:active, &:checked { background-color: transparentize(darken($osd_bg_color,10%),.1); }
} }
.app-well-app, .app-well-app,
.app-well-app.app-folder, .app-well-app.app-folder,
@@ -1513,6 +1480,10 @@ StScrollBar {
& .overview-icon { & .overview-icon {
@extend %icon_tile; @extend %icon_tile;
} }
&:active .overview-icon,
&:checked .overview-icon {
background-color: transparentize(darken($osd_bg_color,10%), 0.5);
}
&:hover .overview-icon, &:hover .overview-icon,
&:focus .overview-icon, &:focus .overview-icon,
&:selected .overview-icon { &:selected .overview-icon {
@@ -1521,13 +1492,7 @@ StScrollBar {
border-image: none; border-image: none;
background-image: none; background-image: none;
} }
&:drop .overview-icon {
background-color: transparentize($selected_bg_color,.15);
}
&:active .overview-icon,
&:checked .overview-icon {
background-color: transparentize(darken($osd_bg_color,10%), 0.5);
}
} }
.app-well-app-running-dot { //running apps indicator .app-well-app-running-dot { //running apps indicator
@@ -1538,7 +1503,7 @@ StScrollBar {
%icon_tile { %icon_tile {
color: $osd_fg_color; color: $osd_fg_color;
border-radius: $button_radius+4; border-radius: $medium_radius;
padding: 6px; padding: 6px;
border: 1px solid transparent; border: 1px solid transparent;
transition-duration: 100ms; transition-duration: 100ms;
@@ -1617,6 +1582,7 @@ StScrollBar {
} }
//Some hacks I don't even //Some hacks I don't even
.search-display > StBoxLayout,
.all-apps, .all-apps,
.frequent-apps > StBoxLayout { .frequent-apps > StBoxLayout {
// horizontal padding to make sure scrollbars or dash don't overlap content // horizontal padding to make sure scrollbars or dash don't overlap content
@@ -1629,9 +1595,9 @@ StScrollBar {
border: none; border: none;
} }
// Search status, like "Searching..." and "No results"
%status_text { %status_text {
font-size: 2em; @extend %large-title;
font-weight: bold;
color: $osd_fg_color; color: $osd_fg_color;
} }
@@ -1641,17 +1607,16 @@ StScrollBar {
// Banners // Banners
.notification-banner { .notification-banner {
font-size: 11pt;
width: 34em; width: 34em;
margin: 5px; margin: 5px;
border-radius: $modal_radius; border-radius: $medium-radius;
border: if($variant == 'light', none, $_bubble_borders_color); border: if($variant == 'light', none, $_bubble_borders_color);
min-height: 64px; min-height: 64px;
box-shadow: 0 1px 2px transparentize(black, 0.7); box-shadow: 0 1px 2px transparentize(black, 0.7);
&:hover { background: $bg_color; } &:hover { background: $bg_color; }
&, &:focus, &:active { &, &:focus, &:active {
background-color: $bg_color; background-color: $bg_color;
.message-title { color: $fg_color } .message-title { color: $fg_color; }
.message-content { color: $fg_color; } .message-content { color: $fg_color; }
} }
@@ -1678,18 +1643,6 @@ StScrollBar {
border: none; border: none;
} }
} }
.summary-source-counter {
font-size: 10pt;
font-weight: bold;
height: 1.6em; width: 1.6em;
-shell-counter-overlap-x: 3px;
-shell-counter-overlap-y: 3px;
background-color: $selected_bg_color;
color: $selected_fg_color;
border: 2px solid $fg_color;
box-shadow: 0 2px 2px rgba(0,0,0,0.5);
border-radius: 0.9em; // should be 0.8 but whatever; wish I could do 50%;
}
.secondary-icon { icon-size: 1.09em; } .secondary-icon { icon-size: 1.09em; }
@@ -1708,9 +1661,8 @@ StScrollBar {
&:rtl { padding-left: 0; padding-right: 18pt; } &:rtl { padding-left: 0; padding-right: 18pt; }
} }
.chat-meta-message { .chat-meta-message {
@extend %caption-heading;
padding-left: 4px; padding-left: 4px;
font-size: 9pt;
font-weight: bold;
color: lighten($fg_color,18%); color: lighten($fg_color,18%);
&:rtl { padding-left: 0; padding-right: 4px; } &:rtl { padding-left: 0; padding-right: 4px; }
} }
@@ -1796,36 +1748,30 @@ StScrollBar {
} }
.keyboard-key { .keyboard-key {
$_key_bg: opacify(lighten($osd_bg_color, 9%), 1); background-color: #393f3f;
background-color: $_key_bg;
min-height: 1.2em; min-height: 1.2em;
min-width: 1.2em; min-width: 1.2em;
font-size: 16pt; font-size: 16pt;
border-radius: $button_radius; border-radius: 3px;
border: 1px solid $osd_outer_borders_color; border: 1px solid #464d4d;
color: $osd_fg_color; color: #e5e5e5;
&:focus { @include button(focus); } &:focus { @include button(focus); }
&:hover, &:checked { background-color: lighten($_key_bg, 3%); } &:hover,&:checked { @include button(hover); }
&:active { background-color: darken($_key_bg, 2%); } &:active { @include button(active);}
&:grayed { //FIXME &:grayed { //FIXME
background-color: $osd_bg_color; background-color: $osd_bg_color;
color: $osd_fg_color; color: $osd_fg_color;
border-color: $osd_borders_color; border-color: $osd_borders_color;
} }
&.default-key { &.default-key {
$_default_key_bg: opacify($osd_bg_color, 1); border-color: #2d3232;
border-color: $osd_outer_borders_color; background-color: #1d2020;
background-color: $_default_key_bg;
background-size: 20px; background-size: 20px;
&:hover, &:checked { background-color: lighten($_default_key_bg, 3%); }
&:active { background-color: darken($_default_key_bg, 2%); }
} }
&.enter-key { &.enter-key {
border-color: lighten($selected_bg_color, 5%); border-color: #005684;
background-color: $selected_bg_color; background-color: #006098;
background-image: url("resource:///org/gnome/shell/theme/key-enter.svg"); background-image: url("resource:///org/gnome/shell/theme/key-enter.svg");
&:hover, &:checked { background-color: lighten($selected_bg_color, 3%); }
&:active { background-color: darken($selected_bg_color, 2%); }
} }
&.shift-key-lowercase { &.shift-key-lowercase {
background-image: url("resource:///org/gnome/shell/theme/key-shift.svg"); background-image: url("resource:///org/gnome/shell/theme/key-shift.svg");
@@ -1864,8 +1810,8 @@ StScrollBar {
.emoji-panel { .emoji-panel {
.keyboard-key:latched { .keyboard-key:latched {
border-color: lighten($selected_bg_color, 5%); border-color: #005684;
background-color: $selected_bg_color; background-color: #006098;
} }
} }
@@ -1929,7 +1875,7 @@ StScrollBar {
StEntry { StEntry {
@extend %search_entry; @extend %search_entry;
border-radius: $button_radius; border-radius: 5px;
@if $variant=='dark' { @if $variant=='dark' {
$_gdm_entry_bg: transparentize(lighten(desaturate(#241f31, 20%), 2%), 0.5); $_gdm_entry_bg: transparentize(lighten(desaturate(#241f31, 20%), 2%), 0.5);
background-color: $_gdm_entry_bg; background-color: $_gdm_entry_bg;
@@ -2002,8 +1948,7 @@ StScrollBar {
} }
} }
.login-dialog-not-listed-label { .login-dialog-not-listed-label {
font-size: 90%; @extend %heading;
font-weight: bold;
color: darken($osd_fg_color,30%); color: darken($osd_fg_color,30%);
padding-top: 1em; padding-top: 1em;
} }
@@ -2032,8 +1977,7 @@ StScrollBar {
.login-dialog-username, .login-dialog-username,
.user-widget-label { .user-widget-label {
color: $osd_fg_color; color: $osd_fg_color;
font-size: 120%; @extend %title-3;
font-weight: bold;
text-align: left; text-align: left;
padding-left: 15px; padding-left: 15px;
} }
@@ -2051,7 +1995,6 @@ StScrollBar {
.login-dialog-prompt-label { .login-dialog-prompt-label {
color: darken($osd_fg_color, 20%); color: darken($osd_fg_color, 20%);
font-size: 110%;
padding-top: 1em; padding-top: 1em;
} }
@@ -2123,7 +2066,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
.screen-shield-notification-label { .screen-shield-notification-label {
font-weight: bold; @extend %heading;
padding: 0px 0px 0px 12px; padding: 0px 0px 0px 12px;
} }
@@ -2163,9 +2106,9 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
} }
.labels { spacing: 4px; } .labels { spacing: 4px; }
.notebook-tab { .notebook-tab {
@extend %heading;
-natural-hpadding: 12px; -natural-hpadding: 12px;
-minimum-hpadding: 6px; -minimum-hpadding: 6px;
font-weight: bold;
color: #ccc; color: #ccc;
transition-duration: 100ms; transition-duration: 100ms;
padding-left: .3em; padding-left: .3em;
@@ -2226,7 +2169,7 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
} }
.lg-extension-name { .lg-extension-name {
font-weight: bold; @extend %heading;
} }
.lg-extension-meta { .lg-extension-meta {
@@ -2239,3 +2182,39 @@ $_screenshield_shadow: 0px 0px 6px rgba(0, 0, 0, 0.726);
border-radius: 4px; border-radius: 4px;
padding: 6px; padding: 6px;
} }
// text styles
%large-title {
font-weight: 300;
font-size: 24pt;
// letter-spacing: 0.2rem; This breaks the style
}
%title-1 {
font-weight: 800;
font-size: 20pt;
}
%title-2 {
font-weight: 800;
font-size: 15pt;
}
%title-3 {
font-weight: 700;
font-size: 15pt;
}
%title-4 {
font-weight: 700;
font-size: 13pt;
}
%heading {
font-weight: 700;
font-size: 11pt;
}
%caption-heading {
font-weight: 700;
font-size: 9pt;
}
%caption {
font-weight: 400;
font-size: 9pt;
}

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());
let backticks = '```';
clipboard.set_text(
// markdown for pasting in gitlab issues // markdown for pasting in gitlab issues
let lines = [ `The settings of extension ${extension.uuid} had an error:\n${
`The settings of extension ${row.uuid} had an error:`, backticks}\n${exc}\n${backticks}\n\nStack trace:\n${
'```', backticks}\n${exc.stack}${backticks}\n`, -1
`${exc}`, );
'```',
'',
'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._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(); 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
ExtensionUtils.getCurrentExtension = () => this._extension;
this._prefsModule = this._extension.imports.prefs;
this._prefsModule.init(this._extension.metadata);
} }
return this._prefsModule; _enable() {
let extensions = this._settings.get_strv('enabled-extensions');
if (extensions.indexOf(this.uuid) != -1)
return;
extensions.push(this.uuid);
this._settings.set_strv('enabled-extensions', extensions);
}
_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,
@@ -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,12 +290,13 @@ 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,
onComplete() {
if (wasSpinner) { if (wasSpinner) {
if (this._spinner) if (this._spinner)
this._spinner.stop(); 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,11 +366,11 @@ 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'
}); });
} }
@@ -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 {
@@ -202,6 +201,7 @@ var ConsecutiveBatch = class extends Batch {
hold.disconnect(signalId); hold.disconnect(signalId);
this.nextTask(); this.nextTask();
}); });
return;
} else { } else {
// This task finished, process the next one // This task finished, process the next one
this.nextTask(); this.nextTask();

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;
@@ -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) {
@@ -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();
@@ -326,7 +329,7 @@ var SessionMenuButton = class {
{ 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;
@@ -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;
} }
@@ -647,7 +654,7 @@ var LoginDialog = GObject.registerClass({
// 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 accommodate
// 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);
@@ -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();
} }
@@ -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();
for (let i = 0; i < children.length; i++) {
if (children[i] != Main.layoutManager.screenShieldGroup)
children[i].opacity = this.opacity;
}
},
onUpdateScope: this,
onComplete() {
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING) if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset(); this._authPrompt.reset();
this._unbindOpacity(); },
} onCompleteScope: this });
});
} }
_gotGreeterSessionProxy(proxy) { _gotGreeterSessionProxy(proxy) {
@@ -943,20 +945,27 @@ 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) {
@@ -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;
} }
}, },
@@ -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,7 +36,7 @@ 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,19 +45,19 @@ 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,16 +71,16 @@ 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,11 +101,11 @@ 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();
} }
@@ -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,10 +423,13 @@ 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,
this._userName,
this._cancellable,
(obj, result) => {
try { try {
obj.call_begin_verification_for_user_finish(result); obj.call_begin_verification_for_user_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 start verification for user', e); this._reportInitError('Failed to start verification for user', e);
@@ -437,10 +439,12 @@ var ShellUserVerifier = class {
this._hold.release(); this._hold.release();
}); });
} else { } else {
this._userVerifier.call_begin_verification(serviceName, this._cancellable, (obj, result) => { this._userVerifier.call_begin_verification(serviceName,
this._cancellable,
(obj, result) => {
try { try {
obj.call_begin_verification_finish(result); obj.call_begin_verification_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 start verification', e); this._reportInitError('Failed to start verification', e);

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 = {};
for (let key in obj) {
let val = obj[key];
let type;
switch (typeof val) {
case 'string':
type = 's';
break;
case 'number':
type = 'd';
break;
case 'boolean':
type = 'b';
break;
default:
continue;
}
res[key] = GLib.Variant.new(type, val);
} }
return res; let metadataContents, success, tag;
} try {
[success, metadataContents, tag] = metadataFile.load_contents(null);
function deserializeExtension(variant) { if (metadataContents instanceof Uint8Array)
let res = { metadata: {} }; metadataContents = imports.byteArray.toString(metadataContents);
for (let prop in variant) { } catch (e) {
let val = variant[prop].unpack(); throw new Error('Failed to load metadata.json: ' + e);
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() let meta;
res.uuid = res.metadata.uuid; try {
res.dir = Gio.File.new_for_path(res.path); meta = JSON.parse(metadataContents);
return res; } catch (e) {
throw new Error('Failed to parse metadata.json: ' + e);
}
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');
}
}
if (uuid != meta.uuid) {
throw new Error('uuid "' + meta.uuid + '" from metadata.json does not match directory name "' + uuid + '"');
}
let extension = {};
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,8 +18,8 @@ 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);
} }
@@ -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,
-1, null,
this._initPanelService.bind(this)); 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,19 +214,17 @@ 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( this._ibus.preload_engines_async(
ids, ids,
-1, -1,
this._cancellable, null,
null); null);
this._preloadEnginesId = 0; this._preloadEnginesId = 0;
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;

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,17 +254,15 @@ 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, this._cancellable, state, -1, null,
(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) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED)) log('Error processing key on IM: ' + e.message);
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';
@@ -127,8 +126,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');

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,7 +151,11 @@ 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 {
@@ -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,7 +43,7 @@ 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;
} }
} }
@@ -110,7 +109,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 +182,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 +199,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;
@@ -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

@@ -89,11 +89,14 @@ var ObjectManager = class {
g_interface_info: info, g_interface_info: info,
g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START }); g_flags: Gio.DBusProxyFlags.DO_NOT_AUTO_START });
proxy.init_async(GLib.PRIORITY_DEFAULT, this._cancellable, (initable, result) => { proxy.init_async(GLib.PRIORITY_DEFAULT,
this._cancellable,
(initable, result) => {
let error = null;
try { try {
initable.init_finish(result); initable.init_finish(result);
} catch (e) { } catch(e) {
logError(e, `could not initialize proxy for interface ${interfaceName}`); logError(e, 'could not initialize proxy for interface ' + interfaceName);
if (onFinished) 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,
this._actions.set(LOGOUT_ACTION_ID, { { // Translators: The name of the logout action in search
// Translators: The name of the logout action in search
name: C_("search-result", "Log Out"), name: C_("search-result", "Log Out"),
iconName: 'application-exit-symbolic', iconName: 'application-exit-symbolic',
// Translators: A list of keywords that match the logout action, separated by semicolons // Translators: A list of keywords that match the logout action, separated by semicolons
keywords: _("logout;log out;sign off").split(/[; ]/), keywords: _("logout;log out;sign off").split(/[; ]/),
available: false available: false });
}); this._actions.set(SUSPEND_ACTION_ID,
this._actions.set(SUSPEND_ACTION_ID, { { // Translators: The name of the suspend action in search
// Translators: The name of the suspend action in search
name: C_("search-result", "Suspend"), name: C_("search-result", "Suspend"),
iconName: 'media-playback-pause-symbolic', iconName: 'media-playback-pause-symbolic',
// Translators: A list of keywords that match the suspend action, separated by semicolons // Translators: A list of keywords that match the suspend action, separated by semicolons
keywords: _("suspend;sleep").split(/[; ]/), keywords: _("suspend;sleep").split(/[; ]/),
available: false available: false });
}); this._actions.set(SWITCH_USER_ACTION_ID,
this._actions.set(SWITCH_USER_ACTION_ID, { { // Translators: The name of the switch user action in search
// Translators: The name of the switch user action in search
name: C_("search-result", "Switch User"), name: C_("search-result", "Switch User"),
iconName: 'system-switch-user-symbolic', iconName: 'system-switch-user-symbolic',
// Translators: A list of keywords that match the switch user action, separated by semicolons // Translators: A list of keywords that match the switch user action, separated by semicolons
keywords: _("switch user").split(/[; ]/), keywords: _("switch user").split(/[; ]/),
available: false available: false });
}); this._actions.set(LOCK_ORIENTATION_ACTION_ID,
this._actions.set(LOCK_ORIENTATION_ACTION_ID, { { // Translators: The name of the lock orientation action in search
// Translators: The name of the lock orientation action in search
name: C_("search-result", "Lock Orientation"), name: C_("search-result", "Lock Orientation"),
iconName: '', iconName: '',
// Translators: A list of keywords that match the lock orientation action, separated by semicolons // Translators: A list of keywords that match the lock orientation action, separated by semicolons
keywords: _("lock orientation;screen;rotation").split(/[; ]/), keywords: _("lock orientation;screen;rotation").split(/[; ]/),
available: false 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);
},
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._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,8 +233,7 @@ 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;
@@ -269,11 +257,11 @@ 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.startsWith(t))))
results.push(key); results.push(key);

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,10 +103,11 @@ 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) {
@@ -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
@@ -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(
Gio.DBus.session,
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES,
nodeInfo.lookup_interface(WEATHER_INTEGRATION_IFACE),
WEATHER_BUS_NAME,
WEATHER_OBJECT_PATH,
WEATHER_INTEGRATION_IFACE,
null,
this._onWeatherProxyReady.bind(this));
this._settings = new Gio.Settings({
schema_id: 'org.gnome.shell.weather'
});
this._settings.connect('changed::automatic-location',
this._onAutomaticLocationChanged.bind(this)); this._onAutomaticLocationChanged.bind(this));
this._onAutomaticLocationChanged(); this._weatherAppMon.watchSetting('locations',
this._settings.connect('changed::locations',
this._onLocationsChanged.bind(this)); 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,4 +1,3 @@
/* exported AccessDialogDBus */
const { Clutter, Gio, GLib, GObject, Shell } = imports.gi; const { Clutter, Gio, GLib, GObject, Shell } = imports.gi;
const CheckBox = imports.ui.checkBox; const CheckBox = imports.ui.checkBox;
@@ -70,7 +69,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 +79,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,
@@ -133,10 +132,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 +146,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,10 +360,10 @@ 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;
@@ -392,13 +391,11 @@ 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,7 +469,7 @@ 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);
} }
}); });
@@ -497,7 +494,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 +645,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 +660,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 +715,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 +724,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 +745,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 +756,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 +793,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._enterItem(index);
this._mouseTimeOutId = 0; this._mouseTimeOutId = 0;
return GLib.SOURCE_REMOVE; 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 +848,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 +877,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 +915,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 +940,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) {
@@ -1014,9 +1014,9 @@ class WindowIcon extends St.BoxLayout {
} }
_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 +1043,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 +1080,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,10 +146,11 @@ 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);
}
}); });
} }
@@ -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,4 +1,3 @@
/* exported AudioDeviceSelectionDBus */
const { Clutter, Gio, GLib, GObject, 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;
@@ -35,7 +34,7 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
throw new Error('Too few devices for a selection'); throw new Error('Too few devices for a selection');
} }
_buildLayout() { _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,7 +54,7 @@ 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:
@@ -68,7 +67,7 @@ var AudioDeviceSelectionDialog = GObject.registerClass({
} }
_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:
@@ -86,7 +85,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 +110,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;
} }
@@ -161,12 +159,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
@@ -332,12 +334,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);
@@ -441,8 +443,7 @@ var Background = class Background {
} }
_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;
@@ -464,9 +465,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 +634,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 +652,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,11 +711,13 @@ 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.destroy();
}
}); });
} }
@@ -749,8 +752,7 @@ 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,

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;
@@ -31,7 +30,7 @@ function addBackgroundMenu(actor, layoutManager) {
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,7 +117,7 @@ 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);
@@ -181,7 +149,7 @@ var BarLevel = GObject.registerClass({
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);
@@ -207,27 +175,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:
@@ -105,18 +105,16 @@ var BoxPointer = GObject.registerClass({
} }
} }
this.ease({ Tweener.addTween(this, { opacity: 255,
opacity: 255,
translation_x: 0, translation_x: 0,
translation_y: 0, translation_y: 0,
duration: animationTime, transition: 'linear',
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => { onComplete: () => {
this._unmuteInput(); this._unmuteInput();
if (onComplete) if (onComplete)
onComplete(); onComplete();
} },
}); time: animationTime });
} }
close(animate, onComplete) { close(animate, onComplete) {
@@ -149,13 +147,12 @@ var BoxPointer = GObject.registerClass({
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,
duration: animationTime, transition: 'linear',
mode: Clutter.AnimationMode.LINEAR, time: animationTime,
onComplete: () => { onComplete: () => {
this.hide(); this.hide();
this.opacity = 0; this.opacity = 0;
@@ -172,8 +169,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;
@@ -267,7 +264,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 +345,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 +366,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 +387,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 +396,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 +408,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);
@@ -440,7 +437,7 @@ var BoxPointer = GObject.registerClass({
this._sourceActorDestroyId = this._sourceActor.connect('destroy', () => { this._sourceActorDestroyId = this._sourceActor.connect('destroy', () => {
this._sourceActor = null; this._sourceActor = null;
delete this._sourceActorDestroyId; delete this._sourceActorDestroyId;
}); })
} }
} }
@@ -472,7 +469,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 +513,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];
@@ -597,7 +594,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) {

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,9 +236,10 @@ 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;
if (appointments != null) {
for (let n = 0; n < appointments.length; n++) { for (let n = 0; n < appointments.length; n++) {
let a = appointments[n]; let a = appointments[n];
let date = new Date(a[4] * 1000); let date = new Date(a[4] * 1000);
@@ -250,6 +251,7 @@ var DBusEventSource = class DBusEventSource {
newEvents.push(event); 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,7 +402,7 @@ 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 });
@@ -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,8 +686,7 @@ 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 });
} }
@@ -690,15 +694,15 @@ var EventMessage = class EventMessage extends MessageList.Message {
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,
@@ -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)
}, },
@@ -148,10 +148,10 @@ 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)
}); });
} }
@@ -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,11 +175,13 @@ 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();
}
}); });
} }

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

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 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;
@@ -38,7 +38,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 +50,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,21 +109,23 @@ 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
(Gio.MountUnmountFlags.FORCE, null, null,
(drive, res) => { (drive, res) => {
try { try {
drive.stop_finish(res); drive.stop_finish(res);
} catch (e) { } catch (e) {
log(`Unable to stop the drive after drive-eject-button ${e.toString()}`); 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
(Gio.MountUnmountFlags.FORCE, null, null,
(drive, res) => { (drive, res) => {
try { try {
drive.eject_with_operation_finish(res); drive.eject_with_operation_finish(res);
} catch (e) { } catch (e) {
log(`Unable to eject the drive after drive-eject-button ${e.toString()}`); log("Unable to eject the drive after drive-eject-button " + e.toString());
} }
}); });
} }
@@ -211,7 +213,7 @@ var AutomountManager = class {
} }
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 +221,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 +250,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) {
@@ -121,7 +124,10 @@ var ContentTypeDiscoverer = class {
} }
} }
_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,9 +329,9 @@ 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);

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;
@@ -173,25 +172,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();
} }
@@ -232,8 +231,7 @@ 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,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, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, NM, Pango, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
@@ -81,9 +80,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);
@@ -112,17 +110,16 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
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 +161,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;
@@ -180,20 +177,19 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
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; return false;
} }
} else if (value.length == 5 || value.length == 13) { } else if (value.length == 5 || value.length == 13) {
for (let i = 0; i < value.length; i++) { for (let i = 0; i < value.length; i++) {
if (!((value[i] >= 'a' && value[i] <= 'z') || if (!((value[i] >= 'a' && value[i] <= 'z')
(value[i] >= 'A' && value[i] <= 'Z'))) || (value[i] >= 'A' && value[i] <= 'Z')))
return false; return false;
} }
} else { } 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;
@@ -201,7 +197,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
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 +209,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 +230,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 +273,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 +304,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 +327,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,8 +343,8 @@ 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;
} }
@@ -363,15 +359,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 +385,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 +407,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 +424,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 +444,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 +459,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 +473,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 +485,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 +540,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,11 +549,10 @@ 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
@@ -566,7 +561,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 +587,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,10 +607,9 @@ 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 = { };
@@ -625,9 +619,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 +632,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 +680,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 +695,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 +708,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; GObject, 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;
@@ -39,19 +39,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',
@@ -99,7 +99,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 +128,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;
@@ -181,9 +181,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 +251,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
@@ -343,7 +343,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 +351,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 +384,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,12 +149,12 @@ 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;
@@ -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();
} }
@@ -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.
} }
@@ -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);
@@ -600,7 +602,7 @@ var ChatSource = class extends MessageTray.Source {
} }
} }
_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,10 +95,10 @@ 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',
}); });
} }
@@ -135,11 +108,13 @@ 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();
}
}); });
} }
@@ -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,12 +136,11 @@ 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
}); });
} }
@@ -176,15 +153,38 @@ 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;
}
}); });
var ShowAppsIcon = GObject.registerClass( var ShowAppsIcon = GObject.registerClass(
@@ -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,11 +633,11 @@ 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',
}); });
} }
} }
@@ -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

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,12 +24,10 @@ 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,
x_expand: true,
can_focus: true, can_focus: true,
reactive: false, 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,40 +95,29 @@ 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',
'/org/gnome/clocks',
this._onProxyReady.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.bind(this));
this._clockAppMon.watchSetting('world-clocks',
this._clocksChanged.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)
continue;
let l = world.deserialize(clocks[i].location);
if (l && l.get_timezone() != null) if (l && l.get_timezone() != null)
this._locations.push({ location: l }); this._locations.push({ location: l });
} }
@@ -148,8 +128,7 @@ 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,
@@ -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 {
@@ -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;

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;
@@ -45,7 +44,7 @@ class Dialog extends St.Widget {
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 });
@@ -181,8 +180,10 @@ var MessageDialogContent = GObject.registerClass({
this._subtitle.clutter_text.set(textProps); this._subtitle.clutter_text.set(textProps);
this._body.clutter_text.set(textProps); this._body.clutter_text.set(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() {
this._dragActor.get_transition('scale-x').connect('new-frame', () => {
let currentScale = this._dragActor.scale_x / origScale; let currentScale = this._dragActor.scale_x / origScale;
this._dragOffsetX = currentScale * origDragOffsetX; this._dragOffsetX = currentScale * origDragOffsetX;
this._dragOffsetY = currentScale * origDragOffsetY; this._dragOffsetY = currentScale * origDragOffsetY;
this._dragActor.set_position( this._dragActor.set_position(this._dragX + this._dragOffsetX,
this._dragX + this._dragOffsetX,
this._dragY + this._dragOffsetY); this._dragY + this._dragOffsetY);
}); },
onUpdateScope: this });
} }
} }
} }
@@ -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.
@@ -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,10 +588,9 @@ 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;
global.display.set_cursor(Meta.Cursor.DEFAULT); global.display.set_cursor(Meta.Cursor.DEFAULT);
@@ -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,12 +657,12 @@ 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,
}); });
} }
@@ -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,6 +16,8 @@
* 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, GObject, Pango, Polkit, Shell, St } = imports.gi;
@@ -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 = {
@@ -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,7 +223,7 @@ 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 = GObject.registerClass(
@@ -230,13 +235,14 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
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',
@@ -331,36 +337,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 +391,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();
@@ -449,16 +434,14 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
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);
@@ -517,12 +500,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 +509,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 +518,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 +530,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 +552,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 +585,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 +637,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 +680,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 +702,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 +712,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 +745,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,27 +93,6 @@ 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);
}; };
@@ -245,21 +106,15 @@ function init() {
} }
}); });
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 +128,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 +138,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, GObject, 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) };
@@ -186,32 +185,36 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
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;

View File

@@ -1,46 +1,47 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported init connect disconnect */
const { Gio, St } = imports.gi; const { Gio, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const FileUtils = imports.misc.fileUtils;
const Main = imports.ui.main; const Main = imports.ui.main;
const { ExtensionState, ExtensionType } = ExtensionUtils; var ExtensionState = {
ENABLED: 1,
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
};
// Arrays of uuids
var enabledExtensions;
// Contains the order that extensions were enabled in.
var extensionOrder = [];
// We don't really have a class to add signals on. So, create
// a simple dummy object, add the signal methods, and export those
// publically.
var _signals = {};
Signals.addSignalMethods(_signals);
var connect = _signals.connect.bind(_signals);
var disconnect = _signals.disconnect.bind(_signals);
const ENABLED_EXTENSIONS_KEY = 'enabled-extensions'; const ENABLED_EXTENSIONS_KEY = 'enabled-extensions';
const DISABLED_EXTENSIONS_KEY = 'disabled-extensions';
const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions'; const DISABLE_USER_EXTENSIONS_KEY = 'disable-user-extensions';
const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation'; const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validation';
var ExtensionManager = class { var initted = false;
constructor() { var enabled;
this._initialized = false;
this._enabled = false;
this._extensions = new Map(); function disableExtension(uuid) {
this._enabledExtensions = []; let extension = ExtensionUtils.extensions[uuid];
this._extensionOrder = [];
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
}
init() {
this._sessionUpdated();
}
lookup(uuid) {
return this._extensions.get(uuid);
}
getUuids() {
return [...this._extensions.keys()];
}
_callExtensionDisable(uuid) {
let extension = this.lookup(uuid);
if (!extension) if (!extension)
return; return;
@@ -55,16 +56,16 @@ var ExtensionManager = class {
// user disables C // user disables C
// this should: disable E, disable D, disable C, enable D, enable E // this should: disable E, disable D, disable C, enable D, enable E
let orderIdx = this._extensionOrder.indexOf(uuid); let orderIdx = extensionOrder.indexOf(uuid);
let order = this._extensionOrder.slice(orderIdx + 1); let order = extensionOrder.slice(orderIdx + 1);
let orderReversed = order.slice().reverse(); let orderReversed = order.slice().reverse();
for (let i = 0; i < orderReversed.length; i++) { for (let i = 0; i < orderReversed.length; i++) {
let uuid = orderReversed[i]; let uuid = orderReversed[i];
try { try {
this.lookup(uuid).stateObj.disable(); ExtensionUtils.extensions[uuid].stateObj.disable();
} catch (e) { } catch(e) {
this.logExtensionError(uuid, e); logExtensionError(uuid, e);
} }
} }
@@ -76,42 +77,41 @@ var ExtensionManager = class {
try { try {
extension.stateObj.disable(); extension.stateObj.disable();
} catch (e) { } catch(e) {
this.logExtensionError(uuid, e); logExtensionError(uuid, e);
} }
for (let i = 0; i < order.length; i++) { for (let i = 0; i < order.length; i++) {
let uuid = order[i]; let uuid = order[i];
try { try {
this.lookup(uuid).stateObj.enable(); ExtensionUtils.extensions[uuid].stateObj.enable();
} catch (e) { } catch(e) {
this.logExtensionError(uuid, e); logExtensionError(uuid, e);
} }
} }
this._extensionOrder.splice(orderIdx, 1); extensionOrder.splice(orderIdx, 1);
if (extension.state != ExtensionState.ERROR) { if ( extension.state != ExtensionState.ERROR ) {
extension.state = ExtensionState.DISABLED; extension.state = ExtensionState.DISABLED;
this.emit('extension-state-changed', extension); _signals.emit('extension-state-changed', extension);
}
} }
}
_callExtensionEnable(uuid) { function enableExtension(uuid) {
if (!Main.sessionMode.allowExtensions) let extension = ExtensionUtils.extensions[uuid];
return;
let extension = this.lookup(uuid);
if (!extension) if (!extension)
return; return;
if (extension.state == ExtensionState.INITIALIZED) if (extension.state == ExtensionState.INITIALIZED)
this._callExtensionInit(uuid); initExtension(uuid);
if (extension.state != ExtensionState.DISABLED) if (extension.state != ExtensionState.DISABLED)
return; return;
let stylesheetNames = [`${global.session_mode}.css`, 'stylesheet.css']; extensionOrder.push(uuid);
let stylesheetNames = [global.session_mode + '.css', 'stylesheet.css'];
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
for (let i = 0; i < stylesheetNames.length; i++) { for (let i = 0; i < stylesheetNames.length; i++) {
try { try {
@@ -122,7 +122,7 @@ var ExtensionManager = class {
} catch (e) { } catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
continue; // not an error continue; // not an error
this.logExtensionError(uuid, e); log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
return; return;
} }
} }
@@ -130,123 +130,37 @@ var ExtensionManager = class {
try { try {
extension.stateObj.enable(); extension.stateObj.enable();
extension.state = ExtensionState.ENABLED; extension.state = ExtensionState.ENABLED;
this._extensionOrder.push(uuid); _signals.emit('extension-state-changed', extension);
this.emit('extension-state-changed', extension); return;
} catch (e) { } catch(e) {
if (extension.stylesheet) { if (extension.stylesheet) {
theme.unload_stylesheet(extension.stylesheet); theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet; delete extension.stylesheet;
} }
this.logExtensionError(uuid, e); logExtensionError(uuid, e);
} return;
} }
}
enableExtension(uuid) { function logExtensionError(uuid, error) {
if (!this._extensions.has(uuid)) let extension = ExtensionUtils.extensions[uuid];
return false;
let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
let disabledExtensions = global.settings.get_strv(DISABLED_EXTENSIONS_KEY);
if (disabledExtensions.includes(uuid)) {
disabledExtensions = disabledExtensions.filter(item => item !== uuid);
global.settings.set_strv(DISABLED_EXTENSIONS_KEY, disabledExtensions);
}
if (!enabledExtensions.includes(uuid)) {
enabledExtensions.push(uuid);
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
}
return true;
}
disableExtension(uuid) {
if (!this._extensions.has(uuid))
return false;
let enabledExtensions = global.settings.get_strv(ENABLED_EXTENSIONS_KEY);
let disabledExtensions = global.settings.get_strv(DISABLED_EXTENSIONS_KEY);
if (enabledExtensions.includes(uuid)) {
enabledExtensions = enabledExtensions.filter(item => item !== uuid);
global.settings.set_strv(ENABLED_EXTENSIONS_KEY, enabledExtensions);
}
if (!disabledExtensions.includes(uuid)) {
disabledExtensions.push(uuid);
global.settings.set_strv(DISABLED_EXTENSIONS_KEY, disabledExtensions);
}
return true;
}
logExtensionError(uuid, error) {
let extension = this.lookup(uuid);
if (!extension) if (!extension)
return; return;
let message = `${error}`; let message = '' + error;
extension.error = message;
extension.state = ExtensionState.ERROR; extension.state = ExtensionState.ERROR;
if (!extension.errors) if (!extension.errors)
extension.errors = []; extension.errors = [];
extension.errors.push(message); extension.errors.push(message);
logError(error, `Extension ${uuid}`); log('Extension "%s" had error: %s'.format(uuid, message));
this.emit('extension-state-changed', extension); _signals.emit('extension-state-changed', { uuid: uuid,
} error: message,
state: extension.state });
}
createExtensionObject(uuid, dir, type) { function loadExtension(extension) {
let metadataFile = dir.get_child('metadata.json');
if (!metadataFile.query_exists(null)) {
throw new Error('Missing metadata.json');
}
let metadataContents, success_;
try {
[success_, metadataContents] = metadataFile.load_contents(null);
if (metadataContents instanceof Uint8Array)
metadataContents = imports.byteArray.toString(metadataContents);
} catch (e) {
throw new Error(`Failed to load metadata.json: ${e}`);
}
let meta;
try {
meta = JSON.parse(metadataContents);
} catch (e) {
throw new Error(`Failed to parse metadata.json: ${e}`);
}
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`);
}
}
if (uuid != meta.uuid) {
throw new Error(`uuid "${meta.uuid}" from metadata.json does not match directory name "${uuid}"`);
}
let extension = {
metadata: meta,
uuid: meta.uuid,
type,
dir,
path: dir.get_path(),
error: '',
hasPrefs: dir.get_child('prefs.js').query_exists(null),
canChange: false
};
this._extensions.set(uuid, extension);
return extension;
}
loadExtension(extension) {
// Default to error, we set success as the last step // Default to error, we set success as the last step
extension.state = ExtensionState.ERROR; extension.state = ExtensionState.ERROR;
@@ -255,66 +169,63 @@ var ExtensionManager = class {
if (checkVersion && ExtensionUtils.isOutOfDate(extension)) { if (checkVersion && ExtensionUtils.isOutOfDate(extension)) {
extension.state = ExtensionState.OUT_OF_DATE; extension.state = ExtensionState.OUT_OF_DATE;
} else { } else {
let enabled = this._enabledExtensions.includes(extension.uuid); let enabled = enabledExtensions.indexOf(extension.uuid) != -1;
if (enabled) { if (enabled) {
if (!this._callExtensionInit(extension.uuid)) if (!initExtension(extension.uuid))
return; return;
if (extension.state == ExtensionState.DISABLED) if (extension.state == ExtensionState.DISABLED)
this._callExtensionEnable(extension.uuid); enableExtension(extension.uuid);
} else { } else {
extension.state = ExtensionState.INITIALIZED; extension.state = ExtensionState.INITIALIZED;
} }
} }
this._updateCanChange(extension); _signals.emit('extension-state-changed', extension);
this.emit('extension-state-changed', extension); }
}
unloadExtension(extension) { function unloadExtension(extension) {
// Try to disable it -- if it's ERROR'd, we can't guarantee that, // Try to disable it -- if it's ERROR'd, we can't guarantee that,
// but it will be removed on next reboot, and hopefully nothing // but it will be removed on next reboot, and hopefully nothing
// broke too much. // broke too much.
this._callExtensionDisable(extension.uuid); disableExtension(extension.uuid);
extension.state = ExtensionState.UNINSTALLED; extension.state = ExtensionState.UNINSTALLED;
this.emit('extension-state-changed', extension); _signals.emit('extension-state-changed', extension);
this._extensions.delete(extension.uuid); delete ExtensionUtils.extensions[extension.uuid];
return true; return true;
} }
reloadExtension(oldExtension) { function reloadExtension(oldExtension) {
// Grab the things we'll need to pass to createExtensionObject // Grab the things we'll need to pass to createExtensionObject
// to reload it. // to reload it.
let { uuid, dir, type } = oldExtension; let { uuid: uuid, dir: dir, type: type } = oldExtension;
// Then unload the old extension. // Then unload the old extension.
this.unloadExtension(oldExtension); unloadExtension(oldExtension);
// Now, recreate the extension and load it. // Now, recreate the extension and load it.
let newExtension; let newExtension;
try { try {
newExtension = this.createExtensionObject(uuid, dir, type); newExtension = ExtensionUtils.createExtensionObject(uuid, dir, type);
} catch (e) { } catch(e) {
this.logExtensionError(uuid, e); logExtensionError(uuid, e);
return; return;
} }
this.loadExtension(newExtension); loadExtension(newExtension);
} }
_callExtensionInit(uuid) {
if (!Main.sessionMode.allowExtensions)
return false;
let extension = this.lookup(uuid);
if (!extension)
throw new Error("Extension was not properly created. Call createExtensionObject first");
function initExtension(uuid) {
let extension = ExtensionUtils.extensions[uuid];
let dir = extension.dir; let dir = extension.dir;
if (!extension)
throw new Error("Extension was not properly created. Call loadExtension first");
let extensionJs = dir.get_child('extension.js'); let extensionJs = dir.get_child('extension.js');
if (!extensionJs.query_exists(null)) { if (!extensionJs.query_exists(null)) {
this.logExtensionError(uuid, new Error('Missing extension.js')); logExtensionError(uuid, new Error('Missing extension.js'));
return false; return false;
} }
@@ -324,16 +235,16 @@ var ExtensionManager = class {
ExtensionUtils.installImporter(extension); ExtensionUtils.installImporter(extension);
try { try {
extensionModule = extension.imports.extension; extensionModule = extension.imports.extension;
} catch (e) { } catch(e) {
this.logExtensionError(uuid, e); logExtensionError(uuid, e);
return false; return false;
} }
if (extensionModule.init) { if (extensionModule.init) {
try { try {
extensionState = extensionModule.init(extension); extensionState = extensionModule.init(extension);
} catch (e) { } catch(e) {
this.logExtensionError(uuid, e); logExtensionError(uuid, e);
return false; return false;
} }
} }
@@ -343,177 +254,121 @@ var ExtensionManager = class {
extension.stateObj = extensionState; extension.stateObj = extensionState;
extension.state = ExtensionState.DISABLED; extension.state = ExtensionState.DISABLED;
this.emit('extension-loaded', uuid); _signals.emit('extension-loaded', uuid);
return true; return true;
} }
_getModeExtensions() { function getEnabledExtensions() {
let extensions;
if (Array.isArray(Main.sessionMode.enabledExtensions)) if (Array.isArray(Main.sessionMode.enabledExtensions))
return Main.sessionMode.enabledExtensions; extensions = Main.sessionMode.enabledExtensions;
return []; else
} extensions = [];
_updateCanChange(extension) { if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
let hasError = return extensions;
extension.state == ExtensionState.ERROR ||
extension.state == ExtensionState.OUT_OF_DATE;
let isMode = this._getModeExtensions().includes(extension.uuid); return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY); }
let changeKey = isMode function onEnabledExtensionsChanged() {
? DISABLE_USER_EXTENSIONS_KEY let newEnabledExtensions = getEnabledExtensions();
: ENABLED_EXTENSIONS_KEY;
extension.canChange = if (!enabled)
!hasError && return;
global.settings.is_writable(changeKey) &&
(isMode || !modeOnly);
}
_getEnabledExtensions() {
let extensions = this._getModeExtensions();
if (!global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
extensions = extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
// filter out 'disabled-extensions' which takes precedence
let disabledExtensions = global.settings.get_strv(DISABLED_EXTENSIONS_KEY);
return extensions.filter(item => !disabledExtensions.includes(item));
}
_onUserExtensionsEnabledChanged() {
this._onEnabledExtensionsChanged();
this._onSettingsWritableChanged();
}
_onEnabledExtensionsChanged() {
let newEnabledExtensions = this._getEnabledExtensions();
// Find and enable all the newly enabled extensions: UUIDs found in the // Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one. // new setting, but not in the old one.
newEnabledExtensions.filter( newEnabledExtensions.filter(
uuid => !this._enabledExtensions.includes(uuid) uuid => !enabledExtensions.includes(uuid)
).forEach(uuid => { ).forEach(uuid => {
this._callExtensionEnable(uuid); enableExtension(uuid);
}); });
// Find and disable all the newly disabled extensions: UUIDs found in the // Find and disable all the newly disabled extensions: UUIDs found in the
// old setting, but not in the new one. // old setting, but not in the new one.
this._extensionOrder.filter( enabledExtensions.filter(
uuid => !newEnabledExtensions.includes(uuid) item => !newEnabledExtensions.includes(item)
).reverse().forEach(uuid => { ).forEach(uuid => {
this._callExtensionDisable(uuid); disableExtension(uuid);
}); });
this._enabledExtensions = newEnabledExtensions; enabledExtensions = newEnabledExtensions;
} }
_onSettingsWritableChanged() { function _onVersionValidationChanged() {
for (let extension of this._extensions.values()) { // we want to reload all extensions, but only enable
this._updateCanChange(extension); // extensions when allowed by the sessionMode, so
this.emit('extension-state-changed', extension); // temporarily disable them all
} enabledExtensions = [];
} for (let uuid in ExtensionUtils.extensions)
reloadExtension(ExtensionUtils.extensions[uuid]);
enabledExtensions = getEnabledExtensions();
_onVersionValidationChanged() { if (Main.sessionMode.allowExtensions) {
// Disabling extensions modifies the order array, so use a copy enabledExtensions.forEach(uuid => {
let extensionOrder = this._extensionOrder.slice(); enableExtension(uuid);
// Disable enabled extensions in the reverse order first to avoid
// the "rebasing" done in _callExtensionDisable...
extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
// ...and then reload and enable extensions in the correct order again.
[...this._extensions.values()].sort((a, b) => {
return extensionOrder.indexOf(a.uuid) - extensionOrder.indexOf(b.uuid);
}).forEach(extension => this.reloadExtension(extension));
}
_loadExtensions() {
global.settings.connect(`changed::${ENABLED_EXTENSIONS_KEY}`,
this._onEnabledExtensionsChanged.bind(this));
global.settings.connect(`changed::${DISABLED_EXTENSIONS_KEY}`,
this._onEnabledExtensionsChanged.bind(this));
global.settings.connect(`changed::${DISABLE_USER_EXTENSIONS_KEY}`,
this._onUserExtensionsEnabledChanged.bind(this));
global.settings.connect(`changed::${EXTENSION_DISABLE_VERSION_CHECK_KEY}`,
this._onVersionValidationChanged.bind(this));
global.settings.connect(`writable-changed::${ENABLED_EXTENSIONS_KEY}`,
this._onSettingsWritableChanged.bind(this));
global.settings.connect(`writable-changed::${DISABLED_EXTENSIONS_KEY}`,
this._onSettingsWritableChanged.bind(this));
this._enabledExtensions = this._getEnabledExtensions();
let perUserDir = Gio.File.new_for_path(global.userdatadir);
FileUtils.collectFromDatadirs('extensions', true, (dir, info) => {
let fileType = info.get_file_type();
if (fileType != Gio.FileType.DIRECTORY)
return;
let uuid = info.get_name();
let existing = this.lookup(uuid);
if (existing) {
log(`Extension ${uuid} already installed in ${existing.path}. ${dir.get_path()} will not be loaded`);
return;
}
let extension;
let type = dir.has_prefix(perUserDir)
? ExtensionType.PER_USER
: ExtensionType.SYSTEM;
try {
extension = this.createExtensionObject(uuid, dir, type);
} catch (e) {
logError(e, `Could not load extension ${uuid}`);
return;
}
this.loadExtension(extension);
}); });
} }
}
_enableAllExtensions() { function _loadExtensions() {
if (this._enabled) global.settings.connect('changed::' + ENABLED_EXTENSIONS_KEY, onEnabledExtensionsChanged);
global.settings.connect('changed::' + DISABLE_USER_EXTENSIONS_KEY, onEnabledExtensionsChanged);
global.settings.connect('changed::' + EXTENSION_DISABLE_VERSION_CHECK_KEY, _onVersionValidationChanged);
enabledExtensions = getEnabledExtensions();
let finder = new ExtensionUtils.ExtensionFinder();
finder.connect('extension-found', (finder, extension) => {
loadExtension(extension);
});
finder.scanExtensions();
}
function enableAllExtensions() {
if (enabled)
return; return;
if (!this._initialized) { if (!initted) {
this._loadExtensions(); _loadExtensions();
this._initialized = true; initted = true;
} else { } else {
this._enabledExtensions.forEach(uuid => { enabledExtensions.forEach(uuid => {
this._callExtensionEnable(uuid); enableExtension(uuid);
}); });
} }
this._enabled = true; enabled = true;
} }
_disableAllExtensions() { function disableAllExtensions() {
if (!this._enabled) if (!enabled)
return; return;
if (this._initialized) { if (initted) {
this._extensionOrder.slice().reverse().forEach(uuid => { extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid); disableExtension(uuid);
}); });
} }
this._enabled = false; enabled = false;
} }
_sessionUpdated() { function _sessionUpdated() {
// For now sessionMode.allowExtensions controls extensions from both the // For now sessionMode.allowExtensions controls extensions from both the
// 'enabled-extensions' preference and the sessionMode.enabledExtensions // 'enabled-extensions' preference and the sessionMode.enabledExtensions
// property; it might make sense to make enabledExtensions independent // property; it might make sense to make enabledExtensions independent
// from allowExtensions in the future // from allowExtensions in the future
if (Main.sessionMode.allowExtensions) { if (Main.sessionMode.allowExtensions) {
// Take care of added or removed sessionMode extensions if (initted)
this._onEnabledExtensionsChanged(); enabledExtensions = getEnabledExtensions();
this._enableAllExtensions(); enableAllExtensions();
} else { } else {
this._disableAllExtensions(); disableAllExtensions();
} }
} }
};
Signals.addSignalMethods(ExtensionManager.prototype); function init() {
Main.sessionMode.connect('updated', _sessionUpdated);
_sessionUpdated();
}

View File

@@ -56,8 +56,8 @@ var FocusCaretTracker = class FocusCaretTracker {
if (!this._initAtspi() || this._focusListenerRegistered) if (!this._initAtspi() || this._focusListenerRegistered)
return; return;
this._atspiListener.register(`${STATECHANGED}:focused`); this._atspiListener.register(STATECHANGED + ':focused');
this._atspiListener.register(`${STATECHANGED}:selected`); this._atspiListener.register(STATECHANGED + ':selected');
this._focusListenerRegistered = true; this._focusListenerRegistered = true;
} }
@@ -73,8 +73,8 @@ var FocusCaretTracker = class FocusCaretTracker {
if (!this._focusListenerRegistered) if (!this._focusListenerRegistered)
return; return;
this._atspiListener.deregister(`${STATECHANGED}:focused`); this._atspiListener.deregister(STATECHANGED + ':focused');
this._atspiListener.deregister(`${STATECHANGED}:selected`); this._atspiListener.deregister(STATECHANGED + ':selected');
this._focusListenerRegistered = false; this._focusListenerRegistered = false;
} }

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 GrabHelper */
const { Clutter, St } = imports.gi; const { Clutter, St } = imports.gi;
@@ -88,7 +87,7 @@ var GrabHelper = class GrabHelper {
_isWithinGrabbedActor(actor) { _isWithinGrabbedActor(actor) {
let currentActor = this.currentGrab.actor; let currentActor = this.currentGrab.actor;
while (actor) { while (actor) {
if (this._actors.includes(actor)) if (this._actors.indexOf(actor) != -1)
return true; return true;
if (actor == currentActor) if (actor == currentActor)
return true; return true;

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 CandidatePopup */
const { Clutter, IBus, St } = imports.gi; const { Clutter, IBus, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
@@ -9,8 +8,8 @@ const Main = imports.ui.main;
var MAX_CANDIDATES_PER_PAGE = 16; var MAX_CANDIDATES_PER_PAGE = 16;
var DEFAULT_INDEX_LABELS = ['1', '2', '3', '4', '5', '6', '7', '8', var DEFAULT_INDEX_LABELS = [ '1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', 'a', 'b', 'c', 'd', 'e', 'f']; '9', '0', 'a', 'b', 'c', 'd', 'e', 'f' ];
var CandidateArea = class CandidateArea { var CandidateArea = class CandidateArea {
constructor() { constructor() {
@@ -38,14 +37,14 @@ var CandidateArea = class CandidateArea {
this.actor.connect('scroll-event', (actor, event) => { this.actor.connect('scroll-event', (actor, event) => {
let direction = event.get_scroll_direction(); let direction = event.get_scroll_direction();
switch (direction) { switch(direction) {
case Clutter.ScrollDirection.UP: case Clutter.ScrollDirection.UP:
this.emit('cursor-up'); this.emit('cursor-up');
break; break;
case Clutter.ScrollDirection.DOWN: case Clutter.ScrollDirection.DOWN:
this.emit('cursor-down'); this.emit('cursor-down');
break; break;
} };
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
}); });
@@ -126,9 +125,6 @@ Signals.addSignalMethods(CandidateArea.prototype);
var CandidatePopup = class CandidatePopup { var CandidatePopup = class CandidatePopup {
constructor() { constructor() {
this._dummyCursor = new St.Widget({ opacity: 0 });
Main.layoutManager.uiGroup.add_actor(this._dummyCursor);
this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP); this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
this._boxPointer.visible = false; this._boxPointer.visible = false;
this._boxPointer.style_class = 'candidate-popup-boxpointer'; this._boxPointer.style_class = 'candidate-popup-boxpointer';
@@ -185,7 +181,7 @@ var CandidatePopup = class CandidatePopup {
let window = global.display.focus_window.get_compositor_private(); let window = global.display.focus_window.get_compositor_private();
this._setDummyCursorGeometry(window.x + x, window.y + y, w, h); this._setDummyCursorGeometry(window.x + x, window.y + y, w, h);
}); });
} catch (e) { } catch(e) {
// Only recent IBus versions have support for this signal // Only recent IBus versions have support for this signal
// which is used for wayland clients. In order to work // which is used for wayland clients. In order to work
// with older IBus versions we can silently ignore the // with older IBus versions we can silently ignore the
@@ -202,29 +198,29 @@ var CandidatePopup = class CandidatePopup {
this._setTextAttributes(this._preeditText.clutter_text, this._setTextAttributes(this._preeditText.clutter_text,
attrs); attrs);
}); });
panelService.connect('show-preedit-text', () => { panelService.connect('show-preedit-text', ps => {
this._preeditText.show(); this._preeditText.show();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('hide-preedit-text', () => { panelService.connect('hide-preedit-text', ps => {
this._preeditText.hide(); this._preeditText.hide();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('update-auxiliary-text', (_ps, text, visible) => { panelService.connect('update-auxiliary-text', (ps, text, visible) => {
this._auxText.visible = visible; this._auxText.visible = visible;
this._updateVisibility(); this._updateVisibility();
this._auxText.text = text.get_text(); this._auxText.text = text.get_text();
}); });
panelService.connect('show-auxiliary-text', () => { panelService.connect('show-auxiliary-text', ps => {
this._auxText.show(); this._auxText.show();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('hide-auxiliary-text', () => { panelService.connect('hide-auxiliary-text', ps => {
this._auxText.hide(); this._auxText.hide();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('update-lookup-table', (_ps, lookupTable, visible) => { panelService.connect('update-lookup-table', (ps, lookupTable, visible) => {
this._candidateArea.actor.visible = visible; this._candidateArea.actor.visible = visible;
this._updateVisibility(); this._updateVisibility();
@@ -260,26 +256,24 @@ var CandidatePopup = class CandidatePopup {
this._candidateArea.setOrientation(lookupTable.get_orientation()); this._candidateArea.setOrientation(lookupTable.get_orientation());
this._candidateArea.updateButtons(lookupTable.is_round(), page, nPages); this._candidateArea.updateButtons(lookupTable.is_round(), page, nPages);
}); });
panelService.connect('show-lookup-table', () => { panelService.connect('show-lookup-table', ps => {
this._candidateArea.actor.show(); this._candidateArea.actor.show();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('hide-lookup-table', () => { panelService.connect('hide-lookup-table', ps => {
this._candidateArea.actor.hide(); this._candidateArea.actor.hide();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('focus-out', () => { panelService.connect('focus-out', ps => {
this._boxPointer.close(BoxPointer.PopupAnimation.NONE); this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
Main.keyboard.resetSuggestions(); Main.keyboard.resetSuggestions();
}); });
} }
_setDummyCursorGeometry(x, y, w, h) { _setDummyCursorGeometry(x, y, w, h) {
this._dummyCursor.set_position(Math.round(x), Math.round(y)); Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
this._dummyCursor.set_size(Math.round(w), Math.round(h));
if (this._boxPointer.visible) if (this._boxPointer.visible)
this._boxPointer.setPosition(this._dummyCursor, 0); this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
} }
_updateVisibility() { _updateVisibility() {
@@ -289,7 +283,7 @@ var CandidatePopup = class CandidatePopup {
this._candidateArea.actor.visible)); this._candidateArea.actor.visible));
if (isVisible) { if (isVisible) {
this._boxPointer.setPosition(this._dummyCursor, 0); this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
this._boxPointer.open(BoxPointer.PopupAnimation.NONE); this._boxPointer.open(BoxPointer.PopupAnimation.NONE);
this._boxPointer.raise_top(); this._boxPointer.raise_top();
} else { } else {

View File

@@ -1,22 +1,22 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported BaseIcon, IconGrid, PaginatedIconGrid */
const { Clutter, GLib, GObject, Meta, St } = imports.gi; const { Clutter, GObject, Meta, St } = imports.gi;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main; const Main = imports.ui.main;
var ICON_SIZE = 96; var ICON_SIZE = 96;
var MIN_ICON_SIZE = 16; var MIN_ICON_SIZE = 16;
var EXTRA_SPACE_ANIMATION_TIME = 250; var EXTRA_SPACE_ANIMATION_TIME = 0.25;
var ANIMATION_TIME_IN = 350; var ANIMATION_TIME_IN = 0.350;
var ANIMATION_TIME_OUT = 1 / 2 * ANIMATION_TIME_IN; var ANIMATION_TIME_OUT = 1/2 * ANIMATION_TIME_IN;
var ANIMATION_MAX_DELAY_FOR_ITEM = 2 / 3 * ANIMATION_TIME_IN; var ANIMATION_MAX_DELAY_FOR_ITEM = 2/3 * ANIMATION_TIME_IN;
var ANIMATION_BASE_DELAY_FOR_ITEM = 1 / 4 * ANIMATION_MAX_DELAY_FOR_ITEM; var ANIMATION_BASE_DELAY_FOR_ITEM = 1/4 * ANIMATION_MAX_DELAY_FOR_ITEM;
var ANIMATION_MAX_DELAY_OUT_FOR_ITEM = 2 / 3 * ANIMATION_TIME_OUT; var ANIMATION_MAX_DELAY_OUT_FOR_ITEM = 2/3 * ANIMATION_TIME_OUT;
var ANIMATION_FADE_IN_TIME_FOR_ITEM = 1 / 4 * ANIMATION_TIME_IN; var ANIMATION_FADE_IN_TIME_FOR_ITEM = 1/4 * ANIMATION_TIME_IN;
var ANIMATION_BOUNCE_ICON_SCALE = 1.1; var ANIMATION_BOUNCE_ICON_SCALE = 1.1;
@@ -26,7 +26,7 @@ var AnimationDirection = {
}; };
var APPICON_ANIMATION_OUT_SCALE = 3; var APPICON_ANIMATION_OUT_SCALE = 3;
var APPICON_ANIMATION_OUT_TIME = 250; var APPICON_ANIMATION_OUT_TIME = 0.25;
var BaseIcon = GObject.registerClass( var BaseIcon = GObject.registerClass(
class BaseIcon extends St.Bin { class BaseIcon extends St.Bin {
@@ -56,10 +56,6 @@ class BaseIcon extends St.Bin {
if (params.showLabel) { if (params.showLabel) {
this.label = new St.Label({ text: label }); this.label = new St.Label({ text: label });
this.label.clutter_text.set({
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER
});
this._box.add_actor(this.label); this._box.add_actor(this.label);
} else { } else {
this.label = null; this.label = null;
@@ -75,14 +71,14 @@ class BaseIcon extends St.Bin {
this._iconThemeChangedId = cache.connect('icon-theme-changed', this._onIconThemeChanged.bind(this)); this._iconThemeChangedId = cache.connect('icon-theme-changed', this._onIconThemeChanged.bind(this));
} }
vfunc_get_preferred_width(_forHeight) { vfunc_get_preferred_width(forHeight) {
// Return the actual height to keep the squared aspect // Return the actual height to keep the squared aspect
return this.get_preferred_height(-1); return this.get_preferred_height(-1);
} }
// This can be overridden by a subclass, or by the createIcon // This can be overridden by a subclass, or by the createIcon
// parameter to _init() // parameter to _init()
createIcon(_size) { createIcon(size) {
throw new GObject.NotImplementedError(`createIcon in ${this.constructor.name}`); throw new GObject.NotImplementedError(`createIcon in ${this.constructor.name}`);
} }
@@ -141,30 +137,17 @@ class BaseIcon extends St.Bin {
// animating. // animating.
zoomOutActor(this.child); zoomOutActor(this.child);
} }
animateZoomOutAtPos(x, y) {
zoomOutActorAtPos(this.child, x, y);
}
update() {
this._createIconTexture(this.iconSize);
}
}); });
function clamp(value, min, max) { function clamp(value, min, max) {
return Math.max(Math.min(value, max), min); return Math.max(Math.min(value, max), min);
} };
function zoomOutActor(actor) { function zoomOutActor(actor) {
let [x, y] = actor.get_transformed_position();
zoomOutActorAtPos(actor, x, y);
}
function zoomOutActorAtPos(actor, x, y) {
let actorClone = new Clutter.Clone({ source: actor, let actorClone = new Clutter.Clone({ source: actor,
reactive: false }); reactive: false });
let [width, height] = actor.get_transformed_size(); let [width, height] = actor.get_transformed_size();
let [x, y] = actor.get_transformed_position();
actorClone.set_size(width, height); actorClone.set_size(width, height);
actorClone.set_position(x, y); actorClone.set_position(x, y);
actorClone.opacity = 255; actorClone.opacity = 255;
@@ -181,21 +164,23 @@ function zoomOutActorAtPos(actor, x, y) {
let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth); let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth);
let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight); let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight);
actorClone.ease({ Tweener.addTween(actorClone,
{ time: APPICON_ANIMATION_OUT_TIME,
scale_x: APPICON_ANIMATION_OUT_SCALE, scale_x: APPICON_ANIMATION_OUT_SCALE,
scale_y: APPICON_ANIMATION_OUT_SCALE, scale_y: APPICON_ANIMATION_OUT_SCALE,
translation_x: containedX - scaledX, translation_x: containedX - scaledX,
translation_y: containedY - scaledY, translation_y: containedY - scaledY,
opacity: 0, opacity: 0,
duration: APPICON_ANIMATION_OUT_TIME, transition: 'easeOutQuad',
mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete() {
onComplete: () => actorClone.destroy() actorClone.destroy();
}
}); });
} }
var IconGrid = GObject.registerClass({ var IconGrid = GObject.registerClass({
Signals: { 'animation-done': {}, Signals: {'animation-done': {},
'child-focused': { param_types: [Clutter.Actor.$gtype] } }, 'child-focused': { param_types: [Clutter.Actor.$gtype]} },
}, class IconGrid extends St.Widget { }, class IconGrid extends St.Widget {
_init(params) { _init(params) {
super._init({ style_class: 'icon-grid', super._init({ style_class: 'icon-grid',
@@ -221,8 +206,6 @@ var IconGrid = GObject.registerClass({
this.rightPadding = 0; this.rightPadding = 0;
this.leftPadding = 0; this.leftPadding = 0;
this._updateIconSizesLaterId = 0;
this._items = []; this._items = [];
this._clonesAnimating = []; this._clonesAnimating = [];
// Pulled from CSS, but hardcode some defaults here // Pulled from CSS, but hardcode some defaults here
@@ -235,19 +218,11 @@ var IconGrid = GObject.registerClass({
// swarming into the void ... // swarming into the void ...
this.connect('notify::mapped', () => { this.connect('notify::mapped', () => {
if (!this.mapped) if (!this.mapped)
this._resetAnimationActors(); this._cancelAnimation();
}); });
this.connect('actor-added', this._childAdded.bind(this)); this.connect('actor-added', this._childAdded.bind(this));
this.connect('actor-removed', this._childRemoved.bind(this)); this.connect('actor-removed', this._childRemoved.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
}
_onDestroy() {
if (this._updateIconSizesLaterId) {
Meta.later_remove (this._updateIconSizesLaterId);
this._updateIconSizesLaterId = 0;
}
} }
_keyFocusIn(actor) { _keyFocusIn(actor) {
@@ -256,34 +231,21 @@ var IconGrid = GObject.registerClass({
_childAdded(grid, child) { _childAdded(grid, child) {
child._iconGridKeyFocusInId = child.connect('key-focus-in', this._keyFocusIn.bind(this)); child._iconGridKeyFocusInId = child.connect('key-focus-in', this._keyFocusIn.bind(this));
child._paintVisible = child.opacity > 0;
child._opacityChangedId = child.connect('notify::opacity', () => {
let paintVisible = child._paintVisible;
child._paintVisible = child.opacity > 0;
if (paintVisible !== child._paintVisible)
this.queue_relayout();
});
} }
_childRemoved(grid, child) { _childRemoved(grid, child) {
child.disconnect(child._iconGridKeyFocusInId); child.disconnect(child._iconGridKeyFocusInId);
delete child._iconGridKeyFocusInId;
child.disconnect(child._opacityChangedId);
delete child._opacityChangedId;
delete child._paintVisible;
} }
vfunc_get_preferred_width(_forHeight) { vfunc_get_preferred_width(forHeight) {
if (this._fillParent) if (this._fillParent)
// Ignore all size requests of children and request a size of 0; // Ignore all size requests of children and request a size of 0;
// later we'll allocate as many children as fit the parent // later we'll allocate as many children as fit the parent
return [0, 0]; return [0, 0];
let nChildren = this.get_n_children(); let nChildren = this.get_n_children();
let nColumns = this._colLimit let nColumns = this._colLimit ? Math.min(this._colLimit,
? Math.min(this._colLimit, nChildren) nChildren)
: nChildren; : nChildren;
let totalSpacing = Math.max(0, nColumns - 1) * this._getSpacing(); let totalSpacing = Math.max(0, nColumns - 1) * this._getSpacing();
// Kind of a lie, but not really an issue right now. If // Kind of a lie, but not really an issue right now. If
@@ -314,7 +276,7 @@ var IconGrid = GObject.registerClass({
if (forWidth < 0) if (forWidth < 0)
nColumns = children.length; nColumns = children.length;
else else
[nColumns] = this._computeLayout(forWidth); [nColumns, ] = this._computeLayout(forWidth);
let nRows; let nRows;
if (nColumns > 0) if (nColumns > 0)
@@ -349,7 +311,7 @@ var IconGrid = GObject.registerClass({
let [nColumns, usedWidth] = this._computeLayout(availWidth); let [nColumns, usedWidth] = this._computeLayout(availWidth);
let leftEmptySpace; let leftEmptySpace;
switch (this._xAlign) { switch(this._xAlign) {
case St.Align.START: case St.Align.START:
leftEmptySpace = 0; leftEmptySpace = 0;
break; break;
@@ -423,7 +385,7 @@ var IconGrid = GObject.registerClass({
let childVolume = child.get_transformed_paint_volume(this); let childVolume = child.get_transformed_paint_volume(this);
if (!childVolume) if (!childVolume)
return false; return false
paintVolume.union(childVolume); paintVolume.union(childVolume);
} }
@@ -436,20 +398,21 @@ var IconGrid = GObject.registerClass({
* set of items to be animated. * set of items to be animated.
*/ */
_getChildrenToAnimate() { _getChildrenToAnimate() {
return this._getVisibleChildren().filter(child => child.opacity > 0); return this._getVisibleChildren();
} }
_resetAnimationActors() { _cancelAnimation() {
this._clonesAnimating.forEach(clone => { clone.destroy(); });
this._clonesAnimating = [];
}
_animationDone() {
this._clonesAnimating.forEach(clone => { this._clonesAnimating.forEach(clone => {
clone.source.reactive = true; clone.source.reactive = true;
clone.source.opacity = 255; clone.source.opacity = 255;
clone.destroy(); clone.destroy();
}); });
this._clonesAnimating = []; this._clonesAnimating = [];
}
_animationDone() {
this._resetAnimationActors();
this.emit('animation-done'); this.emit('animation-done');
} }
@@ -458,7 +421,7 @@ var IconGrid = GObject.registerClass({
throw new GObject.NotImplementedError("Pulse animation only implements " + throw new GObject.NotImplementedError("Pulse animation only implements " +
"'in' animation direction"); "'in' animation direction");
this._resetAnimationActors(); this._cancelAnimation();
let actors = this._getChildrenToAnimate(); let actors = this._getChildrenToAnimate();
if (actors.length == 0) { if (actors.length == 0) {
@@ -481,23 +444,21 @@ var IconGrid = GObject.registerClass({
let delay = index / actors.length * maxDelay; let delay = index / actors.length * maxDelay;
let bounceUpTime = ANIMATION_TIME_IN / 4; let bounceUpTime = ANIMATION_TIME_IN / 4;
let isLastItem = index == actors.length - 1; let isLastItem = index == actors.length - 1;
actor.ease({ Tweener.addTween(actor,
{ time: bounceUpTime,
transition: 'easeInOutQuad',
delay: delay,
scale_x: ANIMATION_BOUNCE_ICON_SCALE, scale_x: ANIMATION_BOUNCE_ICON_SCALE,
scale_y: ANIMATION_BOUNCE_ICON_SCALE, scale_y: ANIMATION_BOUNCE_ICON_SCALE,
duration: bounceUpTime,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay: delay,
onComplete: () => { onComplete: () => {
let duration = ANIMATION_TIME_IN - bounceUpTime; Tweener.addTween(actor,
actor.ease({ { time: ANIMATION_TIME_IN - bounceUpTime,
transition: 'easeInOutQuad',
scale_x: 1, scale_x: 1,
scale_y: 1, scale_y: 1,
duration,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
onComplete: () => { onComplete: () => {
if (isLastItem) if (isLastItem)
this._animationDone(); this._animationDone();
actor.reactive = true;
} }
}); });
} }
@@ -506,7 +467,7 @@ var IconGrid = GObject.registerClass({
} }
animateSpring(animationDirection, sourceActor) { animateSpring(animationDirection, sourceActor) {
this._resetAnimationActors(); this._cancelAnimation();
let actors = this._getChildrenToAnimate(); let actors = this._getChildrenToAnimate();
if (actors.length == 0) { if (actors.length == 0) {
@@ -543,7 +504,7 @@ var IconGrid = GObject.registerClass({
this._clonesAnimating.push(actorClone); this._clonesAnimating.push(actorClone);
Main.uiGroup.add_actor(actorClone); Main.uiGroup.add_actor(actorClone);
let [width, height] = this._getAllocatedChildSizeAndSpacing(actor); let [width, height,,] = this._getAllocatedChildSizeAndSpacing(actor);
actorClone.set_size(width, height); actorClone.set_size(width, height);
let scaleX = sourceScaledWidth / width; let scaleX = sourceScaledWidth / width;
let scaleY = sourceScaledHeight / height; let scaleY = sourceScaledHeight / height;
@@ -560,25 +521,21 @@ var IconGrid = GObject.registerClass({
let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM; let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM;
let [finalX, finalY] = actor._transformedPosition; let [finalX, finalY] = actor._transformedPosition;
movementParams = { movementParams = { time: ANIMATION_TIME_IN,
transition: 'easeInOutQuad',
delay: delay,
x: finalX, x: finalX,
y: finalY, y: finalY,
scale_x: 1, scale_x: 1,
scale_y: 1, scale_y: 1,
duration: ANIMATION_TIME_IN, onComplete: () => {
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay
};
if (isLastItem) if (isLastItem)
movementParams.onComplete = this._animationDone.bind(this); this._animationDone();
}};
fadeParams = { fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
opacity: 255, transition: 'easeInOutQuad',
duration: ANIMATION_FADE_IN_TIME_FOR_ITEM, delay: delay,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, opacity: 255 };
delay
};
} else { } else {
let isLastItem = actor._distance == maxDist; let isLastItem = actor._distance == maxDist;
@@ -586,29 +543,26 @@ var IconGrid = GObject.registerClass({
actorClone.set_position(startX, startY); actorClone.set_position(startX, startY);
let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM; let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM;
movementParams = { movementParams = { time: ANIMATION_TIME_OUT,
transition: 'easeInOutQuad',
delay: delay,
x: adjustedSourcePositionX, x: adjustedSourcePositionX,
y: adjustedSourcePositionY, y: adjustedSourcePositionY,
scale_x: scaleX, scale_x: scaleX,
scale_y: scaleY, scale_y: scaleY,
duration: ANIMATION_TIME_OUT, onComplete: () => {
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay
};
if (isLastItem) if (isLastItem)
movementParams.onComplete = this._animationDone.bind(this); this._animationDone();
}};
fadeParams = { fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
opacity: 0, transition: 'easeInOutQuad',
duration: ANIMATION_FADE_IN_TIME_FOR_ITEM, delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, opacity: 0 };
delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM
};
} }
actorClone.ease(movementParams);
actorClone.ease(fadeParams); Tweener.addTween(actorClone, movementParams);
Tweener.addTween(actorClone, fadeParams);
} }
} }
@@ -648,8 +602,6 @@ var IconGrid = GObject.registerClass({
} }
_computeLayout(forWidth) { _computeLayout(forWidth) {
this.ensure_style();
let nColumns = 0; let nColumns = 0;
let usedWidth = this.leftPadding + this.rightPadding; let usedWidth = this.leftPadding + this.rightPadding;
let spacing = this._getSpacing(); let spacing = this._getSpacing();
@@ -758,8 +710,8 @@ var IconGrid = GObject.registerClass({
if (this._padWithSpacing) { if (this._padWithSpacing) {
// minRows + 1 because we want to put spacing before the first row, so it is like we have one more row // minRows + 1 because we want to put spacing before the first row, so it is like we have one more row
// to divide the empty space // to divide the empty space
maxVSpacing = Math.floor(maxEmptyVArea / (this._minRows + 1)); maxVSpacing = Math.floor(maxEmptyVArea / (this._minRows +1));
maxHSpacing = Math.floor(maxEmptyHArea / (this._minColumns + 1)); maxHSpacing = Math.floor(maxEmptyHArea / (this._minColumns +1));
} else { } else {
if (this._minRows <= 1) if (this._minRows <= 1)
maxVSpacing = maxEmptyVArea; maxVSpacing = maxEmptyVArea;
@@ -791,38 +743,35 @@ var IconGrid = GObject.registerClass({
this._fixedHItemSize = this._hItemSize; this._fixedHItemSize = this._hItemSize;
this._fixedVItemSize = this._vItemSize; this._fixedVItemSize = this._vItemSize;
this._updateSpacingForSize(availWidth, availHeight); this._updateSpacingForSize(availWidth, availHeight);
let spacing = this._getSpacing();
if (this.columnsForWidth(availWidth) < this._minColumns || this.rowsForHeight(availHeight) < this._minRows) { if (this.columnsForWidth(availWidth) < this._minColumns || this.rowsForHeight(availHeight) < this._minRows) {
let neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth; let neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth ;
let neededHeight = this.usedHeightForNRows(this._minRows) - availHeight; let neededHeight = this.usedHeightForNRows(this._minRows) - availHeight ;
let neededSpacePerItem = (neededWidth > neededHeight) let neededSpacePerItem = (neededWidth > neededHeight) ? Math.ceil(neededWidth / this._minColumns)
? Math.ceil(neededWidth / this._minColumns)
: Math.ceil(neededHeight / this._minRows); : Math.ceil(neededHeight / this._minRows);
this._fixedHItemSize = Math.max(this._hItemSize - neededSpacePerItem, MIN_ICON_SIZE); this._fixedHItemSize = Math.max(this._hItemSize - neededSpacePerItem, MIN_ICON_SIZE);
this._fixedVItemSize = Math.max(this._vItemSize - neededSpacePerItem, MIN_ICON_SIZE); this._fixedVItemSize = Math.max(this._vItemSize - neededSpacePerItem, MIN_ICON_SIZE);
this._updateSpacingForSize(availWidth, availHeight); this._updateSpacingForSize(availWidth, availHeight);
} }
if (!this._updateIconSizesLaterId) Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
this._updateIconSizesLaterId = Meta.later_add(Meta.LaterType.BEFORE_REDRAW,
this._updateIconSizes.bind(this)); this._updateIconSizes.bind(this));
} }
// Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up // Note that this is ICON_SIZE as used by BaseIcon, not elsewhere in IconGrid; it's a bit messed up
_updateIconSizes() { _updateIconSizes() {
this._updateIconSizesLaterId = 0;
let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize); let scale = Math.min(this._fixedHItemSize, this._fixedVItemSize) / Math.max(this._hItemSize, this._vItemSize);
let newIconSize = Math.floor(ICON_SIZE * scale); let newIconSize = Math.floor(ICON_SIZE * scale);
for (let i in this._items) { for (let i in this._items) {
this._items[i].icon.setIconSize(newIconSize); this._items[i].icon.setIconSize(newIconSize);
} }
return GLib.SOURCE_REMOVE;
} }
}); });
var PaginatedIconGrid = GObject.registerClass({ var PaginatedIconGrid = GObject.registerClass({
Signals: { 'space-opened': {}, Signals: {'space-opened': {},
'space-closed': {} }, 'space-closed': {} },
}, class PaginatedIconGrid extends IconGrid { }, class PaginatedIconGrid extends IconGrid {
_init(params) { _init(params) {
@@ -834,7 +783,7 @@ var PaginatedIconGrid = GObject.registerClass({
this._childrenPerPage = 0; this._childrenPerPage = 0;
} }
vfunc_get_preferred_height(_forWidth) { vfunc_get_preferred_height(forWidth) {
let height = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * this._nPages + this._spaceBetweenPages * this._nPages; let height = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * this._nPages + this._spaceBetweenPages * this._nPages;
return [height, height]; return [height, height];
} }
@@ -853,11 +802,12 @@ var PaginatedIconGrid = GObject.registerClass({
} }
let children = this._getVisibleChildren(); let children = this._getVisibleChildren();
let availWidth = box.x2 - box.x1; let availWidth = box.x2 - box.x1;
let availHeight = box.y2 - box.y1;
let spacing = this._getSpacing(); let spacing = this._getSpacing();
let [nColumns, usedWidth] = this._computeLayout(availWidth); let [nColumns, usedWidth] = this._computeLayout(availWidth);
let leftEmptySpace; let leftEmptySpace;
switch (this._xAlign) { switch(this._xAlign) {
case St.Align.START: case St.Align.START:
leftEmptySpace = 0; leftEmptySpace = 0;
break; break;
@@ -871,6 +821,7 @@ var PaginatedIconGrid = GObject.registerClass({
let x = box.x1 + leftEmptySpace + this.leftPadding; let x = box.x1 + leftEmptySpace + this.leftPadding;
let y = box.y1 + this.topPadding; let y = box.y1 + this.topPadding;
let columnIndex = 0; let columnIndex = 0;
let rowIndex = 0;
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
let childBox = this._calculateChildBox(children[i], x, y, box); let childBox = this._calculateChildBox(children[i], x, y, box);
@@ -880,21 +831,21 @@ var PaginatedIconGrid = GObject.registerClass({
columnIndex++; columnIndex++;
if (columnIndex == nColumns) { if (columnIndex == nColumns) {
columnIndex = 0; columnIndex = 0;
rowIndex++;
} }
if (columnIndex == 0) { if (columnIndex == 0) {
y += this._getVItemSize() + spacing; y += this._getVItemSize() + spacing;
if ((i + 1) % this._childrenPerPage == 0) if ((i + 1) % this._childrenPerPage == 0)
y += this._spaceBetweenPages - spacing + this.bottomPadding + this.topPadding; y += this._spaceBetweenPages - spacing + this.bottomPadding + this.topPadding;
x = box.x1 + leftEmptySpace + this.leftPadding; x = box.x1 + leftEmptySpace + this.leftPadding;
} else { } else
x += this._getHItemSize() + spacing; x += this._getHItemSize() + spacing;
} }
} }
}
// Overridden from IconGrid // Overridden from IconGrid
_getChildrenToAnimate() { _getChildrenToAnimate() {
let children = super._getChildrenToAnimate(); let children = this._getVisibleChildren();
let firstIndex = this._childrenPerPage * this.currentPage; let firstIndex = this._childrenPerPage * this.currentPage;
let lastIndex = firstIndex + this._childrenPerPage; let lastIndex = firstIndex + this._childrenPerPage;
@@ -902,7 +853,7 @@ var PaginatedIconGrid = GObject.registerClass({
} }
_computePages(availWidthPerPage, availHeightPerPage) { _computePages(availWidthPerPage, availHeightPerPage) {
let [nColumns, usedWidth_] = this._computeLayout(availWidthPerPage); let [nColumns, usedWidth] = this._computeLayout(availWidthPerPage);
let nRows; let nRows;
let children = this._getVisibleChildren(); let children = this._getVisibleChildren();
if (nColumns > 0) if (nColumns > 0)
@@ -912,6 +863,7 @@ var PaginatedIconGrid = GObject.registerClass({
if (this._rowLimit) if (this._rowLimit)
nRows = Math.min(nRows, this._rowLimit); nRows = Math.min(nRows, this._rowLimit);
let spacing = this._getSpacing();
// We want to contain the grid inside the parent box with padding // We want to contain the grid inside the parent box with padding
this._rowsPerPage = this.rowsForHeight(availHeightPerPage); this._rowsPerPage = this.rowsForHeight(availHeightPerPage);
this._nPages = Math.ceil(nRows / this._rowsPerPage); this._nPages = Math.ceil(nRows / this._rowsPerPage);
@@ -940,7 +892,7 @@ var PaginatedIconGrid = GObject.registerClass({
if (!this._nPages) if (!this._nPages)
return 0; return 0;
let firstPageItem = pageNumber * this._childrenPerPage; let firstPageItem = pageNumber * this._childrenPerPage
let childBox = this._getVisibleChildren()[firstPageItem].get_allocation_box(); let childBox = this._getVisibleChildren()[firstPageItem].get_allocation_box();
return childBox.y1 - this.topPadding; return childBox.y1 - this.topPadding;
} }
@@ -973,7 +925,8 @@ var PaginatedIconGrid = GObject.registerClass({
let childrenPerRow = this._childrenPerPage / this._rowsPerPage; let childrenPerRow = this._childrenPerPage / this._rowsPerPage;
let sourceRow = Math.floor((index - pageOffset) / childrenPerRow); let sourceRow = Math.floor((index - pageOffset) / childrenPerRow);
let nRowsAbove = (side == St.Side.TOP) ? sourceRow + 1 : sourceRow; let nRowsAbove = (side == St.Side.TOP) ? sourceRow + 1
: sourceRow;
let nRowsBelow = this._rowsPerPage - nRowsAbove; let nRowsBelow = this._rowsPerPage - nRowsAbove;
let nRowsUp, nRowsDown; let nRowsUp, nRowsDown;
@@ -1013,14 +966,13 @@ var PaginatedIconGrid = GObject.registerClass({
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
children[i].translation_y = 0; children[i].translation_y = 0;
let params = { let params = { translation_y: translationY,
translation_y: translationY, time: EXTRA_SPACE_ANIMATION_TIME,
duration: EXTRA_SPACE_ANIMATION_TIME, transition: 'easeInOutQuad'
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD
}; };
if (i == (children.length - 1)) if (i == (children.length - 1))
params.onComplete = () => this.emit('space-opened'); params.onComplete = () => { this.emit('space-opened'); };
children[i].ease(params); Tweener.addTween(children[i], params);
} }
} }
@@ -1033,11 +985,11 @@ var PaginatedIconGrid = GObject.registerClass({
for (let i = 0; i < this._translatedChildren.length; i++) { for (let i = 0; i < this._translatedChildren.length; i++) {
if (!this._translatedChildren[i].translation_y) if (!this._translatedChildren[i].translation_y)
continue; continue;
this._translatedChildren[i].ease({ Tweener.addTween(this._translatedChildren[i],
translation_y: 0, { translation_y: 0,
duration: EXTRA_SPACE_ANIMATION_TIME, time: EXTRA_SPACE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, transition: 'easeInOutQuad',
onComplete: () => this.emit('space-closed') onComplete: () => { this.emit('space-closed'); }
}); });
} }
} }

View File

@@ -1,4 +1,3 @@
/* exported InhibitShortcutsDialog */
const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell } = imports.gi; const { Clutter, Gio, GLib, GObject, Gtk, Meta, Shell } = imports.gi;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
@@ -76,8 +75,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
let name = this._app ? this._app.get_name() : this._window.title; let name = this._app ? this._app.get_name() : this._window.title;
/* Translators: %s is an application name like "Settings" */ /* Translators: %s is an application name like "Settings" */
let title = name let title = name ? _("%s wants to inhibit shortcuts").format(name)
? _("%s wants to inhibit shortcuts").format(name)
: _("Application wants to inhibit shortcuts"); : _("Application wants to inhibit shortcuts");
let icon = new Gio.ThemedIcon({ name: 'dialog-warning-symbolic' }); let icon = new Gio.ThemedIcon({ name: 'dialog-warning-symbolic' });
@@ -113,7 +111,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
} }
vfunc_show() { vfunc_show() {
if (this._app && APP_WHITELIST.includes(this._app.get_id())) { if (this._app && APP_WHITELIST.indexOf(this._app.get_id()) != -1) {
this._emitResponse(DialogResponse.ALLOW); this._emitResponse(DialogResponse.ALLOW);
return; return;
} }
@@ -141,7 +139,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
return; return;
} }
let [permissions] = res; let [permissions, data] = res;
if (permissions[appId] === undefined) // Not found if (permissions[appId] === undefined) // Not found
this._dialog.open(); this._dialog.open();
else if (permissions[appId] == GRANTED) else if (permissions[appId] == GRANTED)

View File

@@ -1,4 +1,3 @@
/* exported KbdA11yDialog */
const { Clutter, Gio, GObject } = imports.gi; const { Clutter, Gio, GObject } = imports.gi;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
@@ -27,23 +26,23 @@ class KbdA11yDialog extends GObject.Object {
if (whatChanged & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) { if (whatChanged & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) {
key = KEY_SLOW_KEYS_ENABLED; key = KEY_SLOW_KEYS_ENABLED;
enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) > 0; enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) ? true : false;
title = enabled title = enabled ?
? _("Slow Keys Turned On") _("Slow Keys Turned On") :
: _("Slow Keys Turned Off"); _("Slow Keys Turned Off");
body = _("You just held down the Shift key for 8 seconds. This is the shortcut " + body = _("You just held down the Shift key for 8 seconds. This is the shortcut " +
"for the Slow Keys feature, which affects the way your keyboard works."); "for the Slow Keys feature, which affects the way your keyboard works.");
} else if (whatChanged & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) { } else if (whatChanged & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) {
key = KEY_STICKY_KEYS_ENABLED; key = KEY_STICKY_KEYS_ENABLED;
enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) > 0; enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) ? true : false;
title = enabled title = enabled ?
? _("Sticky Keys Turned On") _("Sticky Keys Turned On") :
: _("Sticky Keys Turned Off"); _("Sticky Keys Turned Off");
body = enabled body = enabled ?
? _("You just pressed the Shift key 5 times in a row. This is the shortcut " + _("You just pressed the Shift key 5 times in a row. This is the shortcut " +
"for the Sticky Keys feature, which affects the way your keyboard works.") "for the Sticky Keys feature, which affects the way your keyboard works.") :
: _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " + _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " +
"This turns off the Sticky Keys feature, which affects the way your keyboard works."); "This turns off the Sticky Keys feature, which affects the way your keyboard works.");
} else { } else {
return; return;

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 Keyboard */
const { Clutter, Gio, GLib, GObject, Meta, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Meta, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
@@ -11,10 +10,11 @@ const Layout = imports.ui.layout;
const Main = imports.ui.main; const Main = imports.ui.main;
const PageIndicators = imports.ui.pageIndicators; const PageIndicators = imports.ui.pageIndicators;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const Tweener = imports.ui.tweener;
var KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2; var KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2 * 1000;
var KEY_LONG_PRESS_TIME = 250; var KEY_LONG_PRESS_TIME = 250;
var PANEL_SWITCH_ANIMATION_TIME = 500; var PANEL_SWITCH_ANIMATION_TIME = 0.5;
var PANEL_SWITCH_RELATIVE_DISTANCE = 1 / 3; /* A third of the actor width */ var PANEL_SWITCH_RELATIVE_DISTANCE = 1 / 3; /* A third of the actor width */
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications'; const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
@@ -24,29 +24,29 @@ const SHOW_KEYBOARD = 'screen-keyboard-enabled';
const KEY_SIZE = 2; const KEY_SIZE = 2;
const defaultKeysPre = [ const defaultKeysPre = [
[[], [], [{ width: 1.5, level: 1, extraClassName: 'shift-key-lowercase' }], [{ label: '?123', width: 1.5, level: 2 }]], [ [], [], [{ width: 1.5, level: 1, extraClassName: 'shift-key-lowercase' }], [{ label: '?123', width: 1.5, level: 2 }] ],
[[], [], [{ width: 1.5, level: 0, extraClassName: 'shift-key-uppercase' }], [{ label: '?123', width: 1.5, level: 2 }]], [ [], [], [{ width: 1.5, level: 0, extraClassName: 'shift-key-uppercase' }], [{ label: '?123', width: 1.5, level: 2 }] ],
[[], [], [{ label: '=/<', width: 1.5, level: 3 }], [{ label: 'ABC', width: 1.5, level: 0 }]], [ [], [], [{ label: '=/<', width: 1.5, level: 3 }], [{ label: 'ABC', width: 1.5, level: 0 }] ],
[[], [], [{ label: '?123', width: 1.5, level: 2 }], [{ label: 'ABC', width: 1.5, level: 0 }]], [ [], [], [{ label: '?123', width: 1.5, level: 2 }], [{ label: 'ABC', width: 1.5, level: 0 }] ],
]; ];
const defaultKeysPost = [ const defaultKeysPost = [
[[{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }], [ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
[{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }], [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
[{ width: 3, level: 1, right: true, extraClassName: 'shift-key-lowercase' }], [{ width: 3, level: 1, right: true, extraClassName: 'shift-key-lowercase' }],
[{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }]], [{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }] ],
[[{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }], [ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
[{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }], [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
[{ width: 3, level: 0, right: true, extraClassName: 'shift-key-uppercase' }], [{ width: 3, level: 0, right: true, extraClassName: 'shift-key-uppercase' }],
[{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }]], [{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }] ],
[[{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }], [ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
[{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }], [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
[{ label: '=/<', width: 3, level: 3, right: true }], [{ label: '=/<', width: 3, level: 3, right: true }],
[{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }]], [{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }] ],
[[{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }], [ [{ label: '⌫', width: 1.5, keyval: Clutter.KEY_BackSpace }],
[{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }], [{ width: 2, keyval: Clutter.KEY_Return, extraClassName: 'enter-key' }],
[{ label: '?123', width: 3, level: 2, right: true }], [{ label: '?123', width: 3, level: 2, right: true }],
[{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }]], [{ label: '☻', action: 'emoji' }, { action: 'languageMenu', extraClassName: 'layout-key' }, { action: 'hide', extraClassName: 'hide-key' }] ],
]; ];
var AspectContainer = GObject.registerClass( var AspectContainer = GObject.registerClass(
@@ -100,14 +100,13 @@ class KeyContainer extends St.Widget {
this._rows = []; this._rows = [];
} }
appendRow() { appendRow(length) {
this._currentRow++; this._currentRow++;
this._currentCol = 0; this._currentCol = 0;
let row = { let row = new Object();
keys: [], row.keys = [];
width: 0, row.width = 0;
};
this._rows.push(row); this._rows.push(row);
} }
@@ -194,12 +193,12 @@ var LanguageSelectionPopup = class extends PopupMenu.PopupMenu {
item = this.addAction(is.displayName, () => { item = this.addAction(is.displayName, () => {
inputSourceManager.activateInputSource(is, true); inputSourceManager.activateInputSource(is, true);
}); });
item.can_focus = false; item.actor.can_focus = false;
} }
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
item = this.addSettingsAction(_("Region & Language Settings"), 'gnome-region-panel.desktop'); item = this.addSettingsAction(_("Region & Language Settings"), 'gnome-region-panel.desktop');
item.can_focus = false; item.actor.can_focus = false;
this._capturedEventId = 0; this._capturedEventId = 0;
@@ -298,7 +297,7 @@ var Key = class Key {
} }
_press(key) { _press(key) {
this.emit('activated'); this.emit('activated')
if (key != this.key || this._extended_keys.length == 0) { if (key != this.key || this._extended_keys.length == 0) {
this.emit('pressed', this._getKeyval(key), key); this.emit('pressed', this._getKeyval(key), key);
@@ -406,6 +405,9 @@ var Key = class Key {
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
}); });
button.connect('touch-event', (actor, event) => { button.connect('touch-event', (actor, event) => {
let device = event.get_device();
let sequence = event.get_event_sequence();
// We only handle touch events here on wayland. On X11 // We only handle touch events here on wayland. On X11
// we do get emulated pointer events, which already works // we do get emulated pointer events, which already works
// for single-touch cases. Besides, the X11 passive touch grab // for single-touch cases. Besides, the X11 passive touch grab
@@ -475,7 +477,7 @@ var KeyboardModel = class {
_loadModel(groupName) { _loadModel(groupName) {
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/osk-layouts/%s.json'.format(groupName)); let file = Gio.File.new_for_uri('resource:///org/gnome/shell/osk-layouts/%s.json'.format(groupName));
let [success_, contents] = file.load_contents(null); let [success, contents] = file.load_contents(null);
if (contents instanceof Uint8Array) if (contents instanceof Uint8Array)
contents = imports.byteArray.toString(contents); contents = imports.byteArray.toString(contents);
@@ -570,27 +572,11 @@ var FocusTracker = class {
}; };
Signals.addSignalMethods(FocusTracker.prototype); Signals.addSignalMethods(FocusTracker.prototype);
var EmojiPager = GObject.registerClass({ var EmojiPager = class EmojiPager {
Properties: { constructor(sections, nCols, nRows) {
'delta': GObject.ParamSpec.int( this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
'delta', 'delta', 'delta',
GObject.ParamFlags.READWRITE,
GLib.MININT32, GLib.MAXINT32, 0)
},
Signals: {
'emoji': { param_types: [GObject.TYPE_STRING] },
'page-changed': {
param_types: [GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_INT]
}
}
}, class EmojiPager extends St.Widget {
_init(sections, nCols, nRows) {
super._init({
layout_manager: new Clutter.BinLayout(),
reactive: true, reactive: true,
clip_to_allocation: true clip_to_allocation: true });
});
this._sections = sections; this._sections = sections;
this._nCols = nCols; this._nCols = nCols;
this._nRows = nRows; this._nRows = nRows;
@@ -612,7 +598,7 @@ var EmojiPager = GObject.registerClass({
panAction.connect('gesture-cancel', this._onPanCancel.bind(this)); panAction.connect('gesture-cancel', this._onPanCancel.bind(this));
panAction.connect('gesture-end', this._onPanEnd.bind(this)); panAction.connect('gesture-end', this._onPanEnd.bind(this));
this._panAction = panAction; this._panAction = panAction;
this.add_action(panAction); this.actor.add_action(panAction);
} }
get delta() { get delta() {
@@ -625,11 +611,7 @@ var EmojiPager = GObject.registerClass({
else if (value < -this._width) else if (value < -this._width)
value = -this._width; value = -this._width;
if (this._delta == value)
return;
this._delta = value; this._delta = value;
this.notify('delta');
if (value == 0) if (value == 0)
return; return;
@@ -646,8 +628,8 @@ var EmojiPager = GObject.registerClass({
if (followingPage != null) { if (followingPage != null) {
this._followingPanel = this._generatePanel(followingPage); this._followingPanel = this._generatePanel(followingPage);
this._followingPanel.set_pivot_point(0.5, 0.5); this._followingPanel.set_pivot_point(0.5, 0.5);
this.add_child(this._followingPanel); this.actor.add_child(this._followingPanel);
this.set_child_below_sibling(this._followingPanel, this._panel); this.actor.set_child_below_sibling(this._followingPanel, this._panel);
} }
this._followingPage = followingPage; this._followingPage = followingPage;
@@ -683,7 +665,7 @@ var EmojiPager = GObject.registerClass({
} }
_onPan(action) { _onPan(action) {
let [dist_, dx, dy_] = action.get_motion_delta(0); let [dist, dx, dy] = action.get_motion_delta(0);
this.delta = this.delta + dx; this.delta = this.delta + dx;
if (this._currentKey != null) { if (this._currentKey != null) {
@@ -695,13 +677,13 @@ var EmojiPager = GObject.registerClass({
} }
_onPanBegin() { _onPanBegin() {
this._width = this.width; this._width = this.actor.width;
return true; return true;
} }
_onPanEnd() { _onPanEnd() {
if (Math.abs(this._delta) < this.width * PANEL_SWITCH_RELATIVE_DISTANCE) { if (Math.abs(this._delta) < this.actor.width * PANEL_SWITCH_RELATIVE_DISTANCE) {
this._onPanCancel(); this._onPanCancel()
} else { } else {
let value; let value;
if (this._delta > 0) if (this._delta > 0)
@@ -712,10 +694,12 @@ var EmojiPager = GObject.registerClass({
let relDelta = Math.abs(this._delta - value) / this._width; let relDelta = Math.abs(this._delta - value) / this._width;
let time = PANEL_SWITCH_ANIMATION_TIME * Math.abs(relDelta); let time = PANEL_SWITCH_ANIMATION_TIME * Math.abs(relDelta);
this.remove_all_transitions(); Tweener.removeTweens(this);
this.ease_property('delta', value, { Tweener.addTween(this,
duration: time, { delta: value,
onComplete: () => { time: time,
transition: 'easeInOutQuad',
onComplete() {
this.setCurrentPage(this.getFollowingPage()); this.setCurrentPage(this.getFollowingPage());
} }
}); });
@@ -723,12 +707,14 @@ var EmojiPager = GObject.registerClass({
} }
_onPanCancel() { _onPanCancel() {
let relDelta = Math.abs(this._delta) / this.width; let relDelta = Math.abs(this._delta) / this.actor.width;
let time = PANEL_SWITCH_ANIMATION_TIME * Math.abs(relDelta); let time = PANEL_SWITCH_ANIMATION_TIME * Math.abs(relDelta);
this.remove_all_transitions(); Tweener.removeTweens(this);
this.ease_property('delta', 0, { Tweener.addTween(this,
duration: time, { delta: 0,
time: time,
transition: 'easeInOutQuad',
}); });
} }
@@ -839,7 +825,7 @@ var EmojiPager = GObject.registerClass({
if (!this._panel) { if (!this._panel) {
this._panel = this._generatePanel(nPage); this._panel = this._generatePanel(nPage);
this.add_child(this._panel); this.actor.add_child(this._panel);
} }
let page = this._pages[nPage]; let page = this._pages[nPage];
@@ -856,7 +842,8 @@ var EmojiPager = GObject.registerClass({
} }
} }
} }
}); };
Signals.addSignalMethods(EmojiPager.prototype);
var EmojiSelection = class EmojiSelection { var EmojiSelection = class EmojiSelection {
constructor() { constructor() {
@@ -878,7 +865,7 @@ var EmojiSelection = class EmojiSelection {
x_expand: true, x_expand: true,
y_expand: true, y_expand: true,
vertical: true }); vertical: true });
this.actor.connect('notify::mapped', () => this._emojiPager.setCurrentPage(0)); this.actor.connect('notify::mapped', () => { this._emojiPager.setCurrentPage(0); });
this._emojiPager = new EmojiPager(this._sections, 11, 3); this._emojiPager = new EmojiPager(this._sections, 11, 3);
this._emojiPager.connect('page-changed', (pager, section, page, nPages) => { this._emojiPager.connect('page-changed', (pager, section, page, nPages) => {
@@ -920,12 +907,13 @@ var EmojiSelection = class EmojiSelection {
_populateSections() { _populateSections() {
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/osk-layouts/emoji.json'); let file = Gio.File.new_for_uri('resource:///org/gnome/shell/osk-layouts/emoji.json');
let [success_, contents] = file.load_contents(null); let [success, contents] = file.load_contents(null);
if (contents instanceof Uint8Array) if (contents instanceof Uint8Array)
contents = imports.byteArray.toString(contents); contents = imports.byteArray.toString(contents);
let emoji = JSON.parse(contents); let emoji = JSON.parse(contents);
let pages = [];
let variants = []; let variants = [];
let currentKey = 0; let currentKey = 0;
let currentSection = null; let currentSection = null;
@@ -960,14 +948,14 @@ var EmojiSelection = class EmojiSelection {
key = new Key('ABC', []); key = new Key('ABC', []);
key.keyButton.add_style_class_name('default-key'); key.keyButton.add_style_class_name('default-key');
key.connect('released', () => this.emit('toggle')); key.connect('released', () => { this.emit('toggle'); });
row.appendKey(key.actor, 1.5); row.appendKey(key.actor, 1.5);
for (let i = 0; i < this._sections.length; i++) { for (let i = 0; i < this._sections.length; i++) {
let section = this._sections[i]; let section = this._sections[i];
key = new Key(section.label, []); key = new Key(section.label, []);
key.connect('released', () => this._emojiPager.setCurrentSection(section, 0)); key.connect('released', () => { this._emojiPager.setCurrentSection(section, 0) });
row.appendKey(key.actor); row.appendKey(key.actor);
section.button = key; section.button = key;
@@ -1086,7 +1074,7 @@ var Keyboard = class Keyboard {
let manager = Clutter.DeviceManager.get_default(); let manager = Clutter.DeviceManager.get_default();
let device = manager.get_device(deviceId); let device = manager.get_device(deviceId);
if (!device.get_device_name().includes('XTEST')) { if (device.get_device_name().indexOf('XTEST') < 0) {
this._lastDeviceId = deviceId; this._lastDeviceId = deviceId;
this._syncEnabled(); this._syncEnabled();
} }
@@ -1187,7 +1175,7 @@ var Keyboard = class Keyboard {
this._emojiSelection = new EmojiSelection(); this._emojiSelection = new EmojiSelection();
this._emojiSelection.connect('toggle', this._toggleEmoji.bind(this)); this._emojiSelection.connect('toggle', this._toggleEmoji.bind(this));
this._emojiSelection.connect('hide', () => this.hide()); this._emojiSelection.connect('hide', (selection) => { this.hide(); });
this._emojiSelection.connect('emoji-selected', (selection, emoji) => { this._emojiSelection.connect('emoji-selected', (selection, emoji) => {
this._keyboardController.commitString(emoji); this._keyboardController.commitString(emoji);
}); });
@@ -1298,7 +1286,7 @@ var Keyboard = class Keyboard {
} }
} }
}); });
button.connect('released', (actor, keyval, _str) => { button.connect('released', (actor, keyval, str) => {
if (keyval != 0) { if (keyval != 0) {
if (button._keyvalPress) if (button._keyvalPress)
this._keyboardController.keyvalRelease(keyval); this._keyboardController.keyvalRelease(keyval);
@@ -1418,6 +1406,8 @@ var Keyboard = class Keyboard {
} }
_getDefaultKeysForRow(row, numRows, level) { _getDefaultKeysForRow(row, numRows, level) {
let pre, post;
/* The first 2 rows in defaultKeysPre/Post belong together with /* The first 2 rows in defaultKeysPre/Post belong together with
* the first 2 rows on each keymap. On keymaps that have more than * the first 2 rows on each keymap. On keymaps that have more than
* 4 rows, the last 2 default key rows must be respectively * 4 rows, the last 2 default key rows must be respectively
@@ -1458,8 +1448,8 @@ var Keyboard = class Keyboard {
numOfVertSlots = rows.length; numOfVertSlots = rows.length;
for (let i = 0; i < rows.length; ++i) { for (let i = 0; i < rows.length; ++i) {
let keyboardRow = rows[i]; let keyboard_row = rows[i];
let keys = keyboardRow.get_children(); let keys = keyboard_row.get_children();
numOfHorizSlots = Math.max(numOfHorizSlots, keys.length); numOfHorizSlots = Math.max(numOfHorizSlots, keys.length);
} }
@@ -1483,7 +1473,7 @@ var Keyboard = class Keyboard {
this._setActiveLayer(0); this._setActiveLayer(0);
} }
_onKeyboardGroupsChanged() { _onKeyboardGroupsChanged(keyboard) {
let nonGroupActors = [this._emojiSelection.actor, this._keypad.actor]; let nonGroupActors = [this._emojiSelection.actor, this._keypad.actor];
this._aspectContainer.get_children().filter(c => !nonGroupActors.includes(c)).forEach(c => { this._aspectContainer.get_children().filter(c => !nonGroupActors.includes(c)).forEach(c => {
c.destroy(); c.destroy();
@@ -1656,7 +1646,8 @@ var Keyboard = class Keyboard {
} }
_windowSlideAnimationComplete(window, delta) { _windowSlideAnimationComplete(window, delta) {
// Synchronize window positions again. // Synchronize window and actor positions again.
let windowActor = window.get_compositor_private();
let frameRect = window.get_frame_rect(); let frameRect = window.get_frame_rect();
frameRect.y += delta; frameRect.y += delta;
window.move_frame(true, frameRect.x, frameRect.y); window.move_frame(true, frameRect.x, frameRect.y);
@@ -1669,23 +1660,19 @@ var Keyboard = class Keyboard {
return; return;
if (show) { if (show) {
windowActor.ease({ Tweener.addTween(windowActor,
y: windowActor.y - deltaY, { y: windowActor.y - deltaY,
duration: Layout.KEYBOARD_ANIMATION_TIME, time: Layout.KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete: this._windowSlideAnimationComplete,
this._windowSlideAnimationComplete(window, -deltaY); onCompleteParams: [window, -deltaY] });
}
});
} else { } else {
windowActor.ease({ Tweener.addTween(windowActor,
y: windowActor.y + deltaY, { y: windowActor.y + deltaY,
duration: Layout.KEYBOARD_ANIMATION_TIME, time: Layout.KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_QUAD, transition: 'easeInQuad',
onComplete: () => { onComplete: this._windowSlideAnimationComplete,
this._windowSlideAnimationComplete(window, deltaY); onCompleteParams: [window, deltaY] });
}
});
} }
} }
@@ -1701,11 +1688,12 @@ var Keyboard = class Keyboard {
this._animFocusedWindow = window; this._animFocusedWindow = window;
} }
setCursorLocation(window, x, y, w, h) { setCursorLocation(window, x, y , w, h) {
let monitor = Main.layoutManager.keyboardMonitor; let monitor = Main.layoutManager.keyboardMonitor;
if (window && monitor) { if (window && monitor) {
let keyboardHeight = Main.layoutManager.keyboardBox.height; let keyboardHeight = Main.layoutManager.keyboardBox.height;
let focusObscured = false;
if (y + h >= monitor.y + monitor.height - keyboardHeight) { if (y + h >= monitor.y + monitor.height - keyboardHeight) {
if (this._keyboardVisible) if (this._keyboardVisible)
@@ -1749,13 +1737,14 @@ var KeyboardController = class {
this.emit('groups-changed'); this.emit('groups-changed');
} }
_onSourceChanged(inputSourceManager, _oldSource) { _onSourceChanged(inputSourceManager, oldSource) {
let source = inputSourceManager.currentSource; let source = inputSourceManager.currentSource;
this._currentSource = source; this._currentSource = source;
this.emit('active-group', source.id); this.emit('active-group', source.id);
} }
_onContentPurposeHintsChanged(method) { _onContentPurposeHintsChanged(method) {
let hints = method.content_hints;
let purpose = method.content_purpose; let purpose = method.content_purpose;
let emojiVisible = false; let emojiVisible = false;
let keypadVisible = false; let keypadVisible = false;
@@ -1770,13 +1759,13 @@ var KeyboardController = class {
purpose == Clutter.InputContentPurpose.PHONE) purpose == Clutter.InputContentPurpose.PHONE)
keypadVisible = true; keypadVisible = true;
this.emit('emoji-visible', emojiVisible); this.emit('emoji-visible', emojiVisible)
this.emit('keypad-visible', keypadVisible); this.emit('keypad-visible', keypadVisible);
} }
getGroups() { getGroups() {
let inputSources = this._inputSourceManager.inputSources; let inputSources = this._inputSourceManager.inputSources;
let groups = []; let groups = []
for (let i in inputSources) { for (let i in inputSources) {
let is = inputSources[i]; let is = inputSources[i];

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 MonitorConstraint, LayoutManager */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Background = imports.ui.background; const Background = imports.ui.background;
@@ -11,17 +10,18 @@ const LoginManager = imports.misc.loginManager;
const DND = imports.ui.dnd; const DND = imports.ui.dnd;
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 Ripples = imports.ui.ripples; const Ripples = imports.ui.ripples;
var STARTUP_ANIMATION_TIME = 500; var STARTUP_ANIMATION_TIME = 0.5;
var KEYBOARD_ANIMATION_TIME = 150; var KEYBOARD_ANIMATION_TIME = 0.15;
var BACKGROUND_FADE_ANIMATION_TIME = 1000; var BACKGROUND_FADE_ANIMATION_TIME = 1.0;
var HOT_CORNER_PRESSURE_THRESHOLD = 100; // pixels var HOT_CORNER_PRESSURE_THRESHOLD = 100; // pixels
var HOT_CORNER_PRESSURE_TIMEOUT = 1000; // ms var HOT_CORNER_PRESSURE_TIMEOUT = 1000; // ms
function isPopupMetaWindow(actor) { function isPopupMetaWindow(actor) {
switch (actor.meta_window.get_window_type()) { switch(actor.meta_window.get_window_type()) {
case Meta.WindowType.DROPDOWN_MENU: case Meta.WindowType.DROPDOWN_MENU:
case Meta.WindowType.POPUP_MENU: case Meta.WindowType.POPUP_MENU:
case Meta.WindowType.COMBO: case Meta.WindowType.COMBO:
@@ -32,8 +32,7 @@ function isPopupMetaWindow(actor) {
} }
var MonitorConstraint = GObject.registerClass({ var MonitorConstraint = GObject.registerClass({
Properties: { Properties: {'primary': GObject.ParamSpec.boolean('primary',
'primary': GObject.ParamSpec.boolean('primary',
'Primary', 'Track primary monitor', 'Primary', 'Track primary monitor',
GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
false), false),
@@ -44,8 +43,7 @@ var MonitorConstraint = GObject.registerClass({
'work-area': GObject.ParamSpec.boolean('work-area', 'work-area': GObject.ParamSpec.boolean('work-area',
'Work-area', 'Track monitor\'s work-area', 'Work-area', 'Track monitor\'s work-area',
GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
false) false)},
},
}, class MonitorConstraint extends Clutter.Constraint { }, class MonitorConstraint extends Clutter.Constraint {
_init(props) { _init(props) {
this._primary = false; this._primary = false;
@@ -80,12 +78,10 @@ var MonitorConstraint = GObject.registerClass({
this.notify('index'); this.notify('index');
} }
// eslint-disable-next-line camelcase
get work_area() { get work_area() {
return this._workArea; return this._workArea;
} }
// eslint-disable-next-line camelcase
set work_area(v) { set work_area(v) {
if (v == this._workArea) if (v == this._workArea)
return; return;
@@ -151,13 +147,13 @@ var MonitorConstraint = GObject.registerClass({
}); });
var Monitor = class Monitor { var Monitor = class Monitor {
constructor(index, geometry, geometryScale) { constructor(index, geometry, geometry_scale) {
this.index = index; this.index = index;
this.x = geometry.x; this.x = geometry.x;
this.y = geometry.y; this.y = geometry.y;
this.width = geometry.width; this.width = geometry.width;
this.height = geometry.height; this.height = geometry.height;
this.geometry_scale = geometryScale; this.geometry_scale = geometry_scale;
} }
get inFullscreen() { get inFullscreen() {
@@ -167,12 +163,12 @@ var Monitor = class Monitor {
const UiActor = GObject.registerClass( const UiActor = GObject.registerClass(
class UiActor extends St.Widget { class UiActor extends St.Widget {
vfunc_get_preferred_width (_forHeight) { vfunc_get_preferred_width (forHeight) {
let width = global.stage.width; let width = global.stage.width;
return [width, width]; return [width, width];
} }
vfunc_get_preferred_height (_forWidth) { vfunc_get_preferred_height (forWidth) {
let height = global.stage.height; let height = global.stage.height;
return [height, height]; return [height, height];
} }
@@ -238,8 +234,7 @@ var LayoutManager = GObject.registerClass({
reactive: true }); reactive: true });
this.addChrome(this.overviewGroup); this.addChrome(this.overviewGroup);
this.screenShieldGroup = new St.Widget({ this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
name: 'screenShieldGroup',
visible: false, visible: false,
clip_to_allocation: true, clip_to_allocation: true,
layout_manager: new Clutter.BinLayout(), layout_manager: new Clutter.BinLayout(),
@@ -277,13 +272,6 @@ var LayoutManager = GObject.registerClass({
this._backgroundGroup.lower_bottom(); this._backgroundGroup.lower_bottom();
this._bgManagers = []; this._bgManagers = [];
this._interfaceSettings = new Gio.Settings({
schema_id: 'org.gnome.desktop.interface'
});
this._interfaceSettings.connect('changed::enable-hot-corners',
this._updateHotCorners.bind(this));
// Need to update struts on new workspaces when they are added // Need to update struts on new workspaces when they are added
let workspaceManager = global.workspace_manager; let workspaceManager = global.workspace_manager;
workspaceManager.connect('notify::n-workspaces', workspaceManager.connect('notify::n-workspaces',
@@ -387,11 +375,6 @@ var LayoutManager = GObject.registerClass({
}); });
this.hotCorners = []; this.hotCorners = [];
if (!this._interfaceSettings.get_boolean('enable-hot-corners')) {
this.emit('hot-corners-changed');
return;
}
let size = this.panelBox.height; let size = this.panelBox.height;
// build new hot corners // build new hot corners
@@ -464,11 +447,10 @@ var LayoutManager = GObject.registerClass({
let backgroundActor = this._bgManagers[i].backgroundActor; let backgroundActor = this._bgManagers[i].backgroundActor;
backgroundActor.show(); backgroundActor.show();
backgroundActor.opacity = 0; backgroundActor.opacity = 0;
backgroundActor.ease({ Tweener.addTween(backgroundActor,
opacity: 255, { opacity: 255,
duration: BACKGROUND_FADE_ANIMATION_TIME, time: BACKGROUND_FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad' });
});
} }
} }
} }
@@ -699,23 +681,23 @@ var LayoutManager = GObject.registerClass({
} }
_startupAnimationGreeter() { _startupAnimationGreeter() {
this.panelBox.ease({ Tweener.addTween(this.panelBox,
translation_y: 0, { translation_y: 0,
duration: STARTUP_ANIMATION_TIME, time: STARTUP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => this._startupAnimationComplete() onComplete: this._startupAnimationComplete,
}); onCompleteScope: this });
} }
_startupAnimationSession() { _startupAnimationSession() {
this.uiGroup.ease({ Tweener.addTween(this.uiGroup,
scale_x: 1, { scale_x: 1,
scale_y: 1, scale_y: 1,
opacity: 255, opacity: 255,
duration: STARTUP_ANIMATION_TIME, time: STARTUP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => this._startupAnimationComplete() onComplete: this._startupAnimationComplete,
}); onCompleteScope: this });
} }
_startupAnimationComplete() { _startupAnimationComplete() {
@@ -741,14 +723,13 @@ var LayoutManager = GObject.registerClass({
showKeyboard() { showKeyboard() {
this.keyboardBox.show(); this.keyboardBox.show();
this.keyboardBox.ease({ Tweener.addTween(this.keyboardBox,
anchor_y: this.keyboardBox.height, { anchor_y: this.keyboardBox.height,
opacity: 255, opacity: 255,
duration: KEYBOARD_ANIMATION_TIME, time: KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete: this._showKeyboardComplete,
this._showKeyboardComplete(); onCompleteScope: this
}
}); });
this.emit('keyboard-visible-changed', true); this.emit('keyboard-visible-changed', true);
} }
@@ -768,14 +749,13 @@ var LayoutManager = GObject.registerClass({
this.keyboardBox.disconnect(this._keyboardHeightNotifyId); this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
this._keyboardHeightNotifyId = 0; this._keyboardHeightNotifyId = 0;
} }
this.keyboardBox.ease({ Tweener.addTween(this.keyboardBox,
anchor_y: 0, { anchor_y: 0,
opacity: 0, opacity: 0,
duration: immediate ? 0 : KEYBOARD_ANIMATION_TIME, time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_QUAD, transition: 'easeInQuad',
onComplete: () => { onComplete: this._hideKeyboardComplete,
this._hideKeyboardComplete(); onCompleteScope: this
}
}); });
this.emit('keyboard-visible-changed', false); this.emit('keyboard-visible-changed', false);
@@ -847,7 +827,7 @@ var LayoutManager = GObject.registerClass({
// @params can have any of the same values as in addChrome(), // @params can have any of the same values as in addChrome(),
// though some possibilities don't make sense. By default, @actor has // though some possibilities don't make sense. By default, @actor has
// the same params as its chrome ancestor. // the same params as its chrome ancestor.
trackChrome(actor, params = {}) { trackChrome(actor, params) {
let ancestor = actor.get_parent(); let ancestor = actor.get_parent();
let index = this._findActor(ancestor); let index = this._findActor(ancestor);
while (ancestor && index == -1) { while (ancestor && index == -1) {
@@ -855,13 +835,14 @@ var LayoutManager = GObject.registerClass({
index = this._findActor(ancestor); index = this._findActor(ancestor);
} }
let ancestorData = ancestor let ancestorData = ancestor ? this._trackedActors[index]
? this._trackedActors[index]
: defaultParams; : defaultParams;
if (!params)
params = {};
// We can't use Params.parse here because we want to drop // We can't use Params.parse here because we want to drop
// the extra values like ancestorData.actor // the extra values like ancestorData.actor
for (let prop in defaultParams) { for (let prop in defaultParams) {
if (!Object.prototype.hasOwnProperty.call(params, prop)) if (!params.hasOwnProperty(prop))
params[prop] = ancestorData[prop]; params[prop] = ancestorData[prop];
} }
@@ -1015,6 +996,11 @@ var LayoutManager = GObject.registerClass({
if (Main.modalCount > 0) if (Main.modalCount > 0)
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
// Bug workaround - get_transformed_position()/get_transformed_size() don't work after
// a change in stage size until the first pick or paint.
// https://bugzilla.gnome.org/show_bug.cgi?id=761565
global.stage.get_actor_at_pos(Clutter.PickMode.ALL, 0, 0);
let rects = [], struts = [], i; let rects = [], struts = [], i;
let isPopupMenuVisible = global.top_window_group.get_children().some(isPopupMetaWindow); let isPopupMenuVisible = global.top_window_group.get_children().some(isPopupMetaWindow);
let wantsInputRegion = !isPopupMenuVisible; let wantsInputRegion = !isPopupMenuVisible;
@@ -1070,19 +1056,18 @@ var LayoutManager = GObject.registerClass({
side = Meta.Side.RIGHT; side = Meta.Side.RIGHT;
else else
continue; continue;
} else if (x1 <= monitor.x) { } else if (x1 <= monitor.x)
side = Meta.Side.LEFT; side = Meta.Side.LEFT;
} else if (y1 <= monitor.y) { else if (y1 <= monitor.y)
side = Meta.Side.TOP; side = Meta.Side.TOP;
} else if (x2 >= monitor.x + monitor.width) { else if (x2 >= monitor.x + monitor.width)
side = Meta.Side.RIGHT; side = Meta.Side.RIGHT;
} else if (y2 >= monitor.y + monitor.height) { else if (y2 >= monitor.y + monitor.height)
side = Meta.Side.BOTTOM; side = Meta.Side.BOTTOM;
} else { else
continue; continue;
}
let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1 }); let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1});
let strut = new Meta.Strut({ rect: strutRect, side: side }); let strut = new Meta.Strut({ rect: strutRect, side: side });
struts.push(strut); struts.push(strut);
} }
@@ -1221,8 +1206,6 @@ var HotCorner = class HotCorner {
if (this.actor) if (this.actor)
this.actor.destroy(); this.actor.destroy();
this._ripples.destroy();
} }
_toggleOverview() { _toggleOverview() {
@@ -1235,7 +1218,7 @@ var HotCorner = class HotCorner {
} }
} }
handleDragOver(source, _actor, _x, _y, _time) { handleDragOver(source, actor, x, y, time) {
if (source != Main.xdndHandler) if (source != Main.xdndHandler)
return DND.DragMotionResult.CONTINUE; return DND.DragMotionResult.CONTINUE;
@@ -1336,7 +1319,7 @@ var PressureBarrier = class PressureBarrier {
let threshold = this._lastTime - this._timeout; let threshold = this._lastTime - this._timeout;
while (i < this._barrierEvents.length) { while (i < this._barrierEvents.length) {
let [time, distance_] = this._barrierEvents[i]; let [time, distance] = this._barrierEvents[i];
if (time >= threshold) if (time >= threshold)
break; break;
i++; i++;
@@ -1345,14 +1328,14 @@ var PressureBarrier = class PressureBarrier {
let firstNewEvent = i; let firstNewEvent = i;
for (i = 0; i < firstNewEvent; i++) { for (i = 0; i < firstNewEvent; i++) {
let [time_, distance] = this._barrierEvents[i]; let [time, distance] = this._barrierEvents[i];
this._currentPressure -= distance; this._currentPressure -= distance;
} }
this._barrierEvents = this._barrierEvents.slice(firstNewEvent); this._barrierEvents = this._barrierEvents.slice(firstNewEvent);
} }
_onBarrierLeft(barrier, _event) { _onBarrierLeft(barrier, event) {
barrier._isHit = false; barrier._isHit = false;
if (this._barriers.every(b => !b._isHit)) { if (this._barriers.every(b => !b._isHit)) {
this._reset(); this._reset();

View File

@@ -1,10 +1,10 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Lightbox */
const { Clutter, GObject, Shell, St } = imports.gi; const { Clutter, GObject, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
var DEFAULT_FADE_FACTOR = 0.4; var DEFAULT_FADE_FACTOR = 0.4;
var VIGNETTE_BRIGHTNESS = 0.2; var VIGNETTE_BRIGHTNESS = 0.2;
@@ -23,31 +23,16 @@ t = clamp(t, 0.0, 1.0);\n\
float pixel_brightness = mix(1.0, 1.0 - vignette_sharpness, t);\n\ float pixel_brightness = mix(1.0, 1.0 - vignette_sharpness, t);\n\
cogl_color_out.a = cogl_color_out.a * (1 - pixel_brightness * brightness);'; cogl_color_out.a = cogl_color_out.a * (1 - pixel_brightness * brightness);';
var RadialShaderEffect = GObject.registerClass({ var RadialShaderQuad = GObject.registerClass(
Properties: { class RadialShaderQuad extends Shell.GLSLQuad {
'brightness': GObject.ParamSpec.float(
'brightness', 'brightness', 'brightness',
GObject.ParamFlags.READWRITE,
0, 1, 1
),
'sharpness': GObject.ParamSpec.float(
'sharpness', 'sharpness', 'sharpness',
GObject.ParamFlags.READWRITE,
0, 1, 0
)
}
}, class RadialShaderEffect extends Shell.GLSLEffect {
_init(params) { _init(params) {
this._brightness = undefined;
this._sharpness = undefined;
super._init(params); super._init(params);
this._brightnessLocation = this.get_uniform_location('brightness'); this._brightnessLocation = this.get_uniform_location('brightness');
this._sharpnessLocation = this.get_uniform_location('vignette_sharpness'); this._sharpnessLocation = this.get_uniform_location('vignette_sharpness');
this.brightness = 1.0; this.brightness = 1.0;
this.sharpness = 0.0; this.vignetteSharpness = 0.0;
} }
vfunc_build_pipeline() { vfunc_build_pipeline() {
@@ -60,25 +45,19 @@ var RadialShaderEffect = GObject.registerClass({
} }
set brightness(v) { set brightness(v) {
if (this._brightness == v)
return;
this._brightness = v; this._brightness = v;
this.set_uniform_float(this._brightnessLocation, this.set_uniform_float(this._brightnessLocation,
1, [this._brightness]); 1, [this._brightness]);
this.notify('brightness');
} }
get sharpness() { get vignetteSharpness() {
return this._sharpness; return this._sharpness;
} }
set sharpness(v) { set vignetteSharpness(v) {
if (this._sharpness == v)
return;
this._sharpness = v; this._sharpness = v;
this.set_uniform_float(this._sharpnessLocation, this.set_uniform_float(this._sharpnessLocation,
1, [this._sharpness]); 1, [this._sharpness]);
this.notify('sharpness');
} }
}); });
@@ -89,8 +68,8 @@ var RadialShaderEffect = GObject.registerClass({
* - inhibitEvents: whether to inhibit events for @container * - inhibitEvents: whether to inhibit events for @container
* - width: shade actor width * - width: shade actor width
* - height: shade actor height * - height: shade actor height
* - fadeInTime: milliseconds used to fade in * - fadeInTime: seconds used to fade in
* - fadeOutTime: milliseconds used to fade out * - fadeOutTime: seconds used to fade out
* *
* Lightbox creates a dark translucent "shade" actor to hide the * Lightbox creates a dark translucent "shade" actor to hide the
* contents of @container, and allows you to specify particular actors * contents of @container, and allows you to specify particular actors
@@ -108,8 +87,7 @@ var RadialShaderEffect = GObject.registerClass({
*/ */
var Lightbox = class Lightbox { var Lightbox = class Lightbox {
constructor(container, params) { constructor(container, params) {
params = Params.parse(params, { params = Params.parse(params, { inhibitEvents: false,
inhibitEvents: false,
width: null, width: null,
height: null, height: null,
fadeFactor: DEFAULT_FADE_FACTOR, fadeFactor: DEFAULT_FADE_FACTOR,
@@ -120,13 +98,16 @@ var Lightbox = class Lightbox {
this._children = container.get_children(); this._children = container.get_children();
this._fadeFactor = params.fadeFactor; this._fadeFactor = params.fadeFactor;
this._radialEffect = Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL) && params.radialEffect; this._radialEffect = Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL) && params.radialEffect;
this.actor = new St.Bin({ reactive: params.inhibitEvents });
if (this._radialEffect) if (this._radialEffect)
this.actor.add_effect(new RadialShaderEffect({ name: 'radial' })); this.actor = new RadialShaderQuad({ x: 0,
y: 0,
reactive: params.inhibitEvents });
else else
this.actor.set({ opacity: 0, style_class: 'lightbox' }); this.actor = new St.Bin({ x: 0,
y: 0,
opacity: 0,
style_class: 'lightbox',
reactive: params.inhibitEvents });
container.add_actor(this.actor); container.add_actor(this.actor);
this.actor.raise_top(); this.actor.raise_top();
@@ -173,52 +154,60 @@ var Lightbox = class Lightbox {
} }
show(fadeInTime) { show(fadeInTime) {
this.actor.remove_all_transitions(); fadeInTime = fadeInTime || 0;
let easeProps = { Tweener.removeTweens(this.actor);
duration: fadeInTime || 0, if (this._radialEffect) {
mode: Clutter.AnimationMode.EASE_OUT_QUAD Tweener.addTween(this.actor,
}; { brightness: VIGNETTE_BRIGHTNESS,
vignetteSharpness: VIGNETTE_SHARPNESS,
let onComplete = () => { time: fadeInTime,
transition: 'easeOutQuad',
onComplete: () => {
this.shown = true; this.shown = true;
this.emit('shown'); this.emit('shown');
}; }
});
} else {
Tweener.addTween(this.actor,
{ opacity: 255 * this._fadeFactor,
time: fadeInTime,
transition: 'easeOutQuad',
onComplete: () => {
this.shown = true;
this.emit('shown');
}
});
}
this.actor.show(); this.actor.show();
if (this._radialEffect) {
this.actor.ease_property(
'@effects.radial.brightness', VIGNETTE_BRIGHTNESS, easeProps);
this.actor.ease_property(
'@effects.radial.sharpness', VIGNETTE_SHARPNESS,
Object.assign({ onComplete }, easeProps));
} else {
this.actor.ease(Object.assign(easeProps, {
opacity: 255 * this._fadeFactor,
onComplete
}));
}
} }
hide(fadeOutTime) { hide(fadeOutTime) {
fadeOutTime = fadeOutTime || 0;
this.shown = false; this.shown = false;
this.actor.remove_all_transitions(); Tweener.removeTweens(this.actor);
let easeProps = {
duration: fadeOutTime || 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
};
let onComplete = () => this.actor.hide();
if (this._radialEffect) { if (this._radialEffect) {
this.actor.ease_property( Tweener.addTween(this.actor,
'@effects.radial.brightness', 1.0, easeProps); { brightness: 1.0,
this.actor.ease_property( vignetteSharpness: 0.0,
'@effects.radial.sharpness', 0.0, Object.assign({ onComplete }, easeProps)); opacity: 0,
time: fadeOutTime,
transition: 'easeOutQuad',
onComplete: () => {
this.actor.hide();
}
});
} else { } else {
this.actor.ease(Object.assign(easeProps, { opacity: 0, onComplete })); Tweener.addTween(this.actor,
{ opacity: 0,
time: fadeOutTime,
transition: 'easeOutQuad',
onComplete: () => {
this.actor.hide();
}
});
} }
} }

View File

@@ -1,39 +1,24 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported LocatePointer */
const { Gio } = imports.gi; const { Clutter, Gio, GLib, St } = imports.gi;
const Ripples = imports.ui.ripples; const Ripples = imports.ui.ripples;
const Main = imports.ui.main; const Main = imports.ui.main;
const LOCATE_POINTER_KEY = "locate-pointer"; const LOCATE_POINTER_KEY = "locate-pointer";
const LOCATE_POINTER_SCHEMA = "org.gnome.desktop.interface"; const LOCATE_POINTER_SCHEMA = "org.gnome.desktop.interface"
var LocatePointer = class { var locatePointer = class {
constructor() { constructor() {
this._settings = new Gio.Settings({ schema_id: LOCATE_POINTER_SCHEMA }); this._settings = new Gio.Settings({schema_id: LOCATE_POINTER_SCHEMA});
this._settings.connect(`changed::${LOCATE_POINTER_KEY}`, () => this._syncEnabled());
this._syncEnabled();
}
_syncEnabled() {
let enabled = this._settings.get_boolean(LOCATE_POINTER_KEY);
if (enabled == !!this._ripples)
return;
if (enabled) {
this._ripples = new Ripples.Ripples(0.5, 0.5, 'ripple-pointer-location'); this._ripples = new Ripples.Ripples(0.5, 0.5, 'ripple-pointer-location');
this._ripples.addTo(Main.uiGroup); this._ripples.addTo(Main.uiGroup);
} else {
this._ripples.destroy();
this._ripples = null;
}
} }
show() { show() {
if (!this._ripples) if (!this._settings.get_boolean("locate-pointer"))
return; return;
let [x, y] = global.get_pointer(); let [x, y, mods] = global.get_pointer();
this._ripples.playAnimation(x, y); this._ripples.playAnimation(x, y);
} }
}; };

View File

@@ -1,24 +1,26 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported LookingGlass */
const { Clutter, Cogl, Gio, GLib, const { Clutter, Cogl, Gio, GLib,
GObject, Meta, Pango, Shell, St } = imports.gi; GObject, Meta, Pango, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals; const Signals = imports.signals;
const System = imports.system; const System = imports.system;
const History = imports.misc.history; const History = imports.misc.history;
const ExtensionSystem = imports.ui.extensionSystem;
const ExtensionUtils = imports.misc.extensionUtils; const ExtensionUtils = imports.misc.extensionUtils;
const ShellEntry = imports.ui.shellEntry; const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main; const Main = imports.ui.main;
const JsParse = imports.misc.jsParse; const JsParse = imports.misc.jsParse;
const { ExtensionState } = ExtensionUtils;
const CHEVRON = '>>> '; const CHEVRON = '>>> ';
/* Imports...feel free to add here as needed */ /* Imports...feel free to add here as needed */
var commandHeader = 'const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; ' + var commandHeader = 'const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; ' +
'const Main = imports.ui.main; ' + 'const Main = imports.ui.main; ' +
'const Mainloop = imports.mainloop; ' +
'const Tweener = imports.ui.tweener; ' +
/* Utility functions...we should probably be able to use these /* Utility functions...we should probably be able to use these
* in the shell core code too. */ * in the shell core code too. */
'const stage = global.stage; ' + 'const stage = global.stage; ' +
@@ -30,11 +32,9 @@ var commandHeader = 'const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = im
const HISTORY_KEY = 'looking-glass-history'; const HISTORY_KEY = 'looking-glass-history';
// Time between tabs for them to count as a double-tab event // Time between tabs for them to count as a double-tab event
var AUTO_COMPLETE_DOUBLE_TAB_DELAY = 500; var AUTO_COMPLETE_DOUBLE_TAB_DELAY = 500;
var AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION = 200; var AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION = 0.2;
var AUTO_COMPLETE_GLOBAL_KEYWORDS = _getAutoCompleteGlobalKeywords(); var AUTO_COMPLETE_GLOBAL_KEYWORDS = _getAutoCompleteGlobalKeywords();
const LG_ANIMATION_TIME = 500;
function _getAutoCompleteGlobalKeywords() { function _getAutoCompleteGlobalKeywords() {
const keywords = ['true', 'false', 'null', 'new']; const keywords = ['true', 'false', 'null', 'new'];
// Don't add the private properties of window (i.e., ones starting with '_') // Don't add the private properties of window (i.e., ones starting with '_')
@@ -68,10 +68,10 @@ var AutoComplete = class AutoComplete {
if (commonPrefix.length > 0) { if (commonPrefix.length > 0) {
this.additionalCompletionText(commonPrefix, event.attrHead); this.additionalCompletionText(commonPrefix, event.attrHead);
this.emit('completion', { completion: commonPrefix, type: 'prefix' }); this.emit('completion', { completion: commonPrefix, type: 'prefix' });
this.emit('suggest', { completions: event.completions }); this.emit('suggest', { completions: event.completions});
} }
} else if (event.completions.length > 1 && event.tabType === 'double') { } else if (event.completions.length > 1 && event.tabType === 'double') {
this.emit('suggest', { completions: event.completions }); this.emit('suggest', { completions: event.completions});
} }
} }
@@ -146,8 +146,8 @@ var Notebook = class Notebook {
this.actor.add(scrollview, { expand: true }); this.actor.add(scrollview, { expand: true });
let vAdjust = scrollview.vscroll.adjustment; let vAdjust = scrollview.vscroll.adjustment;
vAdjust.connect('changed', () => this._onAdjustScopeChanged(tabData)); vAdjust.connect('changed', () => { this._onAdjustScopeChanged(tabData); });
vAdjust.connect('notify::value', () => this._onAdjustValueChanged(tabData)); vAdjust.connect('notify::value', () => { this._onAdjustValueChanged(tabData); });
if (this._selectedIndex == -1) if (this._selectedIndex == -1)
this.selectIndex(0); this.selectIndex(0);
@@ -185,9 +185,9 @@ var Notebook = class Notebook {
} }
selectChild(child) { selectChild(child) {
if (child == null) { if (child == null)
this.selectIndex(-1); this.selectIndex(-1);
} else { else {
for (let i = 0; i < this._tabs.length; i++) { for (let i = 0; i < this._tabs.length; i++) {
let tabData = this._tabs[i]; let tabData = this._tabs[i];
if (tabData.child == child) { if (tabData.child == child) {
@@ -238,11 +238,11 @@ var Notebook = class Notebook {
Signals.addSignalMethods(Notebook.prototype); Signals.addSignalMethods(Notebook.prototype);
function objectToString(o) { function objectToString(o) {
if (typeof o == typeof objectToString) { if (typeof(o) == typeof(objectToString)) {
// special case this since the default is way, way too verbose // special case this since the default is way, way too verbose
return '<js function>'; return '<js function>';
} else { } else {
return `${o}`; return '' + o;
} }
} }
@@ -266,7 +266,7 @@ var ObjLink = class ObjLink {
this._lookingGlass = lookingGlass; this._lookingGlass = lookingGlass;
} }
_onClicked() { _onClicked(link) {
this._lookingGlass.inspectObject(this._obj, this.actor); this._lookingGlass.inspectObject(this._obj, this.actor);
} }
}; };
@@ -284,7 +284,7 @@ var Result = class Result {
this.actor.add(cmdTxt); this.actor.add(cmdTxt);
let box = new St.BoxLayout({}); let box = new St.BoxLayout({});
this.actor.add(box); this.actor.add(box);
let resultTxt = new St.Label({ text: `r(${index}) = ` }); let resultTxt = new St.Label({ text: 'r(' + index + ') = ' });
resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END; resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
box.add(resultTxt); box.add(resultTxt);
let objLink = new ObjLink(this._lookingGlass, o); let objLink = new ObjLink(this._lookingGlass, o);
@@ -304,9 +304,6 @@ var WindowList = class WindowList {
} }
_updateWindowList() { _updateWindowList() {
if (!this._lookingGlass.isOpen)
return;
this.actor.destroy_all_children(); this.actor.destroy_all_children();
let windows = global.get_window_actors(); let windows = global.get_window_actors();
let tracker = Shell.WindowTracker.get_default(); let tracker = Shell.WindowTracker.get_default();
@@ -323,7 +320,7 @@ var WindowList = class WindowList {
box.add(windowLink.actor, { x_align: St.Align.START, x_fill: false }); box.add(windowLink.actor, { x_align: St.Align.START, x_fill: false });
let propsBox = new St.BoxLayout({ vertical: true, style: 'padding-left: 6px;' }); let propsBox = new St.BoxLayout({ vertical: true, style: 'padding-left: 6px;' });
box.add(propsBox); box.add(propsBox);
propsBox.add(new St.Label({ text: `wmclass: ${metaWindow.get_wm_class()}` })); propsBox.add(new St.Label({ text: 'wmclass: ' + metaWindow.get_wm_class() }));
let app = tracker.get_window_app(metaWindow); let app = tracker.get_window_app(metaWindow);
if (app != null && !app.is_window_backed()) { if (app != null && !app.is_window_backed()) {
let icon = app.create_icon_texture(22); let icon = app.create_icon_texture(22);
@@ -338,10 +335,6 @@ var WindowList = class WindowList {
} }
} }
} }
update() {
this._updateWindowList();
}
}; };
Signals.addSignalMethods(WindowList.prototype); Signals.addSignalMethods(WindowList.prototype);
@@ -374,7 +367,7 @@ var ObjInspector = class ObjInspector {
let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' }); let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' });
this._container.add_actor(hbox); this._container.add_actor(hbox);
let label = new St.Label({ text: 'Inspecting: %s: %s'.format(typeof obj, let label = new St.Label({ text: 'Inspecting: %s: %s'.format(typeof(obj),
objectToString(obj)) }); objectToString(obj)) });
label.single_line_mode = true; label.single_line_mode = true;
hbox.add(label, { expand: true, y_fill: false }); hbox.add(label, { expand: true, y_fill: false });
@@ -392,7 +385,7 @@ var ObjInspector = class ObjInspector {
button.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); button.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' }));
button.connect('clicked', this.close.bind(this)); button.connect('clicked', this.close.bind(this));
hbox.add(button); hbox.add(button);
if (typeof obj == typeof {}) { if (typeof(obj) == typeof({})) {
let properties = []; let properties = [];
for (let propName in obj) { for (let propName in obj) {
properties.push(propName); properties.push(propName);
@@ -401,6 +394,7 @@ var ObjInspector = class ObjInspector {
for (let i = 0; i < properties.length; i++) { for (let i = 0; i < properties.length; i++) {
let propName = properties[i]; let propName = properties[i];
let valueStr;
let link; let link;
try { try {
let prop = obj[propName]; let prop = obj[propName];
@@ -409,7 +403,8 @@ var ObjInspector = class ObjInspector {
link = new St.Label({ text: '<error>' }); link = new St.Label({ text: '<error>' });
} }
let hbox = new St.BoxLayout(); let hbox = new St.BoxLayout();
hbox.add(new St.Label({ text: `${propName}: ` })); let propText = propName + ': ' + valueStr;
hbox.add(new St.Label({ text: propName + ': ' }));
hbox.add(link); hbox.add(link);
this._container.add_actor(hbox); this._container.add_actor(hbox);
} }
@@ -424,12 +419,9 @@ var ObjInspector = class ObjInspector {
this.actor.show(); this.actor.show();
if (sourceActor) { if (sourceActor) {
this.actor.set_scale(0, 0); this.actor.set_scale(0, 0);
this.actor.ease({ Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
scale_x: 1, transition: 'easeOutQuad',
scale_y: 1, time: 0.2 });
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: 200
});
} else { } else {
this.actor.set_scale(1, 1); this.actor.set_scale(1, 1);
} }
@@ -501,13 +493,8 @@ var Inspector = GObject.registerClass({
eventHandler.connect('button-press-event', this._onButtonPressEvent.bind(this)); eventHandler.connect('button-press-event', this._onButtonPressEvent.bind(this));
eventHandler.connect('scroll-event', this._onScrollEvent.bind(this)); eventHandler.connect('scroll-event', this._onScrollEvent.bind(this));
eventHandler.connect('motion-event', this._onMotionEvent.bind(this)); eventHandler.connect('motion-event', this._onMotionEvent.bind(this));
Clutter.grab_pointer(eventHandler);
let dm = Clutter.DeviceManager.get_default(); Clutter.grab_keyboard(eventHandler);
this._pointerDevice = dm.get_core_device(Clutter.InputDeviceType.POINTER_DEVICE);
this._keyboardDevice = dm.get_core_device(Clutter.InputDeviceType.KEYBOARD_DEVICE);
this._pointerDevice.grab(eventHandler);
this._keyboardDevice.grab(eventHandler);
// this._target is the actor currently shown by the inspector. // this._target is the actor currently shown by the inspector.
// this._pointerTarget is the actor directly under the pointer. // this._pointerTarget is the actor directly under the pointer.
@@ -528,7 +515,7 @@ var Inspector = GObject.registerClass({
let primary = Main.layoutManager.primaryMonitor; let primary = Main.layoutManager.primaryMonitor;
let [, , natWidth, natHeight] = let [minWidth, minHeight, natWidth, natHeight] =
this._eventHandler.get_preferred_size(); this._eventHandler.get_preferred_size();
let childBox = new Clutter.ActorBox(); let childBox = new Clutter.ActorBox();
@@ -540,8 +527,8 @@ var Inspector = GObject.registerClass({
} }
_close() { _close() {
this._pointerDevice.ungrab(); Clutter.ungrab_pointer();
this._keyboardDevice.ungrab(); Clutter.ungrab_keyboard();
this._eventHandler.destroy(); this._eventHandler.destroy();
this._eventHandler = null; this._eventHandler = null;
this.emit('closed'); this.emit('closed');
@@ -564,7 +551,7 @@ var Inspector = GObject.registerClass({
_onScrollEvent(actor, event) { _onScrollEvent(actor, event) {
switch (event.get_scroll_direction()) { switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP: { case Clutter.ScrollDirection.UP:
// select parent // select parent
let parent = this._target.get_parent(); let parent = this._target.get_parent();
if (parent != null) { if (parent != null) {
@@ -572,7 +559,6 @@ var Inspector = GObject.registerClass({
this._update(event); this._update(event);
} }
break; break;
}
case Clutter.ScrollDirection.DOWN: case Clutter.ScrollDirection.DOWN:
// select child // select child
@@ -612,9 +598,9 @@ var Inspector = GObject.registerClass({
this._target = target; this._target = target;
this._pointerTarget = target; this._pointerTarget = target;
let position = `[inspect x: ${stageX} y: ${stageY}]`; let position = '[inspect x: ' + stageX + ' y: ' + stageY + ']';
this._displayText.text = ''; this._displayText.text = '';
this._displayText.text = `${position} ${this._target}`; this._displayText.text = position + ' ' + this._target;
this._lookingGlass.setBorderPaintTarget(this._target); this._lookingGlass.setBorderPaintTarget(this._target);
} }
@@ -633,16 +619,15 @@ var Extensions = class Extensions {
this._extensionsList.add(this._noExtensions); this._extensionsList.add(this._noExtensions);
this.actor.add(this._extensionsList); this.actor.add(this._extensionsList);
Main.extensionManager.getUuids().forEach(uuid => { for (let uuid in ExtensionUtils.extensions)
this._loadExtension(null, uuid); this._loadExtension(null, uuid);
});
Main.extensionManager.connect('extension-loaded', ExtensionSystem.connect('extension-loaded',
this._loadExtension.bind(this)); this._loadExtension.bind(this));
} }
_loadExtension(o, uuid) { _loadExtension(o, uuid) {
let extension = Main.extensionManager.lookup(uuid); let extension = ExtensionUtils.extensions[uuid];
// There can be cases where we create dummy extension metadata // There can be cases where we create dummy extension metadata
// that's not really a proper extension. Don't bother with these. // that's not really a proper extension. Don't bother with these.
if (!extension.metadata.name) if (!extension.metadata.name)
@@ -699,16 +684,16 @@ var Extensions = class Extensions {
_stateToString(extensionState) { _stateToString(extensionState) {
switch (extensionState) { switch (extensionState) {
case ExtensionState.ENABLED: case ExtensionSystem.ExtensionState.ENABLED:
return _("Enabled"); return _("Enabled");
case ExtensionState.DISABLED: case ExtensionSystem.ExtensionState.DISABLED:
case ExtensionState.INITIALIZED: case ExtensionSystem.ExtensionState.INITIALIZED:
return _("Disabled"); return _("Disabled");
case ExtensionState.ERROR: case ExtensionSystem.ExtensionState.ERROR:
return _("Error"); return _("Error");
case ExtensionState.OUT_OF_DATE: case ExtensionSystem.ExtensionState.OUT_OF_DATE:
return _("Out of date"); return _("Out of date");
case ExtensionState.DOWNLOADING: case ExtensionSystem.ExtensionState.DOWNLOADING:
return _("Downloading"); return _("Downloading");
} }
return 'Unknown'; // Not translated, shouldn't appear return 'Unknown'; // Not translated, shouldn't appear
@@ -725,6 +710,7 @@ var Extensions = class Extensions {
let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' }); let metaBox = new St.BoxLayout({ style_class: 'lg-extension-meta' });
box.add(metaBox); box.add(metaBox);
let stateString = this._stateToString(extension.state);
let state = new St.Label({ style_class: 'lg-extension-state', let state = new St.Label({ style_class: 'lg-extension-state',
text: this._stateToString(extension.state) }); text: this._stateToString(extension.state) });
metaBox.add(state); metaBox.add(state);
@@ -809,7 +795,7 @@ var LookingGlass = class LookingGlass {
inspectIcon.connect('button-press-event', () => { inspectIcon.connect('button-press-event', () => {
let inspector = new Inspector(this); let inspector = new Inspector(this);
inspector.connect('target', (i, target, stageX, stageY) => { inspector.connect('target', (i, target, stageX, stageY) => {
this._pushResult(`inspect(${Math.round(stageX)}, ${Math.round(stageY)})`, target); this._pushResult('inspect(' + Math.round(stageX) + ', ' + Math.round(stageY) + ')', target);
}); });
inspector.connect('closed', () => { inspector.connect('closed', () => {
this.actor.show(); this.actor.show();
@@ -826,7 +812,7 @@ var LookingGlass = class LookingGlass {
gcIcon.connect('button-press-event', () => { gcIcon.connect('button-press-event', () => {
gcIcon.icon_name = 'user-trash'; gcIcon.icon_name = 'user-trash';
System.gc(); System.gc();
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => { this._timeoutId = Mainloop.timeout_add(500, () => {
gcIcon.icon_name = 'user-trash-full'; gcIcon.icon_name = 'user-trash-full';
this._timeoutId = 0; this._timeoutId = 0;
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
@@ -865,7 +851,7 @@ var LookingGlass = class LookingGlass {
this._extensions = new Extensions(this); this._extensions = new Extensions(this);
notebook.appendPage('Extensions', this._extensions.actor); notebook.appendPage('Extensions', this._extensions.actor);
this._entry.clutter_text.connect('activate', (o, _e) => { this._entry.clutter_text.connect('activate', (o, e) => {
// Hide any completions we are currently showing // Hide any completions we are currently showing
this._hideCompletions(); this._hideCompletions();
@@ -903,11 +889,9 @@ var LookingGlass = class LookingGlass {
let fontDesc = Pango.FontDescription.from_string(fontName); let fontDesc = Pango.FontDescription.from_string(fontName);
// We ignore everything but size and style; you'd be crazy to set your system-wide // We ignore everything but size and style; you'd be crazy to set your system-wide
// monospace font to be bold/oblique/etc. Could easily be added here. // monospace font to be bold/oblique/etc. Could easily be added here.
let size = fontDesc.get_size() / 1024.; this.actor.style =
let unit = fontDesc.get_size_is_absolute() ? 'px' : 'pt'; 'font-size: ' + fontDesc.get_size() / 1024. + (fontDesc.get_size_is_absolute() ? 'px' : 'pt') + ';'
this.actor.style = ` + 'font-family: "' + fontDesc.get_family() + '";';
font-size: ${size}${unit};
font-family: "${fontDesc.get_family()}";`;
} }
setBorderPaintTarget(obj) { setBorderPaintTarget(obj) {
@@ -949,37 +933,31 @@ var LookingGlass = class LookingGlass {
this._completionActor.set_text(completions.join(', ')); this._completionActor.set_text(completions.join(', '));
// Setting the height to -1 allows us to get its actual preferred height rather than // Setting the height to -1 allows us to get its actual preferred height rather than
// whatever was last set when animating // whatever was last given in set_height by Tweener.
this._completionActor.set_height(-1); this._completionActor.set_height(-1);
let [, naturalHeight] = this._completionActor.get_preferred_height(this._resultsArea.get_width()); let [minHeight, naturalHeight] = this._completionActor.get_preferred_height(this._resultsArea.get_width());
// Don't reanimate if we are already visible // Don't reanimate if we are already visible
if (this._completionActor.visible) { if (this._completionActor.visible) {
this._completionActor.height = naturalHeight; this._completionActor.height = naturalHeight;
} else { } else {
let settings = St.Settings.get();
let duration = AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor;
this._completionActor.show(); this._completionActor.show();
this._completionActor.remove_all_transitions(); Tweener.removeTweens(this._completionActor);
this._completionActor.ease({ Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
transition: 'easeOutQuad',
height: naturalHeight, height: naturalHeight,
opacity: 255, opacity: 255
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
}); });
} }
} }
_hideCompletions() { _hideCompletions() {
if (this._completionActor) { if (this._completionActor) {
let settings = St.Settings.get(); Tweener.removeTweens(this._completionActor);
let duration = AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor; Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / St.get_slow_down_factor(),
this._completionActor.remove_all_transitions(); transition: 'easeOutQuad',
this._completionActor.ease({
height: 0, height: 0,
opacity: 0, opacity: 0,
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => { onComplete: () => {
this._completionActor.hide(); this._completionActor.hide();
} }
@@ -999,7 +977,7 @@ var LookingGlass = class LookingGlass {
try { try {
resultObj = Function(fullCmd)(); resultObj = Function(fullCmd)();
} catch (e) { } catch (e) {
resultObj = `<exception ${e}>`; resultObj = '<exception ' + e + '>';
} }
this._pushResult(command, resultObj); this._pushResult(command, resultObj);
@@ -1015,11 +993,7 @@ var LookingGlass = class LookingGlass {
} }
getResult(idx) { getResult(idx) {
try {
return this._results[idx - this._offset].o; return this._results[idx - this._offset].o;
} catch (e) {
throw new Error(`Unknown result at index ${idx}`);
}
} }
toggle() { toggle() {
@@ -1030,10 +1004,7 @@ var LookingGlass = class LookingGlass {
} }
_queueResize() { _queueResize() {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { this._resize(); });
this._resize();
return GLib.SOURCE_REMOVE;
});
} }
_resize() { _resize() {
@@ -1096,18 +1067,14 @@ var LookingGlass = class LookingGlass {
this._open = true; this._open = true;
this._history.lastItem(); this._history.lastItem();
this.actor.remove_all_transitions(); Tweener.removeTweens(this.actor);
// We inverse compensate for the slow-down so you can change the factor // We inverse compensate for the slow-down so you can change the factor
// through LookingGlass without long waits. // through LookingGlass without long waits.
let duration = LG_ANIMATION_TIME / St.Settings.get().slow_down_factor; Tweener.addTween(this.actor, { time: 0.5 / St.get_slow_down_factor(),
this.actor.ease({ transition: 'easeOutQuad',
y: this._targetY, y: this._targetY
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
}); });
this._windowList.update();
} }
close() { close() {
@@ -1117,25 +1084,19 @@ var LookingGlass = class LookingGlass {
this._objInspector.actor.hide(); this._objInspector.actor.hide();
this._open = false; this._open = false;
this.actor.remove_all_transitions(); Tweener.removeTweens(this.actor);
this.setBorderPaintTarget(null); this.setBorderPaintTarget(null);
Main.popModal(this._entry); Main.popModal(this._entry);
let settings = St.Settings.get(); Tweener.addTween(this.actor, { time: Math.min(0.5 / St.get_slow_down_factor(), 0.5),
let duration = Math.min(LG_ANIMATION_TIME / settings.slow_down_factor, transition: 'easeOutQuad',
LG_ANIMATION_TIME);
this.actor.ease({
y: this._hiddenY, y: this._hiddenY,
duration, onComplete: () => {
mode: Clutter.AnimationMode.EASE_OUT_QUAD, this.actor.hide();
onComplete: () => this.actor.hide()
});
} }
});
get isOpen() {
return this._open;
} }
}; };
Signals.addSignalMethods(LookingGlass.prototype); Signals.addSignalMethods(LookingGlass.prototype);

View File

@@ -2,6 +2,7 @@
const { Atspi, Clutter, GDesktopEnums, const { Atspi, Clutter, GDesktopEnums,
Gio, GLib, GObject, Meta, Shell, St } = imports.gi; Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals; const Signals = imports.signals;
const Background = imports.ui.background; const Background = imports.ui.background;
@@ -40,8 +41,10 @@ const CROSS_HAIRS_OPACITY_KEY = 'cross-hairs-opacity';
const CROSS_HAIRS_LENGTH_KEY = 'cross-hairs-length'; const CROSS_HAIRS_LENGTH_KEY = 'cross-hairs-length';
const CROSS_HAIRS_CLIP_KEY = 'cross-hairs-clip'; const CROSS_HAIRS_CLIP_KEY = 'cross-hairs-clip';
let magDBusService = null;
var MouseSpriteContent = GObject.registerClass({ var MouseSpriteContent = GObject.registerClass({
Implements: [Clutter.Content], Implements: [ Clutter.Content ],
}, class MouseSpriteContent extends GObject.Object { }, class MouseSpriteContent extends GObject.Object {
_init() { _init() {
super._init(); super._init();
@@ -106,7 +109,8 @@ var Magnifier = class Magnifier {
// Create the first ZoomRegion and initialize it according to the // Create the first ZoomRegion and initialize it according to the
// magnification settings. // magnification settings.
[this.xMouse, this.yMouse] = global.get_pointer(); let mask;
[this.xMouse, this.yMouse, mask] = global.get_pointer();
let aZoomRegion = new ZoomRegion(this, this._cursorRoot); let aZoomRegion = new ZoomRegion(this, this._cursorRoot);
this._zoomRegions.push(aZoomRegion); this._zoomRegions.push(aZoomRegion);
@@ -118,7 +122,7 @@ var Magnifier = class Magnifier {
}); });
// Export to dbus. // Export to dbus.
(new MagnifierDBus.ShellMagnifier()); magDBusService = new MagnifierDBus.ShellMagnifier();
this.setActive(St.Settings.get().magnifier_active); this.setActive(St.Settings.get().magnifier_active);
} }
@@ -146,7 +150,7 @@ var Magnifier = class Magnifier {
setActive(activate) { setActive(activate) {
let isActive = this.isActive(); let isActive = this.isActive();
this._zoomRegions.forEach(zoomRegion => { this._zoomRegions.forEach ((zoomRegion, index, array) => {
zoomRegion.setActive(activate); zoomRegion.setActive(activate);
}); });
@@ -225,14 +229,14 @@ var Magnifier = class Magnifier {
* @return true. * @return true.
*/ */
scrollToMousePos() { scrollToMousePos() {
let [xMouse, yMouse] = global.get_pointer(); let [xMouse, yMouse, mask] = global.get_pointer();
if (xMouse != this.xMouse || yMouse != this.yMouse) { if (xMouse != this.xMouse || yMouse != this.yMouse) {
this.xMouse = xMouse; this.xMouse = xMouse;
this.yMouse = yMouse; this.yMouse = yMouse;
let sysMouseOverAny = false; let sysMouseOverAny = false;
this._zoomRegions.forEach(zoomRegion => { this._zoomRegions.forEach((zoomRegion, index, array) => {
if (zoomRegion.scrollToMousePos()) if (zoomRegion.scrollToMousePos())
sysMouseOverAny = true; sysMouseOverAny = true;
}); });
@@ -264,7 +268,7 @@ var Magnifier = class Magnifier {
zoomRegion.setViewPort(viewPort); zoomRegion.setViewPort(viewPort);
// We ignore the redundant width/height on the ROI // We ignore the redundant width/height on the ROI
let fixedROI = Object.create(roi); let fixedROI = new Object(roi);
fixedROI.width = viewPort.width / xMagFactor; fixedROI.width = viewPort.width / xMagFactor;
fixedROI.height = viewPort.height / yMagFactor; fixedROI.height = viewPort.height / yMagFactor;
zoomRegion.setROI(fixedROI); zoomRegion.setROI(fixedROI);
@@ -280,7 +284,7 @@ var Magnifier = class Magnifier {
* @zoomRegion: The zoomRegion to add. * @zoomRegion: The zoomRegion to add.
*/ */
addZoomRegion(zoomRegion) { addZoomRegion(zoomRegion) {
if (zoomRegion) { if(zoomRegion) {
this._zoomRegions.push(zoomRegion); this._zoomRegions.push(zoomRegion);
if (!this.isTrackingMouse()) if (!this.isTrackingMouse())
this.startTrackingMouse(); this.startTrackingMouse();
@@ -330,7 +334,7 @@ var Magnifier = class Magnifier {
this.setCrosshairsClip(clip); this.setCrosshairsClip(clip);
let theCrossHairs = this._crossHairs; let theCrossHairs = this._crossHairs;
this._zoomRegions.forEach (zoomRegion => { this._zoomRegions.forEach ((zoomRegion, index, array) => {
zoomRegion.addCrosshairs(theCrossHairs); zoomRegion.addCrosshairs(theCrossHairs);
}); });
} }
@@ -345,7 +349,8 @@ var Magnifier = class Magnifier {
if (!this._crossHairs) if (!this._crossHairs)
this.addCrosshairs(); this.addCrosshairs();
this._crossHairs.show(); this._crossHairs.show();
} else { }
else {
if (this._crossHairs) if (this._crossHairs)
this._crossHairs.hide(); this._crossHairs.hide();
} }
@@ -358,7 +363,7 @@ var Magnifier = class Magnifier {
*/ */
setCrosshairsColor(color) { setCrosshairsColor(color) {
if (this._crossHairs) { if (this._crossHairs) {
let [res_, clutterColor] = Clutter.Color.from_string(color); let [res, clutterColor] = Clutter.Color.from_string(color);
this._crossHairs.setColor(clutterColor); this._crossHairs.setColor(clutterColor);
} }
} }
@@ -372,9 +377,9 @@ var Magnifier = class Magnifier {
if (this._crossHairs) { if (this._crossHairs) {
let clutterColor = this._crossHairs.getColor(); let clutterColor = this._crossHairs.getColor();
return clutterColor.to_string(); return clutterColor.to_string();
} else {
return '#00000000';
} }
else
return '#00000000';
} }
/** /**
@@ -451,11 +456,16 @@ var Magnifier = class Magnifier {
* @clip: Flag to indicate whether to clip the crosshairs. * @clip: Flag to indicate whether to clip the crosshairs.
*/ */
setCrosshairsClip(clip) { setCrosshairsClip(clip) {
if (!this._crossHairs) if (clip) {
return; if (this._crossHairs)
this._crossHairs.setClip(CROSSHAIRS_CLIP_SIZE);
// Setting no clipping on crosshairs means a zero sized clip rectangle. }
this._crossHairs.setClip(clip ? CROSSHAIRS_CLIP_SIZE : [0, 0]); else {
// Setting no clipping on crosshairs means a zero sized clip
// rectangle.
if (this._crossHairs)
this._crossHairs.setClip([0, 0]);
}
} }
/** /**
@@ -467,9 +477,9 @@ var Magnifier = class Magnifier {
if (this._crossHairs) { if (this._crossHairs) {
let [clipWidth, clipHeight] = this._crossHairs.getClip(); let [clipWidth, clipHeight] = this._crossHairs.getClip();
return (clipWidth > 0 && clipHeight > 0); return (clipWidth > 0 && clipHeight > 0);
} else {
return false;
} }
else
return false;
} }
//// Private methods //// //// Private methods ////
@@ -494,61 +504,61 @@ var Magnifier = class Magnifier {
_settingsInit(zoomRegion) { _settingsInit(zoomRegion) {
this._settings = new Gio.Settings({ schema_id: MAGNIFIER_SCHEMA }); this._settings = new Gio.Settings({ schema_id: MAGNIFIER_SCHEMA });
this._settings.connect(`changed::${SCREEN_POSITION_KEY}`, this._settings.connect('changed::' + SCREEN_POSITION_KEY,
this._updateScreenPosition.bind(this)); this._updateScreenPosition.bind(this));
this._settings.connect(`changed::${MAG_FACTOR_KEY}`, this._settings.connect('changed::' + MAG_FACTOR_KEY,
this._updateMagFactor.bind(this)); this._updateMagFactor.bind(this));
this._settings.connect(`changed::${LENS_MODE_KEY}`, this._settings.connect('changed::' + LENS_MODE_KEY,
this._updateLensMode.bind(this)); this._updateLensMode.bind(this));
this._settings.connect(`changed::${CLAMP_MODE_KEY}`, this._settings.connect('changed::' + CLAMP_MODE_KEY,
this._updateClampMode.bind(this)); this._updateClampMode.bind(this));
this._settings.connect(`changed::${MOUSE_TRACKING_KEY}`, this._settings.connect('changed::' + MOUSE_TRACKING_KEY,
this._updateMouseTrackingMode.bind(this)); this._updateMouseTrackingMode.bind(this));
this._settings.connect(`changed::${FOCUS_TRACKING_KEY}`, this._settings.connect('changed::' + FOCUS_TRACKING_KEY,
this._updateFocusTrackingMode.bind(this)); this._updateFocusTrackingMode.bind(this));
this._settings.connect(`changed::${CARET_TRACKING_KEY}`, this._settings.connect('changed::' + CARET_TRACKING_KEY,
this._updateCaretTrackingMode.bind(this)); this._updateCaretTrackingMode.bind(this));
this._settings.connect(`changed::${INVERT_LIGHTNESS_KEY}`, this._settings.connect('changed::' + INVERT_LIGHTNESS_KEY,
this._updateInvertLightness.bind(this)); this._updateInvertLightness.bind(this));
this._settings.connect(`changed::${COLOR_SATURATION_KEY}`, this._settings.connect('changed::' + COLOR_SATURATION_KEY,
this._updateColorSaturation.bind(this)); this._updateColorSaturation.bind(this));
this._settings.connect(`changed::${BRIGHT_RED_KEY}`, this._settings.connect('changed::' + BRIGHT_RED_KEY,
this._updateBrightness.bind(this)); this._updateBrightness.bind(this));
this._settings.connect(`changed::${BRIGHT_GREEN_KEY}`, this._settings.connect('changed::' + BRIGHT_GREEN_KEY,
this._updateBrightness.bind(this)); this._updateBrightness.bind(this));
this._settings.connect(`changed::${BRIGHT_BLUE_KEY}`, this._settings.connect('changed::' + BRIGHT_BLUE_KEY,
this._updateBrightness.bind(this)); this._updateBrightness.bind(this));
this._settings.connect(`changed::${CONTRAST_RED_KEY}`, this._settings.connect('changed::' + CONTRAST_RED_KEY,
this._updateContrast.bind(this)); this._updateContrast.bind(this));
this._settings.connect(`changed::${CONTRAST_GREEN_KEY}`, this._settings.connect('changed::' + CONTRAST_GREEN_KEY,
this._updateContrast.bind(this)); this._updateContrast.bind(this));
this._settings.connect(`changed::${CONTRAST_BLUE_KEY}`, this._settings.connect('changed::' + CONTRAST_BLUE_KEY,
this._updateContrast.bind(this)); this._updateContrast.bind(this));
this._settings.connect(`changed::${SHOW_CROSS_HAIRS_KEY}`, () => { this._settings.connect('changed::' + SHOW_CROSS_HAIRS_KEY, () => {
this.setCrosshairsVisible(this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY)); this.setCrosshairsVisible(this._settings.get_boolean(SHOW_CROSS_HAIRS_KEY));
}); });
this._settings.connect(`changed::${CROSS_HAIRS_THICKNESS_KEY}`, () => { this._settings.connect('changed::' + CROSS_HAIRS_THICKNESS_KEY, () => {
this.setCrosshairsThickness(this._settings.get_int(CROSS_HAIRS_THICKNESS_KEY)); this.setCrosshairsThickness(this._settings.get_int(CROSS_HAIRS_THICKNESS_KEY));
}); });
this._settings.connect(`changed::${CROSS_HAIRS_COLOR_KEY}`, () => { this._settings.connect('changed::' + CROSS_HAIRS_COLOR_KEY, () => {
this.setCrosshairsColor(this._settings.get_string(CROSS_HAIRS_COLOR_KEY)); this.setCrosshairsColor(this._settings.get_string(CROSS_HAIRS_COLOR_KEY));
}); });
this._settings.connect(`changed::${CROSS_HAIRS_OPACITY_KEY}`, () => { this._settings.connect('changed::' + CROSS_HAIRS_OPACITY_KEY, () => {
this.setCrosshairsOpacity(this._settings.get_double(CROSS_HAIRS_OPACITY_KEY)); this.setCrosshairsOpacity(this._settings.get_double(CROSS_HAIRS_OPACITY_KEY));
}); });
this._settings.connect(`changed::${CROSS_HAIRS_LENGTH_KEY}`, () => { this._settings.connect('changed::' + CROSS_HAIRS_LENGTH_KEY, () => {
this.setCrosshairsLength(this._settings.get_int(CROSS_HAIRS_LENGTH_KEY)); this.setCrosshairsLength(this._settings.get_int(CROSS_HAIRS_LENGTH_KEY));
}); });
this._settings.connect(`changed::${CROSS_HAIRS_CLIP_KEY}`, () => { this._settings.connect('changed::' + CROSS_HAIRS_CLIP_KEY, () => {
this.setCrosshairsClip(this._settings.get_boolean(CROSS_HAIRS_CLIP_KEY)); this.setCrosshairsClip(this._settings.get_boolean(CROSS_HAIRS_CLIP_KEY));
}); });
@@ -790,8 +800,8 @@ var ZoomRegion = class ZoomRegion {
let extents; let extents;
try { try {
extents = component.get_extents(Atspi.CoordType.SCREEN); extents = component.get_extents(Atspi.CoordType.SCREEN);
} catch (e) { } catch(e) {
log(`Failed to read extents of focused component: ${e.message}`); log('Failed to read extents of focused component: ' + e.message);
return; return;
} }
@@ -807,8 +817,8 @@ var ZoomRegion = class ZoomRegion {
let extents; let extents;
try { try {
extents = text.get_character_extents(text.get_caret_offset(), 0); extents = text.get_character_extents(text.get_caret_offset(), 0);
} catch (e) { } catch(e) {
log(`Failed to read extents of text caret: ${e.message}`); log('Failed to read extents of text caret: ' + e.message);
return; return;
} }
@@ -1020,7 +1030,7 @@ var ZoomRegion = class ZoomRegion {
viewPort.x = 0; viewPort.x = 0;
viewPort.y = 0; viewPort.y = 0;
viewPort.width = global.screen_width; viewPort.width = global.screen_width;
viewPort.height = global.screen_height / 2; viewPort.height = global.screen_height/2;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.TOP_HALF; this._screenPosition = GDesktopEnums.MagnifierScreenPosition.TOP_HALF;
} }
@@ -1032,9 +1042,9 @@ var ZoomRegion = class ZoomRegion {
setBottomHalf() { setBottomHalf() {
let viewPort = {}; let viewPort = {};
viewPort.x = 0; viewPort.x = 0;
viewPort.y = global.screen_height / 2; viewPort.y = global.screen_height/2;
viewPort.width = global.screen_width; viewPort.width = global.screen_width;
viewPort.height = global.screen_height / 2; viewPort.height = global.screen_height/2;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF; this._screenPosition = GDesktopEnums.MagnifierScreenPosition.BOTTOM_HALF;
} }
@@ -1047,7 +1057,7 @@ var ZoomRegion = class ZoomRegion {
let viewPort = {}; let viewPort = {};
viewPort.x = 0; viewPort.x = 0;
viewPort.y = 0; viewPort.y = 0;
viewPort.width = global.screen_width / 2; viewPort.width = global.screen_width/2;
viewPort.height = global.screen_height; viewPort.height = global.screen_height;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.LEFT_HALF; this._screenPosition = GDesktopEnums.MagnifierScreenPosition.LEFT_HALF;
@@ -1059,9 +1069,9 @@ var ZoomRegion = class ZoomRegion {
*/ */
setRightHalf() { setRightHalf() {
let viewPort = {}; let viewPort = {};
viewPort.x = global.screen_width / 2; viewPort.x = global.screen_width/2;
viewPort.y = 0; viewPort.y = 0;
viewPort.width = global.screen_width / 2; viewPort.width = global.screen_width/2;
viewPort.height = global.screen_height; viewPort.height = global.screen_height;
this._setViewPort(viewPort); this._setViewPort(viewPort);
this._screenPosition = GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF; this._screenPosition = GDesktopEnums.MagnifierScreenPosition.RIGHT_HALF;
@@ -1139,7 +1149,7 @@ var ZoomRegion = class ZoomRegion {
_clearScrollContentsTimer() { _clearScrollContentsTimer() {
if (this._scrollContentsTimerId != 0) { if (this._scrollContentsTimerId != 0) {
GLib.source_remove(this._scrollContentsTimerId); Mainloop.source_remove(this._scrollContentsTimerId);
this._scrollContentsTimerId = 0; this._scrollContentsTimerId = 0;
} }
} }
@@ -1151,7 +1161,7 @@ var ZoomRegion = class ZoomRegion {
} }
this._clearScrollContentsTimer(); this._clearScrollContentsTimer();
this._scrollContentsTimerId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, POINTER_REST_TIME, () => { this._scrollContentsTimerId = Mainloop.timeout_add(POINTER_REST_TIME, () => {
this._scrollContentsToDelayed(x, y); this._scrollContentsToDelayed(x, y);
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
@@ -1450,9 +1460,11 @@ var ZoomRegion = class ZoomRegion {
if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PROPORTIONAL) { if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PROPORTIONAL) {
return this._centerFromPointProportional(xMouse, yMouse); return this._centerFromPointProportional(xMouse, yMouse);
} else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PUSH) { }
else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.PUSH) {
return this._centerFromPointPush(xMouse, yMouse); return this._centerFromPointPush(xMouse, yMouse);
} else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.CENTERED) { }
else if (this._mouseTrackingMode == GDesktopEnums.MagnifierMouseTrackingMode.CENTERED) {
return this._centerFromPointCentered(xMouse, yMouse); return this._centerFromPointCentered(xMouse, yMouse);
} }
@@ -1509,7 +1521,7 @@ var ZoomRegion = class ZoomRegion {
} }
_centerFromPointProportional(xPoint, yPoint) { _centerFromPointProportional(xPoint, yPoint) {
let [xRoi_, yRoi_, widthRoi, heightRoi] = this.getROI(); let [xRoi, yRoi, widthRoi, heightRoi] = this.getROI();
let halfScreenWidth = global.screen_width / 2; let halfScreenWidth = global.screen_width / 2;
let halfScreenHeight = global.screen_height / 2; let halfScreenHeight = global.screen_height / 2;
// We want to pad with a constant distance after zooming, so divide // We want to pad with a constant distance after zooming, so divide
@@ -1520,7 +1532,7 @@ var ZoomRegion = class ZoomRegion {
let xProportion = (xPoint - halfScreenWidth) / halfScreenWidth; // -1 ... 1 let xProportion = (xPoint - halfScreenWidth) / halfScreenWidth; // -1 ... 1
let yProportion = (yPoint - halfScreenHeight) / halfScreenHeight; // -1 ... 1 let yProportion = (yPoint - halfScreenHeight) / halfScreenHeight; // -1 ... 1
let xPos = xPoint - xProportion * (widthRoi / 2 - xPadding); let xPos = xPoint - xProportion * (widthRoi / 2 - xPadding);
let yPos = yPoint - yProportion * (heightRoi / 2 - yPadding); let yPos = yPoint - yProportion * (heightRoi /2 - yPadding);
return [xPos, yPos]; return [xPos, yPos];
} }
@@ -1650,7 +1662,7 @@ var Crosshairs = class Crosshairs {
container.raise_child(magnifiedMouse, crosshairsActor); container.raise_child(magnifiedMouse, crosshairsActor);
let [xMouse, yMouse] = magnifiedMouse.get_position(); let [xMouse, yMouse] = magnifiedMouse.get_position();
let [crosshairsWidth, crosshairsHeight] = crosshairsActor.get_size(); let [crosshairsWidth, crosshairsHeight] = crosshairsActor.get_size();
crosshairsActor.set_position(xMouse - crosshairsWidth / 2, yMouse - crosshairsHeight / 2); crosshairsActor.set_position(xMouse - crosshairsWidth / 2 , yMouse - crosshairsHeight / 2);
} }
} }
return crosshairsActor; return crosshairsActor;
@@ -1766,7 +1778,8 @@ var Crosshairs = class Crosshairs {
// mouse. // mouse.
this._clipSize = size; this._clipSize = size;
this.reCenter(); this.reCenter();
} else { }
else {
// Restore the missing chunk. // Restore the missing chunk.
this._clipSize = [0, 0]; this._clipSize = [0, 0];
this.reCenter(); this.reCenter();
@@ -1805,7 +1818,9 @@ var Crosshairs = class Crosshairs {
reCenter(clipSize) { reCenter(clipSize) {
let [groupWidth, groupHeight] = this._actor.get_size(); let [groupWidth, groupHeight] = this._actor.get_size();
let leftLength = this._horizLeftHair.get_width(); let leftLength = this._horizLeftHair.get_width();
let rightLength = this._horizRightHair.get_width();
let topLength = this._vertTopHair.get_height(); let topLength = this._vertTopHair.get_height();
let bottomLength = this._vertBottomHair.get_height();
let thickness = this._horizLeftHair.get_height(); let thickness = this._horizLeftHair.get_height();
// Deal with clip rectangle. // Deal with clip rectangle.

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 ShellMagnifier */
const Gio = imports.gi.Gio; const Gio = imports.gi.Gio;
const Main = imports.ui.main; const Main = imports.ui.main;
@@ -86,7 +85,7 @@ var ShellMagnifier = class ShellMagnifier {
let ROI = { x: roi[0], y: roi[1], width: roi[2] - roi[0], height: roi[3] - roi[1] }; let ROI = { x: roi[0], y: roi[1], width: roi[2] - roi[0], height: roi[3] - roi[1] };
let viewBox = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] }; let viewBox = { x: viewPort[0], y: viewPort[1], width: viewPort[2] - viewPort[0], height: viewPort[3] - viewPort[1] };
let realZoomRegion = Main.magnifier.createZoomRegion(xMagFactor, yMagFactor, ROI, viewBox); let realZoomRegion = Main.magnifier.createZoomRegion(xMagFactor, yMagFactor, ROI, viewBox);
let objectPath = `${ZOOM_SERVICE_PATH}/zoomer${_zoomRegionInstanceCount}`; let objectPath = ZOOM_SERVICE_PATH + '/zoomer' + _zoomRegionInstanceCount;
_zoomRegionInstanceCount++; _zoomRegionInstanceCount++;
let zoomRegionProxy = new ShellMagnifierZoomRegion(objectPath, realZoomRegion); let zoomRegionProxy = new ShellMagnifierZoomRegion(objectPath, realZoomRegion);
@@ -107,9 +106,9 @@ var ShellMagnifier = class ShellMagnifier {
if (proxyAndZoomRegion && proxyAndZoomRegion.zoomRegion) { if (proxyAndZoomRegion && proxyAndZoomRegion.zoomRegion) {
Main.magnifier.addZoomRegion(proxyAndZoomRegion.zoomRegion); Main.magnifier.addZoomRegion(proxyAndZoomRegion.zoomRegion);
return true; return true;
} else {
return false;
} }
else
return false;
} }
/** /**
@@ -125,7 +124,7 @@ var ShellMagnifier = class ShellMagnifier {
let zoomRegions = Main.magnifier.getZoomRegions(); let zoomRegions = Main.magnifier.getZoomRegions();
let objectPaths = []; let objectPaths = [];
let thoseZoomers = this._zoomers; let thoseZoomers = this._zoomers;
zoomRegions.forEach (aZoomRegion => { zoomRegions.forEach ((aZoomRegion, index, array) => {
let found = false; let found = false;
for (let objectPath in thoseZoomers) { for (let objectPath in thoseZoomers) {
let proxyAndZoomRegion = thoseZoomers[objectPath]; let proxyAndZoomRegion = thoseZoomers[objectPath];

View File

@@ -1,14 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported componentManager, notificationDaemon, windowAttentionHandler,
ctrlAltTabManager, padOsdService, osdWindowManager,
osdMonitorLabeler, shellMountOpDBusService, shellDBusService,
shellAccessDialogDBusService, shellAudioSelectionDBusService,
screenSaverDBus, screencastService, uiGroup, magnifier,
xdndHandler, keyboard, kbdA11yDialog, introspectService,
start, pushModal, popModal, activateWindow, createLookingGlass,
initializeDeferredWork, getThemeStylesheet, setThemeStylesheet */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const AccessDialog = imports.ui.accessDialog; const AccessDialog = imports.ui.accessDialog;
const AudioDeviceSelection = imports.ui.audioDeviceSelection; const AudioDeviceSelection = imports.ui.audioDeviceSelection;
@@ -53,7 +46,6 @@ const LOG_DOMAIN = 'GNOME Shell';
const GNOMESHELL_STARTED_MESSAGE_ID = 'f3ea493c22934e26811cd62abe8e203a'; const GNOMESHELL_STARTED_MESSAGE_ID = 'f3ea493c22934e26811cd62abe8e203a';
var componentManager = null; var componentManager = null;
var extensionManager = null;
var panel = null; var panel = null;
var overview = null; var overview = null;
var runDialog = null; var runDialog = null;
@@ -92,6 +84,7 @@ let _cssStylesheet = null;
let _a11ySettings = null; let _a11ySettings = null;
let _themeResource = null; let _themeResource = null;
let _oskResource = null; let _oskResource = null;
let pointerA11yTimeout = null;
function _sessionUpdated() { function _sessionUpdated() {
if (sessionMode.isPrimary) if (sessionMode.isPrimary)
@@ -164,8 +157,8 @@ function _initializeUI() {
// Setup the stage hierarchy early // Setup the stage hierarchy early
layoutManager = new Layout.LayoutManager(); layoutManager = new Layout.LayoutManager();
// Various parts of the codebase still refer to Main.uiGroup // Various parts of the codebase still refers to Main.uiGroup
// instead of using the layoutManager. This keeps that code // instead using the layoutManager. This keeps that code
// working until it's updated. // working until it's updated.
uiGroup = layoutManager.uiGroup; uiGroup = layoutManager.uiGroup;
@@ -179,7 +172,7 @@ function _initializeUI() {
kbdA11yDialog = new KbdA11yDialog.KbdA11yDialog(); kbdA11yDialog = new KbdA11yDialog.KbdA11yDialog();
wm = new WindowManager.WindowManager(); wm = new WindowManager.WindowManager();
magnifier = new Magnifier.Magnifier(); magnifier = new Magnifier.Magnifier();
locatePointer = new LocatePointer.LocatePointer(); locatePointer = new LocatePointer.locatePointer();
if (LoginManager.canLock()) if (LoginManager.canLock())
screenShield = new ScreenShield.ScreenShield(); screenShield = new ScreenShield.ScreenShield();
@@ -199,7 +192,7 @@ function _initializeUI() {
layoutManager.init(); layoutManager.init();
overview.init(); overview.init();
(new PointerA11yTimeout.PointerA11yTimeout()); pointerA11yTimeout = new PointerA11yTimeout.PointerA11yTimeout();
_a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA }); _a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA });
@@ -229,17 +222,12 @@ function _initializeUI() {
EndSessionDialog.init(); EndSessionDialog.init();
// We're ready for the session manager to move to the next phase // We're ready for the session manager to move to the next phase
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
Shell.util_sd_notify();
Meta.register_with_session(); Meta.register_with_session();
return GLib.SOURCE_REMOVE;
});
_startDate = new Date(); _startDate = new Date();
ExtensionDownloader.init(); ExtensionDownloader.init();
extensionManager = new ExtensionSystem.ExtensionManager(); ExtensionSystem.init();
extensionManager.init();
if (sessionMode.isGreeter && screenShield) { if (sessionMode.isGreeter && screenShield) {
layoutManager.connect('startup-prepared', () => { layoutManager.connect('startup-prepared', () => {
@@ -262,25 +250,12 @@ function _initializeUI() {
}); });
} }
let credentials = new Gio.Credentials();
if (credentials.get_unix_user() === 0) {
notify(_('Logged in as a privileged user'),
_('Running a session as a privileged user should be avoided for security reasons. If possible, you should log in as a normal user.'));
}
if (sessionMode.currentMode !== 'gdm' &&
sessionMode.currentMode !== 'initial-setup' &&
screenShield === null) {
notify(_('Screen Lock disabled'),
_('Screen Locking requires the GNOME display manager.'));
}
LoginManager.registerSessionWithGDM(); LoginManager.registerSessionWithGDM();
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE"); let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
if (perfModuleName) { if (perfModuleName) {
let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT"); let perfOutput = GLib.getenv("SHELL_PERF_OUTPUT");
let module = eval(`imports.perf.${perfModuleName};`); let module = eval('imports.perf.' + perfModuleName + ';');
Scripting.runPerfScript(module, perfOutput); Scripting.runPerfScript(module, perfOutput);
} }
}); });
@@ -416,9 +391,9 @@ function notify(msg, details) {
function notifyError(msg, details) { function notifyError(msg, details) {
// Also print to stderr so it's logged somewhere // Also print to stderr so it's logged somewhere
if (details) if (details)
log(`error: ${msg}: ${details}`); log('error: ' + msg + ': ' + details);
else else
log(`error: ${msg}`); log('error: ' + msg);
notify(msg, details); notify(msg, details);
} }
@@ -501,7 +476,7 @@ function pushModal(actor, params) {
/** /**
* popModal: * popModal:
* @actor: #ClutterActor passed to original invocation of pushModal() * @actor: #ClutterActor passed to original invocation of pushModal().
* @timestamp: optional timestamp * @timestamp: optional timestamp
* *
* Reverse the effect of pushModal(). If this invocation is undoing * Reverse the effect of pushModal(). If this invocation is undoing
@@ -636,7 +611,7 @@ function _runDeferredWork(workId) {
_deferredWorkQueue.splice(index, 1); _deferredWorkQueue.splice(index, 1);
_deferredWorkData[workId].callback(); _deferredWorkData[workId].callback();
if (_deferredWorkQueue.length == 0 && _deferredTimeoutId > 0) { if (_deferredWorkQueue.length == 0 && _deferredTimeoutId > 0) {
GLib.source_remove(_deferredTimeoutId); Mainloop.source_remove(_deferredTimeoutId);
_deferredTimeoutId = 0; _deferredTimeoutId = 0;
} }
} }
@@ -682,13 +657,13 @@ function _queueBeforeRedraw(workId) {
* *
* Returns: A string work identifier * Returns: A string work identifier
*/ */
function initializeDeferredWork(actor, callback) { function initializeDeferredWork(actor, callback, props) {
// Turn into a string so we can use as an object property // Turn into a string so we can use as an object property
let workId = `${(++_deferredWorkSequence)}`; let workId = '' + (++_deferredWorkSequence);
_deferredWorkData[workId] = { 'actor': actor, _deferredWorkData[workId] = { 'actor': actor,
'callback': callback }; 'callback': callback };
actor.connect('notify::mapped', () => { actor.connect('notify::mapped', () => {
if (!(actor.mapped && _deferredWorkQueue.includes(workId))) if (!(actor.mapped && _deferredWorkQueue.indexOf(workId) >= 0))
return; return;
_queueBeforeRedraw(workId); _queueBeforeRedraw(workId);
}); });
@@ -718,12 +693,13 @@ function queueDeferredWork(workId) {
logError(new Error(message), message); logError(new Error(message), message);
return; return;
} }
if (!_deferredWorkQueue.includes(workId)) if (_deferredWorkQueue.indexOf(workId) < 0)
_deferredWorkQueue.push(workId); _deferredWorkQueue.push(workId);
if (data.actor.mapped) { if (data.actor.mapped) {
_queueBeforeRedraw(workId); _queueBeforeRedraw(workId);
return;
} else if (_deferredTimeoutId == 0) { } else if (_deferredTimeoutId == 0) {
_deferredTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, DEFERRED_TIMEOUT_SECONDS, () => { _deferredTimeoutId = Mainloop.timeout_add_seconds(DEFERRED_TIMEOUT_SECONDS, () => {
_runAllDeferredWork(); _runAllDeferredWork();
_deferredTimeoutId = 0; _deferredTimeoutId = 0;
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;

View File

@@ -4,9 +4,10 @@ const MessageTray = imports.ui.messageTray;
const Signals = imports.signals; const Signals = imports.signals;
const Calendar = imports.ui.calendar; const Calendar = imports.ui.calendar;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util; const Util = imports.misc.util;
var MESSAGE_ANIMATION_TIME = 100; var MESSAGE_ANIMATION_TIME = 0.1;
var DEFAULT_EXPAND_LINES = 6; var DEFAULT_EXPAND_LINES = 6;
@@ -32,7 +33,9 @@ function _fixMarkup(text, allowMarkup) {
} }
var URLHighlighter = class URLHighlighter { var URLHighlighter = class URLHighlighter {
constructor(text = '', lineWrap, allowMarkup) { constructor(text, lineWrap, allowMarkup) {
if (!text)
text = '';
this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter', this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter',
x_expand: true, x_align: Clutter.ActorAlign.START }); x_expand: true, x_align: Clutter.ActorAlign.START });
this._linkColor = '#ccccff'; this._linkColor = '#ccccff';
@@ -69,7 +72,7 @@ var URLHighlighter = class URLHighlighter {
let urlId = this._findUrlAtPos(event); let urlId = this._findUrlAtPos(event);
if (urlId != -1) { if (urlId != -1) {
let url = this._urls[urlId].url; let url = this._urls[urlId].url;
if (!url.includes(':')) if (url.indexOf(':') == -1)
url = 'http://' + url; url = 'http://' + url;
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1)); Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
@@ -129,20 +132,20 @@ var URLHighlighter = class URLHighlighter {
} }
_findUrlAtPos(event) { _findUrlAtPos(event) {
let success_; let success;
let [x, y] = event.get_coords(); let [x, y] = event.get_coords();
[success_, x, y] = this.actor.transform_stage_point(x, y); [success, x, y] = this.actor.transform_stage_point(x, y);
let findPos = -1; let find_pos = -1;
for (let i = 0; i < this.actor.clutter_text.text.length; i++) { for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
let [success_, px, py, lineHeight] = this.actor.clutter_text.position_to_coords(i); let [success, px, py, line_height] = this.actor.clutter_text.position_to_coords(i);
if (py > y || py + lineHeight < y || x < px) if (py > y || py + line_height < y || x < px)
continue; continue;
findPos = i; find_pos = i;
} }
if (findPos != -1) { if (find_pos != -1) {
for (let i = 0; i < this._urls.length; i++) for (let i = 0; i < this._urls.length; i++)
if (findPos >= this._urls[i].pos && if (find_pos >= this._urls[i].pos &&
this._urls[i].pos + this._urls[i].url.length > findPos) this._urls[i].pos + this._urls[i].url.length > find_pos)
return i; return i;
} }
return -1; return -1;
@@ -194,14 +197,12 @@ class ScaleLayout extends Clutter.BinLayout {
}); });
var LabelExpanderLayout = GObject.registerClass({ var LabelExpanderLayout = GObject.registerClass({
Properties: { Properties: { 'expansion': GObject.ParamSpec.double('expansion',
'expansion': GObject.ParamSpec.double('expansion',
'Expansion', 'Expansion',
'Expansion of the layout, between 0 (collapsed) ' + 'Expansion of the layout, between 0 (collapsed) ' +
'and 1 (fully expanded', 'and 1 (fully expanded',
GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE, GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE,
0, 1, 0) 0, 1, 0)},
},
}, class LabelExpanderLayout extends Clutter.LayoutManager { }, class LabelExpanderLayout extends Clutter.LayoutManager {
_init(params) { _init(params) {
this._expansion = 0; this._expansion = 0;
@@ -439,17 +440,15 @@ var Message = class Message {
} }
if (animate) { if (animate) {
this._bodyStack.ease_property('@layout.expansion', 1, { Tweener.addTween(this._bodyStack.layout_manager,
progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD, { expansion: 1,
duration: MessageTray.ANIMATION_TIME, time: MessageTray.ANIMATION_TIME,
}); transition: 'easeOutQuad' });
this._actionBin.scale_y = 0; this._actionBin.scale_y = 0;
this._actionBin.ease({ Tweener.addTween(this._actionBin,
scale_y: 1, { scale_y: 1,
duration: MessageTray.ANIMATION_TIME, time: MessageTray.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad' });
});
} else { } else {
this._bodyStack.layout_manager.expansion = 1; this._bodyStack.layout_manager.expansion = 1;
this._actionBin.scale_y = 1; this._actionBin.scale_y = 1;
@@ -460,20 +459,19 @@ var Message = class Message {
unexpand(animate) { unexpand(animate) {
if (animate) { if (animate) {
this._bodyStack.ease_property('@layout.expansion', 0, { Tweener.addTween(this._bodyStack.layout_manager,
progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD, { expansion: 0,
duration: MessageTray.ANIMATION_TIME, time: MessageTray.ANIMATION_TIME,
}); transition: 'easeOutQuad' });
Tweener.addTween(this._actionBin,
this._actionBin.ease({ { scale_y: 0,
scale_y: 0, time: MessageTray.ANIMATION_TIME,
duration: MessageTray.ANIMATION_TIME, transition: 'easeOutQuad',
mode: Clutter.AnimationMode.EASE_OUT_QUAD, onCompleteScope: this,
onComplete: () => { onComplete() {
this._actionBin.hide(); this._actionBin.hide();
this.expanded = false; this.expanded = false;
} }});
});
} else { } else {
this._bodyStack.layout_manager.expansion = 0; this._bodyStack.layout_manager.expansion = 0;
this._actionBin.scale_y = 0; this._actionBin.scale_y = 0;
@@ -584,12 +582,10 @@ var MessageListSection = class MessageListSection {
this._list.insert_child_at_index(obj.container, index); this._list.insert_child_at_index(obj.container, index);
if (animate) if (animate)
obj.container.ease({ Tweener.addTween(obj.container, { scale_x: 1,
scale_x: 1,
scale_y: 1, scale_y: 1,
duration: MESSAGE_ANIMATION_TIME, time: MESSAGE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad' });
});
} }
moveMessage(message, index, animate) { moveMessage(message, index, animate) {
@@ -602,20 +598,16 @@ var MessageListSection = class MessageListSection {
let onComplete = () => { let onComplete = () => {
this._list.set_child_at_index(obj.container, index); this._list.set_child_at_index(obj.container, index);
obj.container.ease({ Tweener.addTween(obj.container, { scale_x: 1,
scale_x: 1,
scale_y: 1, scale_y: 1,
duration: MESSAGE_ANIMATION_TIME, time: MESSAGE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD transition: 'easeOutQuad' });
});
}; };
obj.container.ease({ Tweener.addTween(obj.container, { scale_x: 0,
scale_x: 0,
scale_y: 0, scale_y: 0,
duration: MESSAGE_ANIMATION_TIME, time: MESSAGE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete onComplete: onComplete });
});
} }
removeMessage(message, animate) { removeMessage(message, animate) {
@@ -628,16 +620,13 @@ var MessageListSection = class MessageListSection {
this._messages.delete(message); this._messages.delete(message);
if (animate) { if (animate) {
obj.container.ease({ Tweener.addTween(obj.container, { scale_x: 0, scale_y: 0,
scale_x: 0, time: MESSAGE_ANIMATION_TIME,
scale_y: 0, transition: 'easeOutQuad',
duration: MESSAGE_ANIMATION_TIME, onComplete() {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
obj.container.destroy(); obj.container.destroy();
global.sync_pointer(); global.sync_pointer();
} }});
});
} else { } else {
obj.container.destroy(); obj.container.destroy();
global.sync_pointer(); global.sync_pointer();
@@ -659,14 +648,15 @@ var MessageListSection = class MessageListSection {
for (let i = 0; i < messages.length; i++) { for (let i = 0; i < messages.length; i++) {
let message = messages[i]; let message = messages[i];
let obj = this._messages.get(message); let obj = this._messages.get(message);
obj.container.ease({ Tweener.addTween(obj.container,
anchor_x: this._list.width, { anchor_x: this._list.width,
opacity: 0, opacity: 0,
duration: MESSAGE_ANIMATION_TIME, time: MESSAGE_ANIMATION_TIME,
delay: i * delay, delay: i * delay,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => message.close() onComplete() {
}); message.close();
}});
} }
} }
} }

View File

@@ -1,9 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NotificationPolicy, NotificationGenericPolicy,
NotificationApplicationPolicy, Source, SourceActor, SourceActorWithLabel,
SystemNotificationSource, MessageTray */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals; const Signals = imports.signals;
const Calendar = imports.ui.calendar; const Calendar = imports.ui.calendar;
@@ -11,14 +9,15 @@ const GnomeSession = imports.misc.gnomeSession;
const Layout = imports.ui.layout; const Layout = imports.ui.layout;
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 SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings'; const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
var ANIMATION_TIME = 200; var ANIMATION_TIME = 0.2;
var NOTIFICATION_TIMEOUT = 4000; var NOTIFICATION_TIMEOUT = 4;
var HIDE_TIMEOUT = 200; var HIDE_TIMEOUT = 0.2;
var LONGER_HIDE_TIMEOUT = 600; var LONGER_HIDE_TIMEOUT = 0.6;
var MAX_NOTIFICATIONS_IN_QUEUE = 3; var MAX_NOTIFICATIONS_IN_QUEUE = 3;
var MAX_NOTIFICATIONS_PER_SOURCE = 3; var MAX_NOTIFICATIONS_PER_SOURCE = 3;
@@ -136,13 +135,12 @@ var FocusGrabber = class FocusGrabber {
// A notification without a policy object will inherit the default one. // A notification without a policy object will inherit the default one.
var NotificationPolicy = class NotificationPolicy { var NotificationPolicy = class NotificationPolicy {
constructor(params) { constructor(params) {
params = Params.parse(params, { params = Params.parse(params, { enable: true,
enable: true,
enableSound: true, enableSound: true,
showBanners: true, showBanners: true,
forceExpanded: false, forceExpanded: false,
showInLockScreen: true, showInLockScreen: true,
detailsInLockScreen: false, detailsInLockScreen: false
}); });
Object.getOwnPropertyNames(params).forEach(key => { Object.getOwnPropertyNames(params).forEach(key => {
let desc = Object.getOwnPropertyDescriptor(params, key); let desc = Object.getOwnPropertyDescriptor(params, key);
@@ -153,7 +151,6 @@ var NotificationPolicy = class NotificationPolicy {
// Do nothing for the default policy. These methods are only useful for the // Do nothing for the default policy. These methods are only useful for the
// GSettings policy. // GSettings policy.
store() { } store() { }
destroy() { } destroy() { }
get enable() { get enable() {
@@ -221,17 +218,17 @@ class NotificationApplicationPolicy extends NotificationPolicy {
this._masterSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications' }); this._masterSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications' });
this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications.application', this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications.application',
path: `/org/gnome/desktop/notifications/application/${this._canonicalId}/` }); path: '/org/gnome/desktop/notifications/application/' + this._canonicalId + '/' });
this._masterSettings.connect('changed', this._changed.bind(this)); this._masterSettings.connect('changed', this._changed.bind(this));
this._settings.connect('changed', this._changed.bind(this)); this._settings.connect('changed', this._changed.bind(this));
} }
store() { store() {
this._settings.set_string('application-id', `${this.id}.desktop`); this._settings.set_string('application-id', this.id + '.desktop');
let apps = this._masterSettings.get_strv('application-children'); let apps = this._masterSettings.get_strv('application-children');
if (!apps.includes(this._canonicalId)) { if (apps.indexOf(this._canonicalId) < 0) {
apps.push(this._canonicalId); apps.push(this._canonicalId);
this._masterSettings.set_strv('application-children', apps); this._masterSettings.set_strv('application-children', apps);
} }
@@ -251,7 +248,7 @@ class NotificationApplicationPolicy extends NotificationPolicy {
_canonicalizeId(id) { _canonicalizeId(id) {
// Keys are restricted to lowercase alphanumeric characters and dash, // Keys are restricted to lowercase alphanumeric characters and dash,
// and two dashes cannot be in succession // and two dashes cannot be in succession
return id.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/--+/g, '-'); return id.toLowerCase().replace(/[^a-z0-9\-]/g, '-').replace(/--+/g, '-');
} }
get enable() { get enable() {
@@ -476,7 +473,9 @@ var Notification = class Notification {
this.destroy(); this.destroy();
} }
destroy(reason = NotificationDestroyedReason.DISMISSED) { destroy(reason) {
if (!reason)
reason = NotificationDestroyedReason.DISMISSED;
this.emit('destroy', reason); this.emit('destroy', reason);
} }
}; };
@@ -591,11 +590,11 @@ class SourceActor extends St.Widget {
}); });
this._actorDestroyed = false; this._actorDestroyed = false;
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scale_factor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._iconBin = new St.Bin({ x_fill: true, this._iconBin = new St.Bin({ x_fill: true,
x_expand: true, x_expand: true,
height: size * scaleFactor, height: size * scale_factor,
width: size * scaleFactor }); width: size * scale_factor });
this.add_actor(this._iconBin); this.add_actor(this._iconBin);
@@ -653,7 +652,7 @@ class SourceActorWithLabel extends SourceActor {
let childBox = new Clutter.ActorBox(); let childBox = new Clutter.ActorBox();
let [, , naturalWidth, naturalHeight] = this._counterBin.get_preferred_size(); let [minWidth, minHeight, naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
let direction = this.get_text_direction(); let direction = this.get_text_direction();
if (direction == Clutter.TextDirection.LTR) { if (direction == Clutter.TextDirection.LTR) {
@@ -735,8 +734,7 @@ var Source = class Source {
} }
get narrowestPrivacyScope() { get narrowestPrivacyScope() {
return this.notifications.every(n => n.privacyScope == PrivacyScope.SYSTEM) return this.notifications.every(n => n.privacyScope == PrivacyScope.SYSTEM) ? PrivacyScope.SYSTEM
? PrivacyScope.SYSTEM
: PrivacyScope.USER; : PrivacyScope.USER;
} }
@@ -774,7 +772,7 @@ var Source = class Source {
} }
pushNotification(notification) { pushNotification(notification) {
if (this.notifications.includes(notification)) if (this.notifications.indexOf(notification) >= 0)
return; return;
while (this.notifications.length >= MAX_NOTIFICATIONS_PER_SOURCE) while (this.notifications.length >= MAX_NOTIFICATIONS_PER_SOURCE)
@@ -831,7 +829,7 @@ Signals.addSignalMethods(Source.prototype);
var MessageTray = class MessageTray { var MessageTray = class MessageTray {
constructor() { constructor() {
this._presence = new GnomeSession.Presence((proxy, _error) => { this._presence = new GnomeSession.Presence((proxy, error) => {
this._onStatusChanged(proxy.status); this._onStatusChanged(proxy.status);
}); });
this._busy = false; this._busy = false;
@@ -990,7 +988,7 @@ var MessageTray = class MessageTray {
add(source) { add(source) {
if (this.contains(source)) { if (this.contains(source)) {
log(`Trying to re-add source ${source.title}`); log('Trying to re-add source ' + source.title);
return; return;
} }
@@ -1006,6 +1004,7 @@ var MessageTray = class MessageTray {
_addSource(source) { _addSource(source) {
let obj = { let obj = {
source: source,
notifyId: 0, notifyId: 0,
destroyId: 0, destroyId: 0,
}; };
@@ -1070,7 +1069,7 @@ var MessageTray = class MessageTray {
// If a new notification is updated while it is being hidden, // If a new notification is updated while it is being hidden,
// we stop hiding it and show it again. // we stop hiding it and show it again.
this._updateShowingNotification(); this._updateShowingNotification();
} else if (!this._notificationQueue.includes(notification)) { } else if (this._notificationQueue.indexOf(notification) < 0) {
// If the queue is "full", we skip banner mode and just show a small // If the queue is "full", we skip banner mode and just show a small
// indicator in the panel; however do make an exception for CRITICAL // indicator in the panel; however do make an exception for CRITICAL
// notifications, as only banner mode allows expansion. // notifications, as only banner mode allows expansion.
@@ -1092,7 +1091,7 @@ var MessageTray = class MessageTray {
_resetNotificationLeftTimeout() { _resetNotificationLeftTimeout() {
this._useLongerNotificationLeftTimeout = false; this._useLongerNotificationLeftTimeout = false;
if (this._notificationLeftTimeoutId) { if (this._notificationLeftTimeoutId) {
GLib.source_remove(this._notificationLeftTimeoutId); Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0; this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1; this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1; this._notificationLeftMouseY = -1;
@@ -1130,15 +1129,15 @@ var MessageTray = class MessageTray {
// this._onNotificationLeftTimeout() to determine if the mouse has moved far enough during the initial timeout for us // this._onNotificationLeftTimeout() to determine if the mouse has moved far enough during the initial timeout for us
// to consider that the user intended to leave the tray and therefore hide the tray. If the mouse is still // to consider that the user intended to leave the tray and therefore hide the tray. If the mouse is still
// close to its previous position, we extend the timeout once. // close to its previous position, we extend the timeout once.
let [x, y] = global.get_pointer(); let [x, y, mods] = global.get_pointer();
this._notificationLeftMouseX = x; this._notificationLeftMouseX = x;
this._notificationLeftMouseY = y; this._notificationLeftMouseY = y;
// We wait just a little before hiding the message tray in case the user quickly moves the mouse back into it. // We wait just a little before hiding the message tray in case the user quickly moves the mouse back into it.
// We wait for a longer period if the notification popped up where the mouse pointer was already positioned. // We wait for a longer period if the notification popped up where the mouse pointer was already positioned.
// That gives the user more time to mouse away from the notification and mouse back in in order to expand it. // That gives the user more time to mouse away from the notification and mouse back in in order to expand it.
let timeout = this._useLongerNotificationLeftTimeout ? LONGER_HIDE_TIMEOUT : HIDE_TIMEOUT; let timeout = this._useLongerNotificationLeftTimeout ? LONGER_HIDE_TIMEOUT * 1000 : HIDE_TIMEOUT * 1000;
this._notificationLeftTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, this._onNotificationLeftTimeout.bind(this)); this._notificationLeftTimeoutId = Mainloop.timeout_add(timeout, this._onNotificationLeftTimeout.bind(this));
GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout'); GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout');
} }
} }
@@ -1159,7 +1158,7 @@ var MessageTray = class MessageTray {
} }
_onNotificationLeftTimeout() { _onNotificationLeftTimeout() {
let [x, y] = global.get_pointer(); let [x, y, mods] = global.get_pointer();
// We extend the timeout once if the mouse moved no further than MOUSE_LEFT_ACTOR_THRESHOLD to either side. // We extend the timeout once if the mouse moved no further than MOUSE_LEFT_ACTOR_THRESHOLD to either side.
if (this._notificationLeftMouseX > -1 && if (this._notificationLeftMouseX > -1 &&
y < this._notificationLeftMouseY + MOUSE_LEFT_ACTOR_THRESHOLD && y < this._notificationLeftMouseY + MOUSE_LEFT_ACTOR_THRESHOLD &&
@@ -1167,9 +1166,7 @@ var MessageTray = class MessageTray {
x < this._notificationLeftMouseX + MOUSE_LEFT_ACTOR_THRESHOLD && x < this._notificationLeftMouseX + MOUSE_LEFT_ACTOR_THRESHOLD &&
x > this._notificationLeftMouseX - MOUSE_LEFT_ACTOR_THRESHOLD) { x > this._notificationLeftMouseX - MOUSE_LEFT_ACTOR_THRESHOLD) {
this._notificationLeftMouseX = -1; this._notificationLeftMouseX = -1;
this._notificationLeftTimeoutId = GLib.timeout_add( this._notificationLeftTimeoutId = Mainloop.timeout_add(LONGER_HIDE_TIMEOUT * 1000,
GLib.PRIORITY_DEFAULT,
LONGER_HIDE_TIMEOUT,
this._onNotificationLeftTimeout.bind(this)); this._onNotificationLeftTimeout.bind(this));
GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout'); GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout');
} else { } else {
@@ -1251,6 +1248,34 @@ var MessageTray = class MessageTray {
this._notificationExpired = false; this._notificationExpired = false;
} }
_tween(actor, statevar, value, params) {
let onComplete = params.onComplete;
let onCompleteScope = params.onCompleteScope;
let onCompleteParams = params.onCompleteParams;
params.onComplete = this._tweenComplete;
params.onCompleteScope = this;
params.onCompleteParams = [statevar, value, onComplete, onCompleteScope, onCompleteParams];
// Remove other tweens that could mess with the state machine
Tweener.removeTweens(actor);
Tweener.addTween(actor, params);
let valuing = (value == State.SHOWN) ? State.SHOWING : State.HIDING;
this[statevar] = valuing;
}
_tweenComplete(statevar, value, onComplete, onCompleteScope, onCompleteParams) {
this[statevar] = value;
if (onComplete)
onComplete.apply(onCompleteScope, onCompleteParams);
this._updateState();
}
_clampOpacity() {
this._bannerBin.opacity = Math.max(0, Math.min(this._bannerBin._opacity, 255));
}
_onIdleMonitorBecameActive() { _onIdleMonitorBecameActive() {
this._userActiveWhileNotificationShown = true; this._userActiveWhileNotificationShown = true;
this._updateNotificationTimeout(2000); this._updateNotificationTimeout(2000);
@@ -1277,6 +1302,7 @@ var MessageTray = class MessageTray {
this._bannerBin.add_actor(this._banner.actor); this._bannerBin.add_actor(this._banner.actor);
this._bannerBin._opacity = 0;
this._bannerBin.opacity = 0; this._bannerBin.opacity = 0;
this._bannerBin.y = -this._banner.actor.height; this._bannerBin.y = -this._banner.actor.height;
this.actor.show(); this.actor.show();
@@ -1284,7 +1310,7 @@ var MessageTray = class MessageTray {
Meta.disable_unredirect_for_display(global.display); Meta.disable_unredirect_for_display(global.display);
this._updateShowingNotification(); this._updateShowingNotification();
let [x, y] = global.get_pointer(); let [x, y, mods] = global.get_pointer();
// We save the position of the mouse at the time when we started showing the notification // We save the position of the mouse at the time when we started showing the notification
// in order to determine if the notification popped up under it. We make that check if // in order to determine if the notification popped up under it. We make that check if
// the user starts moving the mouse and _onNotificationHoverChanged() gets called. We don't // the user starts moving the mouse and _onNotificationHoverChanged() gets called. We don't
@@ -1322,45 +1348,39 @@ var MessageTray = class MessageTray {
// We use this._showNotificationCompleted() onComplete callback to extend the time the updated // We use this._showNotificationCompleted() onComplete callback to extend the time the updated
// notification is being shown. // notification is being shown.
this._notificationState = State.SHOWING; let tweenParams = { y: 0,
this._bannerBin.remove_all_transitions(); _opacity: 255,
this._bannerBin.ease({ time: ANIMATION_TIME,
opacity: 255, transition: 'easeOutBack',
duration: ANIMATION_TIME, onUpdate: this._clampOpacity,
mode: Clutter.AnimationMode.LINEAR onUpdateScope: this,
}); onComplete: this._showNotificationCompleted,
this._bannerBin.ease({ onCompleteScope: this
y: 0, };
duration: ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_BACK, this._tween(this._bannerBin, '_notificationState', State.SHOWN, tweenParams);
onComplete: () => {
this._notificationState = State.SHOWN;
this._showNotificationCompleted();
this._updateState();
}
});
} }
_showNotificationCompleted() { _showNotificationCompleted() {
if (this._notification.urgency != Urgency.CRITICAL) if (this._notification.urgency != Urgency.CRITICAL)
this._updateNotificationTimeout(NOTIFICATION_TIMEOUT); this._updateNotificationTimeout(NOTIFICATION_TIMEOUT * 1000);
} }
_updateNotificationTimeout(timeout) { _updateNotificationTimeout(timeout) {
if (this._notificationTimeoutId) { if (this._notificationTimeoutId) {
GLib.source_remove(this._notificationTimeoutId); Mainloop.source_remove(this._notificationTimeoutId);
this._notificationTimeoutId = 0; this._notificationTimeoutId = 0;
} }
if (timeout > 0) { if (timeout > 0) {
this._notificationTimeoutId = this._notificationTimeoutId =
GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, Mainloop.timeout_add(timeout,
this._notificationTimeout.bind(this)); this._notificationTimeout.bind(this));
GLib.Source.set_name_by_id(this._notificationTimeoutId, '[gnome-shell] this._notificationTimeout'); GLib.Source.set_name_by_id(this._notificationTimeoutId, '[gnome-shell] this._notificationTimeout');
} }
} }
_notificationTimeout() { _notificationTimeout() {
let [x, y] = global.get_pointer(); let [x, y, mods] = global.get_pointer();
if (y < this._lastSeenMouseY - 10 && !this._notificationHovered) { if (y < this._lastSeenMouseY - 10 && !this._notificationHovered) {
// The mouse is moving towards the notification, so don't // The mouse is moving towards the notification, so don't
// hide it yet. (We just create a new timeout (and destroy // hide it yet. (We just create a new timeout (and destroy
@@ -1396,26 +1416,20 @@ var MessageTray = class MessageTray {
} }
this._resetNotificationLeftTimeout(); this._resetNotificationLeftTimeout();
this._bannerBin.remove_all_transitions();
if (animate) { if (animate) {
this._notificationState = State.HIDING; this._tween(this._bannerBin, '_notificationState', State.HIDDEN,
this._bannerBin.ease({ { y: -this._bannerBin.height,
opacity: 0, _opacity: 0,
duration: ANIMATION_TIME, time: ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_BACK transition: 'easeOutBack',
}); onUpdate: this._clampOpacity,
this._bannerBin.ease({ onUpdateScope: this,
y: -this._bannerBin.height, onComplete: this._hideNotificationCompleted,
duration: ANIMATION_TIME, onCompleteScope: this
mode: Clutter.AnimationMode.EASE_OUT_BACK,
onComplete: () => {
this._notificationState = State.HIDDEN;
this._hideNotificationCompleted();
this._updateState();
}
}); });
} else { } else {
Tweener.removeTweens(this._bannerBin);
this._bannerBin.y = -this._bannerBin.height; this._bannerBin.y = -this._bannerBin.height;
this._bannerBin.opacity = 0; this._bannerBin.opacity = 0;
this._notificationState = State.HIDDEN; this._notificationState = State.HIDDEN;

View File

@@ -1,16 +1,17 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ModalDialog */
const { Atk, Clutter, GObject, Shell, St } = imports.gi; const { Atk, Clutter, GObject, Shell, St } = imports.gi;
const Signals = imports.signals;
const Dialog = imports.ui.dialog; const Dialog = imports.ui.dialog;
const Layout = imports.ui.layout; const Layout = imports.ui.layout;
const Lightbox = imports.ui.lightbox; const Lightbox = imports.ui.lightbox;
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 OPEN_AND_CLOSE_TIME = 100; var OPEN_AND_CLOSE_TIME = 0.1;
var FADE_OUT_DIALOG_TIME = 1000; var FADE_OUT_DIALOG_TIME = 1.0;
var State = { var State = {
OPENED: 0, OPENED: 0,
@@ -21,13 +22,11 @@ var State = {
}; };
var ModalDialog = GObject.registerClass({ var ModalDialog = GObject.registerClass({
Properties: { Properties: { 'state': GObject.ParamSpec.int('state', 'Dialog state', 'state',
'state': GObject.ParamSpec.int('state', 'Dialog state', 'state',
GObject.ParamFlags.READABLE, GObject.ParamFlags.READABLE,
Math.min(...Object.values(State)), Math.min(...Object.values(State)),
Math.max(...Object.values(State)), Math.max(...Object.values(State)),
State.CLOSED) State.CLOSED) },
},
Signals: { 'opened': {}, 'closed': {} } Signals: { 'opened': {}, 'closed': {} }
}, class ModalDialog extends St.Widget { }, class ModalDialog extends St.Widget {
_init(params) { _init(params) {
@@ -124,10 +123,10 @@ var ModalDialog = GObject.registerClass({
this._lightbox.show(); this._lightbox.show();
this.opacity = 0; this.opacity = 0;
this.show(); this.show();
this.ease({ Tweener.addTween(this,
opacity: 255, { opacity: 255,
duration: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0, time: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => { onComplete: () => {
this._setState(State.OPENED); this._setState(State.OPENED);
this.emit('opened'); this.emit('opened');
@@ -175,17 +174,16 @@ var ModalDialog = GObject.registerClass({
this.popModal(timestamp); this.popModal(timestamp);
this._savedKeyFocus = null; this._savedKeyFocus = null;
if (this._shouldFadeOut) { if (this._shouldFadeOut)
this.ease({ Tweener.addTween(this,
opacity: 0, { opacity: 0,
duration: OPEN_AND_CLOSE_TIME, time: OPEN_AND_CLOSE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => this._closeComplete() onComplete: this._closeComplete.bind(this)
}); })
} else { else
this._closeComplete(); this._closeComplete();
} }
}
// Drop modal status without closing the dialog; this makes the // Drop modal status without closing the dialog; this makes the
// dialog insensitive as well, so it needs to be followed shortly // dialog insensitive as well, so it needs to be followed shortly
@@ -249,11 +247,13 @@ var ModalDialog = GObject.registerClass({
return; return;
this.popModal(timestamp); this.popModal(timestamp);
this.dialogLayout.ease({ Tweener.addTween(this.dialogLayout,
opacity: 0, { opacity: 0,
duration: FADE_OUT_DIALOG_TIME, time: FADE_OUT_DIALOG_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => (this.state = State.FADED_OUT) onComplete: () => {
this._setState(State.FADED_OUT);
}
}); });
} }
}); });

View File

@@ -1,4 +1,3 @@
/* exported MediaSection */
const { Gio, Shell, St } = imports.gi; const { Gio, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
@@ -71,8 +70,7 @@ var MediaMessage = class MediaMessage extends MessageList.Message {
} }
let isPlaying = this._player.status == 'Playing'; let isPlaying = this._player.status == 'Playing';
let iconName = isPlaying let iconName = isPlaying ? 'media-playback-pause-symbolic'
? 'media-playback-pause-symbolic'
: 'media-playback-start-symbolic'; : 'media-playback-start-symbolic';
this._playPauseButton.child.icon_name = iconName; this._playPauseButton.child.icon_name = iconName;
@@ -137,7 +135,7 @@ var MprisPlayer = class MprisPlayer {
// so prefer activating the app via .desktop file if possible // so prefer activating the app via .desktop file if possible
let app = null; let app = null;
if (this._mprisProxy.DesktopEntry) { if (this._mprisProxy.DesktopEntry) {
let desktopId = `${this._mprisProxy.DesktopEntry}.desktop`; let desktopId = this._mprisProxy.DesktopEntry + '.desktop';
app = Shell.AppSystem.get_default().lookup_app(desktopId); app = Shell.AppSystem.get_default().lookup_app(desktopId);
} }

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 NotificationDaemon */
const { GdkPixbuf, Gio, GLib, Shell, St } = imports.gi; const { GdkPixbuf, Gio, GLib, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Config = imports.misc.config; const Config = imports.misc.config;
const Main = imports.ui.main; const Main = imports.ui.main;
@@ -64,7 +64,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
_imageForNotificationData(hints) { _imageForNotificationData(hints) {
if (hints['image-data']) { if (hints['image-data']) {
let [width, height, rowStride, hasAlpha, let [width, height, rowStride, hasAlpha,
bitsPerSample, nChannels_, data] = hints['image-data']; bitsPerSample, nChannels, data] = hints['image-data'];
return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha, return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
bitsPerSample, width, height, rowStride); bitsPerSample, width, height, rowStride);
} else if (hints['image-path']) { } else if (hints['image-path']) {
@@ -170,11 +170,11 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
// Ignore replacesId since we already sent back a // Ignore replacesId since we already sent back a
// NotificationClosed for that id. // NotificationClosed for that id.
id = this._nextNotificationId++; id = this._nextNotificationId++;
let idleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { let idle_id = Mainloop.idle_add(() => {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED); this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
GLib.Source.set_name_by_id(idleId, '[gnome-shell] this._emitNotificationClosed'); GLib.Source.set_name_by_id(idle_id, '[gnome-shell] this._emitNotificationClosed');
return invocation.return_value(GLib.Variant.new('(u)', [id])); return invocation.return_value(GLib.Variant.new('(u)', [id]));
} }
@@ -231,7 +231,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
// There's already a pending call to GetConnectionUnixProcessID, // There's already a pending call to GetConnectionUnixProcessID,
// which will see the new notification data when it finishes, // which will see the new notification data when it finishes,
// so we don't have to do anything. // so we don't have to do anything.
return invocation.return_value(GLib.Variant.new('(u)', [id])); return invocation.return_value(GLib.Variant.new('(u)', [id]));;
} }
this._busProxy.GetConnectionUnixProcessIDRemote(sender, (result, excp) => { this._busProxy.GetConnectionUnixProcessIDRemote(sender, (result, excp) => {
@@ -259,7 +259,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
} }
_notifyForSource(source, ndata) { _notifyForSource(source, ndata) {
let [id_, icon, summary, body, actions, hints, notification] = let [id, icon, summary, body, actions, hints, notification] =
[ndata.id, ndata.icon, ndata.summary, ndata.body, [ndata.id, ndata.icon, ndata.summary, ndata.body,
ndata.actions, ndata.hints, ndata.notification]; ndata.actions, ndata.hints, ndata.notification];
@@ -309,7 +309,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
if (actions.length) { if (actions.length) {
for (let i = 0; i < actions.length - 1; i += 2) { for (let i = 0; i < actions.length - 1; i += 2) {
let [actionId, label] = [actions[i], actions[i + 1]]; let [actionId, label] = [actions[i], actions[i+1]];
if (actionId == 'default') if (actionId == 'default')
hasDefaultAction = true; hasDefaultAction = true;
else else
@@ -346,8 +346,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
notification.setTransient(!!hints['transient']); notification.setTransient(!!hints['transient']);
let privacyScope = (hints['x-gnome-privacy-scope'] || 'user'); let privacyScope = (hints['x-gnome-privacy-scope'] || 'user');
notification.setPrivacyScope(privacyScope == 'system' notification.setPrivacyScope(privacyScope == 'system' ? MessageTray.PrivacyScope.SYSTEM
? MessageTray.PrivacyScope.SYSTEM
: MessageTray.PrivacyScope.USER); : MessageTray.PrivacyScope.USER);
let sourceGIcon = source.useNotificationIcon ? gicon : null; let sourceGIcon = source.useNotificationIcon ? gicon : null;
@@ -438,7 +437,7 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
_createPolicy() { _createPolicy() {
if (this.app && this.app.get_app_info()) { if (this.app && this.app.get_app_info()) {
let id = this.app.get_id().replace(/\.desktop$/, ''); let id = this.app.get_id().replace(/\.desktop$/,'');
return new MessageTray.NotificationApplicationPolicy(id); return new MessageTray.NotificationApplicationPolicy(id);
} else { } else {
return new MessageTray.NotificationGenericPolicy(); return new MessageTray.NotificationGenericPolicy();
@@ -475,7 +474,7 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
return app; return app;
if (appId) { if (appId) {
app = Shell.AppSystem.get_default().lookup_app(`${appId}.desktop`); app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
if (app != null) if (app != null)
return app; return app;
} }
@@ -541,22 +540,21 @@ class GtkNotificationDaemonNotification extends MessageTray.Notification {
super(source); super(source);
this._serialized = GLib.Variant.new('a{sv}', notification); this._serialized = GLib.Variant.new('a{sv}', notification);
let { title, let { "title": title,
body, "body": body,
icon: gicon, "icon": gicon,
urgent, "urgent": urgent,
priority, "priority": priority,
buttons, "buttons": buttons,
"default-action": defaultAction, "default-action": defaultAction,
"default-action-target": defaultActionTarget, "default-action-target": defaultActionTarget,
timestamp: time } = notification; "timestamp": time } = notification;
if (priority) { if (priority) {
let urgency = PRIORITY_URGENCY_MAP[priority.unpack()]; let urgency = PRIORITY_URGENCY_MAP[priority.unpack()];
this.setUrgency(urgency != undefined ? urgency : MessageTray.Urgency.NORMAL); this.setUrgency(urgency != undefined ? urgency : MessageTray.Urgency.NORMAL);
} else if (urgent) { } else if (urgent) {
this.setUrgency(urgent.unpack() this.setUrgency(urgent.unpack() ? MessageTray.Urgency.CRITICAL
? MessageTray.Urgency.CRITICAL
: MessageTray.Urgency.NORMAL); : MessageTray.Urgency.NORMAL);
} else { } else {
this.setUrgency(MessageTray.Urgency.NORMAL); this.setUrgency(MessageTray.Urgency.NORMAL);
@@ -575,7 +573,7 @@ class GtkNotificationDaemonNotification extends MessageTray.Notification {
this.update(title.unpack(), body ? body.unpack() : null, this.update(title.unpack(), body ? body.unpack() : null,
{ gicon: gicon ? Gio.icon_deserialize(gicon) : null, { gicon: gicon ? Gio.icon_deserialize(gicon) : null,
datetime: time ? GLib.DateTime.new_from_unix_local(time.unpack()) : null }); datetime : time ? GLib.DateTime.new_from_unix_local(time.unpack()) : null });
} }
_activateAction(namespacedActionId, target) { _activateAction(namespacedActionId, target) {
@@ -590,8 +588,8 @@ class GtkNotificationDaemonNotification extends MessageTray.Notification {
} }
_onButtonClicked(button) { _onButtonClicked(button) {
let { action, target } = button; let { 'action': action, 'target': actionTarget } = button;
this._activateAction(action.unpack(), target); this._activateAction(action.unpack(), actionTarget);
} }
activate() { activate() {
@@ -612,7 +610,7 @@ function objectPathFromAppId(appId) {
} }
function getPlatformData() { function getPlatformData() {
let startupId = GLib.Variant.new('s', `_TIME${global.get_current_time()}`); let startupId = GLib.Variant.new('s', '_TIME' + global.get_current_time());
return { "desktop-startup-id": startupId }; return { "desktop-startup-id": startupId };
} }
@@ -625,7 +623,7 @@ class GtkNotificationDaemonAppSource extends MessageTray.Source {
if (!GLib.Variant.is_object_path(objectPath)) if (!GLib.Variant.is_object_path(objectPath))
throw new InvalidAppError(); throw new InvalidAppError();
let app = Shell.AppSystem.get_default().lookup_app(`${appId}.desktop`); let app = Shell.AppSystem.get_default().lookup_app(appId + '.desktop');
if (!app) if (!app)
throw new InvalidAppError(); throw new InvalidAppError();
@@ -751,7 +749,6 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
_loadNotifications() { _loadNotifications() {
this._isLoading = true; this._isLoading = true;
try {
let value = global.get_persistent_state('a(sa(sv))', 'notifications'); let value = global.get_persistent_state('a(sa(sv))', 'notifications');
if (value) { if (value) {
let sources = value.deep_unpack(); let sources = value.deep_unpack();
@@ -762,7 +759,7 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
let source; let source;
try { try {
source = this._ensureAppSource(appId); source = this._ensureAppSource(appId);
} catch (e) { } catch(e) {
if (e instanceof InvalidAppError) if (e instanceof InvalidAppError)
return; return;
throw e; throw e;
@@ -773,12 +770,9 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
}); });
}); });
} }
} catch (e) {
logError(e, 'Failed to load saved notifications');
} finally {
this._isLoading = false; this._isLoading = false;
} }
}
_saveNotifications() { _saveNotifications() {
if (this._isLoading) if (this._isLoading)
@@ -799,7 +793,7 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
let source; let source;
try { try {
source = this._ensureAppSource(appId); source = this._ensureAppSource(appId);
} catch (e) { } catch(e) {
if (e instanceof InvalidAppError) { if (e instanceof InvalidAppError) {
invocation.return_dbus_error('org.gtk.Notifications.InvalidApp', 'The app by ID "%s" could not be found'.format(appId)); invocation.return_dbus_error('org.gtk.Notifications.InvalidApp', 'The app by ID "%s" could not be found'.format(appId));
return; return;

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