Compare commits

..

3 Commits

Author SHA1 Message Date
Allan Day
34e9513e1f adjust UI to new text styles
With the new text styles, some UI needs to adjusted, primarily to
accommodate larger heading text.
2019-06-27 13:52:40 +01:00
Allan Day
40a772c884 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-27 13:51:14 +01:00
Allan Day
2ccd87ae44 theme: Remove unused message tray counters 2019-06-27 13:51:14 +01:00
288 changed files with 27319 additions and 49914 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,114 +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_var=OUTPUT_$1
local output=${!output_var}
# ensure output exists even if eslint doesn't report any errors
mkdir -p $(dirname $output)
touch $output
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
REMOTE=${1:-$CI_MERGE_REQUEST_PROJECT_URL.git}
BRANCH_NAME=${2:-$CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
if [ "$BRANCH_NAME" ]; then
git fetch $REMOTE $BRANCH_NAME
branch_point=$(git merge-base HEAD FETCH_HEAD)
commit_range=$branch_point...HEAD
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 "$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
@@ -186,27 +187,15 @@ and "double quotes" for strings that the user may see. This allows us to
quickly find untranslated or mistranslated strings by grepping through the quickly find untranslated or mistranslated strings by grepping through the
sources for double quotes without a gettext call around them. sources for double quotes without a gettext call around them.
## `actor` (deprecated) and `_delegate` ## `actor` and `_delegate`
gjs allows us to set so-called "expando properties" on introspected objects, gjs allows us to set so-called "expando properties" on introspected objects,
allowing us to treat them like any other. Because the Shell was built before allowing us to treat them like any other. Because the Shell was built before
you could inherit from GTypes natively in JS, in some cases we have a wrapper you could inherit from GTypes natively in JS, we usually have a wrapper class
class that has a property called `actor` (now deprecated). We call this that has a property called `actor`. We call this wrapper class the "delegate".
wrapper class the "delegate".
We sometimes use expando properties to set a property called `_delegate` on We sometimes use expando properties to set a property called `_delegate` on
the actor itself: the actor itself:
```javascript
var MyActor = GObject.registerClass(
class MyActor extends Clutter.Actor {
_init(params) {
super._init(params);
this._delegate = this;
}
});
```
Or using the deprecated `actor`:
```javascript ```javascript
var MyClass = class { var MyClass = class {
constructor() { constructor() {
@@ -227,7 +216,6 @@ delegate object from an associated actor. For instance, the drag and drop
system calls the `handleDragOver` function on the delegate of a "drop target" system calls the `handleDragOver` function on the delegate of a "drop target"
when the user drags an item over it. If you do not set the `_delegate` when the user drags an item over it. If you do not set the `_delegate`
property, your actor will not be able to be dropped onto. property, your actor will not be able to be dropped onto.
In case the class is an actor itself, the `_delegate` can be just set to `this`.
## Functional style ## Functional style
@@ -289,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>
@@ -50,7 +39,7 @@
</description> </description>
</key> </key>
<key name="favorite-apps" type="as"> <key name="favorite-apps" type="as">
<default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'org.gnome.Shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default> <default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
<summary>List of desktop file IDs for favorite applications</summary> <summary>List of desktop file IDs for favorite applications</summary>
<description> <description>
The applications corresponding to these identifiers The applications corresponding to these identifiers
@@ -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;
@@ -189,12 +187,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 +204,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 +212,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 +233,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 */
@@ -255,6 +252,7 @@ StScrollBar {
} }
.end-session-dialog-layout { .end-session-dialog-layout {
spacing: 12px;
padding-left: 17px; padding-left: 17px;
&:rtl { padding-right: 17px; } &:rtl { padding-right: 17px; }
} }
@@ -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 {
@@ -388,7 +380,7 @@ StScrollBar {
.message-dialog-main-layout { spacing: 24px; padding: 10px; } .message-dialog-main-layout { spacing: 24px; padding: 10px; }
.message-dialog-content { spacing: 16px; } .message-dialog-content { spacing: 16px; }
.message-dialog-title { color: lighten($fg_color,15%); } .message-dialog-title { @extend %title-2; color: lighten($fg_color,15%); }
} }
.prompt-dialog-description:rtl { .prompt-dialog-description:rtl {
@@ -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 %title-2;
text-align: center; text-align: center;
} }
@@ -515,7 +504,7 @@ StScrollBar {
.extension-dialog { .extension-dialog {
@extend %bubble-panel; @extend %bubble-panel;
.message-dialog-main-layout { spacing: 24px; padding: 10px; } .message-dialog-main-layout { spacing: 24px; padding: 10px; }
.message-dialog-title { font-weight: normal; color: $fg_color; } .message-dialog-title { @extend %title-2; }
} }
/* Inhibit-Shortcuts Dialog */ /* Inhibit-Shortcuts Dialog */
@@ -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,11 +1092,11 @@ StScrollBar {
} }
.message-secondary-bin > .event-time { .message-secondary-bin > .event-time {
color: $fg_color; @extend %caption;
font-size: 0.7em; color: darken($fg_color,40%);
/* 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: 1px;
} }
.message-secondary-bin > StIcon { .message-secondary-bin > StIcon {
@@ -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;
} }
@@ -1640,18 +1606,22 @@ StScrollBar {
.url-highlighter { link-color: lighten($selected_bg_color,10%); } .url-highlighter { link-color: lighten($selected_bg_color,10%); }
// Banners // Banners
.message-body {
@extend %caption;
padding-top: 2px;
}
.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,20 +1648,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; }
//chat bubbles //chat bubbles
.chat-body { spacing: 5px; } .chat-body { spacing: 5px; }
@@ -1708,9 +1664,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 +1751,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 +1813,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 +1878,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 +1951,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 +1980,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 +1998,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 +2069,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 +2109,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 +2172,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 +2185,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

@@ -31,34 +31,34 @@ its dependencies to build from tarballs.</description>
<programming-language>JavaScript</programming-language> <programming-language>JavaScript</programming-language>
<programming-language>C</programming-language> <programming-language>C</programming-language>
<author> <maintainer>
<foaf:Person> <foaf:Person>
<foaf:name>William Jon McCann</foaf:name> <foaf:name>William Jon McCann</foaf:name>
<foaf:mbox rdf:resource="mailto:jmccann@redhat.com" /> <foaf:mbox rdf:resource="mailto:jmccann@redhat.com" />
<gnome:userid>mccann</gnome:userid> <gnome:userid>mccann</gnome:userid>
</foaf:Person> </foaf:Person>
</author> </maintainer>
<author> <maintainer>
<foaf:Person> <foaf:Person>
<foaf:name>Owen Taylor</foaf:name> <foaf:name>Owen Taylor</foaf:name>
<foaf:mbox rdf:resource="mailto:otaylor@redhat.com" /> <foaf:mbox rdf:resource="mailto:otaylor@redhat.com" />
<gnome:userid>otaylor</gnome:userid> <gnome:userid>otaylor</gnome:userid>
</foaf:Person> </foaf:Person>
</author> </maintainer>
<author> <maintainer>
<foaf:Person> <foaf:Person>
<foaf:name>Colin Walters</foaf:name> <foaf:name>Colin Walters</foaf:name>
<foaf:mbox rdf:resource="mailto:walters@verbum.org" /> <foaf:mbox rdf:resource="mailto:walters@verbum.org" />
<gnome:userid>walters</gnome:userid> <gnome:userid>walters</gnome:userid>
</foaf:Person> </foaf:Person>
</author> </maintainer>
<author> <maintainer>
<foaf:Person> <foaf:Person>
<foaf:name>Marina Zhurakhinskaya</foaf:name> <foaf:name>Marina Zhurakhinskaya</foaf:name>
<foaf:mbox rdf:resource="mailto:marinaz@redhat.com" /> <foaf:mbox rdf:resource="mailto:marinaz@redhat.com" />
<gnome:userid>marinaz</gnome:userid> <gnome:userid>marinaz</gnome:userid>
</foaf:Person> </foaf:Person>
</author> </maintainer>
<maintainer> <maintainer>
<foaf:Person> <foaf:Person>
<foaf:name>Florian Müllner</foaf:name> <foaf:name>Florian Müllner</foaf:name>

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

@@ -1,25 +1,21 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported AuthPrompt */
const { Clutter, GObject, Pango, Shell, St } = imports.gi; const { Clutter, Pango, Shell, St } = imports.gi;
const Signals = imports.signals;
const Animation = imports.ui.animation; const Animation = imports.ui.animation;
const Batch = imports.gdm.batch; const Batch = imports.gdm.batch;
const GdmUtil = imports.gdm.util; const GdmUtil = imports.gdm.util;
const Util = imports.misc.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;
const WIGGLE_OFFSET = 6;
const WIGGLE_DURATION = 65;
const N_WIGGLES = 3;
var AuthPromptMode = { var AuthPromptMode = {
UNLOCK_ONLY: 0, UNLOCK_ONLY: 0,
@@ -38,21 +34,8 @@ var BeginRequestType = {
DONT_PROVIDE_USERNAME: 1 DONT_PROVIDE_USERNAME: 1
}; };
var AuthPrompt = GObject.registerClass({ var AuthPrompt = class {
Signals: { constructor(gdmClient, mode) {
'cancelled': {},
'failed': {},
'next': {},
'prompted': {},
'reset': { param_types: [GObject.TYPE_UINT] },
}
}, class AuthPrompt extends St.BoxLayout {
_init(gdmClient, mode) {
super._init({
style_class: 'login-dialog-prompt-layout',
vertical: true
});
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
this._gdmClient = gdmClient; this._gdmClient = gdmClient;
@@ -85,33 +68,38 @@ var AuthPrompt = GObject.registerClass({
} }
}); });
this.connect('destroy', this._onDestroy.bind(this)); this.actor = new St.BoxLayout({ style_class: 'login-dialog-prompt-layout',
vertical: true });
this.actor.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('key-press-event', (actor, event) => {
if (event.get_key_symbol() == Clutter.KEY_Escape)
this.cancel();
return Clutter.EVENT_PROPAGATE;
});
this._userWell = new St.Bin({ x_fill: true, x_align: St.Align.START }); this._userWell = new St.Bin({ x_fill: true,
this.add(this._userWell, { x_align: St.Align.START });
x_align: St.Align.START, this.actor.add(this._userWell,
{ x_align: St.Align.START,
x_fill: true, x_fill: true,
y_fill: true, y_fill: true,
expand: true expand: true });
});
this._label = new St.Label({ style_class: 'login-dialog-prompt-label' }); this._label = new St.Label({ style_class: 'login-dialog-prompt-label' });
this.add(this._label, { this.actor.add(this._label,
expand: true, { expand: true,
x_fill: false, x_fill: false,
y_fill: true, y_fill: true,
x_align: St.Align.START x_align: St.Align.START });
});
this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry', this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true }); can_focus: true });
ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE }); ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
this.add(this._entry, { this.actor.add(this._entry,
expand: true, { expand: true,
x_fill: true, x_fill: true,
y_fill: false, y_fill: false,
x_align: St.Align.START x_align: St.Align.START });
});
this._entry.grab_key_focus(); this._entry.grab_key_focus();
@@ -119,15 +107,14 @@ var AuthPrompt = GObject.registerClass({
styleClass: 'login-dialog-message' }); styleClass: 'login-dialog-message' });
this._message.clutter_text.line_wrap = true; this._message.clutter_text.line_wrap = true;
this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE; this._message.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
this.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START }); this.actor.add(this._message, { x_fill: false, x_align: St.Align.START, y_align: St.Align.START });
this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box', this._buttonBox = new St.BoxLayout({ style_class: 'login-dialog-button-box',
vertical: false }); vertical: false });
this.add(this._buttonBox, { this.actor.add(this._buttonBox,
expand: true, { expand: true,
x_align: St.Align.MIDDLE, x_align: St.Align.MIDDLE,
y_align: St.Align.END y_align: St.Align.END });
});
this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() }); this._defaultButtonWell = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._defaultButtonWellActor = null; this._defaultButtonWellActor = null;
@@ -135,9 +122,9 @@ var AuthPrompt = GObject.registerClass({
this._initButtons(); this._initButtons();
this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE); this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
this._spinner.opacity = 0; this._spinner.actor.opacity = 0;
this._spinner.show(); this._spinner.actor.show();
this._defaultButtonWell.add_child(this._spinner); this._defaultButtonWell.add_child(this._spinner.actor);
} }
_onDestroy() { _onDestroy() {
@@ -145,19 +132,13 @@ var AuthPrompt = GObject.registerClass({
this._userVerifier = null; this._userVerifier = null;
} }
vfunc_key_press_event(keyPressEvent) {
if (keyPressEvent.keyval == Clutter.KEY_Escape)
this.cancel();
return Clutter.EVENT_PROPAGATE;
}
_initButtons() { _initButtons() {
this.cancelButton = new St.Button({ style_class: 'modal-dialog-button button', this.cancelButton = new St.Button({ style_class: 'modal-dialog-button button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
reactive: true, reactive: true,
can_focus: true, can_focus: true,
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,
@@ -176,7 +157,7 @@ var AuthPrompt = GObject.registerClass({
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,
@@ -261,12 +242,6 @@ var AuthPrompt = GObject.registerClass({
this.updateSensitivity(canRetry); this.updateSensitivity(canRetry);
this.setActorInDefaultButtonWell(null); this.setActorInDefaultButtonWell(null);
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
Util.wiggle(this._entry, {
offset: WIGGLE_OFFSET,
duration: WIGGLE_DURATION,
wiggleCount: N_WIGGLES,
});
} }
_onVerificationComplete() { _onVerificationComplete() {
@@ -292,16 +267,16 @@ var AuthPrompt = GObject.registerClass({
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) if (oldActor == this._spinner.actor)
wasSpinner = true; wasSpinner = true;
else else
wasSpinner = false; wasSpinner = false;
let isSpinner; let isSpinner;
if (actor == this._spinner) if (actor == this._spinner.actor)
isSpinner = true; isSpinner = true;
else else
isSpinner = false; isSpinner = false;
@@ -315,12 +290,13 @@ var AuthPrompt = GObject.registerClass({
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();
@@ -337,19 +313,18 @@ var AuthPrompt = GObject.registerClass({
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;
} }
startSpinning() { startSpinning() {
this.setActorInDefaultButtonWell(this._spinner, true); this.setActorInDefaultButtonWell(this._spinner.actor, true);
} }
stopSpinning() { stopSpinning() {
@@ -391,11 +366,11 @@ var AuthPrompt = GObject.registerClass({
_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'
}); });
} }
@@ -411,7 +386,7 @@ var AuthPrompt = GObject.registerClass({
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 {
@@ -430,9 +405,9 @@ var AuthPrompt = GObject.registerClass({
this._entry.clutter_text.editable = sensitive; this._entry.clutter_text.editable = sensitive;
} }
vfunc_hide() { hide() {
this.setActorInDefaultButtonWell(null, true); this.setActorInDefaultButtonWell(null, true);
super.vfunc_hide(); this.actor.hide();
this._message.opacity = 0; this._message.opacity = 0;
this.setUser(null); this.setUser(null);
@@ -448,7 +423,7 @@ var AuthPrompt = GObject.registerClass({
if (user) { if (user) {
let userWidget = new UserWidget.UserWidget(user); let userWidget = new UserWidget.UserWidget(user);
this._userWell.set_child(userWidget); this._userWell.set_child(userWidget.actor);
} }
} }
@@ -533,4 +508,5 @@ var AuthPrompt = GObject.registerClass({
this.reset(); this.reset();
this.emit('cancelled'); this.emit('cancelled');
} }
}); };
Signals.addSignalMethods(AuthPrompt.prototype);

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;
@@ -25,7 +24,7 @@ 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
* *
@@ -19,6 +18,7 @@
const { AccountsService, Atk, Clutter, Gdm, Gio, const { AccountsService, Atk, Clutter, Gdm, Gio,
GLib, GObject, Meta, Pango, Shell, St } = imports.gi; GLib, GObject, Meta, Pango, Shell, St } = imports.gi;
const Signals = imports.signals;
const AuthPrompt = imports.gdm.authPrompt; const AuthPrompt = imports.gdm.authPrompt;
const Batch = imports.gdm.batch; const Batch = imports.gdm.batch;
@@ -30,43 +30,45 @@ 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;
var UserListItem = GObject.registerClass({ var UserListItem = class {
GTypeName: 'LoginDialog_UserListItem', constructor(user) {
Signals: { 'activate': {} } this.user = user;
}, class UserListItem extends St.Button { this._userChangedId = this.user.connect('changed',
_init(user) { this._onUserChanged.bind(this));
let layout = new St.BoxLayout({ vertical: true }); let layout = new St.BoxLayout({ vertical: true });
super._init({ this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
style_class: 'login-dialog-user-list-item',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
can_focus: true, can_focus: true,
child: layout, child: layout,
reactive: true, reactive: true,
x_align: St.Align.START, x_align: St.Align.START,
x_fill: true x_fill: true });
this.actor.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('key-focus-in', () => {
this._setSelected(true);
}); });
this.actor.connect('key-focus-out', () => {
this.user = user; this._setSelected(false);
this._userChangedId = this.user.connect('changed', });
this._onUserChanged.bind(this)); this.actor.connect('notify::hover', () => {
this._setSelected(this.actor.hover);
this.connect('destroy', this._onDestroy.bind(this));
this.connect('notify::hover', () => {
this._setSelected(this.hover);
}); });
this._userWidget = new UserWidget.UserWidget(this.user); this._userWidget = new UserWidget.UserWidget(this.user);
layout.add(this._userWidget); layout.add(this._userWidget.actor);
this._userWidget.bind_property('label-actor', this, 'label-actor', this._userWidget.actor.bind_property('label-actor', this.actor, 'label-actor',
GObject.BindingFlags.SYNC_CREATE); GObject.BindingFlags.SYNC_CREATE);
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator', this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
@@ -74,44 +76,35 @@ var UserListItem = GObject.registerClass({
visible: false }); visible: false });
layout.add(this._timedLoginIndicator); layout.add(this._timedLoginIndicator);
this.actor.connect('clicked', this._onClicked.bind(this));
this._onUserChanged(); this._onUserChanged();
} }
vfunc_key_focus_in() {
super.vfunc_key_focus_in();
this._setSelected(true);
}
vfunc_key_focus_out() {
super.vfunc_key_focus_out();
this._setSelected(false);
}
_onUserChanged() { _onUserChanged() {
this._updateLoggedIn(); this._updateLoggedIn();
} }
_updateLoggedIn() { _updateLoggedIn() {
if (this.user.is_logged_in()) if (this.user.is_logged_in())
this.add_style_pseudo_class('logged-in'); this.actor.add_style_pseudo_class('logged-in');
else else
this.remove_style_pseudo_class('logged-in'); this.actor.remove_style_pseudo_class('logged-in');
} }
_onDestroy() { _onDestroy() {
this.user.disconnect(this._userChangedId); this.user.disconnect(this._userChangedId);
} }
vfunc_clicked() { _onClicked() {
this.emit('activate'); this.emit('activate');
} }
_setSelected(selected) { _setSelected(selected) {
if (selected) { if (selected) {
this.add_style_pseudo_class('selected'); this.actor.add_style_pseudo_class('selected');
this.grab_key_focus(); this.actor.grab_key_focus();
} else { } else {
this.remove_style_pseudo_class('selected'); this.actor.remove_style_pseudo_class('selected');
} }
} }
@@ -152,30 +145,23 @@ var UserListItem = GObject.registerClass({
this._timedLoginIndicator.visible = false; this._timedLoginIndicator.visible = false;
this._timedLoginIndicator.scale_x = 0.; this._timedLoginIndicator.scale_x = 0.;
} }
}); };
Signals.addSignalMethods(UserListItem.prototype);
var UserList = GObject.registerClass({ var UserList = class {
GTypeName: 'LoginDialog_UserList', constructor() {
Signals: { this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view'});
'activate': { param_types: [UserListItem.$gtype] }, this.actor.set_policy(St.PolicyType.NEVER,
'item-added': { param_types: [UserListItem.$gtype] },
}
}, class UserList extends St.ScrollView {
_init() {
super._init({ style_class: 'login-dialog-user-list-view' });
this.set_policy(St.PolicyType.NEVER,
St.PolicyType.AUTOMATIC); St.PolicyType.AUTOMATIC);
this._box = new St.BoxLayout({ vertical: true, this._box = new St.BoxLayout({ vertical: true,
style_class: 'login-dialog-user-list', style_class: 'login-dialog-user-list',
pseudo_class: 'expanded' }); pseudo_class: 'expanded' });
this.add_actor(this._box); this.actor.add_actor(this._box);
this._items = {}; this._items = {};
}
vfunc_key_focus_in() { this.actor.connect('key-focus-in', this._moveFocusToItems.bind(this));
this._moveFocusToItems();
} }
_moveFocusToItems() { _moveFocusToItems() {
@@ -184,10 +170,10 @@ var UserList = GObject.registerClass({
if (!hasItems) if (!hasItems)
return; return;
if (global.stage.get_key_focus() != this) if (global.stage.get_key_focus() != this.actor)
return; return;
let focusSet = this.navigate_focus(null, St.DirectionType.TAB_FORWARD, false); let focusSet = this.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
if (!focusSet) { if (!focusSet) {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => { Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._moveFocusToItems(); this._moveFocusToItems();
@@ -201,6 +187,8 @@ var UserList = GObject.registerClass({
} }
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
@@ -208,26 +196,27 @@ var UserList = GObject.registerClass({
for (let userName in this._items) { for (let userName in this._items) {
let item = this._items[userName]; let item = this._items[userName];
item.sync_hover(); item.actor.sync_hover();
} }
} }
scrollToItem(item) { scrollToItem(item) {
let box = item.get_allocation_box(); let box = item.actor.get_allocation_box();
let adjustment = this.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) {
let box = item.get_allocation_box(); let box = item.actor.get_allocation_box();
let adjustment = this.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);
@@ -265,14 +254,14 @@ var UserList = GObject.registerClass({
this.removeUser(user); this.removeUser(user);
let item = new UserListItem(user); let item = new UserListItem(user);
this._box.add(item, { x_fill: true }); this._box.add(item.actor, { x_fill: true });
this._items[userName] = item; this._items[userName] = item;
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.connect('key-focus-in', () => this.scrollToItem(item)); item.actor.connect('key-focus-in', () => { this.scrollToItem(item); });
this._moveFocusToItems(); this._moveFocusToItems();
@@ -293,38 +282,33 @@ var UserList = GObject.registerClass({
if (!item) if (!item)
return; return;
item.destroy(); item.actor.destroy();
delete this._items[userName]; delete this._items[userName];
} }
numItems() { numItems() {
return Object.keys(this._items).length; return Object.keys(this._items).length;
} }
}); };
Signals.addSignalMethods(UserList.prototype);
var SessionMenuButton = GObject.registerClass({ var SessionMenuButton = class {
GTypeName: 'LoginDialog_SessionMenuButton', constructor() {
Signals: { 'session-activated': { param_types: [GObject.TYPE_STRING] } }
}, class SessionMenuButton extends St.Bin {
_init() {
let gearIcon = new St.Icon({ icon_name: 'emblem-system-symbolic' }); let gearIcon = new St.Icon({ icon_name: 'emblem-system-symbolic' });
let button = new St.Button({ this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
style_class: 'login-dialog-session-list-button',
reactive: true, reactive: true,
track_hover: true, track_hover: true,
can_focus: true, can_focus: true,
accessible_name: _("Choose Session"), accessible_name: _("Choose Session"),
accessible_role: Atk.Role.MENU, accessible_role: Atk.Role.MENU,
child: gearIcon child: gearIcon });
});
super._init({ child: button }); this.actor = new St.Bin({ child: this._button });
this._button = button;
let side = St.Side.TOP; let side = St.Side.TOP;
let align = 0; let align = 0;
if (Gdm.get_session_ids().length > _MAX_BOTTOM_MENU_ITEMS) { if (Gdm.get_session_ids().length > _MAX_BOTTOM_MENU_ITEMS) {
if (this.text_direction == Clutter.TextDirection.RTL) if (this.actor.text_direction == Clutter.TextDirection.RTL)
side = St.Side.RIGHT; side = St.Side.RIGHT;
else else
side = St.Side.LEFT; side = St.Side.LEFT;
@@ -345,7 +329,7 @@ var SessionMenuButton = GObject.registerClass({
{ 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;
@@ -390,7 +374,7 @@ var SessionMenuButton = GObject.registerClass({
} }
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);
@@ -403,13 +387,15 @@ var SessionMenuButton = GObject.registerClass({
}); });
} }
} }
}); };
Signals.addSignalMethods(SessionMenuButton.prototype);
var LoginDialog = GObject.registerClass({ var LoginDialog = GObject.registerClass({
Signals: { 'failed': {} }, Signals: { 'failed': {} },
}, class LoginDialog extends St.Widget { }, class LoginDialog extends St.Widget {
_init(parentActor) { _init(parentActor) {
super._init({ style_class: 'login-dialog', visible: false }); super._init({ style_class: 'login-dialog',
visible: false });
this.get_accessible().set_role(Atk.Role.WINDOW); this.get_accessible().set_role(Atk.Role.WINDOW);
@@ -417,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();
@@ -443,7 +429,7 @@ var LoginDialog = GObject.registerClass({
this.add_child(this._userSelectionBox); this.add_child(this._userSelectionBox);
this._userList = new UserList(); this._userList = new UserList();
this._userSelectionBox.add(this._userList, this._userSelectionBox.add(this._userList.actor,
{ expand: true, { expand: true,
x_fill: true, x_fill: true,
y_fill: true }); y_fill: true });
@@ -452,7 +438,7 @@ var LoginDialog = GObject.registerClass({
this._authPrompt.connect('prompted', this._onPrompted.bind(this)); this._authPrompt.connect('prompted', this._onPrompted.bind(this));
this._authPrompt.connect('reset', this._onReset.bind(this)); this._authPrompt.connect('reset', this._onReset.bind(this));
this._authPrompt.hide(); this._authPrompt.hide();
this.add_child(this._authPrompt); this.add_child(this._authPrompt.actor);
// translators: this message is shown below the user list on the // translators: this message is shown below the user list on the
// login screen. It can be activated to reveal an entry for // login screen. It can be activated to reveal an entry for
@@ -511,9 +497,9 @@ var LoginDialog = GObject.registerClass({
(list, sessionId) => { (list, sessionId) => {
this._greeter.call_select_session_sync (sessionId, null); this._greeter.call_select_session_sync (sessionId, null);
}); });
this._sessionMenuButton.opacity = 0; this._sessionMenuButton.actor.opacity = 0;
this._sessionMenuButton.show(); this._sessionMenuButton.actor.show();
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton); this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
this._disableUserList = undefined; this._disableUserList = undefined;
this._userListLoaded = false; this._userListLoaded = false;
@@ -534,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);
@@ -548,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);
@@ -562,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;
@@ -589,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.visible) { if (this._authPrompt.actor.visible) {
authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt); authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor);
authPromptHeight = authPromptAllocation.y2 - authPromptAllocation.y1;
authPromptWidth = authPromptAllocation.x2 - authPromptAllocation.x1; authPromptWidth = authPromptAllocation.x2 - authPromptAllocation.x1;
} }
@@ -664,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);
@@ -707,7 +697,7 @@ var LoginDialog = GObject.registerClass({
} }
if (authPromptAllocation) if (authPromptAllocation)
this._authPrompt.allocate(authPromptAllocation, flags); this._authPrompt.actor.allocate(authPromptAllocation, flags);
if (userSelectionAllocation) if (userSelectionAllocation)
this._userSelectionBox.allocate(userSelectionAllocation, flags); this._userSelectionBox.allocate(userSelectionAllocation, flags);
@@ -774,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();
} }
@@ -811,7 +800,7 @@ var LoginDialog = GObject.registerClass({
_onPrompted() { _onPrompted() {
if (this._shouldShowSessionMenuButton()) { if (this._shouldShowSessionMenuButton()) {
this._sessionMenuButton.updateSensitivity(true); this._sessionMenuButton.updateSensitivity(true);
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton); this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
} else { } else {
this._sessionMenuButton.updateSensitivity(false); this._sessionMenuButton.updateSensitivity(false);
} }
@@ -871,15 +860,14 @@ var LoginDialog = GObject.registerClass({
} }
_showPrompt() { _showPrompt() {
if (this._authPrompt.visible) if (this._authPrompt.actor.visible)
return; return;
this._authPrompt.opacity = 0; this._authPrompt.actor.opacity = 0;
this._authPrompt.show(); this._authPrompt.actor.show();
this._authPrompt.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();
} }
@@ -923,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) {
@@ -960,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) {
@@ -991,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;
} }
@@ -1055,19 +1047,18 @@ var LoginDialog = GObject.registerClass({
return this._blockTimedLoginUntilIdle(); return this._blockTimedLoginUntilIdle();
} else { } else {
animationTime = delay; animationTime = delay;
return null;
} }
}, },
() => { () => {
// If idle timeout is done, make sure the timed login indicator is shown // If idle timeout is done, make sure the timed login indicator is shown
if (delay > _TIMED_LOGIN_IDLE_THRESHOLD && if (delay > _TIMED_LOGIN_IDLE_THRESHOLD &&
this._authPrompt.visible) this._authPrompt.actor.visible)
this._authPrompt.cancel(); this._authPrompt.cancel();
if (delay > _TIMED_LOGIN_IDLE_THRESHOLD || firstRun) { if (delay > _TIMED_LOGIN_IDLE_THRESHOLD || firstRun) {
this._userList.scrollToItem(loginItem); this._userList.scrollToItem(loginItem);
loginItem.grab_key_focus(); loginItem.actor.grab_key_focus();
} }
}, },
@@ -1128,7 +1119,7 @@ var LoginDialog = GObject.registerClass({
this._sessionMenuButton.close(); this._sessionMenuButton.close();
this._setUserListExpanded(true); this._setUserListExpanded(true);
this._notListedButton.show(); this._notListedButton.show();
this._userList.grab_key_focus(); this._userList.actor.grab_key_focus();
} }
_beginVerificationForItem(item) { _beginVerificationForItem(item) {
@@ -1236,17 +1227,16 @@ var LoginDialog = GObject.registerClass({
_("Login Window"), _("Login Window"),
'dialog-password-symbolic', 'dialog-password-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE }); { sortGroup: CtrlAltTab.SortGroup.MIDDLE });
this._userList.grab_key_focus(); this._userList.actor.grab_key_focus();
this.show(); this.show();
this.opacity = 0; this.opacity = 0;
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;
} }
@@ -1260,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');
} }
@@ -424,7 +423,10 @@ 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) {
@@ -437,7 +439,9 @@ 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) {

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);
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);
} }
function deserializeExtension(variant) { let requiredProperties = ['uuid', 'name', 'description', 'shell-version'];
let res = { metadata: {} }; for (let i = 0; i < requiredProperties.length; i++) {
for (let prop in variant) { let prop = requiredProperties[i];
let val = variant[prop].unpack(); if (!meta[prop]) {
if (SERIALIZED_PROPERTIES.includes(prop)) throw new Error('missing "' + prop + '" property in metadata.json');
res[prop] = val;
else
res.metadata[prop] = val;
} }
// add the 2 additional properties to create a valid extension object, as createExtensionObject() }
res.uuid = res.metadata.uuid;
res.dir = Gio.File.new_for_path(res.path); if (uuid != meta.uuid) {
return res; 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 {

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,7 +132,7 @@ 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);
@@ -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,7 +51,7 @@ 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
@@ -122,7 +121,7 @@ function getExpressionOffset(expr, offset) {
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 {
@@ -172,7 +175,7 @@ function getPropertyNamesFromExpression(expr, commandHeader = '') {
// 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;
@@ -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;
@@ -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,7 +182,7 @@ 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) {
@@ -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;

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,7 +257,7 @@ const SystemActions = GObject.registerClass({
getMatchingActions(terms) { getMatchingActions(terms) {
// terms is a list of strings // terms is a list of strings
terms = terms.map(term => term.toLowerCase()); terms = terms.map((term) => { return term.toLowerCase(); });
let results = []; let results = [];

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, wiggle */
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);
} }
} }
@@ -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;
} }
@@ -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);
@@ -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,42 +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' });
} }
function wiggle(actor, params) { var AppSettingsMonitor = class {
params = Params.parse(params, { constructor(appId, schemaId) {
offset: 0, this._appId = appId;
duration: 0, this._schemaId = schemaId;
wiggleCount: 0,
});
actor.translation_x = 0;
// Accelerate before wiggling this._app = null;
actor.ease({ this._settings = null;
translation_x: -params.offset, this._handlers = [];
duration: params.duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, this._schemaSource = Gio.SettingsSchemaSource.get_default();
onComplete: () => {
// Wiggle this._appSystem = Shell.AppSystem.get_default();
actor.ease({ this._appSystem.connect('installed-changed',
translation_x: params.offset, this._onInstalledChanged.bind(this));
duration: params.duration, this._onInstalledChanged();
mode: Clutter.AnimationMode.LINEAR, }
repeatCount: params.wiggleCount,
autoReverse: true, get available() {
onComplete: () => { return this._app != null && this._settings != null;
// Decelerate and return to the original position }
actor.ease({
translation_x: 0, activateApp() {
duration: params.duration, if (this._app)
mode: Clutter.AnimationMode.EASE_IN_QUAD, 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);
@@ -242,7 +179,7 @@ var WeatherClient = class {
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;
@@ -126,12 +121,10 @@ 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,8 +117,7 @@ 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();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
@@ -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;
@@ -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);
@@ -281,7 +273,7 @@ function script_collectTimings(_time) {
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;
@@ -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;
@@ -56,8 +55,8 @@ class AccessDialog extends ModalDialog.ModalDialog {
let check = new CheckBox.CheckBox(); let check = new CheckBox.CheckBox();
check.getLabelActor().text = name; check.getLabelActor().text = name;
check.checked = selected == "true"; check.actor.checked = selected == "true";
content.insertBeforeBody(check); content.insertBeforeBody(check.actor);
this._choices.set(id, check); this._choices.set(id, check);
} }
@@ -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,
@@ -99,7 +98,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
let results = {}; let results = {};
if (response == DialogResponse.OK) { if (response == DialogResponse.OK) {
for (let [id, check] of this._choices) { for (let [id, check] of this._choices) {
let checked = check.checked ? 'true' : 'false'; let checked = check.actor.checked ? 'true' : 'false';
results[id] = new GLib.Variant('s', checked); results[id] = new GLib.Variant('s', checked);
} }
} }
@@ -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,39 +391,38 @@ 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);
} }
}); });
var CyclerHighlight = GObject.registerClass( class CyclerHighlight {
class CyclerHighlight extends St.Widget { constructor() {
_init() {
super._init({ layout_manager: new Clutter.BinLayout() });
this._window = null; this._window = null;
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._clone = new Clutter.Clone(); this._clone = new Clutter.Clone();
this.add_actor(this._clone); this.actor.add_actor(this._clone);
this._highlight = new St.Widget({ style_class: 'cycler-highlight' }); this._highlight = new St.Widget({ style_class: 'cycler-highlight' });
this.add_actor(this._highlight); this.actor.add_actor(this._highlight);
let coordinate = Clutter.BindCoordinate.ALL; let coordinate = Clutter.BindCoordinate.ALL;
let constraint = new Clutter.BindConstraint({ coordinate: coordinate }); let constraint = new Clutter.BindConstraint({ coordinate: coordinate });
this._clone.bind_property('source', constraint, 'source', 0); this._clone.bind_property('source', constraint, 'source', 0);
this.add_constraint(constraint); this.actor.add_constraint(constraint);
this.connect('notify::allocation', this._onAllocationChanged.bind(this)); this.actor.connect('notify::allocation',
this.connect('destroy', this._onDestroy.bind(this)); this._onAllocationChanged.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
} }
set window(w) { set window(w) {
@@ -436,8 +434,8 @@ class CyclerHighlight extends St.Widget {
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();
@@ -450,7 +448,7 @@ class CyclerHighlight extends St.Widget {
this._highlight.set_size(0, 0); this._highlight.set_size(0, 0);
this._highlight.hide(); this._highlight.hide();
} else { } else {
let [x, y] = this.allocation.get_origin(); let [x, y] = this.actor.allocation.get_origin();
let rect = this._window.get_frame_rect(); let rect = this._window.get_frame_rect();
this._highlight.set_size(rect.width, rect.height); this._highlight.set_size(rect.width, rect.height);
this._highlight.set_position(rect.x - x, rect.y - y); this._highlight.set_position(rect.x - x, rect.y - y);
@@ -461,7 +459,7 @@ class CyclerHighlight extends St.Widget {
_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
@@ -471,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);
} }
}); });
@@ -488,7 +486,7 @@ var CyclerPopup = GObject.registerClass({
return; return;
this._highlight = new CyclerHighlight(); this._highlight = new CyclerHighlight();
global.window_group.add_actor(this._highlight); global.window_group.add_actor(this._highlight.actor);
this._switcherList = new CyclerList(); this._switcherList = new CyclerList();
this._switcherList.connect('item-highlighted', (list, index) => { this._switcherList.connect('item-highlighted', (list, index) => {
@@ -496,9 +494,9 @@ 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, null); global.window_group.set_child_above_sibling(this._highlight.actor, null);
} }
_finish() { _finish() {
@@ -528,7 +526,7 @@ var CyclerPopup = GObject.registerClass({
} }
_onDestroy() { _onDestroy() {
this._highlight.destroy(); this._highlight.actor.destroy();
super._onDestroy(); super._onDestroy();
} }
@@ -647,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 });
@@ -663,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];
} }
}); });
@@ -711,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);
@@ -724,12 +728,11 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
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
@@ -790,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);
@@ -848,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);
@@ -876,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++) {
@@ -914,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;
@@ -939,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) {
@@ -1013,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;
@@ -1042,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)
}); });
} }
@@ -1079,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,18 +1,21 @@
// -*- 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, GObject, 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 = GObject.registerClass( var Animation = class {
class Animation extends St.Bin { constructor(file, width, height, speed) {
_init(file, width, height, speed) { this.actor = new St.Bin();
super._init({ width: width, height: height }); this.actor.set_size(width, height);
this.connect('destroy', this._onDestroy.bind(this)); this.actor.connect('destroy', this._onDestroy.bind(this));
this.connect('resource-scale-changed', this.actor.connect('notify::size', this._syncAnimationSize.bind(this));
this.actor.connect('resource-scale-changed',
this._loadFile.bind(this, file, width, height)); this._loadFile.bind(this, file, width, height));
let themeContext = St.ThemeContext.get_for_stage(global.stage); let themeContext = St.ThemeContext.get_for_stage(global.stage);
@@ -43,7 +46,7 @@ class Animation extends St.Bin {
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;
} }
@@ -51,30 +54,20 @@ class Animation extends St.Bin {
} }
_loadFile(file, width, height) { _loadFile(file, width, height) {
let [validResourceScale, resourceScale] = this.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.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.set_child(this._animations); this.actor.set_child(this._animations);
if (wasPlaying)
this.play();
} }
_showFrame(frame) { _showFrame(frame) {
@@ -98,7 +91,7 @@ class Animation extends St.Bin {
if (!this._isLoaded) if (!this._isLoaded)
return; return;
let [width, height] = this.get_size(); let [width, height] = this.actor.get_size();
for (let i = 0; i < this._animations.get_n_children(); ++i) for (let i = 0; i < this._animations.get_n_children(); ++i)
this._animations.get_child_at_index(i).set_size(width, height); this._animations.get_child_at_index(i).set_size(width, height);
@@ -121,22 +114,20 @@ class Animation extends St.Bin {
themeContext.disconnect(this._scaleChangedId); themeContext.disconnect(this._scaleChangedId);
this._scaleChangedId = 0; this._scaleChangedId = 0;
} }
}); };
var AnimatedIcon = GObject.registerClass( var AnimatedIcon = class extends Animation {
class AnimatedIcon extends Animation { constructor(file, size) {
_init(file, size) { super(file, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
super._init(file, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
} }
}); };
var Spinner = GObject.registerClass( var Spinner = class extends AnimatedIcon {
class Spinner extends AnimatedIcon { constructor(size, animate=false) {
_init(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._init(file, size); super(file, size);
this.opacity = 0; this.actor.opacity = 0;
this._animate = animate; this._animate = animate;
} }
@@ -146,35 +137,37 @@ class Spinner extends AnimatedIcon {
} }
play() { play() {
this.remove_all_transitions(); Tweener.removeTweens(this.actor);
if (this._animate) { if (this._animate) {
super.play(); super.play();
this.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.opacity = 255; this.actor.opacity = 255;
super.play(); super.play();
} }
} }
stop() { stop() {
this.remove_all_transitions(); Tweener.removeTweens(this.actor);
if (this._animate) { if (this._animate) {
this.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.opacity = 0; this.actor.opacity = 0;
super.stop(); super.stop();
} }
} }
}); };

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;
@@ -55,7 +54,6 @@ const RENAMED_DESKTOP_IDS = {
'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop', 'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop',
'org.gnome.Weather.Application.desktop': 'org.gnome.Weather.desktop', 'org.gnome.Weather.Application.desktop': 'org.gnome.Weather.desktop',
'polari.desktop': 'org.gnome.Polari.desktop', 'polari.desktop': 'org.gnome.Polari.desktop',
'shotwell.desktop': 'org.gnome.Shotwell.desktop',
'tali.desktop': 'org.gnome.Tali.desktop', 'tali.desktop': 'org.gnome.Tali.desktop',
'totem.desktop': 'org.gnome.Totem.desktop', 'totem.desktop': 'org.gnome.Totem.desktop',
'evince.desktop': 'org.gnome.Evince.desktop', 'evince.desktop': 'org.gnome.Evince.desktop',
@@ -65,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();
} }
@@ -148,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);
}
}); });
} }
@@ -181,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 });
@@ -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,7 +159,7 @@ 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 {

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 SystemBackground */
// READ THIS FIRST // READ THIS FIRST
// Background handling is a maze of objects, both objects in this file, and // Background handling is a maze of objects, both objects in this file, and
@@ -94,12 +93,13 @@
// MetaBackgroundImage MetaBackgroundImage // MetaBackgroundImage MetaBackgroundImage
// MetaBackgroundImage MetaBackgroundImage // MetaBackgroundImage MetaBackgroundImage
const { Clutter, GDesktopEnums, Gio, GLib, GObject, GnomeDesktop, Meta } = imports.gi; const { Clutter, GDesktopEnums, Gio, GLib, GnomeDesktop, Meta } = imports.gi;
const Signals = imports.signals; 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);
@@ -108,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
@@ -221,17 +222,16 @@ function getBackgroundCache() {
return _backgroundCache; return _backgroundCache;
} }
var Background = GObject.registerClass({ var Background = class Background {
Signals: { 'loaded': {}, 'bg-changed': {} } constructor(params) {
}, class Background extends Meta.Background {
_init(params) {
params = Params.parse(params, { monitorIndex: 0, params = Params.parse(params, { monitorIndex: 0,
layoutManager: Main.layoutManager, layoutManager: Main.layoutManager,
settings: null, settings: null,
file: null, file: null,
style: null }); style: null });
super._init({ meta_display: global.display }); this.background = new Meta.Background({ meta_display: global.display });
this.background._delegate = this;
this._settings = params.settings; this._settings = params.settings;
this._file = params.file; this._file = params.file;
@@ -264,6 +264,8 @@ var Background = GObject.registerClass({
} }
destroy() { destroy() {
this.background = null;
this._cancellable.cancel(); this._cancellable.cancel();
this._removeAnimationTimeout(); this._removeAnimationTimeout();
@@ -300,11 +302,9 @@ var Background = GObject.registerClass({
this._changedIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => { this._changedIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this._changedIdleId = 0; this._changedIdleId = 0;
this.emit('bg-changed'); this.emit('changed');
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
GLib.Source.set_name_by_id(this._changedIdleId,
'[gnome-shell] Background._emitChangedSignal');
} }
updateResolution() { updateResolution() {
@@ -330,23 +330,23 @@ var Background = GObject.registerClass({
this.emit('loaded'); this.emit('loaded');
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
GLib.Source.set_name_by_id(id, '[gnome-shell] Background._setLoaded Idle'); GLib.Source.set_name_by_id(id, '[gnome-shell] this.emit');
} }
_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);
if (shadingType == GDesktopEnums.BackgroundShading.SOLID) if (shadingType == GDesktopEnums.BackgroundShading.SOLID)
this.set_color(color); this.background.set_color(color);
else else
this.set_gradient(shadingType, color, secondColor); this.background.set_gradient(shadingType, color, secondColor);
} }
_watchFile(file) { _watchFile(file) {
@@ -382,13 +382,13 @@ var Background = GObject.registerClass({
let finish = () => { let finish = () => {
this._setLoaded(); this._setLoaded();
if (files.length > 1) { if (files.length > 1) {
this.set_blend(files[0], files[1], this.background.set_blend(files[0], files[1],
this._animation.transitionProgress, this._animation.transitionProgress,
this._style); this._style);
} else if (files.length > 0) { } else if (files.length > 0) {
this.set_file(files[0], this._style); this.background.set_file(files[0], this._style);
} else { } else {
this.set_file(null, this._style); this.background.set_file(null, this._style);
} }
this._queueUpdateAnimation(); this._queueUpdateAnimation();
}; };
@@ -443,8 +443,7 @@ var Background = GObject.registerClass({
} }
_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;
@@ -461,14 +460,14 @@ var Background = GObject.registerClass({
} }
_loadImage(file) { _loadImage(file) {
this.set_file(file, this._style); this.background.set_file(file, this._style);
this._watchFile(file); this._watchFile(file);
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);
@@ -495,14 +494,13 @@ var Background = GObject.registerClass({
this._loadFile(this._file); this._loadFile(this._file);
} }
}); };
Signals.addSignalMethods(Background.prototype);
let _systemBackground; let _systemBackground;
var SystemBackground = GObject.registerClass({ var SystemBackground = class SystemBackground {
Signals: { 'loaded': {} } constructor() {
}, class SystemBackground extends Meta.BackgroundActor {
_init() {
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/noise-texture.png'); let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/noise-texture.png');
if (_systemBackground == null) { if (_systemBackground == null) {
@@ -511,11 +509,9 @@ var SystemBackground = GObject.registerClass({
_systemBackground.set_file(file, GDesktopEnums.BackgroundStyle.WALLPAPER); _systemBackground.set_file(file, GDesktopEnums.BackgroundStyle.WALLPAPER);
} }
super._init({ this.actor = new Meta.BackgroundActor({ meta_display: global.display,
meta_display: global.display,
monitor: 0, monitor: 0,
background: _systemBackground background: _systemBackground });
});
let cache = Meta.BackgroundImageCache.get_default(); let cache = Meta.BackgroundImageCache.get_default();
let image = cache.load(file); let image = cache.load(file);
@@ -534,7 +530,8 @@ var SystemBackground = GObject.registerClass({
}); });
} }
} }
}); };
Signals.addSignalMethods(SystemBackground.prototype);
var BackgroundSource = class BackgroundSource { var BackgroundSource = class BackgroundSource {
constructor(layoutManager, settingsSchema) { constructor(layoutManager, settingsSchema) {
@@ -570,7 +567,7 @@ var BackgroundSource = class BackgroundSource {
// We don't watch changes to settings here, // We don't watch changes to settings here,
// instead we rely on Background to watch those // instead we rely on Background to watch those
// and emit 'bg-changed' at the right time // and emit 'changed' at the right time
if (this._overrideImage != null) { if (this._overrideImage != null) {
file = Gio.File.new_for_path(this._overrideImage); file = Gio.File.new_for_path(this._overrideImage);
@@ -599,7 +596,7 @@ var BackgroundSource = class BackgroundSource {
style: style style: style
}); });
background._changedId = background.connect('bg-changed', () => { background._changedId = background.connect('changed', () => {
background.disconnect(background._changedId); background.disconnect(background._changedId);
background.destroy(); background.destroy();
delete this._backgrounds[monitorIndex]; delete this._backgrounds[monitorIndex];
@@ -637,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();
@@ -655,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;
@@ -714,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();
}
}); });
} }
@@ -736,7 +735,7 @@ var BackgroundManager = class BackgroundManager {
this._newBackgroundActor = newBackgroundActor; this._newBackgroundActor = newBackgroundActor;
let background = newBackgroundActor.background; let background = newBackgroundActor.background._delegate;
if (background.isLoaded) { if (background.isLoaded) {
this._swapBackgroundActor(); this._swapBackgroundActor();
@@ -753,10 +752,9 @@ 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,
vignette: this._vignette, vignette: this._vignette,
vignette_sharpness: 0.5, vignette_sharpness: 0.5,
brightness: 0.5, brightness: 0.5,
@@ -770,7 +768,7 @@ var BackgroundManager = class BackgroundManager {
backgroundActor.lower_bottom(); backgroundActor.lower_bottom();
} }
let changeSignalId = background.connect('bg-changed', () => { let changeSignalId = background.connect('changed', () => {
background.disconnect(changeSignalId); background.disconnect(changeSignalId);
changeSignalId = null; changeSignalId = null;
this._updateBackgroundActor(); this._updateBackgroundActor();

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:
@@ -46,18 +46,12 @@ var BoxPointer = GObject.registerClass({
this.add_actor(this._border); this.add_actor(this._border);
this.bin.raise(this._border); this.bin.raise(this._border);
this._sourceAlignment = 0.5; this._sourceAlignment = 0.5;
this._muteInput = true; this._capturedEventId = 0;
this._muteInput();
this.connect('destroy', this._onDestroy.bind(this)); this.connect('destroy', this._onDestroy.bind(this));
} }
vfunc_captured_event() {
if (this._muteInput)
return Clutter.EVENT_STOP;
return Clutter.EVENT_PROPAGATE;
}
_onDestroy() { _onDestroy() {
if (this._sourceActorDestroyId) { if (this._sourceActorDestroyId) {
this._sourceActor.disconnect(this._sourceActorDestroyId); this._sourceActor.disconnect(this._sourceActorDestroyId);
@@ -69,6 +63,19 @@ var BoxPointer = GObject.registerClass({
return this._arrowSide; return this._arrowSide;
} }
_muteInput() {
if (this._capturedEventId == 0)
this._capturedEventId = this.connect('captured-event',
() => Clutter.EVENT_STOP);
}
_unmuteInput() {
if (this._capturedEventId != 0) {
this.disconnect(this._capturedEventId);
this._capturedEventId = 0;
}
}
open(animate, onComplete) { open(animate, onComplete) {
let themeNode = this.get_theme_node(); let themeNode = this.get_theme_node();
let rise = themeNode.get_length('-arrow-rise'); let rise = themeNode.get_length('-arrow-rise');
@@ -98,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._muteInput = false; this._unmuteInput();
if (onComplete) if (onComplete)
onComplete(); onComplete();
} },
}); time: animationTime });
} }
close(animate, onComplete) { close(animate, onComplete) {
@@ -140,15 +145,14 @@ var BoxPointer = GObject.registerClass({
} }
} }
this._muteInput = true; 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;
@@ -165,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;
@@ -392,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);
@@ -433,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;
}); })
} }
} }
@@ -465,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
@@ -590,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)
@@ -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;
@@ -313,14 +315,12 @@ var DBusEventSource = class DBusEventSource {
}; };
Signals.addSignalMethods(DBusEventSource.prototype); Signals.addSignalMethods(DBusEventSource.prototype);
var Calendar = GObject.registerClass({ var Calendar = class Calendar {
Signals: { 'selected-date-changed': { param_types: [GLib.DateTime.$gtype] } } constructor() {
}, class Calendar extends St.Widget {
_init() {
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);
/** /**
@@ -346,11 +346,12 @@ var Calendar = GObject.registerClass({
this._shouldDateGrabFocus = false; this._shouldDateGrabFocus = false;
super._init({ this.actor = new St.Widget({ style_class: 'calendar',
style_class: 'calendar',
layout_manager: new Clutter.TableLayout(), layout_manager: new Clutter.TableLayout(),
reactive: true reactive: true });
});
this.actor.connect('scroll-event',
this._onScroll.bind(this));
this._buildHeader (); this._buildHeader ();
} }
@@ -374,10 +375,7 @@ var Calendar = GObject.registerClass({
this._selectedDate = date; this._selectedDate = date;
this._update(); this._update();
this.emit('selected-date-changed', new Date(this._selectedDate));
let datetime = GLib.DateTime.new_from_unix_local(
this._selectedDate.getTime() / 1000);
this.emit('selected-date-changed', datetime);
} }
updateTimeZone() { updateTimeZone() {
@@ -388,9 +386,9 @@ var Calendar = GObject.registerClass({
} }
_buildHeader() { _buildHeader() {
let layout = this.layout_manager; let layout = this.actor.layout_manager;
let offsetCols = this._useWeekdate ? 1 : 0; let offsetCols = this._useWeekdate ? 1 : 0;
this.destroy_all_children(); this.actor.destroy_all_children();
// Top line of the calendar '<| September 2009 |>' // Top line of the calendar '<| September 2009 |>'
this._topBox = new St.BoxLayout(); this._topBox = new St.BoxLayout();
@@ -432,7 +430,7 @@ var Calendar = GObject.registerClass({
can_focus: true }); can_focus: true });
label.accessible_name = iter.toLocaleFormat('%A'); label.accessible_name = iter.toLocaleFormat('%A');
let col; let col;
if (this.get_text_direction() == Clutter.TextDirection.RTL) if (this.actor.get_text_direction() == Clutter.TextDirection.RTL)
col = 6 - (7 + iter.getDay() - this._weekStart) % 7; col = 6 - (7 + iter.getDay() - this._weekStart) % 7;
else else
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7; col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
@@ -441,11 +439,11 @@ var Calendar = GObject.registerClass({
} }
// All the children after this are days, and get removed when we update the calendar // All the children after this are days, and get removed when we update the calendar
this._firstDayIndex = this.get_n_children(); this._firstDayIndex = this.actor.get_n_children();
} }
vfunc_scroll_event(scrollEvent) { _onScroll(actor, event) {
switch (scrollEvent.direction) { switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP: case Clutter.ScrollDirection.UP:
case Clutter.ScrollDirection.LEFT: case Clutter.ScrollDirection.LEFT:
this._onPrevMonthButtonClicked(); this._onPrevMonthButtonClicked();
@@ -468,7 +466,8 @@ var Calendar = GObject.registerClass({
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();
@@ -491,7 +490,8 @@ var Calendar = GObject.registerClass({
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();
@@ -515,7 +515,7 @@ var Calendar = GObject.registerClass({
let now = new Date(); let now = new Date();
// Remove everything but the topBox and the weekday labels // Remove everything but the topBox and the weekday labels
let children = this.get_children(); let children = this.actor.get_children();
for (let i = this._firstDayIndex; i < children.length; i++) for (let i = this._firstDayIndex; i < children.length; i++)
children[i].destroy(); children[i].destroy();
@@ -546,18 +546,20 @@ var Calendar = GObject.registerClass({
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;
beginDate.setTime(beginDate.getTime() - (weekPadding + daysToWeekStart) * MSECS_IN_DAY); beginDate.setTime(beginDate.getTime() - (weekPadding + daysToWeekStart) * MSECS_IN_DAY);
let layout = this.layout_manager; let layout = this.actor.layout_manager;
let iter = new Date(beginDate); let iter = new Date(beginDate);
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 });
@@ -583,13 +585,12 @@ var Calendar = GObject.registerClass({
// 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';
@@ -647,17 +648,17 @@ var Calendar = GObject.registerClass({
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 { }
else
button.remove_style_pseudo_class('selected'); button.remove_style_pseudo_class('selected');
}
}); });
} }
}); };
Signals.addSignalMethods(Calendar.prototype);
var EventMessage = GObject.registerClass( var EventMessage = class EventMessage extends MessageList.Message {
class EventMessage extends MessageList.Message { constructor(event, date) {
_init(event, date) { super('', event.summary);
super._init('', event.summary);
this._event = event; this._event = event;
this._date = date; this._date = date;
@@ -666,12 +667,11 @@ class EventMessage extends MessageList.Message {
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' }); this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
this.setIcon(this._icon); this.setIcon(this._icon);
}
vfunc_style_changed() { this.actor.connect('style-changed', () => {
let iconVisible = this.get_parent().has_style_pseudo_class('first-child'); let iconVisible = this.actor.get_parent().has_style_pseudo_class('first-child');
this._icon.opacity = (iconVisible ? 255 : 0); this._icon.opacity = (iconVisible ? 255 : 0);
super.vfunc_style_changed(); });
} }
_formatEventTime() { _formatEventTime() {
@@ -686,8 +686,7 @@ 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 });
} }
@@ -695,24 +694,24 @@ 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;
} }
}); };
var NotificationMessage = GObject.registerClass( var NotificationMessage =
class NotificationMessage extends MessageList.Message { class NotificationMessage extends MessageList.Message {
_init(notification) { constructor(notification) {
super._init(notification.title, notification.bannerBodyText); super(notification.title, notification.bannerBodyText);
this.setUseBodyMarkup(notification.bannerBodyMarkup); this.setUseBodyMarkup(notification.bannerBodyMarkup);
this.notification = notification; this.notification = notification;
@@ -742,14 +741,14 @@ 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);
this.setUseBodyMarkup(n.bannerBodyMarkup); this.setUseBodyMarkup(n.bannerBodyMarkup);
} }
vfunc_clicked() { _onClicked() {
this.notification.activate(); this.notification.activate();
} }
@@ -771,12 +770,11 @@ class NotificationMessage extends MessageList.Message {
canClose() { canClose() {
return true; return true;
} }
}); };
var EventsSection = GObject.registerClass( var EventsSection = class EventsSection extends MessageList.MessageListSection {
class EventsSection extends MessageList.MessageListSection { constructor() {
_init() { super();
super._init();
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' }); this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', this._reloadEvents.bind(this)); this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
@@ -788,7 +786,7 @@ class EventsSection extends MessageList.MessageListSection {
label: '', label: '',
x_align: St.Align.START, x_align: St.Align.START,
can_focus: true }); can_focus: true });
this.insert_child_below(this._title, null); this.actor.insert_child_below(this._title, null);
this._title.connect('clicked', this._onTitleClicked.bind(this)); this._title.connect('clicked', this._onTitleClicked.bind(this));
this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this)); this._title.connect('key-focus-in', this._onKeyFocusIn.bind(this));
@@ -907,29 +905,12 @@ class EventsSection extends MessageList.MessageListSection {
super._sync(); super._sync();
} }
}); };
var TimeLabel = GObject.registerClass( var NotificationSection =
class NotificationTimeLabel extends St.Label {
_init(datetime) {
super._init({
style_class: 'event-time',
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.END
});
this._datetime = datetime;
}
vfunc_map() {
this.text = Util.formatTimeSpan(this._datetime);
super.vfunc_map();
}
});
var NotificationSection = GObject.registerClass(
class NotificationSection extends MessageList.MessageListSection { class NotificationSection extends MessageList.MessageListSection {
_init() { constructor() {
super._init(); super();
this._sources = new Map(); this._sources = new Map();
this._nUrgent = 0; this._nUrgent = 0;
@@ -938,6 +919,8 @@ class NotificationSection extends MessageList.MessageListSection {
Main.messageTray.getSources().forEach(source => { Main.messageTray.getSources().forEach(source => {
this._sourceAdded(Main.messageTray, source); this._sourceAdded(Main.messageTray, source);
}); });
this.actor.connect('notify::mapped', this._onMapped.bind(this));
} }
get allowed() { get allowed() {
@@ -945,6 +928,17 @@ class NotificationSection extends MessageList.MessageListSection {
!Main.sessionMode.isGreeter; !Main.sessionMode.isGreeter;
} }
_createTimeLabel(datetime) {
let label = new St.Label({ style_class: 'event-time',
x_align: Clutter.ActorAlign.START,
y_align: Clutter.ActorAlign.END });
label.connect('notify::mapped', () => {
if (label.mapped)
label.text = Util.formatTimeSpan(datetime);
});
return label;
}
_sourceAdded(tray, source) { _sourceAdded(tray, source) {
let obj = { let obj = {
destroyId: 0, destroyId: 0,
@@ -962,13 +956,13 @@ class NotificationSection extends MessageList.MessageListSection {
_onNotificationAdded(source, notification) { _onNotificationAdded(source, notification) {
let message = new NotificationMessage(notification); let message = new NotificationMessage(notification);
message.setSecondaryActor(new TimeLabel(notification.datetime)); message.setSecondaryActor(this._createTimeLabel(notification.datetime));
let isUrgent = notification.urgency == MessageTray.Urgency.CRITICAL; let isUrgent = notification.urgency == MessageTray.Urgency.CRITICAL;
let updatedId = notification.connect('updated', () => { let updatedId = notification.connect('updated', () => {
message.setSecondaryActor(new TimeLabel(notification.datetime)); message.setSecondaryActor(this._createTimeLabel(notification.datetime));
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.mapped); this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.actor.mapped);
}); });
let destroyId = notification.connect('destroy', () => { let destroyId = notification.connect('destroy', () => {
notification.disconnect(destroyId); notification.disconnect(destroyId);
@@ -988,7 +982,7 @@ class NotificationSection extends MessageList.MessageListSection {
} }
let index = isUrgent ? 0 : this._nUrgent; let index = isUrgent ? 0 : this._nUrgent;
this.addMessageAtIndex(message, index, this.mapped); this.addMessageAtIndex(message, index, this.actor.mapped);
} }
_onSourceDestroy(source, obj) { _onSourceDestroy(source, obj) {
@@ -998,23 +992,25 @@ class NotificationSection extends MessageList.MessageListSection {
this._sources.delete(source); this._sources.delete(source);
} }
vfunc_map() { _onMapped() {
this._messages.forEach(message => { if (!this.actor.mapped)
return;
for (let message of this._messages.keys())
if (message.notification.urgency != MessageTray.Urgency.CRITICAL) if (message.notification.urgency != MessageTray.Urgency.CRITICAL)
message.notification.acknowledged = true; message.notification.acknowledged = true;
});
super.vfunc_map();
} }
_shouldShow() { _shouldShow() {
return !this.empty && isToday(this._date); return !this.empty && isToday(this._date);
} }
}); };
var Placeholder = class Placeholder {
constructor() {
this.actor = new St.BoxLayout({ style_class: 'message-list-placeholder',
vertical: true });
var Placeholder = GObject.registerClass(
class Placeholder extends St.BoxLayout {
_init() {
super._init({ style_class: 'message-list-placeholder', vertical: true });
this._date = new Date(); this._date = new Date();
let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg'); let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
@@ -1023,10 +1019,10 @@ class Placeholder extends St.BoxLayout {
this._otherIcon = new Gio.FileIcon({ file: otherFile }); this._otherIcon = new Gio.FileIcon({ file: otherFile });
this._icon = new St.Icon(); this._icon = new St.Icon();
this.add_actor(this._icon); this.actor.add_actor(this._icon);
this._label = new St.Label(); this._label = new St.Label();
this.add_actor(this._label); this.actor.add_actor(this._label);
this._sync(); this._sync();
} }
@@ -1053,24 +1049,20 @@ class Placeholder extends St.BoxLayout {
this._label.text = _("No Events"); this._label.text = _("No Events");
} }
} }
}); };
var CalendarMessageList = GObject.registerClass( var CalendarMessageList = class CalendarMessageList {
class CalendarMessageList extends St.Widget { constructor() {
_init() { this.actor = new St.Widget({ style_class: 'message-list',
super._init({
style_class: 'message-list',
layout_manager: new Clutter.BinLayout(), layout_manager: new Clutter.BinLayout(),
x_expand: true, x_expand: true, y_expand: true });
y_expand: true
});
this._placeholder = new Placeholder(); this._placeholder = new Placeholder();
this.add_actor(this._placeholder); this.actor.add_actor(this._placeholder.actor);
let box = new St.BoxLayout({ vertical: true, let box = new St.BoxLayout({ vertical: true,
x_expand: true, y_expand: true }); x_expand: true, y_expand: true });
this.add_actor(box); this.actor.add_actor(box);
this._scrollView = new St.ScrollView({ style_class: 'vfade', this._scrollView = new St.ScrollView({ style_class: 'vfade',
overlay_scrollbars: true, overlay_scrollbars: true,
@@ -1084,21 +1076,17 @@ class CalendarMessageList extends St.Widget {
can_focus: true }); can_focus: true });
this._clearButton.set_x_align(Clutter.ActorAlign.END); this._clearButton.set_x_align(Clutter.ActorAlign.END);
this._clearButton.connect('clicked', () => { this._clearButton.connect('clicked', () => {
this._sectionList.get_children().forEach(s => s.clear()); let sections = [...this._sections.keys()];
sections.forEach((s) => { s.clear(); });
}); });
box.add_actor(this._clearButton); box.add_actor(this._clearButton);
this._placeholder.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,
y_align: Clutter.ActorAlign.START }); y_align: Clutter.ActorAlign.START });
this._sectionList.connect('actor-added', this._sync.bind(this));
this._sectionList.connect('actor-removed', this._sync.bind(this));
this._scrollView.add_actor(this._sectionList); this._scrollView.add_actor(this._sectionList);
this._sections = new Map();
this._mediaSection = new Mpris.MediaSection(); this._mediaSection = new Mpris.MediaSection();
this._addSection(this._mediaSection); this._addSection(this._mediaSection);
@@ -1113,35 +1101,59 @@ class CalendarMessageList extends St.Widget {
} }
_addSection(section) { _addSection(section) {
let connectionsIds = []; let obj = {
destroyId: 0,
visibleId: 0,
emptyChangedId: 0,
canClearChangedId: 0,
keyFocusId: 0
};
obj.destroyId = section.actor.connect('destroy', () => {
this._removeSection(section);
});
obj.visibleId = section.actor.connect('notify::visible',
this._sync.bind(this));
obj.emptyChangedId = section.connect('empty-changed',
this._sync.bind(this));
obj.canClearChangedId = section.connect('can-clear-changed',
this._sync.bind(this));
obj.keyFocusId = section.connect('key-focus-in',
this._onKeyFocusIn.bind(this));
for (let prop of ['visible', 'empty', 'can-clear']) { this._sections.set(section, obj);
connectionsIds.push( this._sectionList.add_actor(section.actor);
section.connect(`notify::${prop}`, this._sync.bind(this))); this._sync();
} }
connectionsIds.push(section.connect('message-focused', (_s, messageActor) => {
Util.ensureActorVisibleInScrollView(this._scrollView, messageActor);
}));
connectionsIds.push(section.connect('destroy', (section) => { _removeSection(section) {
connectionsIds.forEach(id => section.disconnect(id)); let obj = this._sections.get(section);
this._sectionList.remove_actor(section); section.actor.disconnect(obj.destroyId);
})); section.actor.disconnect(obj.visibleId);
section.disconnect(obj.emptyChangedId);
section.disconnect(obj.canClearChangedId);
section.disconnect(obj.keyFocusId);
this._sectionList.add_actor(section); this._sections.delete(section);
this._sectionList.remove_actor(section.actor);
this._sync();
}
_onKeyFocusIn(section, actor) {
Util.ensureActorVisibleInScrollView(this._scrollView, actor);
} }
_sync() { _sync() {
let sections = this._sectionList.get_children(); let sections = [...this._sections.keys()];
let visible = sections.some(s => s.allowed); let visible = sections.some(s => s.allowed);
this.visible = visible; this.actor.visible = visible;
if (!visible) if (!visible)
return; return;
let empty = sections.every(s => s.empty || !s.visible); let empty = sections.every(s => s.empty || !s.actor.visible);
this._placeholder.visible = empty; this._placeholder.actor.visible = empty;
this._clearButton.visible = !empty;
let canClear = sections.some(s => s.canClear && s.visible); let canClear = sections.some(s => s.canClear && s.actor.visible);
this._clearButton.reactive = canClear; this._clearButton.reactive = canClear;
} }
@@ -1150,7 +1162,8 @@ class CalendarMessageList extends St.Widget {
} }
setDate(date) { setDate(date) {
this._sectionList.get_children().forEach(s => s.setDate(date)); for (let section of this._sections.keys())
section.setDate(date);
this._placeholder.setDate(date); this._placeholder.setDate(date);
} }
}); };

View File

@@ -1,19 +1,15 @@
/* exported CheckBox */ const { Clutter, Pango, St } = imports.gi;
const { Clutter, GObject, Pango, St } = imports.gi;
var CheckBox = GObject.registerClass( var CheckBox = class CheckBox {
class CheckBox extends St.Button { constructor(label) {
_init(label) {
let container = new St.BoxLayout(); let container = new St.BoxLayout();
super._init({ this.actor = new St.Button({ style_class: 'check-box',
style_class: 'check-box',
child: container, child: container,
button_mask: St.ButtonMask.ONE, button_mask: St.ButtonMask.ONE,
toggle_mode: true, toggle_mode: true,
can_focus: true, can_focus: true,
x_fill: true, x_fill: true,
y_fill: true y_fill: true });
});
this._box = new St.Bin(); this._box = new St.Bin();
this._box.set_y_align(Clutter.ActorAlign.START); this._box.set_y_align(Clutter.ActorAlign.START);
@@ -35,4 +31,4 @@ class CheckBox extends St.Button {
getLabelActor() { getLabelActor() {
return this._label; return this._label;
} }
}); };

View File

@@ -1,13 +1,13 @@
// -*- 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({
@@ -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,7 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */
const { Gio, GObject, St } = imports.gi; const { Gio, St } = imports.gi;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main; const Main = imports.ui.main;
@@ -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;
@@ -272,10 +278,9 @@ var AutorunDispatcher = class {
} }
}; };
var AutorunSource = GObject.registerClass( var AutorunSource = class extends MessageTray.Source {
class AutorunSource extends MessageTray.Source { constructor(manager, mount, apps) {
_init(manager, mount, apps) { super(mount.get_name());
super._init(mount.get_name());
this._manager = manager; this._manager = manager;
this.mount = mount; this.mount = mount;
@@ -285,7 +290,7 @@ class AutorunSource extends MessageTray.Source {
// add ourselves as a source, and popup the notification // add ourselves as a source, and popup the notification
Main.messageTray.add(this); Main.messageTray.add(this);
this.showNotification(this._notification); this.notify(this._notification);
} }
getIcon() { getIcon() {
@@ -295,12 +300,11 @@ class AutorunSource extends MessageTray.Source {
_createPolicy() { _createPolicy() {
return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus'); return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus');
} }
}); };
var AutorunNotification = GObject.registerClass( var AutorunNotification = class extends MessageTray.Notification {
class AutorunNotification extends MessageTray.Notification { constructor(manager, source) {
_init(manager, source) { super(source, source.title);
super._init(source, source.title);
this._manager = manager; this._manager = manager;
this._mount = source.mount; this._mount = source.mount;
@@ -325,9 +329,9 @@ class AutorunNotification 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);
@@ -352,6 +356,6 @@ class AutorunNotification extends MessageTray.Notification {
let app = Gio.app_info_get_default_for_type('inode/directory', false); let app = Gio.app_info_get_default_for_type('inode/directory', false);
startAppForMount(app, this._mount); startAppForMount(app, this._mount);
} }
}); };
var Component = AutorunManager; var Component = AutorunManager;

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;
@@ -77,13 +76,13 @@ class KeyringDialog extends ModalDialog.ModalDialog {
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true); this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
if (rtl) { if (rtl) {
layout.attach(this._workSpinner, 0, row, 1, 1); layout.attach(this._workSpinner.actor, 0, row, 1, 1);
layout.attach(this._passwordEntry, 1, row, 1, 1); layout.attach(this._passwordEntry, 1, row, 1, 1);
layout.attach(label, 2, row, 1, 1); layout.attach(label, 2, row, 1, 1);
} else { } else {
layout.attach(label, 0, row, 1, 1); layout.attach(label, 0, row, 1, 1);
layout.attach(this._passwordEntry, 1, row, 1, 1); layout.attach(this._passwordEntry, 1, row, 1, 1);
layout.attach(this._workSpinner, 2, row, 1, 1); layout.attach(this._workSpinner.actor, 2, row, 1, 1);
} }
row++; row++;
} else { } else {
@@ -121,8 +120,8 @@ class KeyringDialog extends ModalDialog.ModalDialog {
if (this.prompt.choice_visible) { if (this.prompt.choice_visible) {
let choice = new CheckBox.CheckBox(); let choice = new CheckBox.CheckBox();
this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE); this.prompt.bind_property('choice-label', choice.getLabelActor(), 'text', GObject.BindingFlags.SYNC_CREATE);
this.prompt.bind_property('choice-chosen', choice, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL); this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
layout.attach(choice, rtl ? 0 : 1, row, 1, 1); layout.attach(choice.actor, rtl ? 0 : 1, row, 1, 1);
row++; row++;
} }
@@ -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));
} }
} }
@@ -314,7 +310,7 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
case '802-11-wireless': case '802-11-wireless':
wirelessSetting = this._connection.get_setting_wireless(); wirelessSetting = this._connection.get_setting_wireless();
ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data()); ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data());
content.title = _("Authentication required by wireless network"); content.title = _("Authentication required");
content.message = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid); content.message = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
this._getWirelessSecrets(content.secrets, wirelessSetting); this._getWirelessSecrets(content.secrets, wirelessSetting);
break; break;
@@ -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");
@@ -342,13 +338,13 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
// fall through // fall through
case 'cdma': case 'cdma':
case 'bluetooth': case 'bluetooth':
content.title = _("Mobile broadband network password"); content.title = _("Mobile broadband password");
content.message = _("A password is required to connect to “%s”.").format(connectionSetting.get_id()); content.message = _("A password is required to connect to “%s”.").format(connectionSetting.get_id());
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;
} }
@@ -371,7 +367,8 @@ var VPNRequestHandler = class {
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 */
@@ -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();
} }
@@ -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
@@ -592,12 +587,12 @@ 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) {
@@ -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));
@@ -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");
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;
} }
@@ -734,7 +728,7 @@ var NetworkAgent = class {
}); });
Main.messageTray.add(source); Main.messageTray.add(source);
source.showNotification(notification); source.notify(notification);
} }
_newRequest(agent, requestId, connection, settingName, hints, flags) { _newRequest(agent, requestId, connection, settingName, hints, flags) {

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',
@@ -76,8 +76,8 @@ var AuthenticationDialog = GObject.registerClass({
this._userAvatar = new UserWidget.Avatar(this._user, this._userAvatar = new UserWidget.Avatar(this._user,
{ iconSize: DIALOG_ICON_SIZE, { iconSize: DIALOG_ICON_SIZE,
styleClass: 'polkit-dialog-user-icon' }); styleClass: 'polkit-dialog-user-icon' });
this._userAvatar.hide(); this._userAvatar.actor.hide();
userBox.add(this._userAvatar, userBox.add(this._userAvatar.actor,
{ x_fill: true, { x_fill: true,
y_fill: false, y_fill: false,
x_align: St.Align.END, x_align: St.Align.END,
@@ -106,7 +106,7 @@ var AuthenticationDialog = GObject.registerClass({
{ expand: true }); { expand: true });
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true); this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
this._passwordBox.add(this._workSpinner); this._passwordBox.add(this._workSpinner.actor);
this.setInitialKeyFocus(this._passwordEntry); this.setInitialKeyFocus(this._passwordEntry);
this._passwordBox.hide(); this._passwordBox.hide();
@@ -182,8 +182,8 @@ 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
@@ -305,7 +305,7 @@ var AuthenticationDialog = GObject.registerClass({
_onUserChanged() { _onUserChanged() {
if (this._user.is_loaded && this._userAvatar) { if (this._user.is_loaded && this._userAvatar) {
this._userAvatar.update(); this._userAvatar.update();
this._userAvatar.show(); this._userAvatar.actor.show();
} }
} }
@@ -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,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 { 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;
@@ -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();
} }
@@ -215,13 +217,13 @@ class TelepathyClient extends Tp.BaseClient {
// We are already handling the channel, display the source // We are already handling the channel, display the source
let source = this._chatSources[channel.get_object_path()]; let source = this._chatSources[channel.get_object_path()];
if (source) if (source)
source.showNotification(); source.notify();
} }
} }
} }
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,23 +255,22 @@ 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.
} }
}) : null; }) : null;
var ChatSource = HAVE_TP ? GObject.registerClass( var ChatSource = class extends MessageTray.Source {
class ChatSource extends MessageTray.Source { constructor(account, conn, channel, contact, client) {
_init(account, conn, channel, contact, client) { super(contact.get_alias());
super._init(contact.get_alias());
this._account = account; this._account = account;
this._contact = contact; this._contact = contact;
@@ -327,7 +328,7 @@ class ChatSource extends MessageTray.Source {
// We ack messages when the user expands the new notification // We ack messages when the user expands the new notification
let id = this._banner.connect('expanded', this._ackMessages.bind(this)); let id = this._banner.connect('expanded', this._ackMessages.bind(this));
this._banner.connect('destroy', () => { this._banner.actor.connect('destroy', () => {
this._banner.disconnect(id); this._banner.disconnect(id);
this._banner = null; this._banner = null;
}); });
@@ -428,7 +429,7 @@ class ChatSource 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();
@@ -477,7 +478,7 @@ class ChatSource extends MessageTray.Source {
this._notification.appendMessage(pendingMessages[i], true); this._notification.appendMessage(pendingMessages[i], true);
if (pendingMessages.length > 0) if (pendingMessages.length > 0)
this.showNotification(); this.notify();
} }
destroy(reason) { destroy(reason) {
@@ -546,15 +547,15 @@ class ChatSource 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');
} }
_notifyTimeout() { _notifyTimeout() {
if (this._pendingMessages.length != 0) if (this._pendingMessages.length != 0)
this.showNotification(); this.notify();
this._notifyTimeoutId = 0; this._notifyTimeoutId = 0;
@@ -563,14 +564,14 @@ class ChatSource 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);
} }
showNotification() { notify() {
super.showNotification(this._notification); super.notify(this._notification);
} }
respond(text) { respond(text) {
@@ -601,7 +602,7 @@ class ChatSource 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,
@@ -626,17 +627,11 @@ class ChatSource extends MessageTray.Source {
// 'pending-message-removed' for each one. // 'pending-message-removed' for each one.
this._channel.ack_all_pending_messages_async(null); this._channel.ack_all_pending_messages_async(null);
} }
}) : null; };
var ChatNotification = HAVE_TP ? GObject.registerClass({ var ChatNotification = class extends MessageTray.Notification {
Signals: { constructor(source) {
'message-removed': { param_types: [Tp.Message.$gtype] }, super(source, source.title, null,
'message-added': { param_types: [Tp.Message.$gtype] },
'timestamp-changed': { param_types: [Tp.Message.$gtype] },
}
}, class ChatNotification extends MessageTray.Notification {
_init(source) {
super._init(source, source.title, null,
{ secondaryGIcon: source.getSecondaryIcon() }); { secondaryGIcon: source.getSecondaryIcon() });
this.setUrgency(MessageTray.Urgency.HIGH); this.setUrgency(MessageTray.Urgency.HIGH);
this.setResident(true); this.setResident(true);
@@ -647,7 +642,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
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);
} }
@@ -680,8 +675,8 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
{ 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,
@@ -703,8 +698,8 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
// 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) {
@@ -735,7 +730,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
// 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',
@@ -753,8 +748,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
} 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');
@@ -789,7 +783,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
this._filterMessages(); this._filterMessages();
} }
}) : null; };
var ChatLineBox = GObject.registerClass( var ChatLineBox = GObject.registerClass(
class ChatLineBox extends St.BoxLayout { class ChatLineBox extends St.BoxLayout {
@@ -799,10 +793,9 @@ class ChatLineBox extends St.BoxLayout {
} }
}); });
var ChatNotificationBanner = GObject.registerClass( var ChatNotificationBanner = class extends MessageTray.NotificationBanner {
class ChatNotificationBanner extends MessageTray.NotificationBanner { constructor(notification) {
_init(notification) { super(notification);
super._init(notification);
this._responseEntry = new St.Entry({ style_class: 'chat-response', this._responseEntry = new St.Entry({ style_class: 'chat-response',
x_expand: true, x_expand: true,
@@ -887,7 +880,8 @@ class ChatNotificationBanner extends MessageTray.NotificationBanner {
} }
_addMessage(message) { _addMessage(message) {
let body = new MessageList.URLHighlighter(message.body, true, true); let highlighter = new MessageList.URLHighlighter(message.body, true, true);
let body = highlighter.actor;
let styles = message.styles; let styles = message.styles;
for (let i = 0; i < styles.length; i++) for (let i = 0; i < styles.length; i++)
@@ -959,15 +953,14 @@ class ChatNotificationBanner 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');
@@ -975,6 +968,6 @@ class ChatNotificationBanner extends MessageTray.NotificationBanner {
this.notification.source.setChatState(Tp.ChannelChatState.ACTIVE); this.notification.source.setChatState(Tp.ChannelChatState.ACTIVE);
} }
} }
}); };
var Component = TelepathyComponent; var Component = TelepathyComponent;

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,18 +1,19 @@
// -*- 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, const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
Graphene, Meta, Shell, St } = imports.gi; const Mainloop = imports.mainloop;
const Signals = imports.signals;
const AppDisplay = imports.ui.appDisplay; const AppDisplay = imports.ui.appDisplay;
const AppFavorites = imports.ui.appFavorites; 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,41 +24,13 @@ function getAppFromSource(source) {
} }
} }
var DashIcon = GObject.registerClass(
class DashIcon extends AppDisplay.AppIcon {
_init(app) {
super._init(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(
class DashItemContainer extends St.Widget { class DashItemContainer extends St.Widget {
_init() { _init() {
super._init({ style_class: 'dash-item-container', super._init({ style_class: 'dash-item-container',
pivot_point: new Graphene.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 });
@@ -68,11 +41,10 @@ class DashItemContainer extends St.Widget {
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();
@@ -109,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;
@@ -123,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',
}); });
} }
@@ -136,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();
}
}); });
} }
@@ -152,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) {
@@ -159,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
}); });
} }
@@ -177,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(
@@ -242,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;
@@ -297,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;
@@ -322,8 +321,8 @@ 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];
} }
@@ -331,10 +330,8 @@ class DashActor extends St.Widget {
const baseIconSizes = [ 16, 22, 24, 32, 48, 64 ]; const baseIconSizes = [ 16, 22, 24, 32, 48, 64 ];
var Dash = GObject.registerClass({ var Dash = class Dash {
Signals: { 'icon-size-changed': {} } constructor() {
}, class Dash extends St.Bin {
_init() {
this._maxHeight = -1; this._maxHeight = -1;
this.iconSize = 64; this.iconSize = 64;
this._shownInitially = false; this._shownInitially = false;
@@ -354,7 +351,8 @@ var Dash = GObject.registerClass({
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);
@@ -362,11 +360,11 @@ var Dash = GObject.registerClass({
this._container.add_actor(this._showAppsIcon); this._container.add_actor(this._showAppsIcon);
super._init({ child: this._container }); this.actor = new St.Bin({ child: this._container });
this.connect('notify::height', () => { this.actor.connect('notify::height', () => {
if (this._maxHeight != this.height) if (this._maxHeight != this.actor.height)
this._queueRedisplay(); this._queueRedisplay();
this._maxHeight = this.height; this._maxHeight = this.actor.height;
}); });
this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this)); this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this));
@@ -389,7 +387,7 @@ var Dash = GObject.registerClass({
// Translators: this is the name of the dock/favorites area on // Translators: this is the name of the dock/favorites area on
// the left of the overview // the left of the overview
Main.ctrlAltTabManager.addGroup(this, _("Dash"), 'user-bookmarks-symbolic'); Main.ctrlAltTabManager.addGroup(this.actor, _("Dash"), 'user-bookmarks-symbolic');
} }
_onDragBegin() { _onDragBegin() {
@@ -476,7 +474,19 @@ var Dash = GObject.registerClass({
} }
_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) => {
@@ -484,11 +494,11 @@ var Dash = GObject.registerClass({
}); });
let item = new DashItemContainer(); let item = new DashItemContainer();
item.setChild(appIcon); item.setChild(appIcon.actor);
// Override default AppIcon label_actor, now the // Override default AppIcon label_actor, now the
// accessible_name is set at DashItemContainer.setLabelText // accessible_name is set at DashItemContainer.setLabelText
appIcon.label_actor = null; appIcon.actor.label_actor = null;
item.setLabelText(app.get_name()); item.setLabelText(app.get_name());
appIcon.icon.setIconSize(this.iconSize); appIcon.icon.setIconSize(this.iconSize);
@@ -502,7 +512,7 @@ var Dash = GObject.registerClass({
// 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;
} }
@@ -516,7 +526,7 @@ var Dash = GObject.registerClass({
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();
@@ -525,17 +535,17 @@ var Dash = GObject.registerClass({
}); });
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;
@@ -623,11 +633,11 @@ var Dash = GObject.registerClass({
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',
}); });
} }
} }
@@ -690,14 +700,14 @@ var Dash = GObject.registerClass({
} }
// 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 });
@@ -706,8 +716,8 @@ var Dash = GObject.registerClass({
} }
// 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;
@@ -780,7 +790,7 @@ var Dash = GObject.registerClass({
} }
} }
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
@@ -858,7 +868,7 @@ var Dash = GObject.registerClass({
} }
// 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
@@ -905,4 +915,5 @@ var Dash = GObject.registerClass({
return true; return true;
} }
}); };
Signals.addSignalMethods(Dash.prototype);

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() &&
@@ -25,26 +19,22 @@ function _isToday(date) {
now.getDate() == date.getDate(); now.getDate() == date.getDate();
} }
function _gDateTimeToDate(datetime) { var TodayButton = class TodayButton {
return new Date(datetime.to_unix() * 1000 + datetime.get_microsecond() / 1000); constructor(calendar) {
}
var TodayButton = GObject.registerClass(
class TodayButton extends St.Button {
_init(calendar) {
// 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.
super._init({ 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._calendar.setDate(new Date(), false);
});
let hbox = new St.BoxLayout({ vertical: true }); let hbox = new St.BoxLayout({ vertical: true });
this.add_actor(hbox); this.actor.add_actor(hbox);
this._dayLabel = new St.Label({ style_class: 'day-label', this._dayLabel = new St.Label({ style_class: 'day-label',
x_align: Clutter.ActorAlign.START }); x_align: Clutter.ActorAlign.START });
@@ -54,17 +44,13 @@ class TodayButton extends St.Button {
hbox.add_actor(this._dateLabel); hbox.add_actor(this._dateLabel);
this._calendar = calendar; this._calendar = calendar;
this._calendar.connect('selected-date-changed', (_calendar, datetime) => { 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.reactive = !_isToday(_gDateTimeToDate(datetime)); this.actor.reactive = !_isToday(date)
}); });
} }
vfunc_clicked() {
this._calendar.setDate(new Date(), false);
}
setDate(date) { setDate(date) {
this._dayLabel.set_text(date.toLocaleFormat('%A')); this._dayLabel.set_text(date.toLocaleFormat('%A'));
@@ -81,72 +67,57 @@ class TodayButton extends St.Button {
* date, e.g. "Tuesday February 17 2015". * date, e.g. "Tuesday February 17 2015".
*/ */
dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y")); dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y"));
this.accessible_name = date.toLocaleFormat(dateFormat); this.actor.accessible_name = date.toLocaleFormat(dateFormat);
} }
}); };
var WorldClocksSection = GObject.registerClass( var WorldClocksSection = class WorldClocksSection {
class WorldClocksSection extends St.Button { constructor() {
_init() {
super._init({
style_class: 'world-clocks-button',
x_fill: true,
can_focus: true
});
this._clock = new GnomeDesktop.WallClock(); this._clock = new GnomeDesktop.WallClock();
this._clockNotifyId = 0; this._clockNotifyId = 0;
this._locations = []; this._locations = [];
this.actor = new St.Button({ style_class: 'world-clocks-button',
x_fill: true,
can_focus: true });
this.actor.connect('clicked', () => {
this._clockAppMon.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
});
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
this._grid = new St.Widget({ style_class: 'world-clocks-grid', this._grid = new St.Widget({ style_class: 'world-clocks-grid',
layout_manager: layout }); layout_manager: layout });
layout.hookup_style(this._grid); layout.hookup_style(this._grid);
this.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();
} }
vfunc_clicked() {
if (this._clocksApp)
this._clocksApp.activate();
Main.overview.hide();
Main.panel.closeCalendar();
}
_sync() { _sync() {
this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop'); this.actor.visible = this._clockAppMon.available;
this.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 });
} }
@@ -157,14 +128,13 @@ class WorldClocksSection extends St.Button {
}); });
let layout = this._grid.layout_manager; let layout = this._grid.layout_manager;
let title = (this._locations.length == 0) let title = (this._locations.length == 0) ? _("Add world clocks…")
? _("Add world clocks…")
: _("World Clocks"); : _("World Clocks");
let header = new St.Label({ style_class: 'world-clocks-header', let header = new St.Label({ style_class: 'world-clocks-header',
x_align: Clutter.ActorAlign.START, x_align: Clutter.ActorAlign.START,
text: title }); text: title });
layout.attach(header, 0, 0, 2, 1); layout.attach(header, 0, 0, 2, 1);
this.label_actor = header; this.actor.label_actor = header;
let localOffset = GLib.DateTime.new_now_local().get_utc_offset(); let localOffset = GLib.DateTime.new_now_local().get_utc_offset();
@@ -226,42 +196,30 @@ class WorldClocksSection extends St.Button {
l.actor.text = Util.formatTime(now, { timeOnly: true }); l.actor.text = Util.formatTime(now, { timeOnly: true });
} }
} }
};
_onProxyReady(proxy, error) { var WeatherSection = class WeatherSection {
if (error) { constructor() {
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 = GObject.registerClass(
class WeatherSection extends St.Button {
_init() {
super._init({
style_class: 'weather-button',
x_fill: true,
can_focus: true
});
this._weatherClient = new Weather.WeatherClient(); this._weatherClient = new Weather.WeatherClient();
this.actor = new St.Button({ style_class: 'weather-button',
x_fill: true,
can_focus: true });
this.actor.connect('clicked', () => {
this._weatherClient.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
});
this.actor.connect('notify::mapped', () => {
if (this.actor.mapped)
this._weatherClient.update();
});
let box = new St.BoxLayout({ style_class: 'weather-box', let box = new St.BoxLayout({ style_class: 'weather-box',
vertical: true }); vertical: true });
this.child = box; this.actor.child = box;
let titleBox = new St.BoxLayout(); let titleBox = new St.BoxLayout();
titleBox.add_child(new St.Label({ style_class: 'weather-header', titleBox.add_child(new St.Label({ style_class: 'weather-header',
@@ -284,18 +242,6 @@ class WeatherSection extends St.Button {
this._sync(); this._sync();
} }
vfunc_map() {
this._weatherClient.update();
super.vfunc_map();
}
vfunc_clicked() {
this._weatherClient.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
}
_getInfos() { _getInfos() {
let info = this._weatherClient.info; let info = this._weatherClient.info;
let forecasts = info.get_forecast_list(); let forecasts = info.get_forecast_list();
@@ -303,12 +249,12 @@ class WeatherSection extends St.Button {
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
@@ -329,7 +275,7 @@ class WeatherSection extends St.Button {
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
}); });
@@ -386,27 +332,23 @@ class WeatherSection extends St.Button {
} }
_sync() { _sync() {
this.visible = this._weatherClient.available; this.actor.visible = this._weatherClient.available;
if (!this.visible) if (!this.actor.visible)
return; return;
this._titleLocation.visible = this._weatherClient.hasLocation; this._titleLocation.visible = this._weatherClient.hasLocation;
this._updateForecasts(); this._updateForecasts();
} }
}); };
var MessagesIndicator = GObject.registerClass( var MessagesIndicator = class MessagesIndicator {
class MessagesIndicator extends St.Icon { constructor() {
_init() { this.actor = new St.Icon({ icon_name: 'message-indicator-symbolic',
super._init({
icon_name: 'message-indicator-symbolic',
icon_size: 16, icon_size: 16,
visible: false, visible: false, y_expand: true,
y_expand: true, y_align: Clutter.ActorAlign.CENTER });
y_align: Clutter.ActorAlign.CENTER
});
this._sources = []; this._sources = [];
@@ -415,11 +357,11 @@ class MessagesIndicator extends St.Icon {
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) {
source.connect('notify::count', this._updateCount.bind(this)); source.connect('count-updated', this._updateCount.bind(this));
this._sources.push(source); this._sources.push(source);
this._updateCount(); this._updateCount();
} }
@@ -431,19 +373,19 @@ class MessagesIndicator extends St.Icon {
_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.visible = (count > 0); this.actor.visible = (count > 0);
} }
}); };
var IndicatorPad = GObject.registerClass( 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();
} }
@@ -517,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;
@@ -529,9 +472,9 @@ class DateMenuButton extends PanelMenu.Button {
this._indicator = new MessagesIndicator(); this._indicator = new MessagesIndicator();
let box = new St.BoxLayout(); let box = new St.BoxLayout();
box.add_actor(new IndicatorPad(this._indicator)); box.add_actor(new IndicatorPad(this._indicator.actor));
box.add_actor(this._clockDisplay); box.add_actor(this._clockDisplay);
box.add_actor(this._indicator); box.add_actor(this._indicator.actor);
this.label_actor = this._clockDisplay; this.label_actor = this._clockDisplay;
this.add_actor(box); this.add_actor(box);
@@ -547,8 +490,8 @@ class DateMenuButton extends PanelMenu.Button {
bin.add_actor(hbox); bin.add_actor(hbox);
this._calendar = new Calendar.Calendar(); this._calendar = new Calendar.Calendar();
this._calendar.connect('selected-date-changed', (_calendar, datetime) => { this._calendar.connect('selected-date-changed',
let date = _gDateTimeToDate(datetime); (calendar, date) => {
layout.frozen = !_isToday(date); layout.frozen = !_isToday(date);
this._messageList.setDate(date); this._messageList.setDate(date);
}); });
@@ -565,19 +508,19 @@ class DateMenuButton extends PanelMenu.Button {
// Fill up the first column // Fill up the first column
this._messageList = new Calendar.CalendarMessageList(); this._messageList = new Calendar.CalendarMessageList();
hbox.add(this._messageList, { expand: true, y_fill: false, y_align: St.Align.START }); hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
// Fill up the second column // Fill up the second column
let boxLayout = new CalendarColumnLayout(this._calendar); let boxLayout = new CalendarColumnLayout(this._calendar.actor);
vbox = new St.Widget({ style_class: 'datemenu-calendar-column', vbox = new St.Widget({ style_class: 'datemenu-calendar-column',
layout_manager: boxLayout }); layout_manager: boxLayout });
boxLayout.hookup_style(vbox); boxLayout.hookup_style(vbox);
hbox.add(vbox); hbox.add(vbox);
this._date = new TodayButton(this._calendar); this._date = new TodayButton(this._calendar);
vbox.add_actor(this._date); vbox.add_actor(this._date.actor);
vbox.add_actor(this._calendar); vbox.add_actor(this._calendar.actor);
this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade', this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade',
x_expand: true, x_fill: true, x_expand: true, x_fill: true,
@@ -590,10 +533,10 @@ class DateMenuButton extends PanelMenu.Button {
this._displaysSection.add_actor(displaysBox); this._displaysSection.add_actor(displaysBox);
this._clocksItem = new WorldClocksSection(); this._clocksItem = new WorldClocksSection();
displaysBox.add(this._clocksItem, { x_fill: true }); displaysBox.add(this._clocksItem.actor, { x_fill: true });
this._weatherItem = new WeatherSection(); this._weatherItem = new WeatherSection();
displaysBox.add(this._weatherItem, { x_fill: true }); displaysBox.add(this._weatherItem.actor, { x_fill: true });
// Done with hbox for calendar and event list // Done with hbox for calendar and event list

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

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,26 +576,21 @@ 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);
let accepted = false; if (target._delegate.acceptDrop(this.actor._delegate,
try { this._dragActor,
accepted = target._delegate.acceptDrop(this.actor._delegate, targX,
this._dragActor, targX, targY, event.get_time()); targY,
} catch (e) { event.get_time())) {
// On error, skip this target
logError(e, "Skipping drag target");
}
if (accepted) {
// If it accepted the drop without taking the actor, // If it accepted the drop without taking the actor,
// handle it ourselves. // handle it ourselves.
if (this._dragActor && this._dragActor.get_parent() == Main.uiGroup) { if (this._dragActor && this._dragActor.get_parent() == Main.uiGroup) {
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);
@@ -614,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;
@@ -658,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,
}); });
} }
@@ -676,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 = {
@@ -207,10 +212,10 @@ function _setCheckBoxLabel(checkBox, text) {
if (text) { if (text) {
label.set_text(text); label.set_text(text);
checkBox.show(); checkBox.actor.show();
} else { } else {
label.set_text(''); label.set_text('');
checkBox.hide(); checkBox.actor.hide();
} }
} }
@@ -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',
@@ -297,8 +303,8 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
y_align: St.Align.START }); y_align: St.Align.START });
this._checkBox = new CheckBox.CheckBox(); this._checkBox = new CheckBox.CheckBox();
this._checkBox.connect('clicked', this._sync.bind(this)); this._checkBox.actor.connect('clicked', this._sync.bind(this));
messageLayout.add(this._checkBox); messageLayout.add(this._checkBox.actor);
this._batteryWarning = new St.Label({ style_class: 'end-session-dialog-warning', this._batteryWarning = new St.Label({ style_class: 'end-session-dialog-warning',
text: _("Running on battery power: please plug in before installing updates.") }); text: _("Running on battery power: please plug in before installing updates.") });
@@ -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);
@@ -376,12 +362,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let subject = dialogContent.subject; let subject = dialogContent.subject;
// Use different title when we are installing updates // Use different title when we are installing updates
if (dialogContent.subjectWithUpdates && this._checkBox.checked) if (dialogContent.subjectWithUpdates && this._checkBox.actor.checked)
subject = dialogContent.subjectWithUpdates; subject = dialogContent.subjectWithUpdates;
if (dialogContent.showBatteryWarning) { if (dialogContent.showBatteryWarning) {
// Warn when running on battery power // Warn when running on battery power
if (this._powerProxy.OnBattery && this._checkBox.checked) if (this._powerProxy.OnBattery && this._checkBox.actor.checked)
this._batteryWarning.opacity = 255; this._batteryWarning.opacity = 255;
else else
this._batteryWarning.opacity = 0; this._batteryWarning.opacity = 0;
@@ -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();
@@ -429,7 +414,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let avatarWidget = new UserWidget.Avatar(this._user, let avatarWidget = new UserWidget.Avatar(this._user,
{ iconSize: _DIALOG_ICON_SIZE, { iconSize: _DIALOG_ICON_SIZE,
styleClass: dialogContent.iconStyleClass }); styleClass: dialogContent.iconStyleClass });
this._iconBin.child = avatarWidget; this._iconBin.child = avatarWidget.actor;
avatarWidget.update(); avatarWidget.update();
} }
@@ -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);
@@ -485,13 +468,13 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
}; };
// Offline update not available; just emit the signal // Offline update not available; just emit the signal
if (!this._checkBox.visible) { if (!this._checkBox.actor.visible) {
callback(); callback();
return; return;
} }
// Trigger the offline update as requested // Trigger the offline update as requested
if (this._checkBox.checked) { if (this._checkBox.actor.checked) {
switch (signal) { switch (signal) {
case "ConfirmedReboot": case "ConfirmedReboot":
this._triggerOfflineUpdateReboot(callback); this._triggerOfflineUpdateReboot(callback);
@@ -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;
} }
@@ -656,7 +621,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let actor = new St.BoxLayout({ style_class: 'end-session-dialog-session-list-item', let actor = new St.BoxLayout({ style_class: 'end-session-dialog-session-list-item',
can_focus: true }); can_focus: true });
actor.add(avatar); actor.add(avatar.actor);
let nameLabel = new St.Label({ text: userLabelText, let nameLabel = new St.Label({ text: userLabelText,
style_class: 'end-session-dialog-session-list-item-name', style_class: 'end-session-dialog-session-list-item-name',
@@ -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,20 +712,19 @@ 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 || '');
this._checkBox.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed); this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
this._checkBox.checked = (updatePrepared && updateTriggered); this._checkBox.actor.checked = (updatePrepared && updateTriggered);
// We show the warning either together with the checkbox, or when // We show the warning either together with the checkbox, or when
// updates have already been triggered, but the user doesn't have // updates have already been triggered, but the user doesn't have
// enough permissions to cancel them. // enough permissions to cancel them.
this._batteryWarning.visible = (dialogContent.showBatteryWarning && this._batteryWarning.visible = (dialogContent.showBatteryWarning &&
(this._checkBox.visible || updatePrepared && updateTriggered && !updatesAllowed)); (this._checkBox.actor.visible || updatePrepared && updateTriggered && !updatesAllowed));
this._updateButtons(); this._updateButtons();
@@ -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,156 +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;
let repeatCount = 0;
if (params.repeatCount != undefined)
repeatCount = params.repeatCount;
delete params.repeatCount;
let autoReverse = false;
if (params.autoReverse != undefined)
autoReverse = params.autoReverse;
delete params.autoReverse;
if (params.mode != undefined)
actor.set_easing_mode(params.mode);
delete params.mode;
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.delay)
transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
else
Meta.disable_unredirect_for_display(global.display);
if (transition) {
transition.set({ repeatCount, autoReverse });
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);
let repeatCount = 0;
if (params.repeatCount != undefined)
repeatCount = params.repeatCount;
delete params.repeatCount;
let autoReverse = false;
if (params.autoReverse != undefined)
autoReverse = params.autoReverse;
delete params.autoReverse;
// Copy Clutter's behavior for implicit animations, see
// should_skip_implicit_transition()
if (actor instanceof Clutter.Actor && !actor.mapped)
duration = 0;
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;
Meta.disable_unredirect_for_display(global.display);
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,
repeat_count: repeatCount,
auto_reverse: autoReverse,
}, params));
actor.add_transition(propName, transition);
transition.set_to(target);
if (transition.delay)
transition.connect('started', () => Meta.disable_unredirect_for_display(global.display));
else
Meta.disable_unredirect_for_display(global.display);
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
@@ -242,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);
}; };
@@ -276,18 +106,12 @@ 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) {
@@ -304,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
@@ -314,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,20 @@
// -*- 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, Pango, Soup, St } = imports.gi;
const Config = imports.misc.config; const Config = imports.misc.config;
const Dialog = imports.ui.dialog; 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 +26,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 +35,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 +46,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 +54,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 +115,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 +127,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 +140,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 +153,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,14 +186,13 @@ 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 content = new Dialog.MessageDialogContent({
@@ -206,12 +205,12 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
this.contentLayout.add(content); this.contentLayout.add(content);
} }
_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,15 +222,20 @@ 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))
throw new Error(`Cannot add ${uuid} to enabled extensions gsettings key`);
} catch(e) { } catch(e) {
uninstallExtension(uuid); uninstallExtension(uuid);
errback('LoadExtensionError', e); errback('LoadExtensionError', e);

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);
} }
} }
@@ -77,41 +78,40 @@ 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) { function initExtension(uuid) {
if (!Main.sessionMode.allowExtensions) let extension = ExtensionUtils.extensions[uuid];
return false;
let extension = this.lookup(uuid);
if (!extension)
throw new Error("Extension was not properly created. Call createExtensionObject first");
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;
} }
@@ -325,7 +236,7 @@ var ExtensionManager = class {
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;
} }
@@ -333,7 +244,7 @@ var ExtensionManager = class {
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 = [];
if (global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY))
return extensions;
return extensions.concat(global.settings.get_strv(ENABLED_EXTENSIONS_KEY));
} }
_updateCanChange(extension) { function onEnabledExtensionsChanged() {
let hasError = let newEnabledExtensions = getEnabledExtensions();
extension.state == ExtensionState.ERROR ||
extension.state == ExtensionState.OUT_OF_DATE;
let isMode = this._getModeExtensions().includes(extension.uuid); if (!enabled)
let modeOnly = global.settings.get_boolean(DISABLE_USER_EXTENSIONS_KEY); return;
let changeKey = isMode
? DISABLE_USER_EXTENSIONS_KEY
: ENABLED_EXTENSIONS_KEY;
extension.canChange =
!hasError &&
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,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported CandidatePopup */
const { Clutter, GObject, IBus, St } = imports.gi; const { Clutter, IBus, St } = imports.gi;
const Signals = imports.signals;
const BoxPointer = imports.ui.boxpointer; const BoxPointer = imports.ui.boxpointer;
const Main = imports.ui.main; const Main = imports.ui.main;
@@ -11,23 +11,11 @@ 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 = GObject.registerClass({ var CandidateArea = class CandidateArea {
Signals: { constructor() {
'candidate-clicked': { param_types: [GObject.TYPE_UINT, this.actor = new St.BoxLayout({ vertical: true,
GObject.TYPE_UINT,
Clutter.ModifierType.$gtype] },
'cursor-down': {},
'cursor-up': {},
'next-page': {},
'previous-page': {},
}
}, class CandidateArea extends St.BoxLayout {
_init() {
super._init({
vertical: true,
reactive: true, reactive: true,
visible: false visible: false });
});
this._candidateBoxes = []; this._candidateBoxes = [];
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) { for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
let box = new St.BoxLayout({ style_class: 'candidate-box', let box = new St.BoxLayout({ style_class: 'candidate-box',
@@ -38,7 +26,7 @@ var CandidateArea = GObject.registerClass({
box.add(box._indexLabel, { y_fill: false }); box.add(box._indexLabel, { y_fill: false });
box.add(box._candidateLabel, { y_fill: false }); box.add(box._candidateLabel, { y_fill: false });
this._candidateBoxes.push(box); this._candidateBoxes.push(box);
this.add(box); this.actor.add(box);
let j = i; let j = i;
box.connect('button-release-event', (actor, event) => { box.connect('button-release-event', (actor, event) => {
@@ -47,6 +35,19 @@ var CandidateArea = GObject.registerClass({
}); });
} }
this.actor.connect('scroll-event', (actor, event) => {
let direction = event.get_scroll_direction();
switch(direction) {
case Clutter.ScrollDirection.UP:
this.emit('cursor-up');
break;
case Clutter.ScrollDirection.DOWN:
this.emit('cursor-down');
break;
};
return Clutter.EVENT_PROPAGATE;
});
this._buttonBox = new St.BoxLayout({ style_class: 'candidate-page-button-box' }); this._buttonBox = new St.BoxLayout({ style_class: 'candidate-page-button-box' });
this._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous button' }); this._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous button' });
@@ -57,7 +58,7 @@ var CandidateArea = GObject.registerClass({
this._nextButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' }); this._nextButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' });
this._buttonBox.add(this._nextButton, { expand: true }); this._buttonBox.add(this._nextButton, { expand: true });
this.add(this._buttonBox); this.actor.add(this._buttonBox);
this._previousButton.connect('clicked', () => { this._previousButton.connect('clicked', () => {
this.emit('previous-page'); this.emit('previous-page');
@@ -70,18 +71,6 @@ var CandidateArea = GObject.registerClass({
this._cursorPosition = 0; this._cursorPosition = 0;
} }
vfunc_scroll_event(scrollEvent) {
switch (scrollEvent.direction) {
case Clutter.ScrollDirection.UP:
this.emit('cursor-up');
break;
case Clutter.ScrollDirection.DOWN:
this.emit('cursor-down');
break;
}
return Clutter.EVENT_PROPAGATE;
}
setOrientation(orientation) { setOrientation(orientation) {
if (this._orientation == orientation) if (this._orientation == orientation)
return; return;
@@ -89,15 +78,15 @@ var CandidateArea = GObject.registerClass({
this._orientation = orientation; this._orientation = orientation;
if (this._orientation == IBus.Orientation.HORIZONTAL) { if (this._orientation == IBus.Orientation.HORIZONTAL) {
this.vertical = false; this.actor.vertical = false;
this.remove_style_class_name('vertical'); this.actor.remove_style_class_name('vertical');
this.add_style_class_name('horizontal'); this.actor.add_style_class_name('horizontal');
this._previousButton.child.icon_name = 'go-previous-symbolic'; this._previousButton.child.icon_name = 'go-previous-symbolic';
this._nextButton.child.icon_name = 'go-next-symbolic'; this._nextButton.child.icon_name = 'go-next-symbolic';
} else { // VERTICAL || SYSTEM } else { // VERTICAL || SYSTEM
this.vertical = true; this.actor.vertical = true;
this.add_style_class_name('vertical'); this.actor.add_style_class_name('vertical');
this.remove_style_class_name('horizontal'); this.actor.remove_style_class_name('horizontal');
this._previousButton.child.icon_name = 'go-up-symbolic'; this._previousButton.child.icon_name = 'go-up-symbolic';
this._nextButton.child.icon_name = 'go-down-symbolic'; this._nextButton.child.icon_name = 'go-down-symbolic';
} }
@@ -131,23 +120,19 @@ var CandidateArea = GObject.registerClass({
this._previousButton.reactive = wrapsAround || page > 0; this._previousButton.reactive = wrapsAround || page > 0;
this._nextButton.reactive = wrapsAround || page < nPages - 1; this._nextButton.reactive = wrapsAround || page < nPages - 1;
} }
}); };
Signals.addSignalMethods(CandidateArea.prototype);
var CandidatePopup = GObject.registerClass( var CandidatePopup = class CandidatePopup {
class IbusCandidatePopup extends BoxPointer.BoxPointer { constructor() {
_init() { this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
super._init(St.Side.TOP); this._boxPointer.visible = false;
this.visible = false; this._boxPointer.style_class = 'candidate-popup-boxpointer';
this.style_class = 'candidate-popup-boxpointer'; Main.layoutManager.addChrome(this._boxPointer);
this._dummyCursor = new St.Widget({ opacity: 0 });
Main.layoutManager.uiGroup.add_actor(this._dummyCursor);
Main.layoutManager.addChrome(this);
let box = new St.BoxLayout({ style_class: 'candidate-popup-content', let box = new St.BoxLayout({ style_class: 'candidate-popup-content',
vertical: true }); vertical: true });
this.bin.set_child(box); this._boxPointer.bin.set_child(box);
this._preeditText = new St.Label({ style_class: 'candidate-popup-text', this._preeditText = new St.Label({ style_class: 'candidate-popup-text',
visible: false }); visible: false });
@@ -158,7 +143,7 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
box.add(this._auxText); box.add(this._auxText);
this._candidateArea = new CandidateArea(); this._candidateArea = new CandidateArea();
box.add(this._candidateArea); box.add(this._candidateArea.actor);
this._candidateArea.connect('previous-page', () => { this._candidateArea.connect('previous-page', () => {
this._panelService.page_up(); this._panelService.page_up();
@@ -213,30 +198,30 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
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.visible = visible; this._candidateArea.actor.visible = visible;
this._updateVisibility(); this._updateVisibility();
let nCandidates = lookupTable.get_number_of_candidates(); let nCandidates = lookupTable.get_number_of_candidates();
@@ -271,40 +256,38 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
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.show(); this._candidateArea.actor.show();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('hide-lookup-table', () => { panelService.connect('hide-lookup-table', ps => {
this._candidateArea.hide(); this._candidateArea.actor.hide();
this._updateVisibility(); this._updateVisibility();
}); });
panelService.connect('focus-out', () => { panelService.connect('focus-out', ps => {
this.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)
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
if (this.visible)
this.setPosition(this._dummyCursor, 0);
} }
_updateVisibility() { _updateVisibility() {
let isVisible = (!Main.keyboard.visible && let isVisible = (!Main.keyboard.visible &&
(this._preeditText.visible || (this._preeditText.visible ||
this._auxText.visible || this._auxText.visible ||
this._candidateArea.visible)); this._candidateArea.actor.visible));
if (isVisible) { if (isVisible) {
this.setPosition(this._dummyCursor, 0); this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
this.open(BoxPointer.PopupAnimation.NONE); this._boxPointer.open(BoxPointer.PopupAnimation.NONE);
this.raise_top(); this._boxPointer.raise_top();
} else { } else {
this.close(BoxPointer.PopupAnimation.NONE); this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
} }
} }
@@ -314,4 +297,4 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
if (attr.get_attr_type() == IBus.AttrType.BACKGROUND) if (attr.get_attr_type() == IBus.AttrType.BACKGROUND)
clutterText.set_selection(attr.get_start_index(), attr.get_end_index()); clutterText.set_selection(attr.get_start_index(), attr.get_end_index());
} }
}); };

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 BaseIcon, IconGrid, PaginatedIconGrid */
const { Clutter, GLib, GObject, Graphene, 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;
@@ -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,15 +164,17 @@ 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();
}
}); });
} }
@@ -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
@@ -231,23 +214,15 @@ var IconGrid = GObject.registerClass({
this._fixedHItemSize = this._fixedVItemSize = undefined; this._fixedHItemSize = this._fixedVItemSize = undefined;
this.connect('style-changed', this._onStyleChanged.bind(this)); this.connect('style-changed', this._onStyleChanged.bind(this));
this.connect('actor-added', this._childAdded.bind(this));
this.connect('actor-removed', this._childRemoved.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
}
vfunc_unmap() {
// Cancel animations when hiding the overview, to avoid icons // Cancel animations when hiding the overview, to avoid icons
// swarming into the void ... // swarming into the void ...
this._resetAnimationActors(); this.connect('notify::mapped', () => {
super.vfunc_unmap(); if (!this.mapped)
} this._cancelAnimation();
});
_onDestroy() { this.connect('actor-added', this._childAdded.bind(this));
if (this._updateIconSizesLaterId) { this.connect('actor-removed', this._childRemoved.bind(this));
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)
@@ -402,7 +364,7 @@ var IconGrid = GObject.registerClass({
let allocationBox = this.get_allocation_box(); let allocationBox = this.get_allocation_box();
let paintBox = themeNode.get_paint_box(allocationBox); let paintBox = themeNode.get_paint_box(allocationBox);
let origin = new Graphene.Point3D(); let origin = new Clutter.Vertex();
origin.x = paintBox.x1 - allocationBox.x1; origin.x = paintBox.x1 - allocationBox.x1;
origin.y = paintBox.y1 - allocationBox.y1; origin.y = paintBox.y1 - allocationBox.y1;
origin.z = 0.0; origin.z = 0.0;
@@ -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();
@@ -717,13 +669,13 @@ var IconGrid = GObject.registerClass({
this._items.push(item); this._items.push(item);
if (index !== undefined) if (index !== undefined)
this.insert_child_at_index(item, index); this.insert_child_at_index(item.actor, index);
else else
this.add_actor(item); this.add_actor(item.actor);
} }
removeItem(item) { removeItem(item) {
this.remove_child(item); this.remove_child(item.actor);
} }
getItemAtIndex(index) { getItemAtIndex(index) {
@@ -791,33 +743,30 @@ 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;
} }
}); });
@@ -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,6 +802,7 @@ 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);
@@ -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;
} }
@@ -963,7 +915,7 @@ var PaginatedIconGrid = GObject.registerClass({
*/ */
openExtraSpace(sourceItem, side, nRows) { openExtraSpace(sourceItem, side, nRows) {
let children = this._getVisibleChildren(); let children = this._getVisibleChildren();
let index = children.indexOf(sourceItem); let index = children.indexOf(sourceItem.actor);
if (index == -1) if (index == -1)
throw new Error('Item not found.'); throw new Error('Item not found.');
@@ -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;

File diff suppressed because it is too large Load Diff

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,11 +10,12 @@ 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
@@ -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' });
});
} }
} }
} }
@@ -606,17 +588,17 @@ var LayoutManager = GObject.registerClass({
return; return;
} }
this._systemBackground = new Background.SystemBackground(); this._systemBackground = new Background.SystemBackground();
this._systemBackground.hide(); this._systemBackground.actor.hide();
global.stage.insert_child_below(this._systemBackground, null); global.stage.insert_child_below(this._systemBackground.actor, null);
let constraint = new Clutter.BindConstraint({ source: global.stage, let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.ALL }); coordinate: Clutter.BindCoordinate.ALL });
this._systemBackground.add_constraint(constraint); this._systemBackground.actor.add_constraint(constraint);
let signalId = this._systemBackground.connect('loaded', () => { let signalId = this._systemBackground.connect('loaded', () => {
this._systemBackground.disconnect(signalId); this._systemBackground.disconnect(signalId);
this._systemBackground.show(); this._systemBackground.actor.show();
global.stage.show(); global.stage.show();
this._prepareStartupAnimation(); this._prepareStartupAnimation();
@@ -699,30 +681,30 @@ 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() {
this._coverPane.destroy(); this._coverPane.destroy();
this._coverPane = null; this._coverPane = null;
this._systemBackground.destroy(); this._systemBackground.actor.destroy();
this._systemBackground = null; this._systemBackground = null;
this._startingUp = false; this._startingUp = false;
@@ -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,17 +1056,16 @@ 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 });
@@ -1112,11 +1097,8 @@ var LayoutManager = GObject.registerClass({
// //
// This class manages a "hot corner" that can toggle switching to // This class manages a "hot corner" that can toggle switching to
// overview. // overview.
var HotCorner = GObject.registerClass( var HotCorner = class HotCorner {
class HotCorner extends Clutter.Actor { constructor(layoutManager, monitor, x, y) {
_init(layoutManager, monitor, x, y) {
super._init();
// We use this flag to mark the case where the user has entered the // We use this flag to mark the case where the user has entered the
// hot corner and has not left both the hot corner and a surrounding // hot corner and has not left both the hot corner and a surrounding
// guard area (the "environs"). This avoids triggering the hot corner // guard area (the "environs"). This avoids triggering the hot corner
@@ -1145,8 +1127,6 @@ class HotCorner extends Clutter.Actor {
this._ripples = new Ripples.Ripples(px, py, 'ripple-box'); this._ripples = new Ripples.Ripples(px, py, 'ripple-box');
this._ripples.addTo(layoutManager.uiGroup); this._ripples.addTo(layoutManager.uiGroup);
this.connect('destroy', this._onDestroy.bind(this));
} }
setBarrierSize(size) { setBarrierSize(size) {
@@ -1186,14 +1166,11 @@ class HotCorner extends Clutter.Actor {
_setupFallbackCornerIfNeeded(layoutManager) { _setupFallbackCornerIfNeeded(layoutManager) {
if (!global.display.supports_extended_barriers()) { if (!global.display.supports_extended_barriers()) {
this.set({ this.actor = new Clutter.Actor({ name: 'hot-corner-environs',
name: 'hot-corner-environs', x: this._x, y: this._y,
x: this._x,
y: this._y,
width: 3, width: 3,
height: 3, height: 3,
reactive: true reactive: true });
});
this._corner = new Clutter.Actor({ name: 'hot-corner', this._corner = new Clutter.Actor({ name: 'hot-corner',
width: 1, width: 1,
@@ -1202,16 +1179,19 @@ class HotCorner extends Clutter.Actor {
reactive: true }); reactive: true });
this._corner._delegate = this; this._corner._delegate = this;
this.add_child(this._corner); this.actor.add_child(this._corner);
layoutManager.addChrome(this); layoutManager.addChrome(this.actor);
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) { if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
this._corner.set_position(this.width - this._corner.width, 0); this._corner.set_position(this.actor.width - this._corner.width, 0);
this.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST); this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
} else { } else {
this._corner.set_position(0, 0); this._corner.set_position(0, 0);
} }
this.actor.connect('leave-event',
this._onEnvironsLeft.bind(this));
this._corner.connect('enter-event', this._corner.connect('enter-event',
this._onCornerEntered.bind(this)); this._onCornerEntered.bind(this));
this._corner.connect('leave-event', this._corner.connect('leave-event',
@@ -1219,12 +1199,13 @@ class HotCorner extends Clutter.Actor {
} }
} }
_onDestroy() { destroy() {
this.setBarrierSize(0); this.setBarrierSize(0);
this._pressureBarrier.destroy(); this._pressureBarrier.destroy();
this._pressureBarrier = null; this._pressureBarrier = null;
this._ripples.destroy(); if (this.actor)
this.actor.destroy();
} }
_toggleOverview() { _toggleOverview() {
@@ -1237,7 +1218,7 @@ class HotCorner extends Clutter.Actor {
} }
} }
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;
@@ -1255,18 +1236,18 @@ class HotCorner extends Clutter.Actor {
} }
_onCornerLeft(actor, event) { _onCornerLeft(actor, event) {
if (event.get_related() != this) if (event.get_related() != this.actor)
this._entered = false; this._entered = false;
// Consume event, otherwise this will confuse onEnvironsLeft // Consume event, otherwise this will confuse onEnvironsLeft
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
vfunc_leave_event(crossingEvent) { _onEnvironsLeft(actor, event) {
if (crossingEvent.related != this._corner) if (event.get_related() != this._corner)
this._entered = false; this._entered = false;
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
} }
}); };
var PressureBarrier = class PressureBarrier { var PressureBarrier = class PressureBarrier {
constructor(threshold, timeout, actionMode) { constructor(threshold, timeout, actionMode) {
@@ -1338,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++;
@@ -1347,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,9 +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 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;
@@ -22,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() {
@@ -59,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');
} }
}); });
@@ -88,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
* - fadeFactor: fading opacity factor * - fadeInTime: seconds used to fade in
* - radialEffect: whether to enable the GLSL radial effect * - 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
@@ -105,49 +85,44 @@ var RadialShaderEffect = GObject.registerClass({
* @container and will track any changes in its size. You can override * @container and will track any changes in its size. You can override
* this by passing an explicit width and height in @params. * this by passing an explicit width and height in @params.
*/ */
var Lightbox = GObject.registerClass({ var Lightbox = class Lightbox {
Properties: { constructor(container, params) {
'active': GObject.ParamSpec.boolean( params = Params.parse(params, { inhibitEvents: false,
'active', 'active', 'active', GObject.ParamFlags.READABLE, false),
}
}, class Lightbox extends St.Bin {
_init(container, params) {
params = Params.parse(params, {
inhibitEvents: false,
width: null, width: null,
height: null, height: null,
fadeFactor: DEFAULT_FADE_FACTOR, fadeFactor: DEFAULT_FADE_FACTOR,
radialEffect: false, radialEffect: false,
}); });
super._init({
reactive: params.inhibitEvents,
width: params.width,
height: params.height,
visible: false
});
this._active = false;
this._container = container; this._container = container;
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;
if (this._radialEffect) if (this._radialEffect)
this.add_effect(new RadialShaderEffect({ name: 'radial' })); this.actor = new RadialShaderQuad({ x: 0,
y: 0,
reactive: params.inhibitEvents });
else else
this.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); container.add_actor(this.actor);
this.raise_top(); this.actor.raise_top();
this.actor.hide();
this.shown = false;
this.connect('destroy', this._onDestroy.bind(this)); this.actor.connect('destroy', this._onDestroy.bind(this));
if (!params.width || !params.height) { if (params.width && params.height) {
this.add_constraint(new Clutter.BindConstraint({ this.actor.width = params.width;
source: container, this.actor.height = params.height;
coordinate: Clutter.BindCoordinate.ALL } else {
})); let constraint = new Clutter.BindConstraint({ source: container,
coordinate: Clutter.BindCoordinate.ALL });
this.actor.add_constraint(constraint);
} }
this._actorAddedSignalId = container.connect('actor-added', this._actorAdded.bind(this)); this._actorAddedSignalId = container.connect('actor-added', this._actorAdded.bind(this));
@@ -156,20 +131,16 @@ var Lightbox = GObject.registerClass({
this._highlighted = null; this._highlighted = null;
} }
get active() {
return this._active;
}
_actorAdded(container, newChild) { _actorAdded(container, newChild) {
let children = this._container.get_children(); let children = this._container.get_children();
let myIndex = children.indexOf(this); let myIndex = children.indexOf(this.actor);
let newChildIndex = children.indexOf(newChild); let newChildIndex = children.indexOf(newChild);
if (newChildIndex > myIndex) { if (newChildIndex > myIndex) {
// The child was added above the shade (presumably it was // The child was added above the shade (presumably it was
// made the new top-most child). Move it below the shade, // made the new top-most child). Move it below the shade,
// and add it to this._children as the new topmost actor. // and add it to this._children as the new topmost actor.
this._container.set_child_above_sibling(this, newChild); newChild.lower(this.actor);
this._children.push(newChild); this._children.push(newChild);
} else if (newChildIndex == 0) { } else if (newChildIndex == 0) {
// Bottom of stack // Bottom of stack
@@ -182,55 +153,61 @@ var Lightbox = GObject.registerClass({
} }
} }
lightOn(fadeInTime) { show(fadeInTime) {
this.remove_all_transitions(); fadeInTime = fadeInTime || 0;
let easeProps = {
duration: fadeInTime || 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
};
let onComplete = () => {
this._active = true;
this.notify('active');
};
this.show();
Tweener.removeTweens(this.actor);
if (this._radialEffect) { if (this._radialEffect) {
this.ease_property( Tweener.addTween(this.actor,
'@effects.radial.brightness', VIGNETTE_BRIGHTNESS, easeProps); { brightness: VIGNETTE_BRIGHTNESS,
this.ease_property( vignetteSharpness: VIGNETTE_SHARPNESS,
'@effects.radial.sharpness', VIGNETTE_SHARPNESS, time: fadeInTime,
Object.assign({ onComplete }, easeProps)); transition: 'easeOutQuad',
} else { onComplete: () => {
this.ease(Object.assign(easeProps, { this.shown = true;
opacity: 255 * this._fadeFactor, this.emit('shown');
onComplete
}));
} }
});
} else {
Tweener.addTween(this.actor,
{ opacity: 255 * this._fadeFactor,
time: fadeInTime,
transition: 'easeOutQuad',
onComplete: () => {
this.shown = true;
this.emit('shown');
}
});
} }
lightOff(fadeOutTime) { this.actor.show();
this.remove_all_transitions(); }
this._active = false; hide(fadeOutTime) {
this.notify('active'); fadeOutTime = fadeOutTime || 0;
let easeProps = {
duration: fadeOutTime || 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
};
let onComplete = () => this.hide();
this.shown = false;
Tweener.removeTweens(this.actor);
if (this._radialEffect) { if (this._radialEffect) {
this.ease_property( Tweener.addTween(this.actor,
'@effects.radial.brightness', 1.0, easeProps); { brightness: 1.0,
this.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.ease(Object.assign(easeProps, { opacity: 0, onComplete })); Tweener.addTween(this.actor,
{ opacity: 0,
time: fadeOutTime,
transition: 'easeOutQuad',
onComplete: () => {
this.actor.hide();
}
});
} }
} }
@@ -261,7 +238,7 @@ var Lightbox = GObject.registerClass({
// case we may need to indicate some *other* actor as the new // case we may need to indicate some *other* actor as the new
// sibling of the to-be-lowered one. // sibling of the to-be-lowered one.
let below = this; let below = this.actor;
for (let i = this._children.length - 1; i >= 0; i--) { for (let i = this._children.length - 1; i >= 0; i--) {
if (this._children[i] == window) if (this._children[i] == window)
this._children[i].raise_top(); this._children[i].raise_top();
@@ -274,6 +251,15 @@ var Lightbox = GObject.registerClass({
this._highlighted = window; this._highlighted = window;
} }
/**
* destroy:
*
* Destroys the lightbox.
*/
destroy() {
this.actor.destroy();
}
/** /**
* _onDestroy: * _onDestroy:
* *
@@ -281,15 +267,10 @@ var Lightbox = GObject.registerClass({
* by destroying its container or by explicitly calling this.destroy(). * by destroying its container or by explicitly calling this.destroy().
*/ */
_onDestroy() { _onDestroy() {
if (this._actorAddedSignalId) {
this._container.disconnect(this._actorAddedSignalId); this._container.disconnect(this._actorAddedSignalId);
this._actorAddedSignalId = 0;
}
if (this._actorRemovedSignalId) {
this._container.disconnect(this._actorRemovedSignalId); this._container.disconnect(this._actorRemovedSignalId);
this._actorRemovedSignalId = 0;
}
this.highlight(null); this.highlight(null);
} }
}); };
Signals.addSignalMethods(Lightbox.prototype);

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, GObject, const { Clutter, Cogl, Gio, GLib,
Graphene, 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 '_')
@@ -110,11 +110,9 @@ var AutoComplete = class AutoComplete {
Signals.addSignalMethods(AutoComplete.prototype); Signals.addSignalMethods(AutoComplete.prototype);
var Notebook = GObject.registerClass({ var Notebook = class Notebook {
Signals: { 'selection': { param_types: [Clutter.Actor.$gtype] } }, constructor() {
}, class Notebook extends St.BoxLayout { this.actor = new St.BoxLayout({ vertical: true });
_init() {
super._init({ vertical: true });
this.tabControls = new St.BoxLayout({ style_class: 'labels' }); this.tabControls = new St.BoxLayout({ style_class: 'labels' });
@@ -145,11 +143,11 @@ var Notebook = GObject.registerClass({
_scrollToBottom: false }; _scrollToBottom: false };
this._tabs.push(tabData); this._tabs.push(tabData);
scrollview.hide(); scrollview.hide();
this.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);
@@ -176,7 +174,7 @@ var Notebook = GObject.registerClass({
// Focus the new tab before unmapping the old one // Focus the new tab before unmapping the old one
let tabData = this._tabs[index]; let tabData = this._tabs[index];
if (!tabData.scrollView.navigate_focus(null, St.DirectionType.TAB_FORWARD, false)) if (!tabData.scrollView.navigate_focus(null, St.DirectionType.TAB_FORWARD, false))
this.grab_key_focus(); this.actor.grab_key_focus();
this._unselect(); this._unselect();
@@ -187,9 +185,9 @@ var Notebook = GObject.registerClass({
} }
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) {
@@ -236,75 +234,69 @@ var Notebook = GObject.registerClass({
this.selectIndex(prevIndex); this.selectIndex(prevIndex);
} }
}); };
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;
} }
} }
var ObjLink = GObject.registerClass( var ObjLink = class ObjLink {
class ObjLink extends St.Button { constructor(lookingGlass, o, title) {
_init(lookingGlass, o, title) {
let text; let text;
if (title) if (title)
text = title; text = title;
else else
text = objectToString(o); text = objectToString(o);
text = GLib.markup_escape_text(text, -1); text = GLib.markup_escape_text(text, -1);
this._obj = o;
super._init({ this.actor = new St.Button({ reactive: true,
reactive: true,
track_hover: true, track_hover: true,
style_class: 'shell-link', style_class: 'shell-link',
label: text label: text });
}); this.actor.get_child().single_line_mode = true;
this.get_child().single_line_mode = true; this.actor.connect('clicked', this._onClicked.bind(this));
this._obj = o;
this._lookingGlass = lookingGlass; this._lookingGlass = lookingGlass;
} }
vfunc_clicked() { _onClicked(link) {
this._lookingGlass.inspectObject(this._obj, this); this._lookingGlass.inspectObject(this._obj, this.actor);
} }
}); };
var Result = GObject.registerClass({
GTypeName: 'LookingClass_Result'
}, class Result extends St.BoxLayout {
_init(lookingGlass, command, o, index) {
super._init({ vertical: true });
var Result = class Result {
constructor(lookingGlass, command, o, index) {
this.index = index; this.index = index;
this.o = o; this.o = o;
this.actor = new St.BoxLayout({ vertical: true });
this._lookingGlass = lookingGlass; this._lookingGlass = lookingGlass;
let cmdTxt = new St.Label({ text: command }); let cmdTxt = new St.Label({ text: command });
cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END; cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
this.add(cmdTxt); this.actor.add(cmdTxt);
let box = new St.BoxLayout({}); let box = new St.BoxLayout({});
this.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);
box.add(objLink); box.add(objLink.actor);
} }
}); };
var WindowList = GObject.registerClass({ var WindowList = class WindowList {
GTypeName: 'LookingClass_WindowList' constructor(lookingGlass) {
}, class WindowList extends St.BoxLayout { this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
_init(lookingGlass) {
super._init({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
let tracker = Shell.WindowTracker.get_default(); let tracker = Shell.WindowTracker.get_default();
this._updateId = Main.initializeDeferredWork(this, this._updateWindowList.bind(this)); this._updateId = Main.initializeDeferredWork(this.actor, this._updateWindowList.bind(this));
global.display.connect('window-created', this._updateWindowList.bind(this)); global.display.connect('window-created', this._updateWindowList.bind(this));
tracker.connect('tracked-windows-changed', this._updateWindowList.bind(this)); tracker.connect('tracked-windows-changed', this._updateWindowList.bind(this));
@@ -312,10 +304,7 @@ var WindowList = GObject.registerClass({
} }
_updateWindowList() { _updateWindowList() {
if (!this._lookingGlass.isOpen) this.actor.destroy_all_children();
return;
this.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();
for (let i = 0; i < windows.length; i++) { for (let i = 0; i < windows.length; i++) {
@@ -326,12 +315,12 @@ var WindowList = GObject.registerClass({
metaWindow._lookingGlassManaged = true; metaWindow._lookingGlassManaged = true;
} }
let box = new St.BoxLayout({ vertical: true }); let box = new St.BoxLayout({ vertical: true });
this.add(box); this.actor.add(box);
let windowLink = new ObjLink(this._lookingGlass, metaWindow, metaWindow.title); let windowLink = new ObjLink(this._lookingGlass, metaWindow, metaWindow.title);
box.add(windowLink, { 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);
@@ -339,38 +328,30 @@ var WindowList = GObject.registerClass({
propsBox.add(propBox); propsBox.add(propBox);
propBox.add(new St.Label({ text: 'app: ' }), { y_fill: false }); propBox.add(new St.Label({ text: 'app: ' }), { y_fill: false });
let appLink = new ObjLink(this._lookingGlass, app, app.get_id()); let appLink = new ObjLink(this._lookingGlass, app, app.get_id());
propBox.add(appLink, { y_fill: false }); propBox.add(appLink.actor, { y_fill: false });
propBox.add(icon, { y_fill: false }); propBox.add(icon, { y_fill: false });
} else { } else {
propsBox.add(new St.Label({ text: '<untracked>' })); propsBox.add(new St.Label({ text: '<untracked>' }));
} }
} }
} }
};
Signals.addSignalMethods(WindowList.prototype);
update() { var ObjInspector = class ObjInspector {
this._updateWindowList(); constructor(lookingGlass) {
}
});
var ObjInspector = GObject.registerClass(
class ObjInspector extends St.ScrollView {
_init(lookingGlass) {
super._init({
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
x_fill: true,
y_fill: true
});
this._obj = null; this._obj = null;
this._previousObj = null; this._previousObj = null;
this._parentList = []; this._parentList = [];
this.get_hscroll_bar().hide(); this.actor = new St.ScrollView({ pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
x_fill: true, y_fill: true });
this.actor.get_hscroll_bar().hide();
this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector', this._container = new St.BoxLayout({ name: 'LookingGlassPropertyInspector',
style_class: 'lg-dialog', style_class: 'lg-dialog',
vertical: true }); vertical: true });
this.add_actor(this._container); this.actor.add_actor(this._container);
this._lookingGlass = lookingGlass; this._lookingGlass = lookingGlass;
} }
@@ -386,7 +367,7 @@ class ObjInspector extends St.ScrollView {
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 });
@@ -404,7 +385,7 @@ class ObjInspector extends St.ScrollView {
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);
@@ -413,15 +394,17 @@ class ObjInspector extends St.ScrollView {
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];
link = new ObjLink(this._lookingGlass, prop); link = new ObjLink(this._lookingGlass, prop).actor;
} catch (e) { } catch (e) {
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);
} }
@@ -433,17 +416,14 @@ class ObjInspector extends St.ScrollView {
return; return;
this._previousObj = null; this._previousObj = null;
this._open = true; this._open = true;
this.show(); this.actor.show();
if (sourceActor) { if (sourceActor) {
this.set_scale(0, 0); this.actor.set_scale(0, 0);
this.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.set_scale(1, 1); this.actor.set_scale(1, 1);
} }
} }
@@ -451,7 +431,7 @@ class ObjInspector extends St.ScrollView {
if (!this._open) if (!this._open)
return; return;
this._open = false; this._open = false;
this.hide(); this.actor.hide();
this._previousObj = null; this._previousObj = null;
this._obj = null; this._obj = null;
} }
@@ -465,7 +445,7 @@ class ObjInspector extends St.ScrollView {
_onBack() { _onBack() {
this.selectObject(this._previousObj, true); this.selectObject(this._previousObj, true);
} }
}); };
var RedBorderEffect = GObject.registerClass( var RedBorderEffect = GObject.registerClass(
class RedBorderEffect extends Clutter.Effect { class RedBorderEffect extends Clutter.Effect {
@@ -477,16 +457,16 @@ class RedBorderEffect extends Clutter.Effect {
color.init_from_4ub(0xff, 0, 0, 0xc4); color.init_from_4ub(0xff, 0, 0, 0xc4);
Cogl.set_source_color(color); Cogl.set_source_color(color);
let alloc = actor.get_allocation_box(); let geom = actor.get_allocation_geometry();
let width = 2; let width = 2;
// clockwise order // clockwise order
Cogl.rectangle(0, 0, alloc.get_width(), width); Cogl.rectangle(0, 0, geom.width, width);
Cogl.rectangle(alloc.get_width() - width, width, Cogl.rectangle(geom.width - width, width,
alloc.get_width(), alloc.get_height()); geom.width, geom.height);
Cogl.rectangle(0, alloc.get_height(), Cogl.rectangle(0, geom.height,
alloc.get_width() - width, alloc.get_height() - width); geom.width - width, geom.height - width);
Cogl.rectangle(0, alloc.get_height() - width, Cogl.rectangle(0, geom.height - width,
width, width); width, width);
} }
}); });
@@ -496,7 +476,8 @@ var Inspector = GObject.registerClass({
'target': { param_types: [Clutter.Actor.$gtype, GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE] } }, 'target': { param_types: [Clutter.Actor.$gtype, GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE] } },
}, class Inspector extends Clutter.Actor { }, class Inspector extends Clutter.Actor {
_init(lookingGlass) { _init(lookingGlass) {
super._init({ width: 0, height: 0 }); super._init({ width: 0,
height: 0 });
Main.uiGroup.add_actor(this); Main.uiGroup.add_actor(this);
@@ -512,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.
@@ -539,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();
@@ -551,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');
@@ -575,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) {
@@ -583,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
@@ -623,39 +598,36 @@ 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);
} }
}); });
var Extensions = GObject.registerClass({ var Extensions = class Extensions {
GTypeName: 'LookingClass_Extensions' constructor(lookingGlass) {
}, class Extensions extends St.BoxLayout {
_init(lookingGlass) {
super._init({ vertical: true, name: 'lookingGlassExtensions' });
this._lookingGlass = lookingGlass; this._lookingGlass = lookingGlass;
this.actor = new St.BoxLayout({ vertical: true,
name: 'lookingGlassExtensions' });
this._noExtensions = new St.Label({ style_class: 'lg-extensions-none', this._noExtensions = new St.Label({ style_class: 'lg-extensions-none',
text: _("No extensions installed") }); text: _("No extensions installed") });
this._numExtensions = 0; this._numExtensions = 0;
this._extensionsList = new St.BoxLayout({ vertical: true, this._extensionsList = new St.BoxLayout({ vertical: true,
style_class: 'lg-extensions-list' }); style_class: 'lg-extensions-list' });
this._extensionsList.add(this._noExtensions); this._extensionsList.add(this._noExtensions);
this.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)
@@ -712,16 +684,16 @@ var Extensions = GObject.registerClass({
_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
@@ -738,6 +710,7 @@ var Extensions = GObject.registerClass({
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);
@@ -772,19 +745,10 @@ var Extensions = GObject.registerClass({
return box; return box;
} }
}); };
var LookingGlass = GObject.registerClass(
class LookingGlass extends St.BoxLayout {
_init() {
super._init({
name: 'LookingGlassDialog',
style_class: 'lg-dialog',
vertical: true,
visible: false,
reactive: true
});
var LookingGlass = class LookingGlass {
constructor() {
this._borderPaintTarget = null; this._borderPaintTarget = null;
this._redBorderEffect = new RedBorderEffect(); this._redBorderEffect = new RedBorderEffect();
@@ -792,18 +756,26 @@ class LookingGlass extends St.BoxLayout {
this._it = null; this._it = null;
this._offset = 0; this._offset = 0;
this._results = [];
// Sort of magic, but...eh. // Sort of magic, but...eh.
this._maxItems = 150; this._maxItems = 150;
this.actor = new St.BoxLayout({ name: 'LookingGlassDialog',
style_class: 'lg-dialog',
vertical: true,
visible: false,
reactive: true });
this.actor.connect('key-press-event', this._globalKeyPressEvent.bind(this));
this._interfaceSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' }); this._interfaceSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._interfaceSettings.connect('changed::monospace-font-name', this._interfaceSettings.connect('changed::monospace-font-name',
this._updateFont.bind(this)); this._updateFont.bind(this));
this._updateFont(); this._updateFont();
// We want it to appear to slide out from underneath the panel // We want it to appear to slide out from underneath the panel
Main.uiGroup.add_actor(this); Main.uiGroup.add_actor(this.actor);
Main.uiGroup.set_child_below_sibling(this, Main.uiGroup.set_child_below_sibling(this.actor,
Main.layoutManager.panelBox); Main.layoutManager.panelBox);
Main.layoutManager.panelBox.connect('allocation-changed', Main.layoutManager.panelBox.connect('allocation-changed',
this._queueResize.bind(this)); this._queueResize.bind(this));
@@ -811,11 +783,11 @@ class LookingGlass extends St.BoxLayout {
this._queueResize.bind(this)); this._queueResize.bind(this));
this._objInspector = new ObjInspector(this); this._objInspector = new ObjInspector(this);
Main.uiGroup.add_actor(this._objInspector); Main.uiGroup.add_actor(this._objInspector.actor);
this._objInspector.hide(); this._objInspector.actor.hide();
let toolbar = new St.BoxLayout({ name: 'Toolbar' }); let toolbar = new St.BoxLayout({ name: 'Toolbar' });
this.add_actor(toolbar); this.actor.add_actor(toolbar);
let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker', let inspectIcon = new St.Icon({ icon_name: 'gtk-color-picker',
icon_size: 24 }); icon_size: 24 });
toolbar.add_actor(inspectIcon); toolbar.add_actor(inspectIcon);
@@ -823,13 +795,13 @@ class LookingGlass extends St.BoxLayout {
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.show(); this.actor.show();
global.stage.set_key_focus(this._entry); global.stage.set_key_focus(this._entry);
}); });
this.hide(); this.actor.hide();
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
}); });
@@ -840,7 +812,7 @@ class LookingGlass extends St.BoxLayout {
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;
@@ -851,7 +823,7 @@ class LookingGlass extends St.BoxLayout {
let notebook = new Notebook(); let notebook = new Notebook();
this._notebook = notebook; this._notebook = notebook;
this.add(notebook, { expand: true }); this.actor.add(notebook.actor, { expand: true });
let emptyBox = new St.Bin(); let emptyBox = new St.Bin();
toolbar.add(emptyBox, { expand: true }); toolbar.add(emptyBox, { expand: true });
@@ -874,12 +846,12 @@ class LookingGlass extends St.BoxLayout {
this._entryArea.add(this._entry, { expand: true }); this._entryArea.add(this._entry, { expand: true });
this._windowList = new WindowList(this); this._windowList = new WindowList(this);
notebook.appendPage('Windows', this._windowList); notebook.appendPage('Windows', this._windowList.actor);
this._extensions = new Extensions(this); this._extensions = new Extensions(this);
notebook.appendPage('Extensions', this._extensions); 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();
@@ -917,11 +889,9 @@ class LookingGlass extends St.BoxLayout {
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.style = ` + 'font-family: "' + fontDesc.get_family() + '";';
font-size: ${size}${unit};
font-family: "${fontDesc.get_family()}";`;
} }
setBorderPaintTarget(obj) { setBorderPaintTarget(obj) {
@@ -933,14 +903,17 @@ class LookingGlass extends St.BoxLayout {
} }
_pushResult(command, obj) { _pushResult(command, obj) {
let index = this._resultsArea.get_n_children() + this._offset; let index = this._results.length + this._offset;
let result = new Result(this, CHEVRON + command, obj, index); let result = new Result(this, CHEVRON + command, obj, index);
this._resultsArea.add(result); this._results.push(result);
this._resultsArea.add(result.actor);
if (obj instanceof Clutter.Actor) if (obj instanceof Clutter.Actor)
this.setBorderPaintTarget(obj); this.setBorderPaintTarget(obj);
if (this._resultsArea.get_n_children() > this._maxItems) { let children = this._resultsArea.get_children();
this._resultsArea.get_first_child().destroy(); if (children.length > this._maxItems) {
this._results.shift();
children[0].destroy();
this._offset++; this._offset++;
} }
this._it = obj; this._it = obj;
@@ -960,37 +933,31 @@ class LookingGlass extends St.BoxLayout {
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();
} }
@@ -1010,7 +977,7 @@ class LookingGlass extends St.BoxLayout {
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);
@@ -1026,11 +993,7 @@ class LookingGlass extends St.BoxLayout {
} }
getResult(idx) { getResult(idx) {
try { return this._results[idx - this._offset].o;
return this._resultsArea.get_child_at_index(idx - this._offset).o;
} catch (e) {
throw new Error(`Unknown result at index ${idx}`);
}
} }
toggle() { toggle() {
@@ -1041,10 +1004,7 @@ class LookingGlass extends St.BoxLayout {
} }
_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() {
@@ -1052,14 +1012,14 @@ class LookingGlass extends St.BoxLayout {
let myWidth = primary.width * 0.7; let myWidth = primary.width * 0.7;
let availableHeight = primary.height - Main.layoutManager.keyboardBox.height; let availableHeight = primary.height - Main.layoutManager.keyboardBox.height;
let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9); let myHeight = Math.min(primary.height * 0.7, availableHeight * 0.9);
this.x = primary.x + (primary.width - myWidth) / 2; this.actor.x = primary.x + (primary.width - myWidth) / 2;
this._hiddenY = primary.y + Main.layoutManager.panelBox.height - myHeight; this._hiddenY = primary.y + Main.layoutManager.panelBox.height - myHeight;
this._targetY = this._hiddenY + myHeight; this._targetY = this._hiddenY + myHeight;
this.y = this._hiddenY; this.actor.y = this._hiddenY;
this.width = myWidth; this.actor.width = myWidth;
this.height = myHeight; this.actor.height = myHeight;
this._objInspector.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8)); this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
this._objInspector.set_position(this.x + Math.floor(myWidth * 0.1), this._objInspector.actor.set_position(this.actor.x + Math.floor(myWidth * 0.1),
this._targetY + Math.floor(myHeight * 0.1)); this._targetY + Math.floor(myHeight * 0.1));
} }
@@ -1073,10 +1033,11 @@ class LookingGlass extends St.BoxLayout {
} }
// Handle key events which are relevant for all tabs of the LookingGlass // Handle key events which are relevant for all tabs of the LookingGlass
vfunc_key_press_event(keyPressEvent) { _globalKeyPressEvent(actor, event) {
let symbol = keyPressEvent.keyval; let symbol = event.get_key_symbol();
let modifierState = event.get_state();
if (symbol == Clutter.Escape) { if (symbol == Clutter.Escape) {
if (this._objInspector.visible) { if (this._objInspector.actor.visible) {
this._objInspector.close(); this._objInspector.close();
} else { } else {
this.close(); this.close();
@@ -1084,7 +1045,7 @@ class LookingGlass extends St.BoxLayout {
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
// Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view // Ctrl+PgUp and Ctrl+PgDown switches tabs in the notebook view
if (keyPressEvent.modifier_state & Clutter.ModifierType.CONTROL_MASK) { if (modifierState & Clutter.ModifierType.CONTROL_MASK) {
if (symbol == Clutter.KEY_Page_Up) { if (symbol == Clutter.KEY_Page_Up) {
this._notebook.prevTab(); this._notebook.prevTab();
} else if (symbol == Clutter.KEY_Page_Down) { } else if (symbol == Clutter.KEY_Page_Down) {
@@ -1102,49 +1063,40 @@ class LookingGlass extends St.BoxLayout {
return; return;
this._notebook.selectIndex(0); this._notebook.selectIndex(0);
this.show(); this.actor.show();
this._open = true; this._open = true;
this._history.lastItem(); this._history.lastItem();
this.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.ease({ transition: 'easeOutQuad',
y: this._targetY, y: this._targetY
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
}); });
this._windowList.update();
} }
close() { close() {
if (!this._open) if (!this._open)
return; return;
this._objInspector.hide(); this._objInspector.actor.hide();
this._open = false; this._open = false;
this.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.ease({
y: this._hiddenY, y: this._hiddenY,
duration, onComplete: () => {
mode: Clutter.AnimationMode.EASE_OUT_QUAD, this.actor.hide();
onComplete: () => this.hide()
});
}
get isOpen() {
return this._open;
} }
}); });
}
};
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,6 +41,8 @@ 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 {
@@ -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);
@@ -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));
}); });
@@ -791,7 +801,7 @@ var ZoomRegion = class ZoomRegion {
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;
} }
@@ -808,7 +818,7 @@ var ZoomRegion = class ZoomRegion {
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;
} }
@@ -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;
}); });
@@ -1290,7 +1300,7 @@ var ZoomRegion = class ZoomRegion {
// Add a background for when the magnified uiGroup is scrolled // Add a background for when the magnified uiGroup is scrolled
// out of view (don't want to see desktop showing through). // out of view (don't want to see desktop showing through).
this._background = new Background.SystemBackground(); this._background = (new Background.SystemBackground()).actor;
mainGroup.add_actor(this._background); mainGroup.add_actor(this._background);
// Clone the group that contains all of UI on the screen. This is the // Clone the group that contains all of UI on the screen. This is the
@@ -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
@@ -1587,9 +1599,8 @@ var ZoomRegion = class ZoomRegion {
} }
}; };
var Crosshairs = GObject.registerClass( var Crosshairs = class Crosshairs {
class Crosshairs extends Clutter.Actor { constructor() {
_init() {
// Set the group containing the crosshairs to three times the desktop // Set the group containing the crosshairs to three times the desktop
// size in case the crosshairs need to appear to be infinite in // size in case the crosshairs need to appear to be infinite in
@@ -1597,7 +1608,7 @@ class Crosshairs extends Clutter.Actor {
let groupWidth = global.screen_width * 3; let groupWidth = global.screen_width * 3;
let groupHeight = global.screen_height * 3; let groupHeight = global.screen_height * 3;
super._init({ this._actor = new Clutter.Actor({
clip_to_allocation: false, clip_to_allocation: false,
width: groupWidth, width: groupWidth,
height: groupHeight height: groupHeight
@@ -1606,10 +1617,10 @@ class Crosshairs extends Clutter.Actor {
this._horizRightHair = new Clutter.Actor(); this._horizRightHair = new Clutter.Actor();
this._vertTopHair = new Clutter.Actor(); this._vertTopHair = new Clutter.Actor();
this._vertBottomHair = new Clutter.Actor(); this._vertBottomHair = new Clutter.Actor();
this.add_actor(this._horizLeftHair); this._actor.add_actor(this._horizLeftHair);
this.add_actor(this._horizRightHair); this._actor.add_actor(this._horizRightHair);
this.add_actor(this._vertTopHair); this._actor.add_actor(this._vertTopHair);
this.add_actor(this._vertBottomHair); this._actor.add_actor(this._vertBottomHair);
this._clipSize = [0, 0]; this._clipSize = [0, 0];
this._clones = []; this._clones = [];
this.reCenter(); this.reCenter();
@@ -1619,7 +1630,7 @@ class Crosshairs extends Clutter.Actor {
} }
_monitorsChanged() { _monitorsChanged() {
this.set_size(global.screen_width * 3, global.screen_height * 3); this._actor.set_size(global.screen_width * 3, global.screen_height * 3);
this.reCenter(); this.reCenter();
} }
@@ -1640,15 +1651,12 @@ class Crosshairs extends Clutter.Actor {
if (zoomRegion && magnifiedMouse) { if (zoomRegion && magnifiedMouse) {
let container = magnifiedMouse.get_parent(); let container = magnifiedMouse.get_parent();
if (container) { if (container) {
crosshairsActor = this; crosshairsActor = this._actor;
if (this.get_parent() != null) { if (this._actor.get_parent() != null) {
crosshairsActor = new Clutter.Clone({ source: this }); crosshairsActor = new Clutter.Clone({ source: this._actor });
this._clones.push(crosshairsActor); this._clones.push(crosshairsActor);
// Clones don't share visibility.
this.bind_property('visible', crosshairsActor, 'visible',
GObject.BindingFlags.SYNC_CREATE);
} }
crosshairsActor.visible = this._actor.visible;
container.add_actor(crosshairsActor); container.add_actor(crosshairsActor);
container.raise_child(magnifiedMouse, crosshairsActor); container.raise_child(magnifiedMouse, crosshairsActor);
@@ -1667,7 +1675,7 @@ class Crosshairs extends Clutter.Actor {
* child actor if it was just a clone of the crosshairs actor. * child actor if it was just a clone of the crosshairs actor.
*/ */
removeFromParent(childActor) { removeFromParent(childActor) {
if (childActor == this) if (childActor == this._actor)
childActor.get_parent().remove_actor(childActor); childActor.get_parent().remove_actor(childActor);
else else
childActor.destroy(); childActor.destroy();
@@ -1770,13 +1778,36 @@ class Crosshairs extends Clutter.Actor {
// 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();
} }
} }
/**
* show:
* Show the crosshairs.
*/
show() {
this._actor.show();
// Clones don't share visibility.
for (let i = 0; i < this._clones.length; i++)
this._clones[i].show();
}
/**
* hide:
* Hide the crosshairs.
*/
hide() {
this._actor.hide();
// Clones don't share visibility.
for (let i = 0; i < this._clones.length; i++)
this._clones[i].hide();
}
/** /**
* reCenter: * reCenter:
* Reposition the horizontal and vertical hairs such that they cross at * Reposition the horizontal and vertical hairs such that they cross at
@@ -1785,9 +1816,11 @@ class Crosshairs extends Clutter.Actor {
* @clipSize: Optional. If present, an array of the form [width, height]. * @clipSize: Optional. If present, an array of the form [width, height].
*/ */
reCenter(clipSize) { reCenter(clipSize) {
let [groupWidth, groupHeight] = this.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.
@@ -1807,7 +1840,7 @@ class Crosshairs extends Clutter.Actor {
this._vertTopHair.set_position((groupWidth - thickness) / 2, top); this._vertTopHair.set_position((groupWidth - thickness) / 2, top);
this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom); this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom);
} }
}); };
var MagShaderEffects = class MagShaderEffects { var MagShaderEffects = class MagShaderEffects {
constructor(uiGroupClone) { constructor(uiGroupClone) {

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)
@@ -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();
@@ -189,7 +182,7 @@ function _initializeUI() {
messageTray = new MessageTray.MessageTray(); messageTray = new MessageTray.MessageTray();
panel = new Panel.Panel(); panel = new Panel.Panel();
keyboard = new Keyboard.KeyboardManager(); keyboard = new Keyboard.Keyboard();
notificationDaemon = new NotificationDaemon.NotificationDaemon(); notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler(); windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
componentManager = new Components.ComponentManager(); componentManager = new Components.ComponentManager();
@@ -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);
} }
}); });
@@ -403,7 +378,7 @@ function notify(msg, details) {
messageTray.add(source); messageTray.add(source);
let notification = new MessageTray.Notification(source, msg, details); let notification = new MessageTray.Notification(source, msg, details);
notification.setTransient(true); notification.setTransient(true);
source.showNotification(notification); source.notify(notification);
} }
/** /**
@@ -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);
} }
@@ -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

@@ -1,13 +1,13 @@
/* exported MessageListSection */ const { Atk, Clutter, Gio, GLib, GObject, Meta, Pango, St } = imports.gi;
const { Atk, Clutter, Gio, GLib,
GObject, Graphene, Meta, Pango, St } = imports.gi;
const Main = imports.ui.main; const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray; const MessageTray = imports.ui.messageTray;
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,18 +32,15 @@ function _fixMarkup(text, allowMarkup) {
return GLib.markup_escape_text(text, -1); return GLib.markup_escape_text(text, -1);
} }
var URLHighlighter = GObject.registerClass( var URLHighlighter = class URLHighlighter {
class URLHighlighter extends St.Label { constructor(text, lineWrap, allowMarkup) {
_init(text = '', lineWrap, allowMarkup) { if (!text)
super._init({ text = '';
reactive: true, this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter',
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';
this.connect('style-changed', () => { this.actor.connect('style-changed', () => {
let [hasColor, color] = this.get_theme_node().lookup_color('link-color', false); let [hasColor, color] = this.actor.get_theme_node().lookup_color('link-color', false);
if (hasColor) { if (hasColor) {
let linkColor = color.to_string().substr(0, 7); let linkColor = color.to_string().substr(0, 7);
if (linkColor != this._linkColor) { if (linkColor != this._linkColor) {
@@ -52,47 +49,42 @@ class URLHighlighter extends St.Label {
} }
} }
}); });
this.clutter_text.line_wrap = lineWrap; this.actor.clutter_text.line_wrap = lineWrap;
this.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR; this.actor.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
this.setMarkup(text, allowMarkup); this.setMarkup(text, allowMarkup);
} this.actor.connect('button-press-event', (actor, event) => {
vfunc_button_press_event(buttonEvent) {
// Don't try to URL highlight when invisible. // Don't try to URL highlight when invisible.
// The MessageTray doesn't actually hide us, so // The MessageTray doesn't actually hide us, so
// we need to check for paint opacities as well. // we need to check for paint opacities as well.
if (!this.visible || this.get_paint_opacity() == 0) if (!actor.visible || actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
// Keep Notification from seeing this and taking // Keep Notification.actor from seeing this and taking
// a pointer grab, which would block our button-release-event // a pointer grab, which would block our button-release-event
// handler, if an URL is clicked // handler, if an URL is clicked
return this._findUrlAtPos(buttonEvent) != -1; return this._findUrlAtPos(event) != -1;
} });
this.actor.connect('button-release-event', (actor, event) => {
vfunc_button_release_event(buttonEvent) { if (!actor.visible || actor.get_paint_opacity() == 0)
if (!this.visible || this.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(buttonEvent); 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( Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
url, global.create_app_launch_context(0, -1));
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
} }
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
} });
this.actor.connect('motion-event', (actor, event) => {
vfunc_motion_event(motionEvent) { if (!actor.visible || actor.get_paint_opacity() == 0)
if (!this.visible || this.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(motionEvent); let urlId = this._findUrlAtPos(event);
if (urlId != -1 && !this._cursorChanged) { if (urlId != -1 && !this._cursorChanged) {
global.display.set_cursor(Meta.Cursor.POINTING_HAND); global.display.set_cursor(Meta.Cursor.POINTING_HAND);
this._cursorChanged = true; this._cursorChanged = true;
@@ -101,26 +93,26 @@ class URLHighlighter extends St.Label {
this._cursorChanged = false; this._cursorChanged = false;
} }
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
} });
this.actor.connect('leave-event', () => {
vfunc_leave_event(crossingEvent) { if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
if (!this.visible || this.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
if (this._cursorChanged) { if (this._cursorChanged) {
this._cursorChanged = false; this._cursorChanged = false;
global.display.set_cursor(Meta.Cursor.DEFAULT); global.display.set_cursor(Meta.Cursor.DEFAULT);
} }
return super.vfunc_leave_event(crossingEvent); return Clutter.EVENT_PROPAGATE;
});
} }
setMarkup(text, allowMarkup) { setMarkup(text, allowMarkup) {
text = text ? _fixMarkup(text, allowMarkup) : ''; text = text ? _fixMarkup(text, allowMarkup) : '';
this._text = text; this._text = text;
this.clutter_text.set_markup(text); this.actor.clutter_text.set_markup(text);
/* clutter_text.text contain text without markup */ /* clutter_text.text contain text without markup */
this._urls = Util.findUrls(this.clutter_text.text); this._urls = Util.findUrls(this.actor.clutter_text.text);
this._highlightUrls(); this._highlightUrls();
} }
@@ -136,28 +128,29 @@ class URLHighlighter extends St.Label {
pos = url.pos + url.url.length; pos = url.pos + url.url.length;
} }
markup += this._text.substr(pos); markup += this._text.substr(pos);
this.clutter_text.set_markup(markup); this.actor.clutter_text.set_markup(markup);
} }
_findUrlAtPos(event) { _findUrlAtPos(event) {
let { x, y } = event; let success;
[, x, y] = this.transform_stage_point(x, y); let [x, y] = event.get_coords();
let findPos = -1; [success, x, y] = this.actor.transform_stage_point(x, y);
for (let i = 0; i < this.clutter_text.text.length; i++) { let find_pos = -1;
let [, px, py, lineHeight] = this.clutter_text.position_to_coords(i); for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
if (py > y || py + lineHeight < y || x < px) let [success, px, py, line_height] = this.actor.clutter_text.position_to_coords(i);
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;
} }
}); };
var ScaleLayout = GObject.registerClass( var ScaleLayout = GObject.registerClass(
class ScaleLayout extends Clutter.BinLayout { class ScaleLayout extends Clutter.BinLayout {
@@ -204,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;
@@ -293,29 +284,21 @@ var LabelExpanderLayout = GObject.registerClass({
} }
}); });
var Message = class Message {
var Message = GObject.registerClass({ constructor(title, body) {
GTypeName: 'MessageList_Message',
Signals: {
'close': {},
'expanded': {},
'unexpanded': {},
}
}, class Message extends St.Button {
_init(title, body) {
super._init({
style_class: 'message',
accessible_role: Atk.Role.NOTIFICATION,
can_focus: true,
x_expand: true,
x_fill: true
});
this.expanded = false; this.expanded = false;
this._useBodyMarkup = false; this._useBodyMarkup = false;
this.actor = new St.Button({ style_class: 'message',
accessible_role: Atk.Role.NOTIFICATION,
can_focus: true,
x_expand: true, x_fill: true });
this.actor.connect('key-press-event',
this._onKeyPressed.bind(this));
let vbox = new St.BoxLayout({ vertical: true }); let vbox = new St.BoxLayout({ vertical: true });
this.set_child(vbox); this.actor.set_child(vbox);
let hbox = new St.BoxLayout(); let hbox = new St.BoxLayout();
vbox.add_actor(hbox); vbox.add_actor(hbox);
@@ -359,14 +342,15 @@ var Message = GObject.registerClass({
contentBox.add_actor(this._bodyStack); contentBox.add_actor(this._bodyStack);
this.bodyLabel = new URLHighlighter('', false, this._useBodyMarkup); this.bodyLabel = new URLHighlighter('', false, this._useBodyMarkup);
this.bodyLabel.add_style_class_name('message-body'); this.bodyLabel.actor.add_style_class_name('message-body');
this._bodyStack.add_actor(this.bodyLabel); this._bodyStack.add_actor(this.bodyLabel.actor);
this.setBody(body); this.setBody(body);
this._closeButton.connect('clicked', this.close.bind(this)); this._closeButton.connect('clicked', this.close.bind(this));
let actorHoverId = this.connect('notify::hover', this._sync.bind(this)); let actorHoverId = this.actor.connect('notify::hover', this._sync.bind(this));
this._closeButton.connect('destroy', this.disconnect.bind(this, actorHoverId)); this._closeButton.connect('destroy', this.actor.disconnect.bind(this.actor, actorHoverId));
this.connect('destroy', this._onDestroy.bind(this)); this.actor.connect('clicked', this._onClicked.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
this._sync(); this._sync();
} }
@@ -452,21 +436,19 @@ var Message = GObject.registerClass({
if (this._bodyStack.get_n_children() < 2) { if (this._bodyStack.get_n_children() < 2) {
this._expandedLabel = new URLHighlighter(this._bodyText, this._expandedLabel = new URLHighlighter(this._bodyText,
true, this._useBodyMarkup); true, this._useBodyMarkup);
this.setExpandedBody(this._expandedLabel); this.setExpandedBody(this._expandedLabel.actor);
} }
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;
@@ -477,20 +459,19 @@ var Message = GObject.registerClass({
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;
@@ -505,16 +486,19 @@ var Message = GObject.registerClass({
} }
_sync() { _sync() {
let visible = this.hover && this.canClose(); let visible = this.actor.hover && this.canClose();
this._closeButton.opacity = visible ? 255 : 0; this._closeButton.opacity = visible ? 255 : 0;
this._closeButton.reactive = visible; this._closeButton.reactive = visible;
} }
_onClicked() {
}
_onDestroy() { _onDestroy() {
} }
vfunc_key_press_event(keyEvent) { _onKeyPressed(a, event) {
let keysym = keyEvent.keyval; let keysym = event.get_key_symbol();
if (keysym == Clutter.KEY_Delete || if (keysym == Clutter.KEY_Delete ||
keysym == Clutter.KEY_KP_Delete) { keysym == Clutter.KEY_KP_Delete) {
@@ -523,66 +507,37 @@ var Message = GObject.registerClass({
} }
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
} }
}); };
Signals.addSignalMethods(Message.prototype);
var MessageListSection = GObject.registerClass({ var MessageListSection = class MessageListSection {
Properties: { constructor() {
'can-clear': GObject.ParamSpec.boolean( this.actor = new St.BoxLayout({ style_class: 'message-list-section',
'can-clear', 'can-clear', 'can-clear',
GObject.ParamFlags.READABLE,
false),
'empty': GObject.ParamSpec.boolean(
'empty', 'empty', 'empty',
GObject.ParamFlags.READABLE,
true),
},
Signals: {
'can-clear-changed': {},
'empty-changed': {},
'message-focused': { param_types: [Message.$gtype] },
}
}, class MessageListSection extends St.BoxLayout {
_init() {
super._init({
style_class: 'message-list-section',
clip_to_allocation: true, clip_to_allocation: true,
vertical: true, x_expand: true, vertical: true });
x_expand: true
});
this._list = new St.BoxLayout({ style_class: 'message-list-section-list', this._list = new St.BoxLayout({ style_class: 'message-list-section-list',
vertical: true }); vertical: true });
this.add_actor(this._list); this.actor.add_actor(this._list);
this._list.connect('actor-added', this._sync.bind(this)); this._list.connect('actor-added', this._sync.bind(this));
this._list.connect('actor-removed', this._sync.bind(this)); this._list.connect('actor-removed', this._sync.bind(this));
let id = Main.sessionMode.connect('updated', let id = Main.sessionMode.connect('updated',
this._sync.bind(this)); this._sync.bind(this));
this.connect('destroy', () => { this.actor.connect('destroy', () => {
Main.sessionMode.disconnect(id); Main.sessionMode.disconnect(id);
}); });
this._messages = new Map();
this._date = new Date(); this._date = new Date();
this._empty = true; this.empty = true;
this._canClear = false; this.canClear = false;
this._sync(); this._sync();
} }
get empty() { _onKeyFocusIn(actor) {
return this._empty; this.emit('key-focus-in', actor);
}
get canClear() {
return this._canClear;
}
get _messages() {
return this._list.get_children().map(i => i.child);
}
_onKeyFocusIn(messageActor) {
this.emit('message-focused', messageActor);
} }
get allowed() { get allowed() {
@@ -601,96 +556,85 @@ var MessageListSection = GObject.registerClass({
} }
addMessageAtIndex(message, index, animate) { addMessageAtIndex(message, index, animate) {
if (this._messages.includes(message)) let obj = {
throw new Error('Message was already added previously'); container: null,
destroyId: 0,
let listItem = new St.Bin({ keyFocusId: 0,
child: message, closeId: 0
x_fill: true, };
y_fill: true, let pivot = new Clutter.Point({ x: .5, y: .5 });
layout_manager: new ScaleLayout(), let scale = animate ? 0 : 1;
pivot_point: new Graphene.Point({ x: .5, y: .5 }), obj.container = new St.Widget({ layout_manager: new ScaleLayout(),
pivot_point: pivot,
scale_x: scale, scale_y: scale });
obj.keyFocusId = message.actor.connect('key-focus-in',
this._onKeyFocusIn.bind(this));
obj.destroyId = message.actor.connect('destroy', () => {
this.removeMessage(message, false);
}); });
listItem._connectionsIds = []; obj.closeId = message.connect('close', () => {
listItem._connectionsIds.push(message.connect('key-focus-in',
this._onKeyFocusIn.bind(this)));
listItem._connectionsIds.push(message.connect('close', () => {
this.removeMessage(message, true); this.removeMessage(message, true);
}));
listItem._connectionsIds.push(message.connect('destroy', () => {
listItem._connectionsIds.forEach(id => message.disconnect(id));
listItem.destroy();
}));
this._list.insert_child_at_index(listItem, index);
if (animate) {
listItem.set({ scale_x: 0, scale_y: 0 });
listItem.ease({
scale_x: 1,
scale_y: 1,
duration: MESSAGE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
}); });
}
this._messages.set(message, obj);
obj.container.add_actor(message.actor);
this._list.insert_child_at_index(obj.container, index);
if (animate)
Tweener.addTween(obj.container, { scale_x: 1,
scale_y: 1,
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad' });
} }
moveMessage(message, index, animate) { moveMessage(message, index, animate) {
if (!this._messages.includes(message)) let obj = this._messages.get(message);
throw new Error(`Impossible to move the untracked message ${message}`);
let listItem = message.get_parent();
if (!animate) { if (!animate) {
this._list.set_child_at_index(listItem, index); this._list.set_child_at_index(obj.container, index);
return; return;
} }
let onComplete = () => { let onComplete = () => {
this._list.set_child_at_index(listItem, index); this._list.set_child_at_index(obj.container, index);
listItem.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' });
});
}; };
listItem.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) {
if (!this._messages.includes(message)) let obj = this._messages.get(message);
throw new Error(`Impossible to remove the untracked message ${message}`);
let listItem = message.get_parent(); message.actor.disconnect(obj.destroyId);
listItem._connectionsIds.forEach(id => message.disconnect(id)); message.actor.disconnect(obj.keyFocusId);
message.disconnect(obj.closeId);
this._messages.delete(message);
if (animate) { if (animate) {
listItem.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, obj.container.destroy();
onComplete: () => {
listItem.destroy();
global.sync_pointer(); global.sync_pointer();
} }});
});
} else { } else {
listItem.destroy(); obj.container.destroy();
global.sync_pointer(); global.sync_pointer();
} }
} }
clear() { clear() {
let messages = this._messages.filter(msg => msg.canClose()); let messages = [...this._messages.keys()].filter(msg => msg.canClose());
// If there are few messages, letting them all zoom out looks OK // If there are few messages, letting them all zoom out looks OK
if (messages.length < 2) { if (messages.length < 2) {
@@ -703,37 +647,47 @@ var MessageListSection = GObject.registerClass({
let delay = MESSAGE_ANIMATION_TIME / Math.max(messages.length, 5); let delay = MESSAGE_ANIMATION_TIME / Math.max(messages.length, 5);
for (let i = 0; i < messages.length; i++) { for (let i = 0; i < messages.length; i++) {
let message = messages[i]; let message = messages[i];
message.get_parent().ease({ let obj = this._messages.get(message);
translation_x: this._list.width, Tweener.addTween(obj.container,
{ 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();
}});
} }
} }
} }
_canClear() {
for (let message of this._messages.keys())
if (message.canClose())
return true;
return false;
}
_shouldShow() { _shouldShow() {
return !this.empty; return !this.empty;
} }
_sync() { _sync() {
let messages = this._messages; let empty = this._list.get_n_children() == 0;
let empty = messages.length == 0; let changed = this.empty !== empty;
this.empty = empty;
if (this._empty != empty) { if (changed)
this._empty = empty; this.emit('empty-changed');
this.notify('empty');
}
let canClear = messages.some(m => m.canClose()); let canClear = this._canClear();
if (this._canClear != canClear) { changed = this.canClear !== canClear;
this._canClear = canClear; this.canClear = canClear;
this.notify('can-clear');
}
this.visible = this.allowed && this._shouldShow(); if (changed)
this.emit('can-clear-changed');
this.actor.visible = this.allowed && this._shouldShow();
} }
}); };
Signals.addSignalMethods(MessageListSection.prototype);

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 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 Calendar = imports.ui.calendar; const Calendar = imports.ui.calendar;
const GnomeSession = imports.misc.gnomeSession; 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;
@@ -133,84 +133,70 @@ var FocusGrabber = class FocusGrabber {
// source, such as whether to play sound or honour the critical bit. // source, such as whether to play sound or honour the critical bit.
// //
// A notification without a policy object will inherit the default one. // A notification without a policy object will inherit the default one.
var NotificationPolicy = GObject.registerClass({ var NotificationPolicy = class NotificationPolicy {
GTypeName: 'MessageTray_NotificationPolicy', constructor(params) {
Properties: { params = Params.parse(params, { enable: true,
'enable': GObject.ParamSpec.boolean( enableSound: true,
'enable', 'enable', 'enable', showBanners: true,
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, forceExpanded: false,
true), showInLockScreen: true,
'enable-sound': GObject.ParamSpec.boolean( detailsInLockScreen: false
'enable-sound', 'enable-sound', 'enable-sound', });
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, Object.getOwnPropertyNames(params).forEach(key => {
true), let desc = Object.getOwnPropertyDescriptor(params, key);
'show-banners': GObject.ParamSpec.boolean( Object.defineProperty(this, `_${key}`, desc);
'show-banners', 'show-banners', 'show-banners', });
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'force-expanded': GObject.ParamSpec.boolean(
'force-expanded', 'force-expanded', 'force-expanded',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
'show-in-lock-screen': GObject.ParamSpec.boolean(
'show-in-lock-screen', 'show-in-lock-screen', 'show-in-lock-screen',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
'details-in-lock-screen': GObject.ParamSpec.boolean(
'details-in-lock-screen', 'details-in-lock-screen', 'details-in-lock-screen',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
false),
} }
}, class NotificationPolicy extends GObject.Object {
// Do nothing for the default policy. These methods are only useful for the // Do nothing for the default policy. These methods are only useful for the
// GSettings policy. // GSettings policy.
store() { } store() { }
destroy() { }
destroy() { get enable() {
this.run_dispose(); return this._enable;
} }
get enableSound() { get enableSound() {
return this.enable_sound; return this._enableSound;
} }
get showBanners() { get showBanners() {
return this.show_banners; return this._showBanners;
} }
get forceExpanded() { get forceExpanded() {
return this.force_expanded; return this._forceExpanded;
} }
get showInLockScreen() { get showInLockScreen() {
return this.show_in_lock_screen; return this._showInLockScreen;
} }
get detailsInLockScreen() { get detailsInLockScreen() {
return this.details_in_lock_screen; return this._detailsInLockScreen;
} }
}); };
Signals.addSignalMethods(NotificationPolicy.prototype);
var NotificationGenericPolicy = GObject.registerClass({ var NotificationGenericPolicy =
GTypeName: 'MessageTray_NotificationGenericPolicy' class NotificationGenericPolicy extends NotificationPolicy {
}, class NotificationGenericPolicy extends NotificationPolicy { constructor() {
_init() { super();
super._init();
this.id = 'generic'; this.id = 'generic';
this._masterSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications' }); this._masterSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications' });
this._masterSettings.connect('changed', this._changed.bind(this)); this._masterSettings.connect('changed', this._changed.bind(this));
} }
store() { }
destroy() { destroy() {
this._masterSettings.run_dispose(); this._masterSettings.run_dispose();
super.destroy();
} }
_changed(settings, key) { _changed(settings, key) {
if (this.constructor.find_property(key)) this.emit('policy-changed', key);
this.notify(key);
} }
get showBanners() { get showBanners() {
@@ -220,30 +206,29 @@ var NotificationGenericPolicy = GObject.registerClass({
get showInLockScreen() { get showInLockScreen() {
return this._masterSettings.get_boolean('show-in-lock-screen'); return this._masterSettings.get_boolean('show-in-lock-screen');
} }
}); };
var NotificationApplicationPolicy = GObject.registerClass({ var NotificationApplicationPolicy =
GTypeName: 'MessageTray_NotificationApplicationPolicy' class NotificationApplicationPolicy extends NotificationPolicy {
}, class NotificationApplicationPolicy extends NotificationPolicy { constructor(id) {
_init(id) { super();
super._init();
this.id = id; this.id = id;
this._canonicalId = this._canonicalizeId(id); this._canonicalId = this._canonicalizeId(id);
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);
} }
@@ -252,19 +237,18 @@ var NotificationApplicationPolicy = GObject.registerClass({
destroy() { destroy() {
this._masterSettings.run_dispose(); this._masterSettings.run_dispose();
this._settings.run_dispose(); this._settings.run_dispose();
super.destroy();
} }
_changed(settings, key) { _changed(settings, key) {
if (this.constructor.find_property(key)) this.emit('policy-changed', key);
this.notify(key); if (key == 'enable')
this.emit('enable-changed');
} }
_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() {
@@ -292,7 +276,7 @@ var NotificationApplicationPolicy = GObject.registerClass({
get detailsInLockScreen() { get detailsInLockScreen() {
return this._settings.get_boolean('details-in-lock-screen'); return this._settings.get_boolean('details-in-lock-screen');
} }
}); };
// Notification: // Notification:
// @source: the notification's Source // @source: the notification's Source
@@ -349,26 +333,12 @@ var NotificationApplicationPolicy = GObject.registerClass({
// @source allows playing sounds). // @source allows playing sounds).
// //
// [1] https://developer.gnome.org/notification-spec/#markup // [1] https://developer.gnome.org/notification-spec/#markup
var Notification = GObject.registerClass({ var Notification = class Notification {
GTypeName: 'MessageTray_Notification', constructor(source, title, banner, params) {
Properties: {
'acknowledged': GObject.ParamSpec.boolean(
'acknowledged', 'acknowledged', 'acknowledged',
GObject.ParamFlags.READWRITE,
false),
},
Signals: {
'activated': {},
'destroy': { param_types: [GObject.TYPE_UINT] },
'updated': { param_types: [GObject.TYPE_BOOLEAN] },
}
}, class Notification extends GObject.Object {
_init(source, title, banner, params) {
super._init();
this.source = source; this.source = source;
this.title = title; this.title = title;
this.urgency = Urgency.NORMAL; this.urgency = Urgency.NORMAL;
this.resident = false;
// 'transient' is a reserved keyword in JS, so we have to use an alternate variable name // 'transient' is a reserved keyword in JS, so we have to use an alternate variable name
this.isTransient = false; this.isTransient = false;
this.privacyScope = PrivacyScope.USER; this.privacyScope = PrivacyScope.USER;
@@ -380,7 +350,6 @@ var Notification = GObject.registerClass({
this._soundFile = null; this._soundFile = null;
this._soundPlayed = false; this._soundPlayed = false;
this.actions = []; this.actions = [];
this.setResident(false);
// If called with only one argument we assume the caller // If called with only one argument we assume the caller
// will call .update() later on. This is the case of // will call .update() later on. This is the case of
@@ -450,7 +419,7 @@ var Notification = GObject.registerClass({
if (this._acknowledged == v) if (this._acknowledged == v)
return; return;
this._acknowledged = v; this._acknowledged = v;
this.notify('acknowledged'); this.emit('acknowledged-changed');
} }
setUrgency(urgency) { setUrgency(urgency) {
@@ -459,15 +428,6 @@ var Notification = GObject.registerClass({
setResident(resident) { setResident(resident) {
this.resident = resident; this.resident = resident;
if (this.resident) {
if (this._activatedId) {
this.disconnect(this._activatedId);
this._activatedId = 0;
}
} else if (!this._activatedId) {
this._activatedId = this.connect_after('activated', () => this.destroy());
}
} }
setTransient(isTransient) { setTransient(isTransient) {
@@ -509,30 +469,25 @@ var Notification = GObject.registerClass({
activate() { activate() {
this.emit('activated'); this.emit('activated');
if (!this.resident)
this.destroy();
} }
destroy(reason = NotificationDestroyedReason.DISMISSED) { destroy(reason) {
if (this._activatedId) { if (!reason)
this.disconnect(this._activatedId); reason = NotificationDestroyedReason.DISMISSED;
delete this._activatedId;
}
this.emit('destroy', reason); this.emit('destroy', reason);
this.run_dispose();
} }
}); };
Signals.addSignalMethods(Notification.prototype);
var NotificationBanner = GObject.registerClass({ var NotificationBanner =
Signals: { class NotificationBanner extends Calendar.NotificationMessage {
'done-displaying': {}, constructor(notification) {
'unfocused': {}, super(notification);
}
}, class NotificationBanner extends Calendar.NotificationMessage {
_init(notification) {
super._init(notification);
this.can_focus = false; this.actor.can_focus = false;
this.add_style_class_name('notification-banner'); this.actor.add_style_class_name('notification-banner');
this._buttonBox = null; this._buttonBox = null;
@@ -619,7 +574,7 @@ var NotificationBanner = GObject.registerClass({
return this.addButton(button, callback); return this.addButton(button, callback);
} }
}); };
var SourceActor = GObject.registerClass( var SourceActor = GObject.registerClass(
class SourceActor extends St.Widget { class SourceActor extends St.Widget {
@@ -635,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);
@@ -661,105 +616,11 @@ class SourceActor extends St.Widget {
} }
}); });
var SourceActorWithLabel = GObject.registerClass( var Source = class Source {
class SourceActorWithLabel extends SourceActor { constructor(title, iconName) {
_init(source, size) {
super._init(source, size);
this._counterLabel = new St.Label({ x_align: Clutter.ActorAlign.CENTER,
x_expand: true,
y_align: Clutter.ActorAlign.CENTER,
y_expand: true });
this._counterBin = new St.Bin({ style_class: 'summary-source-counter',
child: this._counterLabel,
layout_manager: new Clutter.BinLayout() });
this._counterBin.hide();
this._counterBin.connect('style-changed', () => {
let themeNode = this._counterBin.get_theme_node();
this._counterBin.translation_x = themeNode.get_length('-shell-counter-overlap-x');
this._counterBin.translation_y = themeNode.get_length('-shell-counter-overlap-y');
});
this.add_actor(this._counterBin);
this._countUpdatedId = this._source.connect('notify::count', this._updateCount.bind(this));
this._updateCount();
this.connect('destroy', () => {
this._source.disconnect(this._countUpdatedId);
});
}
vfunc_allocate(box, flags) {
super.vfunc_allocate(box, flags);
let childBox = new Clutter.ActorBox();
let [, , naturalWidth, naturalHeight] = this._counterBin.get_preferred_size();
let direction = this.get_text_direction();
if (direction == Clutter.TextDirection.LTR) {
// allocate on the right in LTR
childBox.x1 = box.x2 - naturalWidth;
childBox.x2 = box.x2;
} else {
// allocate on the left in RTL
childBox.x1 = 0;
childBox.x2 = naturalWidth;
}
childBox.y1 = box.y2 - naturalHeight;
childBox.y2 = box.y2;
this._counterBin.allocate(childBox, flags);
}
_updateCount() {
if (this._actorDestroyed)
return;
this._counterBin.visible = this._source.countVisible;
let text;
if (this._source.count < 100)
text = this._source.count.toString();
else
text = String.fromCharCode(0x22EF); // midline horizontal ellipsis
this._counterLabel.set_text(text);
}
});
var Source = GObject.registerClass({
GTypeName: 'MessageTray_Source',
Properties: {
'count': GObject.ParamSpec.int(
'count', 'count', 'count',
GObject.ParamFlags.READABLE,
0, GLib.MAXINT32, 0),
'policy': GObject.ParamSpec.object(
'policy', 'policy', 'policy',
GObject.ParamFlags.READWRITE,
NotificationPolicy.$gtype),
'title': GObject.ParamSpec.string(
'title', 'title', 'title',
GObject.ParamFlags.READWRITE,
null),
},
Signals: {
'destroy': { param_types: [GObject.TYPE_UINT] },
'icon-updated': {},
'notification-added': { param_types: [Notification.$gtype] },
'notification-show': { param_types: [Notification.$gtype] },
}
}, class Source extends GObject.Object {
_init(title, iconName) {
super._init({ title: title });
this.SOURCE_ICON_SIZE = 48; this.SOURCE_ICON_SIZE = 48;
this.title = title;
this.iconName = iconName; this.iconName = iconName;
this.isChat = false; this.isChat = false;
@@ -794,7 +655,7 @@ var Source = GObject.registerClass({
} }
countUpdated() { countUpdated() {
super.notify('count'); this.emit('count-updated');
} }
_createPolicy() { _createPolicy() {
@@ -802,17 +663,13 @@ var Source = GObject.registerClass({
} }
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;
} }
setTitle(newTitle) { setTitle(newTitle) {
if (this.title == newTitle)
return;
this.title = newTitle; this.title = newTitle;
this.notify('title'); this.emit('title-changed');
} }
createBanner(notification) { createBanner(notification) {
@@ -837,53 +694,38 @@ var Source = GObject.registerClass({
return; return;
this.notifications.splice(index, 1); this.notifications.splice(index, 1);
this.countUpdated();
if (this.notifications.length == 0) if (this.notifications.length == 0)
this.destroy(); this.destroy();
this.countUpdated();
} }
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)
this.notifications.shift().destroy(NotificationDestroyedReason.EXPIRED); this.notifications.shift().destroy(NotificationDestroyedReason.EXPIRED);
notification.connect('destroy', this._onNotificationDestroy.bind(this)); notification.connect('destroy', this._onNotificationDestroy.bind(this));
notification.connect('notify::acknowledged', this.countUpdated.bind(this)); notification.connect('acknowledged-changed', this.countUpdated.bind(this));
this.notifications.push(notification); this.notifications.push(notification);
this.emit('notification-added', notification); this.emit('notification-added', notification);
this.countUpdated(); this.countUpdated();
} }
showNotification(notification) { notify(notification) {
notification.acknowledged = false; notification.acknowledged = false;
this.pushNotification(notification); this.pushNotification(notification);
if (this.policy.showBanners || notification.urgency == Urgency.CRITICAL) { if (this.policy.showBanners || notification.urgency == Urgency.CRITICAL) {
this.emit('notification-show', notification); this.emit('notify', notification);
} else { } else {
notification.playSound(); notification.playSound();
} }
} }
notify(propName) {
if (propName instanceof Notification) {
try {
throw new Error('Source.notify() has been moved to Source.showNotification()' +
'this code will break in the future');
} catch (e) {
logError(e);
this.showNotification(propName);
return;
}
}
super.notify(propName);
}
destroy(reason) { destroy(reason) {
this.policy.destroy(); this.policy.destroy();
@@ -894,8 +736,6 @@ var Source = GObject.registerClass({
notifications[i].destroy(reason); notifications[i].destroy(reason);
this.emit('destroy', reason); this.emit('destroy', reason);
this.run_dispose();
} }
iconUpdated() { iconUpdated() {
@@ -910,24 +750,15 @@ var Source = GObject.registerClass({
for (let i = this.notifications.length - 1; i >= 0; i--) for (let i = this.notifications.length - 1; i >= 0; i--)
if (!this.notifications[i].resident) if (!this.notifications[i].resident)
this.notifications[i].destroy(); this.notifications[i].destroy();
}
});
var MessageTray = GObject.registerClass({ this.countUpdated();
Signals: {
'queue-changed': {},
'source-added': { param_types: [Source.$gtype] },
'source-removed': { param_types: [Source.$gtype] },
} }
}, class MessageTray extends St.Widget { };
_init() { Signals.addSignalMethods(Source.prototype);
super._init({
visible: false,
clip_to_allocation: true,
layout_manager: new Clutter.BinLayout()
});
this._presence = new GnomeSession.Presence((proxy, _error) => { var MessageTray = class MessageTray {
constructor() {
this._presence = new GnomeSession.Presence((proxy, error) => {
this._onStatusChanged(proxy.status); this._onStatusChanged(proxy.status);
}); });
this._busy = false; this._busy = false;
@@ -943,15 +774,18 @@ var MessageTray = GObject.registerClass({
// so fix up Clutter's view of the pointer position in // so fix up Clutter's view of the pointer position in
// that case. // that case.
let related = ev.get_related(); let related = ev.get_related();
if (!related || this.contains(related)) if (!related || this.actor.contains(related))
global.sync_pointer(); global.sync_pointer();
}); });
this.actor = new St.Widget({ visible: false,
clip_to_allocation: true,
layout_manager: new Clutter.BinLayout() });
let constraint = new Layout.MonitorConstraint({ primary: true }); let constraint = new Layout.MonitorConstraint({ primary: true });
Main.layoutManager.panelBox.bind_property('visible', Main.layoutManager.panelBox.bind_property('visible',
constraint, 'work-area', constraint, 'work-area',
GObject.BindingFlags.SYNC_CREATE); GObject.BindingFlags.SYNC_CREATE);
this.add_constraint(constraint); this.actor.add_constraint(constraint);
this._bannerBin = new St.Widget({ name: 'notification-container', this._bannerBin = new St.Widget({ name: 'notification-container',
reactive: true, reactive: true,
@@ -965,7 +799,7 @@ var MessageTray = GObject.registerClass({
this._onNotificationKeyRelease.bind(this)); this._onNotificationKeyRelease.bind(this));
this._bannerBin.connect('notify::hover', this._bannerBin.connect('notify::hover',
this._onNotificationHoverChanged.bind(this)); this._onNotificationHoverChanged.bind(this));
this.add_actor(this._bannerBin); this.actor.add_actor(this._bannerBin);
this._notificationFocusGrabber = new FocusGrabber(this._bannerBin); this._notificationFocusGrabber = new FocusGrabber(this._bannerBin);
this._notificationQueue = []; this._notificationQueue = [];
@@ -994,7 +828,7 @@ var MessageTray = GObject.registerClass({
this._notificationTimeoutId = 0; this._notificationTimeoutId = 0;
this._notificationRemoved = false; this._notificationRemoved = false;
Main.layoutManager.addChrome(this, { affectsInputRegion: false }); Main.layoutManager.addChrome(this.actor, { affectsInputRegion: false });
Main.layoutManager.trackChrome(this._bannerBin, { affectsInputRegion: true }); Main.layoutManager.trackChrome(this._bannerBin, { affectsInputRegion: true });
global.display.connect('in-fullscreen-changed', this._updateState.bind(this)); global.display.connect('in-fullscreen-changed', this._updateState.bind(this));
@@ -1037,11 +871,11 @@ var MessageTray = GObject.registerClass({
} }
_onDragBegin() { _onDragBegin() {
Shell.util_set_hidden_from_pick(this, true); Shell.util_set_hidden_from_pick(this.actor, true);
} }
_onDragEnd() { _onDragEnd() {
Shell.util_set_hidden_from_pick(this, false); Shell.util_set_hidden_from_pick(this.actor, false);
} }
get bannerAlignment() { get bannerAlignment() {
@@ -1083,29 +917,30 @@ var MessageTray = GObject.registerClass({
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;
} }
// Register that we got a notification for this source // Register that we got a notification for this source
source.policy.store(); source.policy.store();
source.policy.connect('notify::enable', () => { source.policy.connect('enable-changed', () => {
this._onSourceEnableChanged(source.policy, source); this._onSourceEnableChanged(source.policy, source);
}); });
source.policy.connect('notify', this._updateState.bind(this)); source.policy.connect('policy-changed', this._updateState.bind(this));
this._onSourceEnableChanged(source.policy, source); this._onSourceEnableChanged(source.policy, source);
} }
_addSource(source) { _addSource(source) {
let obj = { let obj = {
showId: 0, source: source,
notifyId: 0,
destroyId: 0, destroyId: 0,
}; };
this._sources.set(source, obj); this._sources.set(source, obj);
obj.showId = source.connect('notification-show', this._onNotificationShow.bind(this)); obj.notifyId = source.connect('notify', this._onNotify.bind(this));
obj.destroyId = source.connect('destroy', this._onSourceDestroy.bind(this)); obj.destroyId = source.connect('destroy', this._onSourceDestroy.bind(this));
this.emit('source-added', source); this.emit('source-added', source);
@@ -1115,7 +950,7 @@ var MessageTray = GObject.registerClass({
let obj = this._sources.get(source); let obj = this._sources.get(source);
this._sources.delete(source); this._sources.delete(source);
source.disconnect(obj.showId); source.disconnect(obj.notifyId);
source.disconnect(obj.destroyId); source.disconnect(obj.destroyId);
this.emit('source-removed', source); this.emit('source-removed', source);
@@ -1156,14 +991,14 @@ var MessageTray = GObject.registerClass({
} }
} }
_onNotificationShow(_source, notification) { _onNotify(source, notification) {
if (this._notification == notification) { if (this._notification == notification) {
// If a notification that is being shown is updated, we update // If a notification that is being shown is updated, we update
// how it is shown and extend the time until it auto-hides. // how it is shown and extend the time until it auto-hides.
// 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.
@@ -1185,7 +1020,7 @@ var MessageTray = GObject.registerClass({
_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;
@@ -1223,15 +1058,15 @@ var MessageTray = GObject.registerClass({
// 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');
} }
} }
@@ -1252,7 +1087,7 @@ var MessageTray = GObject.registerClass({
} }
_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 &&
@@ -1260,9 +1095,7 @@ var MessageTray = GObject.registerClass({
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 {
@@ -1288,7 +1121,7 @@ var MessageTray = GObject.registerClass({
// at the present time. // at the present time.
_updateState() { _updateState() {
let hasMonitor = Main.layoutManager.primaryMonitor != null; let hasMonitor = Main.layoutManager.primaryMonitor != null;
this.visible = !this._bannerBlocked && hasMonitor && this._banner != null; this.actor.visible = !this._bannerBlocked && hasMonitor && this._banner != null;
if (this._bannerBlocked || !hasMonitor) if (this._bannerBlocked || !hasMonitor)
return; return;
@@ -1344,6 +1177,34 @@ var MessageTray = GObject.registerClass({
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);
@@ -1368,16 +1229,17 @@ var MessageTray = GObject.registerClass({
this._updateState(); this._updateState();
}); });
this._bannerBin.add_actor(this._banner); this._bannerBin.add_actor(this._banner.actor);
this._bannerBin._opacity = 0;
this._bannerBin.opacity = 0; this._bannerBin.opacity = 0;
this._bannerBin.y = -this._banner.height; this._bannerBin.y = -this._banner.actor.height;
this.show(); this.actor.show();
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
@@ -1415,45 +1277,39 @@ var MessageTray = GObject.registerClass({
// 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
@@ -1489,26 +1345,20 @@ var MessageTray = GObject.registerClass({
} }
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;
@@ -1519,16 +1369,16 @@ var MessageTray = GObject.registerClass({
_hideNotificationCompleted() { _hideNotificationCompleted() {
let notification = this._notification; let notification = this._notification;
this._notification = null; this._notification = null;
if (!this._notificationRemoved && notification.isTransient) if (notification.isTransient)
notification.destroy(NotificationDestroyedReason.EXPIRED); notification.destroy(NotificationDestroyedReason.EXPIRED);
this._pointerInNotification = false; this._pointerInNotification = false;
this._notificationRemoved = false; this._notificationRemoved = false;
Meta.enable_unredirect_for_display(global.display); Meta.enable_unredirect_for_display(global.display);
this._banner.destroy(); this._banner.actor.destroy();
this._banner = null; this._banner = null;
this.hide(); this.actor.hide();
} }
_expandActiveNotification() { _expandActiveNotification() {
@@ -1550,15 +1400,15 @@ var MessageTray = GObject.registerClass({
_ensureBannerFocused() { _ensureBannerFocused() {
this._notificationFocusGrabber.grabFocus(); this._notificationFocusGrabber.grabFocus();
} }
}); };
Signals.addSignalMethods(MessageTray.prototype);
var SystemNotificationSource = GObject.registerClass( var SystemNotificationSource = class SystemNotificationSource extends Source {
class SystemNotificationSource extends Source { constructor() {
_init() { super(_("System Information"), 'dialog-information-symbolic');
super._init(_("System Information"), 'dialog-information-symbolic');
} }
open() { open() {
this.destroy(); this.destroy();
} }
}); };

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) {
@@ -121,13 +120,13 @@ var ModalDialog = GObject.registerClass({
this.dialogLayout.opacity = 255; this.dialogLayout.opacity = 255;
if (this._lightbox) if (this._lightbox)
this._lightbox.lightOn(); 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,5 +1,4 @@
/* exported MediaSection */ const { Gio, Shell, St } = imports.gi;
const { Gio, GObject, Shell, St } = imports.gi;
const Signals = imports.signals; const Signals = imports.signals;
const Calendar = imports.ui.calendar; const Calendar = imports.ui.calendar;
@@ -19,10 +18,9 @@ const MprisPlayerProxy = Gio.DBusProxy.makeProxyWrapper(MprisPlayerIface);
const MPRIS_PLAYER_PREFIX = 'org.mpris.MediaPlayer2.'; const MPRIS_PLAYER_PREFIX = 'org.mpris.MediaPlayer2.';
var MediaMessage = GObject.registerClass( var MediaMessage = class MediaMessage extends MessageList.Message {
class MediaMessage extends MessageList.Message { constructor(player) {
_init(player) { super('', '');
super._init('', '');
this._player = player; this._player = player;
@@ -49,7 +47,7 @@ class MediaMessage extends MessageList.Message {
this._update(); this._update();
} }
vfunc_clicked() { _onClicked() {
this._player.raise(); this._player.raise();
Main.panel.closeCalendar(); Main.panel.closeCalendar();
} }
@@ -72,15 +70,14 @@ 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;
this._updateNavButton(this._prevButton, this._player.canGoPrevious); this._updateNavButton(this._prevButton, this._player.canGoPrevious);
this._updateNavButton(this._nextButton, this._player.canGoNext); this._updateNavButton(this._nextButton, this._player.canGoNext);
} }
}); };
var MprisPlayer = class MprisPlayer { var MprisPlayer = class MprisPlayer {
constructor(busName) { constructor(busName) {
@@ -138,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);
} }
@@ -195,10 +192,9 @@ var MprisPlayer = class MprisPlayer {
}; };
Signals.addSignalMethods(MprisPlayer.prototype); Signals.addSignalMethods(MprisPlayer.prototype);
var MediaSection = GObject.registerClass( var MediaSection = class MediaSection extends MessageList.MessageListSection {
class MediaSection extends MessageList.MessageListSection { constructor() {
_init() { super();
super._init();
this._players = new Map(); this._players = new Map();
@@ -249,4 +245,4 @@ class MediaSection extends MessageList.MessageListSection {
if (newOwner && !oldOwner) if (newOwner && !oldOwner)
this._addPlayer(name); this._addPlayer(name);
} }
}); };

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