Compare commits

..

36 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
87a76a5757 appDisplay: Close popup when dragging
When a drag starts inside a folder, and the cursor moves to
outside it, close the currently opened folder popup.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:04 -03:00
Georges Basile Stavracas Neto
717ec0f8a4 folderView: Allow moving to specific position
As of now, the only way to add an app icon to a folder is
by dragging it to the folder icon itself. Even though we
allow opening the folder popup when hovering the icon,
dropping an app icon there wouldn't work.

Make the folder view add the app icon to it's GSettings
key (which will trigger _redisplay() and will show the
new icon) when dropping to a specific position.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:03 -03:00
Georges Basile Stavracas Neto
854922866b appIcon: Create and delete folders with DnD
Create a new folder when dropping an icon over another
icon. Try and find a good folder name by looking into
the categories of the applications.

Delete the folder when removing the last icon.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:03 -03:00
Georges Basile Stavracas Neto
40ad9ab18c appIcon: Show folder preview when dragging over
WIP

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:03 -03:00
Georges Basile Stavracas Neto
55eb949def baseViewIcon: Introduce base class for view icons
Right now, only AppIcon supports being dragged. In the future,
however, both app and folder icons will be reorderable, and to
avoid copying the same code between FolderIcon and AppIcon,
add a new base class BaseViewIcon that contains the shared code
between them.

Adding this new base class also has the side effect that it
already allows for folder icons to be dragged, although full
support for that will come in next commits.

Because the Dash icons are not drop targets themselves, add a
tiny DashIcon class, which is an AppDisplay.AppIcon subclass,
and disable all DND drop code from it.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:03 -03:00
Georges Basile Stavracas Neto
0596848c27 appIcon: Use a real BaseIcon as the drag actor
Moving an app icon to other positions is semantically different
to dragging an actor to the dash; the act of moving should itself
be semantic, in that we should feel like we are moving the actual
icon.

Currently, AppIcon gives the DnD code a simplified version of itself,
with just its icon, instead of a complete copy with the label.

Make AppIcon create a new IconGrid.BaseIcon and use it as the drag
actor.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:02 -03:00
Georges Basile Stavracas Neto
0bdcf2958f iconGrid: Apply delay to easing state
Also following design suggestion, add a small delay to the icons
moving so as to give the impression that they're moving in order.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:02 -03:00
Georges Basile Stavracas Neto
ac3bc03f3f iconGrid: Implicitly animate icon positions
Add a proper easing state, and animate icon positions using
Clutter implicit animations.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:02 -03:00
Georges Basile Stavracas Neto
bf322cd51a appIcon: Scale and fade itself when starting drag
As per design direction, scale and fade the app icon
when starting dragging it, and show it again if the
drop is accepted. Clutter takes care of animating the
rest of icon positions through implicit animations.

Scale and fade the dragged icon while it's being dragged.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:02 -03:00
Georges Basile Stavracas Neto
6e3696baad allView, folderView: Implement moving icons
This makes use of the new BaseAppIcon.moveItem() API.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:01 -03:00
Georges Basile Stavracas Neto
4056c56800 allView: Add support for custom positioning
Use the new 'icon-grid-layout' key to sort the applications and folders
as it is saved. Applications that are not in the key are appended, and
when compared to each other, fallback to alphabetical order.

Because the 'icon-grid-layout' key is, by default, empty, this means that
all icons and folders are sorted alphabetically the first time they are
displayed, preserving the current behavior.

This commit does not add any way to change the order without modifying
the GSettings key directly.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:01 -03:00
Georges Basile Stavracas Neto
ebf2610140 folderView: Move DnD functions to BaseAppView
It will be much easier to handle Drag n' Drop with BaseAppView
implementing default handlers for it.

Move handleDragOver() and acceptDrop() to BaseAppView.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:01 -03:00
Georges Basile Stavracas Neto
a9e7b7853a iconGrid: Add item nudge API
Nudging an item can be done via one side, or both. This is
essentially a set of helpers for Drag n' Drop to use. The
x and y values are relative to the icon grid itself.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:00 -03:00
Georges Basile Stavracas Neto
0dd430f2f4 appDisplay: Add moveItem()
This is a handy function to implement changing an icon's position
in the grid.

WIP: better commit message

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:00 -03:00
Georges Basile Stavracas Neto
ca01b0287e allView: Don't sort icons
We are moving towards being able to move icons to custom
positions. To achieve that, the icon grid should stop
sort its icons.

Remove the sorting code from AllView and BaseAppView.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:00 -03:00
Georges Basile Stavracas Neto
37aa5d0faf gschema: Add the 'icons-data' key
This is the key that will store the icons of the icon grid. It is a
sorted array of application ids, and the order of items saved in this
key corresponds to the icon order.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:33:00 -03:00
Georges Basile Stavracas Neto
2e4fb404a7 controlsManager: Don't fade icon grid while dragging
As pointed out by designers, fading it signals that the
icon grid is not a drop target, when now it actually is.

Remove the fade effect applied to the icon grid when
dragging.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:59 -03:00
Georges Basile Stavracas Neto
11ce7829bc allView: Scale in when moving icons from folders
App icons inside folders are already animated when the folder is
opened, but moving an app icon from a folder doesn't, making the
transition abrupt.

Fortunately, it's easy to detect icons that were previously hidden
but are not anymore.

Add an animation to these icons when showing.

WIP: tentatively using the Tweener parameters from Endless OS.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:59 -03:00
Georges Basile Stavracas Neto
52257f5137 folderIcon: Add visual drag-over feedback
WIP: This is not exactly what was discussed on IRC, but
it's looking alright as a first iteration. Design feedback
welcomed.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:59 -03:00
Georges Basile Stavracas Neto
74077b0f6e allView: Remove icon from folder when dropping outside
When dropping an app icon to outside the folder, remove the
app from that folder. GNOME Shell is already smart enough
to figure out the setting changes and update the icons.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:59 -03:00
Georges Basile Stavracas Neto
241b4cd1c8 allView: Set delegate field
DnD still relies on the _delegate field being set, so
set it.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:59 -03:00
Georges Basile Stavracas Neto
79f9391c00 allView: Switch pages when dragging above or below the grid
This is necessary for being able to drag application icons
to folders in different pages.

Add a drag motion handler to AllView and handle overshoots
when dragging. Only handle it when dragging from AllView.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:58 -03:00
Georges Basile Stavracas Neto
6da23c8d4d appIcon: Always pass parent view
We will soon need to know which view this icon belongs to,
so add an extra parameter to the constructor to store the
parent view.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:58 -03:00
Georges Basile Stavracas Neto
bb9f05843f folderIcon: Update folder icon after dropping
After dropping an application into the folder icon, the
list of applications is updated but the folder icon itself
is not.

Introduce BaseIcon.update() and call it from FolderIcon
when redisplaying.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:58 -03:00
Georges Basile Stavracas Neto
cc9f949b65 folderIcon: Allow dropping application icons
Connect to the overview signals related to Drag n' Drop, and
allow dropping application icons in it. Dropping an icon
appends the application id to the folder's GSettings key.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:58 -03:00
Georges Basile Stavracas Neto
23191ec239 appDisplay: Add event blocker inhibition API
The event blocker is an actor that is added in between the
icon grid and the app folder popup in order to guarantee
that clicking outside the app folder will collapse it.

However, the next patch will require allowing dragging events
to be passed to folder icons, and the event blocker gets in
our way here, preventing drag n' drop to work properly.

Add an API to inhibit the event blocker. This API will be
used by the app folders while an item is dragged.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/603
2019-08-02 16:32:57 -03:00
Georges Basile Stavracas Neto
038917e5f1 allView: Redisplay on folder changes
Now that redisplaying is a lightweight operation that only
adds and removes what changed, we don't need to just refilter
the app icons in AllView when a folder changes.

Call _redisplay() in AllView when folders change.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:57 -03:00
Georges Basile Stavracas Neto
f214c5b572 baseAppView: Remove unused BaseAppView.addItem
Now that BaseAppView does not allow for subclasses to add
and remove items directly, the addItem() method can be
removed.

Remove BaseAppView.addItem().

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:57 -03:00
Georges Basile Stavracas Neto
9da49606f7 allView, folderView: Only add icons once
FolderView and AllView currently check if the item is
present in the BaseAppView._items map, in order to avoid
adding the same icon multiple times.

Now that BaseAppView._loadGrid() has a different role
-- it returns a list with all app icons, and BaseAppView
diffs with the current list of app icons -- checking the
BaseAppView._items map is wrong.

Make sure there are no duplicated items in the temporary
array returned by all _loadGrid() implementations. Remove
the now unused BaseAppView.hasItem() method.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:57 -03:00
Georges Basile Stavracas Neto
c13efe96dc baseAppView: Only add and remove when necessary
BaseAppView currently removes all icons, and readds them, every
time the list of app icons needs to be redisplayed. In order to
allow animating app icon positions in the future, however, we
cannot destroy the actors of the app icons.

Previous commits paved the way for us to do differential loading,
i.e. add only the icons that were added, and remove only what was
removed.

Make the BaseAppView effectively implement differential loading.
The BaseAppView.removeAll() method is removed, since we do not
remove all icons anymore. BaseAppView._loadApps() now returns an
array with the new apps, instead of putting them directly at the
BaseAppView lists.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:56 -03:00
Georges Basile Stavracas Neto
47d2f4dbeb baseAppView: Add only non-added icons, in order
In the close future, BaseAppView will only add new icons (compared
to the remove all + readd all approach that is now). With that, the
items in the this._allItems array will be iterated multiple times,
but items can only be added once, and in the order they're in the
array.

Add the items in the this._allItems array passing the index they
should be added, and don't add icons with a parent already set.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:56 -03:00
Georges Basile Stavracas Neto
48a2b6cb0b baseAppView: Call loadGrid() directly
Now that the three views follow the exact same loading routine
(remove all + load apps + load grid), we don't need each view
call loadGrid() directly anymore.

This is an important step in order to animate adding and removing
icons, since now we can diff old and new app icons properly.

Move all calls to BaseAppView.loadGrid() to a single one after
BaseAppView._loadApps(). Also add the underscore prefix, since
this is now considered a protected function.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:56 -03:00
Georges Basile Stavracas Neto
ce78e8ae54 frequentView: Use BaseAppView.addItem() and loadGrid()
FrequentView is another view that is slightly not unified with how
BaseAppView expects subclasses to load app icons. Instead of using
BaseAppView.addItem() and then calling BaseAppview.loadGrid(), it
adds the app icons directly to the icon grid.

Make FrequentView add icons using BaseAppview.addItem(), and load
the icons using BaseAppView.loadGrid().

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:56 -03:00
Georges Basile Stavracas Neto
abe9b82c48 folderIcon: Move app icon loading to FolderView
Future patches will diff the old and new icons of views, in order to
animate them when necessary (e.g. adding an app icon to a folder, or
from a folder back to the app grid). In order to do that, all views
must be streamlined in how they load app icons.

Currently, FrequentView and AllView are already following the behavior
expected by BaseAppView, but FolderView isn't. Its icons are loaded by
FolderIcon, and FolderView doesn't implement BaseView._loadApps(),
which makes it impossible to diff old and new apps.

Move the app icon loading routine from FolderIcon to FolderView, by
implementing the _loadApps() method.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/645
2019-08-02 16:32:56 -03:00
Georges Basile Stavracas Neto
6c85bd6aeb shell/app-system: Monitor for icon theme changes
Whenever an app is installed, the usual routine is
to run 'gtk-update-icon-cache' after installing all
of the app's files.

The side effect of that is that the .desktop file of
the application is installed before the icon theme
is updated. By the time GAppInfoMonitor emits the
'changed' signal, the icon theme is not yet updated,
leading to StIcon use the fallback icon.

Under some circumstances (e.g. on very slow spinning
disks) the app icon is never actually loaded, and we
see the fallback icon forever.

Monitor the icon theme for changes when an app is
installed. Try as many as 6 times before giving up
on detecting an icon theme update.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/661
2019-08-02 16:31:54 -03:00
Georges Basile Stavracas Neto
06a7ab871f st/texture-cache: Monitor GtkIconTheme changes
The texture cache, right now, only monitors for
complete theme changes. If the contents of the
icon theme change, however, the texture cache
isn't properly invalidated.

This manifests itself as a randomly reproducible
bug when installing an app; the app icon may be
the fallback forever, or as long as something else
updates the icon theme.

Watch for the GtkIconTheme:changed signal, and
evict the texture cache when the theme changes.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/661
2019-08-02 16:31:39 -03:00
223 changed files with 23917 additions and 41778 deletions

View File

@@ -54,7 +54,7 @@ build:
- meson mutter mutter/build --prefix=/usr -Dtests=false
- ninja -C mutter/build install
script:
- meson . build -Dbuiltype=debugoptimized -Dman=false --werror
- meson . build -Dbuiltype=debugoptimized
- ninja -C build
- ninja -C build install
<<: *only_default
@@ -67,8 +67,6 @@ build:
test:
image: registry.gitlab.gnome.org/gnome/mutter/master:v2
stage: test
variables:
XDG_RUNTIME_DIR: "$CI_PROJECT_DIR/runtime-dir"
before_script:
- ninja -C mutter/build install
script:

View File

@@ -16,14 +16,8 @@ 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
local output=OUTPUT_$1
eslint -f unix ${!extra_args} -o ${!output} js
}
list_commit_range_additions() {
@@ -72,17 +66,10 @@ create_common() {
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
if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
git fetch $CI_MERGE_REQUEST_PROJECT_URL.git $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
branch_point=$(git merge-base HEAD FETCH_HEAD)
commit_range=$branch_point...HEAD
commit_range=$branch_point...$CI_COMMIT_SHA
list_commit_range_additions $commit_range > $LINE_CHANGES
@@ -99,16 +86,12 @@ 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
if [ -z "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
cat $OUTPUT_FINAL
exit 0
fi
copy_matched_lines $OUTPUT_REGULAR $LINE_CHANGES $OUTPUT_MR
copy_matched_lines $OUTPUT_FINAL $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 Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
```
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
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,
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
class that has a property called `actor` (now deprecated). We call this
wrapper class the "delegate".
you could inherit from GTypes natively in JS, we usually have a wrapper class
that has a property called `actor`. We call this wrapper class the "delegate".
We sometimes use expando properties to set a property called `_delegate` on
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
var MyClass = class {
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"
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.
In case the class is an actor itself, the `_delegate` can be just set to `this`.
## 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
}`, `foo['bar']`.
## Animations
Most objects that are animated are actors, and most properties used in animations
are animatable, which means they can use implicit animations:
## Getters, setters, and Tweener
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
moveActor(actor, x, y) {
actor.ease({
x,
y,
duration: 500, // ms
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
var ANIMATION_TIME = 2000;
var MyClass = class {
constructor() {
this.actor = new St.BoxLayout();
this._position = 0;
}
```
The above is a convenience wrapper around the actual Clutter API, and should generally
be preferred over the more verbose:
```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();
get position() {
return this._position;
}
```
There is a similar convenience API around Clutter.PropertyTransition to animate
actor (or actor meta) properties that cannot use implicit animations:
```javascript
desaturateActor(actor, desaturate) {
let factor = desaturate ? 1.0 : 0.0;
actor.ease_property('@effects.desaturate.factor', factor, {
duration: 500, // ms
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
set position(value) {
this._position = value;
this.actor.set_position(value, value);
}
};
let myThing = new MyClass();
Tweener.addTween(myThing,
{ position: 100,
time: ANIMATION_TIME,
transition: 'easeOutQuad' });
```

125
NEWS
View File

@@ -1,128 +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]

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

@@ -40,7 +40,6 @@
<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.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.Introspect.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.HotplugSniffer.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]
Description=GNOME Shell on Wayland
DefaultDependencies=no
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
Requires=gnome-shell-wayland.service
After=gnome-shell-wayland.service
Description=GNOME Shell (wayland sync point)
After=gnome-shell.service
BindsTo=gnome-shell.service
Conflicts=gnome-shell-x11.target

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]
Description=GNOME Shell on X11
DefaultDependencies=no
Requisite=gnome-session-initialized.target
PartOf=gnome-session-initialized.target
Before=gnome-session-initialized.target
Requires=gnome-shell-x11.service
After=gnome-shell-x11.service
Description=GNOME Shell (x11 sync point)
After=gnome-shell.service
BindsTo=gnome-shell.service
Conflicts=gnome-shell-wayland.target

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
desktopconf.set('bindir', bindir)
desktopconf.set('VERSION', meson.project_version())
desktopconf.set('systemd_hidden', have_systemd ? 'true' : 'false')
foreach desktop_file : desktop_files
i18n.merge_file('desktop',
input: configure_file(
@@ -24,7 +22,7 @@ foreach desktop_file : desktop_files
configuration: desktopconf
),
output: desktop_file,
po_dir: po_dir,
po_dir: '../po',
install: true,
install_dir: desktopdir,
type: 'desktop'
@@ -100,23 +98,15 @@ if have_systemd
unitconf = configuration_data()
unitconf.set('bindir', bindir)
configure_file(
input: 'gnome-shell-x11.service.in',
output: 'gnome-shell-x11.service',
unit = configure_file(
input: 'gnome-shell.service.in',
output: 'gnome-shell.service',
configuration: unitconf,
install_dir: systemduserunitdir
)
configure_file(
input: 'gnome-shell-wayland.service.in',
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')
units = files('gnome-shell-wayland.target',
'gnome-shell-x11.target')
install_data(units, install_dir: systemduserunitdir)
endif

View File

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

View File

@@ -50,7 +50,7 @@
</description>
</key>
<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>
<description>
The applications corresponding to these identifiers
@@ -109,6 +109,10 @@
the shell.
</description>
</key>
<key name="icons-data" type="a{sv}">
<default>[]</default>
<summary>Data about the icons in the icon grid</summary>
</key>
<child name="keybindings" schema="org.gnome.shell.keybindings"/>
</schema>
@@ -150,6 +154,11 @@
Keybinding to focus the active notification.
</description>
</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">
<default>["&lt;Super&gt;1"]</default>
<summary>Switch to application 1</summary>
@@ -228,17 +237,6 @@
</key>
</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">

View File

@@ -610,13 +610,6 @@ StScrollBar {
border-bottom-style: solid;
}
// Rename popup
.rename-folder-popup {
.rename-folder-popup-item {
spacing: 6px;
&:ltr, &:rtl { padding: 0, 12px; }
}
}
// Background menu
.background-menu { -boxpointer-gap: 4px; -arrow-rise: 0px; }
@@ -749,7 +742,7 @@ StScrollBar {
.ws-switcher-active-up, .ws-switcher-active-down,
.ws-switcher-active-left, .ws-switcher-active-right {
height: 52px;
height: 50px;
background-color: $selected_bg_color;
color: $selected_fg_color;
background-size: 32px;

View File

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

View File

@@ -1,7 +1,4 @@
/* exported main */
imports.gi.versions.Gdk = '3.0';
imports.gi.versions.Gtk = '3.0';
const Gettext = imports.gettext;
const { Gdk, GLib, Gio, GObject, Gtk, Pango } = imports.gi;
const Format = imports.format;
@@ -285,9 +282,8 @@ var Application = GObject.registerClass({
log(`Failed to connect to shell proxy: ${e}`);
this._mainStack.add_named(new NoShellPlaceholder(), 'noshell');
this._mainStack.visible_child_name = 'noshell';
} else {
} else
throw e;
}
return;
}
@@ -568,10 +564,6 @@ class ExtensionRow extends Gtk.ListBoxRow {
this._extension = extension;
this._prefsModule = null;
this.connect('destroy', this._onDestroy.bind(this));
this._buildUI();
this._extensionStateChangedId = this._app.shellProxy.connectSignal(
'ExtensionStateChanged', (p, sender, [uuid, newState]) => {
if (this.uuid !== uuid)
@@ -579,13 +571,13 @@ class ExtensionRow extends Gtk.ListBoxRow {
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();
});
this.connect('destroy', this._onDestroy.bind(this));
this._buildUI();
}
get uuid() {
@@ -651,7 +643,7 @@ class ExtensionRow extends Gtk.ListBoxRow {
sensitive: this._canToggle(),
state: this._extension.state === ExtensionState.ENABLED
});
this._notifyActiveId = this._switch.connect('notify::active', () => {
this._switch.connect('notify::active', () => {
if (this._switch.active)
this._app.shellProxy.EnableExtensionRemote(this.uuid);
else

View File

@@ -1,25 +1,21 @@
// -*- 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 Batch = imports.gdm.batch;
const GdmUtil = imports.gdm.util;
const Util = imports.misc.util;
const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
var DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000;
var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 300;
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0;
var DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3;
var MESSAGE_FADE_OUT_ANIMATION_TIME = 500;
const WIGGLE_OFFSET = 6;
const WIGGLE_DURATION = 65;
const N_WIGGLES = 3;
var MESSAGE_FADE_OUT_ANIMATION_TIME = 0.5;
var AuthPromptMode = {
UNLOCK_ONLY: 0,
@@ -38,21 +34,8 @@ var BeginRequestType = {
DONT_PROVIDE_USERNAME: 1
};
var AuthPrompt = GObject.registerClass({
Signals: {
'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
});
var AuthPrompt = class {
constructor(gdmClient, mode) {
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
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.add(this._userWell, {
x_align: St.Align.START,
this._userWell = new St.Bin({ x_fill: true,
x_align: St.Align.START });
this.actor.add(this._userWell,
{ x_align: St.Align.START,
x_fill: true,
y_fill: true,
expand: true
});
expand: true });
this._label = new St.Label({ style_class: 'login-dialog-prompt-label' });
this.add(this._label, {
expand: true,
this.actor.add(this._label,
{ expand: true,
x_fill: false,
y_fill: true,
x_align: St.Align.START
});
x_align: St.Align.START });
this._entry = new St.Entry({ style_class: 'login-dialog-prompt-entry',
can_focus: true });
ShellEntry.addContextMenu(this._entry, { isPassword: true, actionMode: Shell.ActionMode.NONE });
this.add(this._entry, {
expand: true,
this.actor.add(this._entry,
{ expand: true,
x_fill: true,
y_fill: false,
x_align: St.Align.START
});
x_align: St.Align.START });
this._entry.grab_key_focus();
@@ -119,15 +107,14 @@ var AuthPrompt = GObject.registerClass({
styleClass: 'login-dialog-message' });
this._message.clutter_text.line_wrap = true;
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',
vertical: false });
this.add(this._buttonBox, {
expand: true,
this.actor.add(this._buttonBox,
{ expand: true,
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._defaultButtonWellActor = null;
@@ -135,9 +122,9 @@ var AuthPrompt = GObject.registerClass({
this._initButtons();
this._spinner = new Animation.Spinner(DEFAULT_BUTTON_WELL_ICON_SIZE);
this._spinner.opacity = 0;
this._spinner.show();
this._defaultButtonWell.add_child(this._spinner);
this._spinner.actor.opacity = 0;
this._spinner.actor.show();
this._defaultButtonWell.add_child(this._spinner.actor);
}
_onDestroy() {
@@ -145,12 +132,6 @@ var AuthPrompt = GObject.registerClass({
this._userVerifier = null;
}
vfunc_key_press_event(keyPressEvent) {
if (keyPressEvent.keyval == Clutter.KEY_Escape)
this.cancel();
return Clutter.EVENT_PROPAGATE;
}
_initButtons() {
this.cancelButton = new St.Button({ style_class: 'modal-dialog-button button',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
@@ -261,12 +242,6 @@ var AuthPrompt = GObject.registerClass({
this.updateSensitivity(canRetry);
this.setActorInDefaultButtonWell(null);
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
Util.wiggle(this._entry, {
offset: WIGGLE_OFFSET,
duration: WIGGLE_DURATION,
wiggleCount: N_WIGGLES,
});
}
_onVerificationComplete() {
@@ -292,16 +267,16 @@ var AuthPrompt = GObject.registerClass({
let oldActor = this._defaultButtonWellActor;
if (oldActor)
oldActor.remove_all_transitions();
Tweener.removeTweens(oldActor);
let wasSpinner;
if (oldActor == this._spinner)
if (oldActor == this._spinner.actor)
wasSpinner = true;
else
wasSpinner = false;
let isSpinner;
if (actor == this._spinner)
if (actor == this._spinner.actor)
isSpinner = true;
else
isSpinner = false;
@@ -315,11 +290,11 @@ var AuthPrompt = GObject.registerClass({
this._spinner.stop();
}
} else {
oldActor.ease({
opacity: 0,
duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
Tweener.addTween(oldActor,
{ opacity: 0,
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
mode: Clutter.AnimationMode.LINEAR,
transition: 'linear',
onComplete: () => {
if (wasSpinner) {
if (this._spinner)
@@ -337,19 +312,18 @@ var AuthPrompt = GObject.registerClass({
if (!animate)
actor.opacity = 255;
else
actor.ease({
opacity: 255,
duration: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
Tweener.addTween(actor,
{ opacity: 255,
time: DEFAULT_BUTTON_WELL_ANIMATION_TIME,
delay: DEFAULT_BUTTON_WELL_ANIMATION_DELAY,
mode: Clutter.AnimationMode.LINEAR
});
transition: 'linear' });
}
this._defaultButtonWellActor = actor;
}
startSpinning() {
this.setActorInDefaultButtonWell(this._spinner, true);
this.setActorInDefaultButtonWell(this._spinner.actor, true);
}
stopSpinning() {
@@ -391,11 +365,11 @@ var AuthPrompt = GObject.registerClass({
_fadeOutMessage() {
if (this._message.opacity == 0)
return;
this._message.remove_all_transitions();
this._message.ease({
opacity: 0,
duration: MESSAGE_FADE_OUT_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
Tweener.removeTweens(this._message);
Tweener.addTween(this._message,
{ opacity: 0,
time: MESSAGE_FADE_OUT_ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
@@ -411,7 +385,7 @@ var AuthPrompt = GObject.registerClass({
this._message.remove_style_class_name('login-dialog-message-hint');
if (message) {
this._message.remove_all_transitions();
Tweener.removeTweens(this._message);
this._message.text = message;
this._message.opacity = 255;
} else {
@@ -430,9 +404,9 @@ var AuthPrompt = GObject.registerClass({
this._entry.clutter_text.editable = sensitive;
}
vfunc_hide() {
hide() {
this.setActorInDefaultButtonWell(null, true);
super.vfunc_hide();
this.actor.hide();
this._message.opacity = 0;
this.setUser(null);
@@ -448,7 +422,7 @@ var AuthPrompt = GObject.registerClass({
if (user) {
let userWidget = new UserWidget.UserWidget(user);
this._userWell.set_child(userWidget);
this._userWell.set_child(userWidget.actor);
}
}
@@ -533,4 +507,5 @@ var AuthPrompt = GObject.registerClass({
this.reset();
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
* 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
* 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:
*
@@ -202,6 +202,7 @@ var ConsecutiveBatch = class extends Batch {
hold.disconnect(signalId);
this.nextTask();
});
return;
} else {
// This task finished, process the next one
this.nextTask();

View File

@@ -19,6 +19,7 @@
const { AccountsService, Atk, Clutter, Gdm, Gio,
GLib, GObject, Meta, Pango, Shell, St } = imports.gi;
const Signals = imports.signals;
const AuthPrompt = imports.gdm.authPrompt;
const Batch = imports.gdm.batch;
@@ -30,43 +31,45 @@ const LoginManager = imports.misc.loginManager;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const Realmd = imports.gdm.realmd;
const Tweener = imports.ui.tweener;
const UserWidget = imports.ui.userWidget;
const _FADE_ANIMATION_TIME = 250;
const _SCROLL_ANIMATION_TIME = 500;
const _FADE_ANIMATION_TIME = 0.25;
const _SCROLL_ANIMATION_TIME = 0.5;
const _TIMED_LOGIN_IDLE_THRESHOLD = 5.0;
const _LOGO_ICON_HEIGHT = 48;
const _MAX_BOTTOM_MENU_ITEMS = 5;
var UserListItem = GObject.registerClass({
GTypeName: 'LoginDialog_UserListItem',
Signals: { 'activate': {} }
}, class UserListItem extends St.Button {
_init(user) {
var UserListItem = class {
constructor(user) {
this.user = user;
this._userChangedId = this.user.connect('changed',
this._onUserChanged.bind(this));
let layout = new St.BoxLayout({ vertical: true });
super._init({
style_class: 'login-dialog-user-list-item',
this.actor = new St.Button({ style_class: 'login-dialog-user-list-item',
button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE,
can_focus: true,
child: layout,
reactive: true,
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.user = user;
this._userChangedId = this.user.connect('changed',
this._onUserChanged.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
this.connect('notify::hover', () => {
this._setSelected(this.hover);
this.actor.connect('key-focus-out', () => {
this._setSelected(false);
});
this.actor.connect('notify::hover', () => {
this._setSelected(this.actor.hover);
});
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);
this._timedLoginIndicator = new St.Bin({ style_class: 'login-dialog-timed-login-indicator',
@@ -74,44 +77,35 @@ var UserListItem = GObject.registerClass({
visible: false });
layout.add(this._timedLoginIndicator);
this.actor.connect('clicked', this._onClicked.bind(this));
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() {
this._updateLoggedIn();
}
_updateLoggedIn() {
if (this.user.is_logged_in())
this.add_style_pseudo_class('logged-in');
this.actor.add_style_pseudo_class('logged-in');
else
this.remove_style_pseudo_class('logged-in');
this.actor.remove_style_pseudo_class('logged-in');
}
_onDestroy() {
this.user.disconnect(this._userChangedId);
}
vfunc_clicked() {
_onClicked() {
this.emit('activate');
}
_setSelected(selected) {
if (selected) {
this.add_style_pseudo_class('selected');
this.grab_key_focus();
this.actor.add_style_pseudo_class('selected');
this.actor.grab_key_focus();
} else {
this.remove_style_pseudo_class('selected');
this.actor.remove_style_pseudo_class('selected');
}
}
@@ -152,30 +146,23 @@ var UserListItem = GObject.registerClass({
this._timedLoginIndicator.visible = false;
this._timedLoginIndicator.scale_x = 0.;
}
});
};
Signals.addSignalMethods(UserListItem.prototype);
var UserList = GObject.registerClass({
GTypeName: 'LoginDialog_UserList',
Signals: {
'activate': { param_types: [UserListItem.$gtype] },
'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,
var UserList = class {
constructor() {
this.actor = new St.ScrollView({ style_class: 'login-dialog-user-list-view' });
this.actor.set_policy(St.PolicyType.NEVER,
St.PolicyType.AUTOMATIC);
this._box = new St.BoxLayout({ vertical: true,
style_class: 'login-dialog-user-list',
pseudo_class: 'expanded' });
this.add_actor(this._box);
this.actor.add_actor(this._box);
this._items = {};
}
vfunc_key_focus_in() {
this._moveFocusToItems();
this.actor.connect('key-focus-in', this._moveFocusToItems.bind(this));
}
_moveFocusToItems() {
@@ -184,10 +171,10 @@ var UserList = GObject.registerClass({
if (!hasItems)
return;
if (global.stage.get_key_focus() != this)
if (global.stage.get_key_focus() != this.actor)
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) {
Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this._moveFocusToItems();
@@ -208,26 +195,27 @@ var UserList = GObject.registerClass({
for (let userName in this._items) {
let item = this._items[userName];
item.sync_hover();
item.actor.sync_hover();
}
}
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);
adjustment.ease(value, {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: _SCROLL_ANIMATION_TIME
});
Tweener.removeTweens(adjustment);
Tweener.addTween (adjustment,
{ value: value,
time: _SCROLL_ANIMATION_TIME,
transition: 'easeOutQuad' });
}
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);
@@ -265,14 +253,14 @@ var UserList = GObject.registerClass({
this.removeUser(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;
item.connect('activate', this._onItemActivated.bind(this));
// 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();
@@ -293,38 +281,33 @@ var UserList = GObject.registerClass({
if (!item)
return;
item.destroy();
item.actor.destroy();
delete this._items[userName];
}
numItems() {
return Object.keys(this._items).length;
}
});
};
Signals.addSignalMethods(UserList.prototype);
var SessionMenuButton = GObject.registerClass({
GTypeName: 'LoginDialog_SessionMenuButton',
Signals: { 'session-activated': { param_types: [GObject.TYPE_STRING] } }
}, class SessionMenuButton extends St.Bin {
_init() {
var SessionMenuButton = class {
constructor() {
let gearIcon = new St.Icon({ icon_name: 'emblem-system-symbolic' });
let button = new St.Button({
style_class: 'login-dialog-session-list-button',
this._button = new St.Button({ style_class: 'login-dialog-session-list-button',
reactive: true,
track_hover: true,
can_focus: true,
accessible_name: _("Choose Session"),
accessible_role: Atk.Role.MENU,
child: gearIcon
});
child: gearIcon });
super._init({ child: button });
this._button = button;
this.actor = new St.Bin({ child: this._button });
let side = St.Side.TOP;
let align = 0;
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;
else
side = St.Side.LEFT;
@@ -403,13 +386,15 @@ var SessionMenuButton = GObject.registerClass({
});
}
}
});
};
Signals.addSignalMethods(SessionMenuButton.prototype);
var LoginDialog = GObject.registerClass({
Signals: { 'failed': {} },
}, class LoginDialog extends St.Widget {
_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);
@@ -443,7 +428,7 @@ var LoginDialog = GObject.registerClass({
this.add_child(this._userSelectionBox);
this._userList = new UserList();
this._userSelectionBox.add(this._userList,
this._userSelectionBox.add(this._userList.actor,
{ expand: true,
x_fill: true,
y_fill: true });
@@ -452,7 +437,7 @@ var LoginDialog = GObject.registerClass({
this._authPrompt.connect('prompted', this._onPrompted.bind(this));
this._authPrompt.connect('reset', this._onReset.bind(this));
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
// login screen. It can be activated to reveal an entry for
@@ -511,9 +496,9 @@ var LoginDialog = GObject.registerClass({
(list, sessionId) => {
this._greeter.call_select_session_sync (sessionId, null);
});
this._sessionMenuButton.opacity = 0;
this._sessionMenuButton.show();
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton);
this._sessionMenuButton.actor.opacity = 0;
this._sessionMenuButton.actor.show();
this._authPrompt.addActorToDefaultButtonWell(this._sessionMenuButton.actor);
this._disableUserList = undefined;
this._userListLoaded = false;
@@ -596,8 +581,8 @@ var LoginDialog = GObject.registerClass({
let authPromptAllocation = null;
let authPromptWidth = 0;
if (this._authPrompt.visible) {
authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt);
if (this._authPrompt.actor.visible) {
authPromptAllocation = this._getCenterActorAllocation(dialogBox, this._authPrompt.actor);
authPromptWidth = authPromptAllocation.x2 - authPromptAllocation.x1;
}
@@ -707,7 +692,7 @@ var LoginDialog = GObject.registerClass({
}
if (authPromptAllocation)
this._authPrompt.allocate(authPromptAllocation, flags);
this._authPrompt.actor.allocate(authPromptAllocation, flags);
if (userSelectionAllocation)
this._userSelectionBox.allocate(userSelectionAllocation, flags);
@@ -774,15 +759,14 @@ var LoginDialog = GObject.registerClass({
_fadeInBannerView() {
this._bannerView.show();
this._bannerView.ease({
opacity: 255,
duration: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
Tweener.addTween(this._bannerView,
{ opacity: 255,
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad' });
}
_hideBannerView() {
this._bannerView.remove_all_transitions();
Tweener.removeTweens(this._bannerView);
this._bannerView.opacity = 0;
this._bannerView.hide();
}
@@ -811,7 +795,7 @@ var LoginDialog = GObject.registerClass({
_onPrompted() {
if (this._shouldShowSessionMenuButton()) {
this._sessionMenuButton.updateSensitivity(true);
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton);
this._authPrompt.setActorInDefaultButtonWell(this._sessionMenuButton.actor);
} else {
this._sessionMenuButton.updateSensitivity(false);
}
@@ -871,15 +855,14 @@ var LoginDialog = GObject.registerClass({
}
_showPrompt() {
if (this._authPrompt.visible)
if (this._authPrompt.actor.visible)
return;
this._authPrompt.opacity = 0;
this._authPrompt.show();
this._authPrompt.ease({
opacity: 255,
duration: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
this._authPrompt.actor.opacity = 0;
this._authPrompt.actor.show();
Tweener.addTween(this._authPrompt.actor,
{ opacity: 255,
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad' });
this._fadeInBannerView();
}
@@ -923,31 +906,26 @@ var LoginDialog = GObject.registerClass({
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() {
if (this.opacity == 255 && this._authPrompt.verificationStatus == AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
return;
this._bindOpacity();
this.ease({
opacity: 255,
duration: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.addTween(this,
{ opacity: 255,
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onUpdate: () => {
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;
}
},
onComplete: () => {
if (this._authPrompt.verificationStatus != AuthPrompt.AuthPromptStatus.NOT_VERIFYING)
this._authPrompt.reset();
this._unbindOpacity();
}
});
} });
}
_gotGreeterSessionProxy(proxy) {
@@ -960,16 +938,21 @@ var LoginDialog = GObject.registerClass({
}
_startSession(serviceName) {
this._bindOpacity();
this.ease({
opacity: 0,
duration: _FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.addTween(this,
{ opacity: 0,
time: _FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onUpdate: () => {
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;
}
},
onComplete: () => {
this._greeter.call_start_session_when_ready_sync(serviceName, true, null);
this._unbindOpacity();
}
});
} });
}
_onSessionOpened(client, serviceName) {
@@ -1062,12 +1045,12 @@ var LoginDialog = GObject.registerClass({
() => {
// If idle timeout is done, make sure the timed login indicator is shown
if (delay > _TIMED_LOGIN_IDLE_THRESHOLD &&
this._authPrompt.visible)
this._authPrompt.actor.visible)
this._authPrompt.cancel();
if (delay > _TIMED_LOGIN_IDLE_THRESHOLD || firstRun) {
this._userList.scrollToItem(loginItem);
loginItem.grab_key_focus();
loginItem.actor.grab_key_focus();
}
},
@@ -1128,7 +1111,7 @@ var LoginDialog = GObject.registerClass({
this._sessionMenuButton.close();
this._setUserListExpanded(true);
this._notListedButton.show();
this._userList.grab_key_focus();
this._userList.actor.grab_key_focus();
}
_beginVerificationForItem(item) {
@@ -1236,17 +1219,16 @@ var LoginDialog = GObject.registerClass({
_("Login Window"),
'dialog-password-symbolic',
{ sortGroup: CtrlAltTab.SortGroup.MIDDLE });
this._userList.grab_key_focus();
this._userList.actor.grab_key_focus();
this.show();
this.opacity = 0;
Main.pushModal(this, { actionMode: Shell.ActionMode.LOGIN_SCREEN });
this.ease({
opacity: 255,
duration: 1000,
mode: Clutter.AnimationMode.EASE_IN_QUAD
});
Tweener.addTween(this,
{ opacity: 255,
time: 1,
transition: 'easeInQuad' });
return true;
}

View File

@@ -21,7 +21,6 @@ var Manager = class {
'/org/freedesktop/realmd',
this._reloadRealms.bind(this));
this._realms = {};
this._loginFormat = null;
this._signalId = this._aggregateProvider.connect('g-properties-changed',
(proxy, properties) => {
@@ -87,7 +86,7 @@ var Manager = class {
}
get loginFormat() {
if (this._loginFormat)
if (this._loginFormat !== undefined)
return this._loginFormat;
this._updateLoginFormat();

View File

@@ -11,13 +11,14 @@ const OVirt = imports.gdm.oVirt;
const Main = imports.ui.main;
const Params = imports.misc.params;
const SmartcardManager = imports.misc.smartcardManager;
const Tweener = imports.ui.tweener;
var PASSWORD_SERVICE_NAME = 'gdm-password';
var FINGERPRINT_SERVICE_NAME = 'gdm-fingerprint';
var SMARTCARD_SERVICE_NAME = 'gdm-smartcard';
var OVIRT_SERVICE_NAME = 'gdm-ovirtcred';
var FADE_ANIMATION_TIME = 160;
var CLONE_FADE_ANIMATION_TIME = 250;
var FADE_ANIMATION_TIME = 0.16;
var CLONE_FADE_ANIMATION_TIME = 0.25;
var LOGIN_SCREEN_SCHEMA = 'org.gnome.login-screen';
var PASSWORD_AUTHENTICATION_KEY = 'enable-password-authentication';
@@ -50,15 +51,15 @@ function fadeInActor(actor) {
actor.opacity = 0;
actor.set_height(0);
actor.ease({
opacity: 255,
Tweener.addTween(actor,
{ opacity: 255,
height: naturalHeight,
duration: FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
time: FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete() {
this.set_height(-1);
hold.release();
}
},
});
return hold;
@@ -72,16 +73,16 @@ function fadeOutActor(actor) {
}
let hold = new Batch.Hold();
actor.ease({
opacity: 0,
Tweener.addTween(actor,
{ opacity: 0,
height: 0,
duration: FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
time: FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete() {
this.hide();
this.set_height(-1);
hold.release();
}
},
});
return hold;
}
@@ -102,11 +103,11 @@ function cloneAndFadeOutActor(actor) {
clone.set_position(x, y);
let hold = new Batch.Hold();
clone.ease({
opacity: 0,
duration: CLONE_FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
Tweener.addTween(clone,
{ opacity: 0,
time: CLONE_FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete() {
clone.destroy();
hold.release();
}

View File

@@ -165,8 +165,8 @@ function versionCheck(required, current) {
let requiredArray = required[i].split('.');
if (requiredArray[0] == major &&
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 false;

View File

@@ -2,6 +2,7 @@
/* exported getIBusManager */
const { Gio, GLib, IBus } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const IBusCandidatePopup = imports.ui.ibusCandidatePopup;
@@ -18,8 +19,8 @@ function _checkIBusVersion(requiredMajor, requiredMinor, requiredMicro) {
IBus.MICRO_VERSION >= requiredMicro))
return;
throw "Found IBus version %d.%d.%d but required is %d.%d.%d"
.format(IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MINOR_VERSION,
throw "Found IBus version %d.%d.%d but required is %d.%d.%d".
format(IBus.MAJOR_VERSION, IBus.MINOR_VERSION, IBus.MINOR_VERSION,
requiredMajor, requiredMinor, requiredMicro);
}
@@ -58,30 +59,16 @@ var IBusManager = class {
this._spawn();
}
_spawn(extraArgs = []) {
_spawn() {
try {
let cmdLine = ['ibus-daemon', '--panel', 'disable', ...extraArgs];
Gio.Subprocess.new(cmdLine, Gio.SubprocessFlags.NONE);
Gio.Subprocess.new(['ibus-daemon', '--xim', '--panel', 'disable'],
Gio.SubprocessFlags.NONE);
} catch (e) {
log(`Failed to launch ibus-daemon: ${e.message}`);
}
}
restartDaemon(extraArgs = []) {
this._spawn(['-r', ...extraArgs]);
}
_clear() {
if (this._cancellable) {
this._cancellable.cancel();
this._cancellable = null;
}
if (this._preloadEnginesId) {
GLib.source_remove(this._preloadEnginesId);
this._preloadEnginesId = 0;
}
if (this._panelService)
this._panelService.destroy();
@@ -93,44 +80,33 @@ var IBusManager = class {
this._currentEngineName = null;
this.emit('ready', false);
this._spawn();
}
_onConnected() {
this._cancellable = new Gio.Cancellable();
this._ibus.list_engines_async(-1, this._cancellable,
this._initEngines.bind(this));
this._ibus.list_engines_async(-1, null, this._initEngines.bind(this));
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));
}
_initEngines(ibus, result) {
try {
let enginesList = this._ibus.list_engines_async_finish(result);
if (enginesList) {
for (let i = 0; i < enginesList.length; ++i) {
let name = enginesList[i].get_name();
this._engines.set(name, enginesList[i]);
}
this._updateReadiness();
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
logError(e);
} else {
this._clear();
}
}
_initPanelService(ibus, result) {
let success = false;
try {
success = !!this._ibus.request_name_async_finish(result);
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
return;
logError(e);
}
let success = this._ibus.request_name_async_finish(result);
if (success) {
this._panelService = new IBus.PanelService({ connection: this._ibus.get_connection(),
object_path: IBus.PATH_PANEL });
@@ -157,7 +133,7 @@ var IBusManager = class {
} catch (e) {
}
// 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;
try {
engine = this._ibus.get_global_engine_async_finish(result);
@@ -229,18 +205,8 @@ var IBusManager = class {
return;
}
this._ibus.set_global_engine_async(id,
this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
this._cancellable, (_bus, res) => {
try {
this._ibus.set_global_engine_async_finish(res);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
logError(e);
}
if (callback)
callback();
});
this._ibus.set_global_engine_async(id, this._MAX_INPUT_SOURCE_ACTIVATION_TIME,
null, callback || null);
}
preloadEngines(ids) {
@@ -248,19 +214,17 @@ var IBusManager = class {
return;
if (this._preloadEnginesId != 0) {
GLib.source_remove(this._preloadEnginesId);
Mainloop.source_remove(this._preloadEnginesId);
this._preloadEnginesId = 0;
}
this._preloadEnginesId =
GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT,
this._PRELOAD_ENGINES_DELAY_TIME,
Mainloop.timeout_add_seconds(this._PRELOAD_ENGINES_DELAY_TIME,
() => {
this._ibus.preload_engines_async(
ids,
-1,
this._cancellable,
null,
null);
this._preloadEnginesId = 0;
return GLib.SOURCE_REMOVE;

View File

@@ -1,6 +1,6 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported InputMethod */
const { Clutter, GLib, Gio, GObject, IBus } = imports.gi;
const { Clutter, GLib, GObject, IBus } = imports.gi;
const Keyboard = imports.ui.status.keyboard;
@@ -36,7 +36,15 @@ class InputMethod extends Clutter.InputMethod {
}
_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)
this._context.set_capabilities(caps);
@@ -47,22 +55,12 @@ class InputMethod extends Clutter.InputMethod {
}
_onConnected() {
this._cancellable = new Gio.Cancellable();
this._ibus.create_input_context_async ('gnome-shell', -1,
this._cancellable, this._setContext.bind(this));
this._ibus.create_input_context_async ('gnome-shell', -1, null,
this._setContext.bind(this));
}
_setContext(bus, res) {
try {
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('delete-surrounding-text', this._onDeleteSurroundingText.bind(this));
this._context.connect('update-preedit-text', this._onUpdatePreeditText.bind(this));
@@ -74,11 +72,6 @@ class InputMethod extends Clutter.InputMethod {
}
_clear() {
if (this._cancellable) {
this._cancellable.cancel();
this._cancellable = null;
}
this._context = null;
this._hints = 0;
this._purpose = 0;
@@ -144,6 +137,7 @@ class InputMethod extends Clutter.InputMethod {
this._currentFocus = focus;
if (this._context) {
this._context.focus_in();
this._updateCapabilities();
this._emitRequestSurrounding();
}
@@ -155,8 +149,10 @@ class InputMethod extends Clutter.InputMethod {
vfunc_focus_out() {
this._currentFocus = null;
if (this._context)
if (this._context) {
this._context.focus_out();
this._updateCapabilities();
}
if (this._preeditStr) {
// Unset any preedit text
@@ -259,16 +255,14 @@ class InputMethod extends Clutter.InputMethod {
if (event.type() == Clutter.EventType.KEY_RELEASE)
state |= IBus.ModifierType.RELEASE_MASK;
this._context.process_key_event_async(
event.get_key_symbol(),
this._context.process_key_event_async(event.get_key_symbol(),
event.get_key_code() - 8, // Convert XKB keycodes to evcodes
state, -1, this._cancellable,
state, -1, null,
(context, res) => {
try {
let retval = context.process_key_event_async_finish(res);
this.notify_key_event(event, retval);
} catch (e) {
if (!e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
log(`Error processing key on IM: ${e.message}`);
}
});

View File

@@ -127,8 +127,7 @@ var IntrospectService = class {
let apps = this._appSystem.get_running();
let windowsList = {};
if (!this._isIntrospectEnabled() &&
!this._isSenderWhitelisted(invocation.get_sender())) {
if (!this._isIntrospectEnabled()) {
invocation.return_error_literal(Gio.DBusError,
Gio.DBusError.ACCESS_DENIED,
'App introspection not allowed');

View File

@@ -172,7 +172,7 @@ function getPropertyNamesFromExpression(expr, commandHeader = '') {
// Make sure propsUnique contains one key for every
// 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();
}
@@ -217,7 +217,7 @@ function isUnsafeExpression(str) {
prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing
prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing
if (prunedStr.match(/[=]/)) {
if (prunedStr.match(/=/)) {
return true;
} else if (prunedStr.match(/;/)) {
// If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well

View File

@@ -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
@@ -182,9 +182,9 @@ var ModemCdma = class {
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 BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface);

View File

@@ -174,19 +174,11 @@ const SystemActions = GObject.registerClass({
});
Main.layoutManager.connect('monitors-changed',
() => this._updateOrientationLock());
this._sensorProxy = new SensorProxy(Gio.DBus.system,
SENSOR_BUS_NAME,
SENSOR_OBJECT_PATH,
(proxy, error) => {
if (error)
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', () => {
Gio.DBus.system.watch_name(SENSOR_BUS_NAME,
Gio.BusNameWatcherFlags.NONE,
() => this._sensorProxyAppeared(),
() => {
this._sensorProxy = null;
this._updateOrientationLock();
});
this._updateOrientationLock();
@@ -231,9 +223,22 @@ const SystemActions = GObject.registerClass({
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() {
let available = false;
if (this._sensorProxy.g_name_owner)
if (this._sensorProxy)
available = this._sensorProxy.HasAccelerometer &&
this._monitorManager.get_is_builtin_display_on();
@@ -244,8 +249,7 @@ const SystemActions = GObject.registerClass({
_updateOrientationLockIcon() {
let locked = this._orientationSettings.get_boolean('orientation-lock');
let iconName = locked
? 'rotation-locked-symbolic'
let iconName = locked ? 'rotation-locked-symbolic'
: 'rotation-allowed-symbolic';
this._actions.get(LOCK_ORIENTATION_ACTION_ID).iconName = iconName;
@@ -269,7 +273,7 @@ const SystemActions = GObject.registerClass({
getMatchingActions(terms) {
// terms is a list of strings
terms = terms.map(term => term.toLowerCase());
terms = terms.map((term) => term.toLowerCase());
let results = [];

View File

@@ -1,20 +1,23 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
formatTime, formatTimeSpan, createTimeLabel, insertSorted,
makeCloseButton, ensureActorVisibleInScrollView, wiggle */
makeCloseButton, ensureActorVisibleInScrollView */
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
const Gettext = imports.gettext;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Params = imports.misc.params;
var SCROLL_TIME = 100;
var SCROLL_TIME = 0.1;
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
const _balancedParens = '\\([^\\s()<>]+\\)';
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(
`(^|${_leadingJunk})` +
@@ -313,8 +316,7 @@ function lowerBound(array, val, cmp) {
if (array.length == 0)
return 0;
min = 0;
max = array.length;
min = 0; max = array.length;
while (min < (max - 1)) {
mid = Math.floor((min + max) / 2);
v = cmp(array[mid], val);
@@ -424,42 +426,97 @@ function ensureActorVisibleInScrollView(scrollView, actor) {
else
return;
adjustment.ease(value, {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: SCROLL_TIME
});
Tweener.addTween(adjustment,
{ value: value,
time: SCROLL_TIME,
transition: 'easeOutQuad' });
}
function wiggle(actor, params) {
params = Params.parse(params, {
offset: 0,
duration: 0,
wiggleCount: 0,
});
actor.translation_x = 0;
var AppSettingsMonitor = class {
constructor(appId, schemaId) {
this._appId = appId;
this._schemaId = schemaId;
// Accelerate before wiggling
actor.ease({
translation_x: -params.offset,
duration: params.duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
// Wiggle
actor.ease({
translation_x: params.offset,
duration: params.duration,
mode: Clutter.AnimationMode.LINEAR,
repeatCount: params.wiggleCount,
autoReverse: true,
onComplete: () => {
// Decelerate and return to the original position
actor.ease({
translation_x: 0,
duration: params.duration,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
this._app = null;
this._settings = null;
this._handlers = [];
this._schemaSource = Gio.SettingsSchemaSource.get_default();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed',
this._onInstalledChanged.bind(this));
this._onInstalledChanged();
}
get available() {
return this._app != null && this._settings != null;
}
activateApp() {
if (this._app)
this._app.activate();
}
watchSetting(key, callback) {
let handler = { id: 0, key: key, callback: callback };
this._handlers.push(handler);
this._connectHandler(handler);
}
_connectHandler(handler) {
if (!this._settings || handler.id > 0)
return;
handler.id = this._settings.connect(`changed::${handler.key}`,
handler.callback);
handler.callback(this._settings, handler.key);
}
_disconnectHandler(handler) {
if (this._settings && handler.id > 0)
this._settings.disconnect(handler.id);
handler.id = 0;
}
_onInstalledChanged() {
let hadApp = (this._app != null);
this._app = this._appSystem.lookup_app(this._appId);
let haveApp = (this._app != null);
if (hadApp == haveApp)
return;
if (haveApp)
this._checkSettings();
else
this._setSettings(null);
}
_setSettings(settings) {
this._handlers.forEach((handler) => this._disconnectHandler(handler));
let hadSettings = (this._settings != null);
this._settings = settings;
let haveSettings = (this._settings != null);
this._handlers.forEach((handler) => this._connectHandler(handler));
if (hadSettings != haveSettings)
this.emit('available-changed');
}
_checkSettings() {
let schema = this._schemaSource.lookup(this._schemaId, true);
if (schema) {
this._setSettings(new Gio.Settings({ settings_schema: schema }));
} else if (this._app) {
Mainloop.timeout_add_seconds(1, () => {
this._checkSettings();
return GLib.SOURCE_REMOVE;
});
}
});
}
});
}
};
Signals.addSignalMethods(AppSettingsMonitor.prototype);

View File

@@ -94,10 +94,8 @@ var WeatherClient = class {
});
this._settings.connect('changed::automatic-location',
this._onAutomaticLocationChanged.bind(this));
this._onAutomaticLocationChanged();
this._settings.connect('changed::locations',
this._onLocationsChanged.bind(this));
this._onLocationsChanged();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed',
@@ -155,13 +153,12 @@ var WeatherClient = class {
this._weatherProxy.connect('g-properties-changed',
this._onWeatherPropertiesChanged.bind(this));
if (this._weatherProxy.g_name_owner != null)
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',
@@ -261,8 +258,8 @@ var WeatherClient = class {
this._setLocation(location);
}
_onAutomaticLocationChanged() {
let useAutoLocation = this._settings.get_boolean('automatic-location');
_onAutomaticLocationChanged(settings, key) {
let useAutoLocation = settings.get_boolean(key);
if (this._autoLocationRequested == useAutoLocation)
return;
@@ -280,9 +277,8 @@ var WeatherClient = class {
this._setLocation(this._mostRecentLocation);
}
_onLocationsChanged() {
let locations = this._settings.get_value('locations').deep_unpack();
let serialized = locations.shift();
_onLocationsChanged(settings, key) {
let serialized = settings.get_value(key).deep_unpack().shift();
let mostRecentLocation = null;
if (serialized)

View File

@@ -127,11 +127,11 @@ function *run() {
for (let i = 0; i < 2; i++) {
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();
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();
}
}

View File

@@ -57,7 +57,7 @@ function waitAndDraw(milliseconds) {
cb();
});
return callback => (cb = callback);
return callback => cb = callback;
}
function waitSignal(object, signal) {
@@ -69,7 +69,7 @@ function waitSignal(object, signal) {
cb();
});
return callback => (cb = callback);
return callback => cb = callback;
}
function extractBootTimestamp() {
@@ -127,7 +127,7 @@ function *run() {
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();
Scripting.scriptEvent('applicationsShowDone');
@@ -137,9 +137,9 @@ function *run() {
Main.overview.hide();
yield Scripting.waitLeisure();
// --------------------- //
// Tests of redraw speed //
// --------------------- //
////////////////////////////////////////
// Tests of redraw speed
////////////////////////////////////////
global.frame_timestamps = true;
global.frame_finish_timestamp = true;
@@ -186,6 +186,8 @@ function *run() {
yield Scripting.sleep(1000);
////////////////////////////////////////
let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('org.gnome.gedit.desktop');

View File

@@ -56,8 +56,8 @@ class AccessDialog extends ModalDialog.ModalDialog {
let check = new CheckBox.CheckBox();
check.getLabelActor().text = name;
check.checked = selected == "true";
content.insertBeforeBody(check);
check.actor.checked = selected == "true";
content.insertBeforeBody(check.actor);
this._choices.set(id, check);
}
@@ -99,7 +99,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
let results = {};
if (response == DialogResponse.OK) {
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);
}
}
@@ -147,7 +147,7 @@ var AccessDialogDBus = class {
subtitle, body, options);
dialog.open();
dialog.connect('closed', () => (this._accessDialog = null));
dialog.connect('closed', () => this._accessDialog = null);
this._accessDialog = dialog;
}

View File

@@ -3,15 +3,17 @@
WindowCyclerPopup */
const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const SwitcherPopup = imports.ui.switcherPopup;
const Tweener = imports.ui.tweener;
var APP_ICON_HOVER_TIMEOUT = 200; // milliseconds
var THUMBNAIL_DEFAULT_SIZE = 256;
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 APP_ICON_SIZE = 96;
@@ -291,7 +293,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
if (this._thumbnails)
this._destroyThumbnails();
if (this._thumbnailTimeoutId != 0)
GLib.source_remove(this._thumbnailTimeoutId);
Mainloop.source_remove(this._thumbnailTimeoutId);
}
/**
@@ -326,7 +328,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
}
if (this._thumbnailTimeoutId != 0) {
GLib.source_remove(this._thumbnailTimeoutId);
Mainloop.source_remove(this._thumbnailTimeoutId);
this._thumbnailTimeoutId = 0;
}
@@ -343,8 +345,7 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._thumbnails.highlight(window, forceAppFocus);
} else if (this._items[this._selectedIndex].cachedWindows.length > 1 &&
!forceAppFocus) {
this._thumbnailTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
this._thumbnailTimeoutId = Mainloop.timeout_add (
THUMBNAIL_POPUP_TIME,
this._timeoutPopupThumbnails.bind(this));
GLib.Source.set_name_by_id(this._thumbnailTimeoutId, '[gnome-shell] this._timeoutPopupThumbnails');
@@ -361,10 +362,10 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
_destroyThumbnails() {
let thumbnailsActor = this._thumbnails;
this._thumbnails.ease({
opacity: 0,
duration: THUMBNAIL_FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.addTween(thumbnailsActor,
{ opacity: 0,
time: THUMBNAIL_FADE_TIME,
transition: 'easeOutQuad',
onComplete: () => {
thumbnailsActor.destroy();
this.thumbnailsVisible = false;
@@ -392,39 +393,38 @@ class AppSwitcherPopup extends SwitcherPopup.SwitcherPopup {
this._thumbnails.get_allocation_box();
this._thumbnails.opacity = 0;
this._thumbnails.ease({
opacity: 255,
duration: THUMBNAIL_FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this.thumbnailsVisible = true;
}
Tweener.addTween(this._thumbnails,
{ opacity: 255,
time: THUMBNAIL_FADE_TIME,
transition: 'easeOutQuad',
onComplete: () => this.thumbnailsVisible = true
});
this._switcherList._items[this._selectedIndex].add_accessible_state (Atk.StateType.EXPANDED);
}
});
var CyclerHighlight = GObject.registerClass(
class CyclerHighlight extends St.Widget {
_init() {
super._init({ layout_manager: new Clutter.BinLayout() });
class CyclerHighlight {
constructor() {
this._window = null;
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout() });
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.add_actor(this._highlight);
this.actor.add_actor(this._highlight);
let coordinate = Clutter.BindCoordinate.ALL;
let constraint = new Clutter.BindConstraint({ coordinate: coordinate });
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.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('notify::allocation',
this._onAllocationChanged.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
}
set window(w) {
@@ -436,8 +436,8 @@ class CyclerHighlight extends St.Widget {
if (this._clone.source)
this._clone.source.sync_visibility();
let windowActor = this._window
? this._window.get_compositor_private() : null;
let windowActor = this._window ? this._window.get_compositor_private()
: null;
if (windowActor)
windowActor.hide();
@@ -450,7 +450,7 @@ class CyclerHighlight extends St.Widget {
this._highlight.set_size(0, 0);
this._highlight.hide();
} else {
let [x, y] = this.allocation.get_origin();
let [x, y] = this.actor.allocation.get_origin();
let rect = this._window.get_frame_rect();
this._highlight.set_size(rect.width, rect.height);
this._highlight.set_position(rect.x - x, rect.y - y);
@@ -461,7 +461,7 @@ class CyclerHighlight extends St.Widget {
_onDestroy() {
this.window = null;
}
});
}
// We don't show an actual popup, so just provide what SwitcherPopup
// expects instead of inheriting from SwitcherList
@@ -488,7 +488,7 @@ var CyclerPopup = GObject.registerClass({
return;
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.connect('item-highlighted', (list, index) => {
@@ -498,7 +498,7 @@ var CyclerPopup = GObject.registerClass({
_highlightItem(index, _justOutline) {
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() {
@@ -528,7 +528,7 @@ var CyclerPopup = GObject.registerClass({
}
_onDestroy() {
this._highlight.destroy();
this._highlight.actor.destroy();
super._onDestroy();
}
@@ -647,9 +647,8 @@ class WindowCyclerPopup extends CyclerPopup {
}
});
var AppIcon = GObject.registerClass({
GTypeName: 'AltTab_AppIcon'
}, class AppIcon extends St.BoxLayout {
var AppIcon = GObject.registerClass(
class AppIcon extends St.BoxLayout {
_init(app) {
super._init({ style_class: 'alt-tab-app',
vertical: true });
@@ -711,7 +710,7 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
_onDestroy() {
if (this._mouseTimeOutId != 0)
GLib.source_remove(this._mouseTimeOutId);
Mainloop.source_remove(this._mouseTimeOutId);
this.icons.forEach(icon => {
icon.app.disconnect(icon._stateChangedId);
@@ -790,11 +789,9 @@ class AppSwitcher extends SwitcherPopup.SwitcherList {
// activation when the thumbnail list is open
_onItemEnter(index) {
if (this._mouseTimeOutId != 0)
GLib.source_remove(this._mouseTimeOutId);
Mainloop.source_remove(this._mouseTimeOutId);
if (this._altTabPopup.thumbnailsVisible) {
this._mouseTimeOutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
APP_ICON_HOVER_TIMEOUT,
this._mouseTimeOutId = Mainloop.timeout_add(APP_ICON_HOVER_TIMEOUT,
() => {
this._enterItem(index);
this._mouseTimeOutId = 0;
@@ -876,9 +873,9 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
_init(windows) {
super._init(false);
this._labels = [];
this._thumbnailBins = [];
this._clones = [];
this._labels = new Array();
this._thumbnailBins = new Array();
this._clones = new Array();
this._windows = windows;
for (let i = 0; i < windows.length; i++) {
@@ -939,7 +936,7 @@ class ThumbnailList extends SwitcherPopup.SwitcherList {
}
// Make sure we only do this once
this._thumbnailBins = [];
this._thumbnailBins = new Array();
}
_removeThumbnail(source, clone) {
@@ -1013,9 +1010,9 @@ class WindowIcon extends St.BoxLayout {
}
_createAppIcon(app, size) {
let appIcon = app
? app.create_icon_texture(size)
: new St.Icon({ icon_name: 'icon-missing', icon_size: size });
let appIcon = app ? app.create_icon_texture(size)
: new St.Icon({ icon_name: 'icon-missing',
icon_size: size });
appIcon.x_expand = appIcon.y_expand = true;
appIcon.x_align = appIcon.y_align = Clutter.ActorAlign.END;
@@ -1042,7 +1039,7 @@ class WindowList extends SwitcherPopup.SwitcherList {
this.addItem(icon, icon.label);
this.icons.push(icon);
icon._unmanagedSignalId = icon.window.connect('unmanaged', window => {
icon._unmanagedSignalId = icon.window.connect('unmanaged', (window) => {
this._removeWindow(window);
});
}

View File

@@ -1,18 +1,22 @@
// -*- 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 SPINNER_ANIMATION_TIME = 300;
var SPINNER_ANIMATION_DELAY = 1000;
var SPINNER_ANIMATION_TIME = 0.3;
var SPINNER_ANIMATION_DELAY = 1.0;
var Animation = GObject.registerClass(
class Animation extends St.Bin {
_init(file, width, height, speed) {
super._init({ width: width, height: height });
this.connect('destroy', this._onDestroy.bind(this));
this.connect('resource-scale-changed',
var Animation = class {
constructor(file, width, height, speed) {
this.actor = new St.Bin();
this.actor.set_size(width, height);
this.actor.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('notify::size', this._syncAnimationSize.bind(this));
this.actor.connect('resource-scale-changed',
this._loadFile.bind(this, file, width, height));
let themeContext = St.ThemeContext.get_for_stage(global.stage);
@@ -43,7 +47,7 @@ class Animation extends St.Bin {
stop() {
if (this._timeoutId > 0) {
GLib.source_remove(this._timeoutId);
Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0;
}
@@ -51,30 +55,20 @@ class Animation extends St.Bin {
}
_loadFile(file, width, height) {
let [validResourceScale, resourceScale] = this.get_resource_scale();
let wasPlaying = this._isPlaying;
if (this._isPlaying)
this.stop();
let [validResourceScale, resourceScale] = this.actor.get_resource_scale();
this._isLoaded = false;
this.destroy_all_children();
this.actor.destroy_all_children();
if (!validResourceScale) {
if (wasPlaying)
this.play();
if (!validResourceScale)
return;
}
let textureCache = St.TextureCache.get_default();
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._animations = textureCache.load_sliced_image(file, width, height,
scaleFactor, resourceScale,
this._animationsLoaded.bind(this));
this.set_child(this._animations);
if (wasPlaying)
this.play();
this.actor.set_child(this._animations);
}
_showFrame(frame) {
@@ -98,7 +92,7 @@ class Animation extends St.Bin {
if (!this._isLoaded)
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)
this._animations.get_child_at_index(i).set_size(width, height);
@@ -121,22 +115,20 @@ class Animation extends St.Bin {
themeContext.disconnect(this._scaleChangedId);
this._scaleChangedId = 0;
}
});
};
var AnimatedIcon = GObject.registerClass(
class AnimatedIcon extends Animation {
_init(file, size) {
super._init(file, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
var AnimatedIcon = class extends Animation {
constructor(file, size) {
super(file, size, size, ANIMATED_ICON_UPDATE_TIMEOUT);
}
});
};
var Spinner = GObject.registerClass(
class Spinner extends AnimatedIcon {
_init(size, animate = false) {
var Spinner = class extends AnimatedIcon {
constructor(size, animate = false) {
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;
}
@@ -146,35 +138,37 @@ class Spinner extends AnimatedIcon {
}
play() {
this.remove_all_transitions();
Tweener.removeTweens(this.actor);
if (this._animate) {
super.play();
this.ease({
Tweener.addTween(this.actor, {
opacity: 255,
delay: SPINNER_ANIMATION_DELAY,
duration: SPINNER_ANIMATION_TIME,
mode: Clutter.AnimationMode.LINEAR
time: SPINNER_ANIMATION_TIME,
transition: 'linear'
});
} else {
this.opacity = 255;
this.actor.opacity = 255;
super.play();
}
}
stop() {
this.remove_all_transitions();
Tweener.removeTweens(this.actor);
if (this._animate) {
this.ease({
Tweener.addTween(this.actor, {
opacity: 0,
duration: SPINNER_ANIMATION_TIME,
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => super.stop()
time: SPINNER_ANIMATION_TIME,
transition: 'linear',
onComplete: () => {
super.stop();
}
});
} else {
this.opacity = 0;
this.actor.opacity = 0;
super.stop();
}
}
});
};

File diff suppressed because it is too large Load Diff

View File

@@ -55,7 +55,6 @@ const RENAMED_DESKTOP_IDS = {
'org.gnome.taquin.desktop': 'org.gnome.Taquin.desktop',
'org.gnome.Weather.Application.desktop': 'org.gnome.Weather.desktop',
'polari.desktop': 'org.gnome.Polari.desktop',
'shotwell.desktop': 'org.gnome.Shotwell.desktop',
'tali.desktop': 'org.gnome.Tali.desktop',
'totem.desktop': 'org.gnome.Totem.desktop',
'evince.desktop': 'org.gnome.Evince.desktop',
@@ -148,10 +147,11 @@ class AppFavorites {
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(msg, {
forFeedback: true,
undoCallback: () => this._removeFavorite(appId),
Main.overview.setMessage(_("%s has been added to your favorites.").format(app.get_name()),
{ forFeedback: true,
undoCallback: () => {
this._removeFavorite(appId);
}
});
}
@@ -181,10 +181,11 @@ class AppFavorites {
if (!this._removeFavorite(appId))
return;
let msg = _("%s has been removed from your favorites.").format(app.get_name());
Main.overview.setMessage(msg, {
forFeedback: true,
undoCallback: () => this._addFavorite(appId, pos),
Main.overview.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
{ forFeedback: true,
undoCallback: () => {
this._addFavorite(appId, pos);
}
});
}
}

View File

@@ -161,7 +161,7 @@ var AudioDeviceSelectionDBus = class AudioDeviceSelectionDBus {
let [deviceNames] = params;
let devices = 0;
deviceNames.forEach(n => (devices |= AudioDevice[n.toUpperCase()]));
deviceNames.forEach(n => devices |= AudioDevice[n.toUpperCase()]);
let dialog;
try {

View File

@@ -1,5 +1,4 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported SystemBackground */
// READ THIS FIRST
// Background handling is a maze of objects, both objects in this file, and
@@ -94,12 +93,13 @@
// 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 LoginManager = imports.misc.loginManager;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
var DEFAULT_BACKGROUND_COLOR = Clutter.Color.from_pixel(0x2e3436ff);
@@ -110,7 +110,7 @@ const COLOR_SHADING_TYPE_KEY = 'color-shading-type';
const BACKGROUND_STYLE_KEY = 'picture-options';
const PICTURE_URI_KEY = 'picture-uri';
var FADE_ANIMATION_TIME = 1000;
var FADE_ANIMATION_TIME = 1.0;
// These parameters affect how often we redraw.
// The first is how different (percent crossfaded) the slide show
@@ -221,17 +221,16 @@ function getBackgroundCache() {
return _backgroundCache;
}
var Background = GObject.registerClass({
Signals: { 'loaded': {}, 'bg-changed': {} }
}, class Background extends Meta.Background {
_init(params) {
var Background = class Background {
constructor(params) {
params = Params.parse(params, { monitorIndex: 0,
layoutManager: Main.layoutManager,
settings: null,
file: 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._file = params.file;
@@ -264,6 +263,8 @@ var Background = GObject.registerClass({
}
destroy() {
this.background = null;
this._cancellable.cancel();
this._removeAnimationTimeout();
@@ -300,11 +301,9 @@ var Background = GObject.registerClass({
this._changedIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this._changedIdleId = 0;
this.emit('bg-changed');
this.emit('changed');
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._changedIdleId,
'[gnome-shell] Background._emitChangedSignal');
}
updateResolution() {
@@ -330,7 +329,7 @@ var Background = GObject.registerClass({
this.emit('loaded');
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() {
@@ -344,9 +343,9 @@ var Background = GObject.registerClass({
let shadingType = this._settings.get_enum(COLOR_SHADING_TYPE_KEY);
if (shadingType == GDesktopEnums.BackgroundShading.SOLID)
this.set_color(color);
this.background.set_color(color);
else
this.set_gradient(shadingType, color, secondColor);
this.background.set_gradient(shadingType, color, secondColor);
}
_watchFile(file) {
@@ -382,13 +381,13 @@ var Background = GObject.registerClass({
let finish = () => {
this._setLoaded();
if (files.length > 1) {
this.set_blend(files[0], files[1],
this.background.set_blend(files[0], files[1],
this._animation.transitionProgress,
this._style);
} else if (files.length > 0) {
this.set_file(files[0], this._style);
this.background.set_file(files[0], this._style);
} else {
this.set_file(null, this._style);
this.background.set_file(null, this._style);
}
this._queueUpdateAnimation();
};
@@ -443,8 +442,7 @@ var Background = GObject.registerClass({
}
_loadAnimation(file) {
this._cache.getAnimation({
file: file,
this._cache.getAnimation({ file: file,
settingsSchema: this._settings.schema_id,
onLoaded: animation => {
this._animation = animation;
@@ -461,7 +459,7 @@ var Background = GObject.registerClass({
}
_loadImage(file) {
this.set_file(file, this._style);
this.background.set_file(file, this._style);
this._watchFile(file);
let cache = Meta.BackgroundImageCache.get_default();
@@ -495,14 +493,13 @@ var Background = GObject.registerClass({
this._loadFile(this._file);
}
});
};
Signals.addSignalMethods(Background.prototype);
let _systemBackground;
var SystemBackground = GObject.registerClass({
Signals: { 'loaded': {} }
}, class SystemBackground extends Meta.BackgroundActor {
_init() {
var SystemBackground = class SystemBackground {
constructor() {
let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/noise-texture.png');
if (_systemBackground == null) {
@@ -511,11 +508,9 @@ var SystemBackground = GObject.registerClass({
_systemBackground.set_file(file, GDesktopEnums.BackgroundStyle.WALLPAPER);
}
super._init({
meta_display: global.display,
this.actor = new Meta.BackgroundActor({ meta_display: global.display,
monitor: 0,
background: _systemBackground
});
background: _systemBackground });
let cache = Meta.BackgroundImageCache.get_default();
let image = cache.load(file);
@@ -534,7 +529,8 @@ var SystemBackground = GObject.registerClass({
});
}
}
});
};
Signals.addSignalMethods(SystemBackground.prototype);
var BackgroundSource = class BackgroundSource {
constructor(layoutManager, settingsSchema) {
@@ -570,7 +566,7 @@ var BackgroundSource = class BackgroundSource {
// We don't watch changes to settings here,
// 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) {
file = Gio.File.new_for_path(this._overrideImage);
@@ -599,7 +595,7 @@ var BackgroundSource = class BackgroundSource {
style: style
});
background._changedId = background.connect('bg-changed', () => {
background._changedId = background.connect('changed', () => {
background.disconnect(background._changedId);
background.destroy();
delete this._backgrounds[monitorIndex];
@@ -714,11 +710,13 @@ var BackgroundManager = class BackgroundManager {
this._newBackgroundActor = null;
this.emit('changed');
oldBackgroundActor.ease({
opacity: 0,
duration: FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => oldBackgroundActor.destroy()
Tweener.addTween(oldBackgroundActor,
{ opacity: 0,
time: FADE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete() {
oldBackgroundActor.destroy();
}
});
}
@@ -736,7 +734,7 @@ var BackgroundManager = class BackgroundManager {
this._newBackgroundActor = newBackgroundActor;
let background = newBackgroundActor.background;
let background = newBackgroundActor.background._delegate;
if (background.isLoaded) {
this._swapBackgroundActor();
@@ -753,10 +751,9 @@ var BackgroundManager = class BackgroundManager {
_createBackgroundActor() {
let background = this._backgroundSource.getBackground(this._monitorIndex);
let backgroundActor = new Meta.BackgroundActor({
meta_display: global.display,
let backgroundActor = new Meta.BackgroundActor({ meta_display: global.display,
monitor: this._monitorIndex,
background,
background: background.background,
vignette: this._vignette,
vignette_sharpness: 0.5,
brightness: 0.5,
@@ -770,7 +767,7 @@ var BackgroundManager = class BackgroundManager {
backgroundActor.lower_bottom();
}
let changeSignalId = background.connect('bg-changed', () => {
let changeSignalId = background.connect('changed', () => {
background.disconnect(changeSignalId);
changeSignalId = null;
this._updateBackgroundActor();

View File

@@ -31,7 +31,7 @@ function addBackgroundMenu(actor, layoutManager) {
function openMenu(x, y) {
Main.layoutManager.setDummyCursorGeometry(x, y, 0, 0);
actor._backgroundMenu.open(BoxPointer.PopupAnimation.FULL);
actor._backgroundMenu.open(BoxPointer.PopupAnimation.NONE);
}
let clickAction = new Clutter.ClickAction();

View File

@@ -1,48 +1,37 @@
/* -*- 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({
Properties: {
'value': GObject.ParamSpec.double(
'value', 'value', 'value',
GObject.ParamFlags.READWRITE,
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) {
var BarLevel = class {
constructor(value, params = {}) {
if (isNaN(value))
// Avoid spreading NaNs around
throw TypeError('The bar level value must be a number');
this._maxValue = 1;
this._value = 0;
this._value = Math.max(Math.min(value, this._maxValue), 0);
this._overdriveStart = 1;
this._barLevelWidth = 0;
let defaultParams = {
style_class: 'barlevel',
accessible_role: Atk.Role.LEVEL_BAR
};
super._init(Object.assign(defaultParams, params));
this.connect('allocation-changed', (actor, box) => {
this.actor = new St.DrawingArea({ styleClass: params['styleClass'] || 'barlevel',
can_focus: params['canFocus'] || false,
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._customAccessible = St.GenericAccessible.new_for_actor(this);
this.set_accessible(this._customAccessible);
this._customAccessible = St.GenericAccessible.new_for_actor(this.actor);
this.actor.set_accessible(this._customAccessible);
this._customAccessible.connect('get-current-value', this._getCurrentValue.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('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() {
@@ -50,14 +39,16 @@ var BarLevel = GObject.registerClass({
}
set value(value) {
if (isNaN(value))
throw TypeError('The bar level value must be a number');
value = Math.max(Math.min(value, this._maxValue), 0);
if (this._value == value)
return;
this._value = value;
this.notify('value');
this.queue_repaint();
this.actor.queue_repaint();
}
// eslint-disable-next-line camelcase
@@ -67,6 +58,9 @@ var BarLevel = GObject.registerClass({
// eslint-disable-next-line camelcase
set maximum_value(value) {
if (isNaN(value))
throw TypeError('The bar level max value must be a number');
value = Math.max(value, 1);
if (this._maxValue == value)
@@ -74,8 +68,7 @@ var BarLevel = GObject.registerClass({
this._maxValue = value;
this._overdriveStart = Math.min(this._overdriveStart, this._maxValue);
this.notify('maximum-value');
this.queue_repaint();
this.actor.queue_repaint();
}
// eslint-disable-next-line camelcase
@@ -85,6 +78,9 @@ var BarLevel = GObject.registerClass({
// eslint-disable-next-line camelcase
set overdrive_start(value) {
if (isNaN(value))
throw TypeError('The overdrive limit value must be a number');
if (this._overdriveStart == value)
return;
@@ -93,14 +89,14 @@ var BarLevel = GObject.registerClass({
`which is a number greater than the maximum allowed value ${this._maxValue}`);
this._overdriveStart = value;
this.notify('overdrive-start');
this.queue_repaint();
this._value = Math.max(Math.min(value, this._maxValue), 0);
this.actor.queue_repaint();
}
vfunc_repaint() {
let cr = this.get_context();
let themeNode = this.get_theme_node();
let [width, height] = this.get_surface_size();
_barLevelRepaint(area) {
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let barLevelHeight = themeNode.get_length('-barlevel-height');
let barLevelBorderRadius = Math.min(width, barLevelHeight) / 2;
@@ -230,4 +226,5 @@ var BarLevel = GObject.registerClass({
_valueChanged() {
this._customAccessible.notify("accessible-value");
}
});
};
Signals.addSignalMethods(BarLevel.prototype);

View File

@@ -4,6 +4,7 @@
const { Clutter, GObject, Shell, St } = imports.gi;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var PopupAnimation = {
NONE: 0,
@@ -12,7 +13,7 @@ var PopupAnimation = {
FULL: ~0,
};
var POPUP_ANIMATION_TIME = 150;
var POPUP_ANIMATION_TIME = 0.15;
/**
* BoxPointer:
@@ -46,18 +47,12 @@ var BoxPointer = GObject.registerClass({
this.add_actor(this._border);
this.bin.raise(this._border);
this._sourceAlignment = 0.5;
this._muteInput = true;
this._capturedEventId = 0;
this._muteInput();
this.connect('destroy', this._onDestroy.bind(this));
}
vfunc_captured_event() {
if (this._muteInput)
return Clutter.EVENT_STOP;
return Clutter.EVENT_PROPAGATE;
}
_onDestroy() {
if (this._sourceActorDestroyId) {
this._sourceActor.disconnect(this._sourceActorDestroyId);
@@ -69,6 +64,19 @@ var BoxPointer = GObject.registerClass({
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) {
let themeNode = this.get_theme_node();
let rise = themeNode.get_length('-arrow-rise');
@@ -98,18 +106,16 @@ var BoxPointer = GObject.registerClass({
}
}
this.ease({
opacity: 255,
Tweener.addTween(this, { opacity: 255,
translation_x: 0,
translation_y: 0,
duration: animationTime,
mode: Clutter.AnimationMode.LINEAR,
transition: 'linear',
onComplete: () => {
this._muteInput = false;
this._unmuteInput();
if (onComplete)
onComplete();
}
});
},
time: animationTime });
}
close(animate, onComplete) {
@@ -140,15 +146,14 @@ var BoxPointer = GObject.registerClass({
}
}
this._muteInput = true;
this._muteInput();
this.remove_all_transitions();
this.ease({
opacity: fade ? 0 : 255,
Tweener.removeTweens(this);
Tweener.addTween(this, { opacity: fade ? 0 : 255,
translation_x: translationX,
translation_y: translationY,
duration: animationTime,
mode: Clutter.AnimationMode.LINEAR,
transition: 'linear',
time: animationTime,
onComplete: () => {
this.hide();
this.opacity = 0;
@@ -165,8 +170,8 @@ var BoxPointer = GObject.registerClass({
let borderWidth = themeNode.get_length('-arrow-border-width');
minSize += borderWidth * 2;
natSize += borderWidth * 2;
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM)) ||
(isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
if ((!isWidth && (this._arrowSide == St.Side.TOP || this._arrowSide == St.Side.BOTTOM))
|| (isWidth && (this._arrowSide == St.Side.LEFT || this._arrowSide == St.Side.RIGHT))) {
let rise = themeNode.get_length('-arrow-rise');
minSize += rise;
natSize += rise;

View File

@@ -1,7 +1,7 @@
// -*- 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 Main = imports.ui.main;
@@ -313,10 +313,8 @@ var DBusEventSource = class DBusEventSource {
};
Signals.addSignalMethods(DBusEventSource.prototype);
var Calendar = GObject.registerClass({
Signals: { 'selected-date-changed': { param_types: [GLib.DateTime.$gtype] } }
}, class Calendar extends St.Widget {
_init() {
var Calendar = class Calendar {
constructor() {
this._weekStart = Shell.util_get_week_start();
this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.calendar' });
@@ -346,11 +344,12 @@ var Calendar = GObject.registerClass({
this._shouldDateGrabFocus = false;
super._init({
style_class: 'calendar',
this.actor = new St.Widget({ style_class: 'calendar',
layout_manager: new Clutter.TableLayout(),
reactive: true
});
reactive: true });
this.actor.connect('scroll-event',
this._onScroll.bind(this));
this._buildHeader ();
}
@@ -374,10 +373,7 @@ var Calendar = GObject.registerClass({
this._selectedDate = date;
this._update();
let datetime = GLib.DateTime.new_from_unix_local(
this._selectedDate.getTime() / 1000);
this.emit('selected-date-changed', datetime);
this.emit('selected-date-changed', new Date(this._selectedDate));
}
updateTimeZone() {
@@ -388,9 +384,9 @@ var Calendar = GObject.registerClass({
}
_buildHeader() {
let layout = this.layout_manager;
let layout = this.actor.layout_manager;
let offsetCols = this._useWeekdate ? 1 : 0;
this.destroy_all_children();
this.actor.destroy_all_children();
// Top line of the calendar '<| September 2009 |>'
this._topBox = new St.BoxLayout();
@@ -432,7 +428,7 @@ var Calendar = GObject.registerClass({
can_focus: true });
label.accessible_name = iter.toLocaleFormat('%A');
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;
else
col = offsetCols + (7 + iter.getDay() - this._weekStart) % 7;
@@ -441,11 +437,11 @@ var Calendar = GObject.registerClass({
}
// 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) {
switch (scrollEvent.direction) {
_onScroll(actor, event) {
switch (event.get_scroll_direction()) {
case Clutter.ScrollDirection.UP:
case Clutter.ScrollDirection.LEFT:
this._onPrevMonthButtonClicked();
@@ -515,7 +511,7 @@ var Calendar = GObject.registerClass({
let now = new Date();
// 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++)
children[i].destroy();
@@ -552,7 +548,7 @@ var Calendar = GObject.registerClass({
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 row = 2;
// nRows here means 6 weeks + one header + one navbar
@@ -585,8 +581,7 @@ var Calendar = GObject.registerClass({
if (row == 2)
styleClass = `calendar-day-top ${styleClass}`;
let leftMost = rtl
? iter.getDay() == (this._weekStart + 6) % 7
let leftMost = rtl ? iter.getDay() == (this._weekStart + 6) % 7
: iter.getDay() == this._weekStart;
if (leftMost)
styleClass = `calendar-day-left ${styleClass}`;
@@ -652,12 +647,12 @@ var Calendar = GObject.registerClass({
}
});
}
});
};
Signals.addSignalMethods(Calendar.prototype);
var EventMessage = GObject.registerClass(
class EventMessage extends MessageList.Message {
_init(event, date) {
super._init('', event.summary);
var EventMessage = class EventMessage extends MessageList.Message {
constructor(event, date) {
super('', event.summary);
this._event = event;
this._date = date;
@@ -666,12 +661,11 @@ class EventMessage extends MessageList.Message {
this._icon = new St.Icon({ icon_name: 'x-office-calendar-symbolic' });
this.setIcon(this._icon);
}
vfunc_style_changed() {
let iconVisible = this.get_parent().has_style_pseudo_class('first-child');
this.actor.connect('style-changed', () => {
let iconVisible = this.actor.get_parent().has_style_pseudo_class('first-child');
this._icon.opacity = (iconVisible ? 255 : 0);
super.vfunc_style_changed();
});
}
_formatEventTime() {
@@ -686,8 +680,7 @@ class EventMessage extends MessageList.Message {
*/
title = C_("event list time", "All Day");
} else {
let date = this._event.date >= periodBegin
? this._event.date
let date = this._event.date >= periodBegin ? this._event.date
: this._event.end;
title = Util.formatTime(date, { timeOnly: true });
}
@@ -695,24 +688,24 @@ class EventMessage extends MessageList.Message {
let rtl = Clutter.get_default_text_direction() == Clutter.TextDirection.RTL;
if (this._event.date < periodBegin && !this._event.allDay) {
if (rtl)
title = `${title}${ELLIPSIS_CHAR}`;
title = title + ELLIPSIS_CHAR;
else
title = `${ELLIPSIS_CHAR}${title}`;
title = ELLIPSIS_CHAR + title;
}
if (this._event.end > periodEnd && !this._event.allDay) {
if (rtl)
title = `${ELLIPSIS_CHAR}${title}`;
title = ELLIPSIS_CHAR + title;
else
title = `${title}${ELLIPSIS_CHAR}`;
title = title + ELLIPSIS_CHAR;
}
return title;
}
});
};
var NotificationMessage = GObject.registerClass(
var NotificationMessage =
class NotificationMessage extends MessageList.Message {
_init(notification) {
super._init(notification.title, notification.bannerBodyText);
constructor(notification) {
super(notification.title, notification.bannerBodyText);
this.setUseBodyMarkup(notification.bannerBodyMarkup);
this.notification = notification;
@@ -749,7 +742,7 @@ class NotificationMessage extends MessageList.Message {
this.setUseBodyMarkup(n.bannerBodyMarkup);
}
vfunc_clicked() {
_onClicked() {
this.notification.activate();
}
@@ -771,12 +764,11 @@ class NotificationMessage extends MessageList.Message {
canClose() {
return true;
}
});
};
var EventsSection = GObject.registerClass(
class EventsSection extends MessageList.MessageListSection {
_init() {
super._init();
var EventsSection = class EventsSection extends MessageList.MessageListSection {
constructor() {
super();
this._desktopSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.interface' });
this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
@@ -788,7 +780,7 @@ class EventsSection extends MessageList.MessageListSection {
label: '',
x_align: St.Align.START,
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('key-focus-in', this._onKeyFocusIn.bind(this));
@@ -907,29 +899,12 @@ class EventsSection extends MessageList.MessageListSection {
super._sync();
}
});
};
var TimeLabel = GObject.registerClass(
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(
var NotificationSection =
class NotificationSection extends MessageList.MessageListSection {
_init() {
super._init();
constructor() {
super();
this._sources = new Map();
this._nUrgent = 0;
@@ -938,6 +913,8 @@ class NotificationSection extends MessageList.MessageListSection {
Main.messageTray.getSources().forEach(source => {
this._sourceAdded(Main.messageTray, source);
});
this.actor.connect('notify::mapped', this._onMapped.bind(this));
}
get allowed() {
@@ -945,6 +922,17 @@ class NotificationSection extends MessageList.MessageListSection {
!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) {
let obj = {
destroyId: 0,
@@ -962,13 +950,13 @@ class NotificationSection extends MessageList.MessageListSection {
_onNotificationAdded(source, 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 updatedId = notification.connect('updated', () => {
message.setSecondaryActor(new TimeLabel(notification.datetime));
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.mapped);
message.setSecondaryActor(this._createTimeLabel(notification.datetime));
this.moveMessage(message, isUrgent ? 0 : this._nUrgent, this.actor.mapped);
});
let destroyId = notification.connect('destroy', () => {
notification.disconnect(destroyId);
@@ -988,7 +976,7 @@ class NotificationSection extends MessageList.MessageListSection {
}
let index = isUrgent ? 0 : this._nUrgent;
this.addMessageAtIndex(message, index, this.mapped);
this.addMessageAtIndex(message, index, this.actor.mapped);
}
_onSourceDestroy(source, obj) {
@@ -998,23 +986,25 @@ class NotificationSection extends MessageList.MessageListSection {
this._sources.delete(source);
}
vfunc_map() {
this._messages.forEach(message => {
_onMapped() {
if (!this.actor.mapped)
return;
for (let message of this._messages.keys())
if (message.notification.urgency != MessageTray.Urgency.CRITICAL)
message.notification.acknowledged = true;
});
super.vfunc_map();
}
_shouldShow() {
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();
let todayFile = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/no-notifications.svg');
@@ -1023,10 +1013,10 @@ class Placeholder extends St.BoxLayout {
this._otherIcon = new Gio.FileIcon({ file: otherFile });
this._icon = new St.Icon();
this.add_actor(this._icon);
this.actor.add_actor(this._icon);
this._label = new St.Label();
this.add_actor(this._label);
this.actor.add_actor(this._label);
this._sync();
}
@@ -1053,24 +1043,20 @@ class Placeholder extends St.BoxLayout {
this._label.text = _("No Events");
}
}
});
};
var CalendarMessageList = GObject.registerClass(
class CalendarMessageList extends St.Widget {
_init() {
super._init({
style_class: 'message-list',
var CalendarMessageList = class CalendarMessageList {
constructor() {
this.actor = new St.Widget({ style_class: 'message-list',
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true
});
x_expand: true, y_expand: true });
this._placeholder = new Placeholder();
this.add_actor(this._placeholder);
this.actor.add_actor(this._placeholder.actor);
let box = new St.BoxLayout({ vertical: true,
x_expand: true, y_expand: true });
this.add_actor(box);
this.actor.add_actor(box);
this._scrollView = new St.ScrollView({ style_class: 'vfade',
overlay_scrollbars: true,
@@ -1084,21 +1070,17 @@ class CalendarMessageList extends St.Widget {
can_focus: true });
this._clearButton.set_x_align(Clutter.ActorAlign.END);
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);
this._placeholder.bind_property('visible',
this._clearButton, 'visible',
GObject.BindingFlags.INVERT_BOOLEAN);
this._sectionList = new St.BoxLayout({ style_class: 'message-list-sections',
vertical: true,
y_expand: true,
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._sections = new Map();
this._mediaSection = new Mpris.MediaSection();
this._addSection(this._mediaSection);
@@ -1113,35 +1095,59 @@ class CalendarMessageList extends St.Widget {
}
_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']) {
connectionsIds.push(
section.connect(`notify::${prop}`, this._sync.bind(this)));
this._sections.set(section, obj);
this._sectionList.add_actor(section.actor);
this._sync();
}
connectionsIds.push(section.connect('message-focused', (_s, messageActor) => {
Util.ensureActorVisibleInScrollView(this._scrollView, messageActor);
}));
connectionsIds.push(section.connect('destroy', (section) => {
connectionsIds.forEach(id => section.disconnect(id));
this._sectionList.remove_actor(section);
}));
_removeSection(section) {
let obj = this._sections.get(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() {
let sections = this._sectionList.get_children();
let sections = [...this._sections.keys()];
let visible = sections.some(s => s.allowed);
this.visible = visible;
this.actor.visible = visible;
if (!visible)
return;
let empty = sections.every(s => s.empty || !s.visible);
this._placeholder.visible = empty;
let empty = sections.every(s => s.empty || !s.actor.visible);
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;
}
@@ -1150,7 +1156,8 @@ class CalendarMessageList extends St.Widget {
}
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);
}
});
};

View File

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

View File

@@ -5,9 +5,10 @@ const { Clutter, Gio, GLib, GObject, Meta, Shell } = imports.gi;
const Dialog = imports.ui.dialog;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var FROZEN_WINDOW_BRIGHTNESS = -0.3;
var DIALOG_TRANSITION_TIME = 150;
var DIALOG_TRANSITION_TIME = 0.15;
var ALIVE_TIMEOUT = 5000;
var CloseDialog = GObject.registerClass({
@@ -148,10 +149,10 @@ var CloseDialog = GObject.registerClass({
this._dialog.scale_y = 0;
this._dialog.set_pivot_point(0.5, 0.5);
this._dialog.ease({
scale_y: 1,
mode: Clutter.AnimationMode.LINEAR,
duration: DIALOG_TRANSITION_TIME,
Tweener.addTween(this._dialog,
{ scale_y: 1,
transition: 'linear',
time: DIALOG_TRANSITION_TIME,
onComplete: this._onFocusChanged.bind(this)
});
}
@@ -175,11 +176,13 @@ var CloseDialog = GObject.registerClass({
this._dialog = null;
this._removeWindowEffect();
dialog.ease({
scale_y: 0,
mode: Clutter.AnimationMode.LINEAR,
duration: DIALOG_TRANSITION_TIME,
onComplete: () => dialog.destroy()
Tweener.addTween(dialog,
{ scale_y: 0,
transition: 'linear',
time: DIALOG_TRANSITION_TIME,
onComplete: () => {
dialog.destroy();
}
});
}

View File

@@ -2,6 +2,7 @@
/* exported Component */
const { Gio, GLib } = imports.gi;
const Mainloop = imports.mainloop;
const Params = imports.misc.params;
const GnomeSession = imports.misc.gnomeSession;
@@ -38,7 +39,7 @@ var AutomountManager = class {
this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', this._onDriveDisconnected.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');
}
@@ -50,7 +51,7 @@ var AutomountManager = class {
this._volumeMonitor.disconnect(this._driveEjectButtonId);
if (this._mountAllId > 0) {
GLib.source_remove(this._mountAllId);
Mainloop.source_remove(this._mountAllId);
this._mountAllId = 0;
}
}
@@ -219,7 +220,7 @@ var AutomountManager = class {
_onVolumeRemoved(monitor, volume) {
if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) {
GLib.source_remove(volume._allowAutorunExpireId);
Mainloop.source_remove(volume._allowAutorunExpireId);
delete volume._allowAutorunExpireId;
}
this._volumeQueue =
@@ -248,7 +249,7 @@ var AutomountManager = class {
}
_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;
delete volume._allowAutorunExpireId;
return GLib.SOURCE_REMOVE;

View File

@@ -1,7 +1,7 @@
// -*- 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 Main = imports.ui.main;
@@ -72,6 +72,8 @@ function startAppForMount(app, mount) {
return retval;
}
/******************************************/
const HotplugSnifferIface = loadInterfaceXML('org.gnome.Shell.HotplugSniffer');
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
function HotplugSniffer() {
@@ -272,10 +274,9 @@ var AutorunDispatcher = class {
}
};
var AutorunSource = GObject.registerClass(
class AutorunSource extends MessageTray.Source {
_init(manager, mount, apps) {
super._init(mount.get_name());
var AutorunSource = class extends MessageTray.Source {
constructor(manager, mount, apps) {
super(mount.get_name());
this._manager = manager;
this.mount = mount;
@@ -285,7 +286,7 @@ class AutorunSource extends MessageTray.Source {
// add ourselves as a source, and popup the notification
Main.messageTray.add(this);
this.showNotification(this._notification);
this.notify(this._notification);
}
getIcon() {
@@ -295,12 +296,11 @@ class AutorunSource extends MessageTray.Source {
_createPolicy() {
return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus');
}
});
};
var AutorunNotification = GObject.registerClass(
class AutorunNotification extends MessageTray.Notification {
_init(manager, source) {
super._init(source, source.title);
var AutorunNotification = class extends MessageTray.Notification {
constructor(manager, source) {
super(source, source.title);
this._manager = manager;
this._mount = source.mount;
@@ -325,9 +325,9 @@ class AutorunNotification extends MessageTray.Notification {
style_class: 'hotplug-notification-item-icon' });
box.add(icon);
let label = new St.Bin({
y_align: St.Align.MIDDLE,
child: new St.Label({ text: _("Open with %s").format(app.get_name()) }),
let label = new St.Bin({ y_align: St.Align.MIDDLE,
child: new St.Label
({ text: _("Open with %s").format(app.get_name()) })
});
box.add(label);
@@ -352,6 +352,6 @@ class AutorunNotification extends MessageTray.Notification {
let app = Gio.app_info_get_default_for_type('inode/directory', false);
startAppForMount(app, this._mount);
}
});
};
var Component = AutorunManager;

View File

@@ -77,13 +77,13 @@ class KeyringDialog extends ModalDialog.ModalDialog {
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
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(label, 2, row, 1, 1);
} else {
layout.attach(label, 0, 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++;
} else {
@@ -121,8 +121,8 @@ class KeyringDialog extends ModalDialog.ModalDialog {
if (this.prompt.choice_visible) {
let choice = new CheckBox.CheckBox();
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);
layout.attach(choice, rtl ? 0 : 1, row, 1, 1);
this.prompt.bind_property('choice-chosen', choice.actor, 'checked', GObject.BindingFlags.SYNC_CREATE | GObject.BindingFlags.BIDIRECTIONAL);
layout.attach(choice.actor, rtl ? 0 : 1, row, 1, 1);
row++;
}
@@ -232,8 +232,7 @@ var KeyringPrompter = class {
constructor() {
this._prompter = new Gcr.SystemPrompter();
this._prompter.connect('new-prompt', () => {
let dialog = this._enabled
? new KeyringDialog()
let dialog = this._enabled ? new KeyringDialog()
: new KeyringDummyDialog();
this._currentPrompt = dialog.prompt;
return this._currentPrompt;

View File

@@ -112,17 +112,16 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
expand: true });
}
this._okButton = {
label: _("Connect"),
this._okButton = { label: _("Connect"),
action: this._onOk.bind(this),
default: true,
default: true
};
this.setButtons([{
label: _("Cancel"),
this.setButtons([{ label: _("Cancel"),
action: this.cancel.bind(this),
key: Clutter.KEY_Escape,
}, this._okButton]);
},
this._okButton]);
this._updateOkButton();
}
@@ -164,9 +163,9 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
if (value.length == 64) {
// must be composed of hexadecimal digits only
for (let i = 0; i < 64; i++) {
if (!((value[i] >= 'a' && value[i] <= 'f') ||
(value[i] >= 'A' && value[i] <= 'F') ||
(value[i] >= '0' && value[i] <= '9')))
if (!((value[i] >= 'a' && value[i] <= 'f')
|| (value[i] >= 'A' && value[i] <= 'F')
|| (value[i] >= '0' && value[i] <= '9')))
return false;
}
return true;
@@ -180,15 +179,15 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
if (secret.wep_key_type == NM.WepKeyType.KEY) {
if (value.length == 10 || value.length == 26) {
for (let i = 0; i < value.length; i++) {
if (!((value[i] >= 'a' && value[i] <= 'f') ||
(value[i] >= 'A' && value[i] <= 'F') ||
(value[i] >= '0' && value[i] <= '9')))
if (!((value[i] >= 'a' && value[i] <= 'f')
|| (value[i] >= 'A' && value[i] <= 'F')
|| (value[i] >= '0' && value[i] <= '9')))
return false;
}
} else if (value.length == 5 || value.length == 13) {
for (let i = 0; i < value.length; i++) {
if (!((value[i] >= 'a' && value[i] <= 'z') ||
(value[i] >= 'A' && value[i] <= 'Z')))
if (!((value[i] >= 'a' && value[i] <= 'z')
|| (value[i] >= 'A' && value[i] <= 'Z')))
return false;
}
} else {
@@ -213,7 +212,6 @@ class NetworkSecretDialog extends ModalDialog.ModalDialog {
// First the easy ones
case 'wpa-none':
case 'wpa-psk':
case 'sae':
secrets.push({ label: _("Password: "), key: 'psk',
value: wirelessSecuritySetting.psk || '',
validate: this._validateWpaPsk, password: true });
@@ -553,11 +551,10 @@ var VPNRequestHandler = class {
let shouldAsk = keyfile.get_boolean(groups[i], 'ShouldAsk');
if (shouldAsk) {
contentOverride.secrets.push({
label: keyfile.get_string(groups[i], 'Label'),
contentOverride.secrets.push({ label: keyfile.get_string(groups[i], 'Label'),
key: groups[i],
value: value,
password: keyfile.get_boolean(groups[i], 'IsSecret'),
password: keyfile.get_boolean(groups[i], 'IsSecret')
});
} else {
if (!value.length) // Ignore empty secrets
@@ -612,10 +609,9 @@ Signals.addSignalMethods(VPNRequestHandler.prototype);
var NetworkAgent = class {
constructor() {
this._native = new Shell.NetworkAgent({
identifier: 'org.gnome.Shell.NetworkAgent',
this._native = new Shell.NetworkAgent({ identifier: 'org.gnome.Shell.NetworkAgent',
capabilities: NM.SecretAgentCapabilities.VPN_HINTS,
auto_register: false,
auto_register: false
});
this._dialogs = { };
@@ -625,7 +621,7 @@ var NetworkAgent = class {
this._pluginDir = Gio.file_new_for_path(Config.VPNDIR);
try {
let monitor = this._pluginDir.monitor(Gio.FileMonitorFlags.NONE, null);
monitor.connect('changed', () => (this._vpnCacheBuilt = false));
monitor.connect('changed', () => this._vpnCacheBuilt = false);
} catch (e) {
log(`Failed to create monitor for VPN plugin dir: ${e.message}`);
}
@@ -734,7 +730,7 @@ var NetworkAgent = class {
});
Main.messageTray.add(source);
source.showNotification(notification);
source.notify(notification);
}
_newRequest(agent, requestId, connection, settingName, hints, flags) {

View File

@@ -76,8 +76,8 @@ var AuthenticationDialog = GObject.registerClass({
this._userAvatar = new UserWidget.Avatar(this._user,
{ iconSize: DIALOG_ICON_SIZE,
styleClass: 'polkit-dialog-user-icon' });
this._userAvatar.hide();
userBox.add(this._userAvatar,
this._userAvatar.actor.hide();
userBox.add(this._userAvatar.actor,
{ x_fill: true,
y_fill: false,
x_align: St.Align.END,
@@ -106,7 +106,7 @@ var AuthenticationDialog = GObject.registerClass({
{ expand: 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._passwordBox.hide();
@@ -305,7 +305,7 @@ var AuthenticationDialog = GObject.registerClass({
_onUserChanged() {
if (this._user.is_loaded && this._userAvatar) {
this._userAvatar.update();
this._userAvatar.show();
this._userAvatar.actor.show();
}
}

View File

@@ -3,6 +3,7 @@
const { Clutter, Gio, GLib, GObject, St } = imports.gi;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
var Tpl = null;
var Tp = null;
@@ -215,7 +216,7 @@ class TelepathyClient extends Tp.BaseClient {
// We are already handling the channel, display the source
let source = this._chatSources[channel.get_object_path()];
if (source)
source.showNotification();
source.notify();
}
}
}
@@ -266,10 +267,9 @@ class TelepathyClient extends Tp.BaseClient {
}
}) : null;
var ChatSource = HAVE_TP ? GObject.registerClass(
class ChatSource extends MessageTray.Source {
_init(account, conn, channel, contact, client) {
super._init(contact.get_alias());
var ChatSource = class extends MessageTray.Source {
constructor(account, conn, channel, contact, client) {
super(contact.get_alias());
this._account = account;
this._contact = contact;
@@ -327,7 +327,7 @@ class ChatSource extends MessageTray.Source {
// We ack messages when the user expands the new notification
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 = null;
});
@@ -477,7 +477,7 @@ class ChatSource extends MessageTray.Source {
this._notification.appendMessage(pendingMessages[i], true);
if (pendingMessages.length > 0)
this.showNotification();
this.notify();
}
destroy(reason) {
@@ -546,15 +546,15 @@ class ChatSource extends MessageTray.Source {
// Wait a bit before notifying for the received message, a handler
// could ack it in the meantime.
if (this._notifyTimeoutId != 0)
GLib.source_remove(this._notifyTimeoutId);
this._notifyTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500,
Mainloop.source_remove(this._notifyTimeoutId);
this._notifyTimeoutId = Mainloop.timeout_add(500,
this._notifyTimeout.bind(this));
GLib.Source.set_name_by_id(this._notifyTimeoutId, '[gnome-shell] this._notifyTimeout');
}
_notifyTimeout() {
if (this._pendingMessages.length != 0)
this.showNotification();
this.notify();
this._notifyTimeoutId = 0;
@@ -569,8 +569,8 @@ class ChatSource extends MessageTray.Source {
this._notification.appendMessage(message);
}
showNotification() {
super.showNotification(this._notification);
notify() {
super.notify(this._notification);
}
respond(text) {
@@ -626,17 +626,11 @@ class ChatSource extends MessageTray.Source {
// 'pending-message-removed' for each one.
this._channel.ack_all_pending_messages_async(null);
}
}) : null;
};
var ChatNotification = HAVE_TP ? GObject.registerClass({
Signals: {
'message-removed': { param_types: [Tp.Message.$gtype] },
'message-added': { param_types: [Tp.Message.$gtype] },
'timestamp-changed': { param_types: [Tp.Message.$gtype] },
}
}, class ChatNotification extends MessageTray.Notification {
_init(source) {
super._init(source, source.title, null,
var ChatNotification = class extends MessageTray.Notification {
constructor(source) {
super(source, source.title, null,
{ secondaryGIcon: source.getSecondaryIcon() });
this.setUrgency(MessageTray.Urgency.HIGH);
this.setResident(true);
@@ -647,7 +641,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
destroy(reason) {
if (this._timestampTimeoutId)
GLib.source_remove(this._timestampTimeoutId);
Mainloop.source_remove(this._timestampTimeoutId);
this._timestampTimeoutId = 0;
super.destroy(reason);
}
@@ -680,8 +674,8 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
{ datetime: GLib.DateTime.new_from_unix_local (message.timestamp),
bannerMarkup: true });
let group = (message.direction == NotificationDirection.RECEIVED
? 'received' : 'sent');
let group = (message.direction == NotificationDirection.RECEIVED ?
'received' : 'sent');
this._append({ body: messageBody,
group: group,
@@ -703,8 +697,8 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
// SCROLLBACK_RECENT_LENGTH previous messages. Otherwise
// we'll keep SCROLLBACK_IDLE_LENGTH messages.
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME)
? SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
let maxLength = (lastMessageTime < currentTime - SCROLLBACK_RECENT_TIME) ?
SCROLLBACK_IDLE_LENGTH : SCROLLBACK_RECENT_LENGTH;
let filteredHistory = this.messages.filter(item => item.realMessage);
if (filteredHistory.length > maxLength) {
@@ -735,7 +729,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
// Reset the old message timeout
if (this._timestampTimeoutId)
GLib.source_remove(this._timestampTimeoutId);
Mainloop.source_remove(this._timestampTimeoutId);
this._timestampTimeoutId = 0;
let message = { realMessage: props.group != 'meta',
@@ -753,8 +747,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
} else {
// Schedule a new timestamp in SCROLLBACK_IMMEDIATE_TIME
// from the timestamp of the message.
this._timestampTimeoutId = GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT,
this._timestampTimeoutId = Mainloop.timeout_add_seconds(
SCROLLBACK_IMMEDIATE_TIME - (currentTime - timestamp),
this.appendTimestamp.bind(this));
GLib.Source.set_name_by_id(this._timestampTimeoutId, '[gnome-shell] this.appendTimestamp');
@@ -789,7 +782,7 @@ var ChatNotification = HAVE_TP ? GObject.registerClass({
this._filterMessages();
}
}) : null;
};
var ChatLineBox = GObject.registerClass(
class ChatLineBox extends St.BoxLayout {
@@ -799,10 +792,9 @@ class ChatLineBox extends St.BoxLayout {
}
});
var ChatNotificationBanner = GObject.registerClass(
class ChatNotificationBanner extends MessageTray.NotificationBanner {
_init(notification) {
super._init(notification);
var ChatNotificationBanner = class extends MessageTray.NotificationBanner {
constructor(notification) {
super(notification);
this._responseEntry = new St.Entry({ style_class: 'chat-response',
x_expand: true,
@@ -887,7 +879,8 @@ class ChatNotificationBanner extends MessageTray.NotificationBanner {
}
_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;
for (let i = 0; i < styles.length; i++)
@@ -959,15 +952,14 @@ class ChatNotificationBanner extends MessageTray.NotificationBanner {
// Remove composing timeout.
if (this._composingTimeoutId > 0) {
GLib.source_remove(this._composingTimeoutId);
Mainloop.source_remove(this._composingTimeoutId);
this._composingTimeoutId = 0;
}
if (text != '') {
this.notification.source.setChatState(Tp.ChannelChatState.COMPOSING);
this._composingTimeoutId = GLib.timeout_add_seconds(
GLib.PRIORITY_DEFAULT,
this._composingTimeoutId = Mainloop.timeout_add_seconds(
COMPOSING_STOP_TIMEOUT,
this._composingStopTimeout.bind(this));
GLib.Source.set_name_by_id(this._composingTimeoutId, '[gnome-shell] this._composingStopTimeout');
@@ -975,6 +967,6 @@ class ChatNotificationBanner extends MessageTray.NotificationBanner {
this.notification.source.setChatState(Tp.ChannelChatState.ACTIVE);
}
}
});
};
var Component = TelepathyComponent;

View File

@@ -1,18 +1,20 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Dash */
const { Clutter, GLib, GObject,
Graphene, Meta, Shell, St } = imports.gi;
const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const AppDisplay = imports.ui.appDisplay;
const AppFavorites = imports.ui.appFavorites;
const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var DASH_ANIMATION_TIME = 200;
var DASH_ITEM_LABEL_SHOW_TIME = 150;
var DASH_ITEM_LABEL_HIDE_TIME = 100;
var DASH_ANIMATION_TIME = 0.2;
var DASH_ITEM_LABEL_SHOW_TIME = 0.15;
var DASH_ITEM_LABEL_HIDE_TIME = 0.1;
var DASH_ITEM_HOVER_TIMEOUT = 300;
function getAppFromSource(source) {
@@ -23,13 +25,14 @@ function getAppFromSource(source) {
}
}
var DashIcon = GObject.registerClass(
class DashIcon extends AppDisplay.AppIcon {
_init(app) {
super._init(app, {
var DashIcon = class DashIcon extends AppDisplay.AppIcon {
constructor(app) {
super(app, null, {
setSizeManually: true,
showLabel: false
});
}
// Disable all DnD methods
@@ -46,7 +49,7 @@ class DashIcon extends AppDisplay.AppIcon {
acceptDrop() {
return false;
}
});
}
// A container like StBin, but taking the child's scale into account
// when requesting a size
@@ -54,10 +57,7 @@ var DashItemContainer = GObject.registerClass(
class DashItemContainer extends St.Widget {
_init() {
super._init({ style_class: 'dash-item-container',
pivot_point: new Graphene.Point({ x: .5, y: .5 }),
scale_x: 0,
scale_y: 0,
opacity: 0,
pivot_point: new Clutter.Point({ x: .5, y: .5 }),
x_expand: true,
x_align: Clutter.ActorAlign.CENTER });
@@ -68,11 +68,10 @@ class DashItemContainer extends St.Widget {
this.label_actor = this.label;
this.child = null;
this._childScale = 0;
this._childOpacity = 0;
this.animatingOut = false;
this.connect('notify::scale-x', () => this.queue_relayout());
this.connect('notify::scale-y', () => this.queue_relayout());
this.connect('destroy', () => {
if (this.child != null)
this.child.destroy();
@@ -123,10 +122,10 @@ class DashItemContainer extends St.Widget {
x = stageX + this.get_width() + xOffset;
this.label.set_position(x, y);
this.label.ease({
opacity: 255,
duration: DASH_ITEM_LABEL_SHOW_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
Tweener.addTween(this.label,
{ opacity: 255,
time: DASH_ITEM_LABEL_SHOW_TIME,
transition: 'easeOutQuad',
});
}
@@ -136,11 +135,13 @@ class DashItemContainer extends St.Widget {
}
hideLabel() {
this.label.ease({
opacity: 0,
duration: DASH_ITEM_LABEL_HIDE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this.label.hide()
Tweener.addTween(this.label,
{ opacity: 0,
time: DASH_ITEM_LABEL_HIDE_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this.label.hide();
}
});
}
@@ -152,6 +153,9 @@ class DashItemContainer extends St.Widget {
this.child = actor;
this.add_actor(this.child);
this.set_scale(this._childScale, this._childScale);
this.set_opacity(this._childOpacity);
}
show(animate) {
@@ -159,12 +163,11 @@ class DashItemContainer extends St.Widget {
return;
let time = animate ? DASH_ANIMATION_TIME : 0;
this.ease({
scale_x: 1,
scale_y: 1,
opacity: 255,
duration: time,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
Tweener.addTween(this,
{ childScale: 1.0,
childOpacity: 255,
time: time,
transition: 'easeOutQuad'
});
}
@@ -177,15 +180,38 @@ class DashItemContainer extends St.Widget {
}
this.animatingOut = true;
this.ease({
scale_x: 0,
scale_y: 0,
opacity: 0,
duration: DASH_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this.destroy()
Tweener.addTween(this,
{ childScale: 0.0,
childOpacity: 0,
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: () => {
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(
@@ -331,10 +357,8 @@ class DashActor extends St.Widget {
const baseIconSizes = [16, 22, 24, 32, 48, 64];
var Dash = GObject.registerClass({
Signals: { 'icon-size-changed': {} }
}, class Dash extends St.Bin {
_init() {
var Dash = class Dash {
constructor() {
this._maxHeight = -1;
this.iconSize = 64;
this._shownInitially = false;
@@ -354,7 +378,8 @@ var Dash = GObject.registerClass({
this._container.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
this._showAppsIcon = new ShowAppsIcon();
this._showAppsIcon.show(false);
this._showAppsIcon.childScale = 1;
this._showAppsIcon.childOpacity = 255;
this._showAppsIcon.icon.setIconSize(this.iconSize);
this._hookUpLabel(this._showAppsIcon);
@@ -362,11 +387,11 @@ var Dash = GObject.registerClass({
this._container.add_actor(this._showAppsIcon);
super._init({ child: this._container });
this.connect('notify::height', () => {
if (this._maxHeight != this.height)
this.actor = new St.Bin({ child: this._container });
this.actor.connect('notify::height', () => {
if (this._maxHeight != this.actor.height)
this._queueRedisplay();
this._maxHeight = this.height;
this._maxHeight = this.actor.height;
});
this._workId = Main.initializeDeferredWork(this._box, this._redisplay.bind(this));
@@ -389,7 +414,7 @@ var Dash = GObject.registerClass({
// Translators: this is the name of the dock/favorites area on
// the left of the overview
Main.ctrlAltTabManager.addGroup(this, _("Dash"), 'user-bookmarks-symbolic');
Main.ctrlAltTabManager.addGroup(this.actor, _("Dash"), 'user-bookmarks-symbolic');
}
_onDragBegin() {
@@ -484,11 +509,11 @@ var Dash = GObject.registerClass({
});
let item = new DashItemContainer();
item.setChild(appIcon);
item.setChild(appIcon.actor);
// Override default AppIcon label_actor, now the
// accessible_name is set at DashItemContainer.setLabelText
appIcon.label_actor = null;
appIcon.actor.label_actor = null;
item.setLabelText(app.get_name());
appIcon.icon.setIconSize(this.iconSize);
@@ -502,7 +527,7 @@ var Dash = GObject.registerClass({
// that the notify::hover handler does everything we need to.
if (opened) {
if (this._showLabelTimeoutId > 0) {
GLib.source_remove(this._showLabelTimeoutId);
Mainloop.source_remove(this._showLabelTimeoutId);
this._showLabelTimeoutId = 0;
}
@@ -516,7 +541,7 @@ var Dash = GObject.registerClass({
if (shouldShow) {
if (this._showLabelTimeoutId == 0) {
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;
item.showLabel();
@@ -525,17 +550,17 @@ var Dash = GObject.registerClass({
});
GLib.Source.set_name_by_id(this._showLabelTimeoutId, '[gnome-shell] item.showLabel');
if (this._resetHoverTimeoutId > 0) {
GLib.source_remove(this._resetHoverTimeoutId);
Mainloop.source_remove(this._resetHoverTimeoutId);
this._resetHoverTimeoutId = 0;
}
}
} else {
if (this._showLabelTimeoutId > 0)
GLib.source_remove(this._showLabelTimeoutId);
Mainloop.source_remove(this._showLabelTimeoutId);
this._showLabelTimeoutId = 0;
item.hideLabel();
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._resetHoverTimeoutId = 0;
@@ -623,11 +648,11 @@ var Dash = GObject.registerClass({
icon.icon.set_size(icon.icon.width * scale,
icon.icon.height * scale);
icon.icon.ease({
width: targetWidth,
Tweener.addTween(icon.icon,
{ width: targetWidth,
height: targetHeight,
duration: DASH_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
time: DASH_ANIMATION_TIME,
transition: 'easeOutQuad',
});
}
}
@@ -706,8 +731,8 @@ var Dash = GObject.registerClass({
}
// App moved
let nextApp = newApps.length > newIndex + 1
? newApps[newIndex + 1] : null;
let nextApp = newApps.length > newIndex + 1 ? newApps[newIndex + 1]
: null;
let insertHere = nextApp && nextApp == oldApp;
let alreadyRemoved = removedActors.reduce((result, actor) => {
let removedApp = actor.child._delegate.app;
@@ -905,4 +930,5 @@ var Dash = GObject.registerClass({
return true;
}
});
};
Signals.addSignalMethods(Dash.prototype);

View File

@@ -1,7 +1,7 @@
// -*- 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;
const Util = imports.misc.util;
@@ -11,13 +11,8 @@ const Calendar = imports.ui.calendar;
const Weather = imports.misc.weather;
const System = imports.system;
const { loadInterfaceXML } = imports.misc.fileUtils;
const MAX_FORECASTS = 5;
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
function _isToday(date) {
let now = new Date();
return now.getYear() == date.getYear() &&
@@ -25,26 +20,22 @@ function _isToday(date) {
now.getDate() == date.getDate();
}
function _gDateTimeToDate(datetime) {
return new Date(datetime.to_unix() * 1000 + datetime.get_microsecond() / 1000);
}
var TodayButton = GObject.registerClass(
class TodayButton extends St.Button {
_init(calendar) {
var TodayButton = class TodayButton {
constructor(calendar) {
// 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
// until the selected date changes.
super._init({
style_class: 'datemenu-today-button',
x_align: St.Align.START,
x_expand: true,
this.actor = new St.Button({ style_class: 'datemenu-today-button',
x_expand: true, x_align: St.Align.START,
can_focus: true,
reactive: false
});
this.actor.connect('clicked', () => {
this._calendar.setDate(new Date(), false);
});
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',
x_align: Clutter.ActorAlign.START });
@@ -54,17 +45,13 @@ class TodayButton extends St.Button {
hbox.add_actor(this._dateLabel);
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
// current date.
this.reactive = !_isToday(_gDateTimeToDate(datetime));
this.actor.reactive = !_isToday(date);
});
}
vfunc_clicked() {
this._calendar.setDate(new Date(), false);
}
setDate(date) {
this._dayLabel.set_text(date.toLocaleFormat('%A'));
@@ -81,72 +68,57 @@ class TodayButton extends St.Button {
* date, e.g. "Tuesday February 17 2015".
*/
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(
class WorldClocksSection extends St.Button {
_init() {
super._init({
style_class: 'world-clocks-button',
x_fill: true,
can_focus: true
});
var WorldClocksSection = class WorldClocksSection {
constructor() {
this._clock = new GnomeDesktop.WallClock();
this._clockNotifyId = 0;
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 });
this._grid = new St.Widget({ style_class: 'world-clocks-grid',
layout_manager: layout });
layout.hookup_style(this._grid);
this.child = this._grid;
this.actor.child = this._grid;
this._clocksApp = null;
this._clocksProxy = new ClocksProxy(
Gio.DBus.session,
'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._clockAppMon = new Util.AppSettingsMonitor('org.gnome.clocks.desktop',
'org.gnome.clocks');
this._clockAppMon.connect('available-changed',
this._sync.bind(this));
this._clockAppMon.watchSetting('world-clocks',
this._clocksChanged.bind(this));
this._sync();
}
vfunc_clicked() {
if (this._clocksApp)
this._clocksApp.activate();
Main.overview.hide();
Main.panel.closeCalendar();
}
_sync() {
this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop');
this.visible = this._clocksApp != null;
this.actor.visible = this._clockAppMon.available;
}
_clocksChanged() {
_clocksChanged(settings) {
this._grid.destroy_all_children();
this._locations = [];
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++) {
let l = world.deserialize(clocks[i]);
if (!clocks[i].location)
continue;
let l = world.deserialize(clocks[i].location);
if (l && l.get_timezone() != null)
this._locations.push({ location: l });
}
@@ -157,14 +129,13 @@ class WorldClocksSection extends St.Button {
});
let layout = this._grid.layout_manager;
let title = (this._locations.length == 0)
? _("Add world clocks…")
let title = (this._locations.length == 0) ? _("Add world clocks…")
: _("World Clocks");
let header = new St.Label({ style_class: 'world-clocks-header',
x_align: Clutter.ActorAlign.START,
text: title });
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();
@@ -226,42 +197,30 @@ class WorldClocksSection extends St.Button {
l.actor.text = Util.formatTime(now, { timeOnly: true });
}
}
};
_onProxyReady(proxy, error) {
if (error) {
log(`Failed to create GNOME Clocks proxy: ${error}`);
return;
}
this._clocksProxy.connect('g-properties-changed',
this._onClocksPropertiesChanged.bind(this));
this._onClocksPropertiesChanged();
}
_onClocksPropertiesChanged() {
if (this._clocksProxy.g_name_owner == null)
return;
this._settings.set_value('locations',
new GLib.Variant('av', this._clocksProxy.Locations));
}
});
var WeatherSection = GObject.registerClass(
class WeatherSection extends St.Button {
_init() {
super._init({
style_class: 'weather-button',
x_fill: true,
can_focus: true
});
var WeatherSection = class WeatherSection {
constructor() {
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',
vertical: true });
this.child = box;
this.actor.child = box;
let titleBox = new St.BoxLayout();
titleBox.add_child(new St.Label({ style_class: 'weather-header',
@@ -284,18 +243,6 @@ class WeatherSection extends St.Button {
this._sync();
}
vfunc_map() {
this._weatherClient.update();
super.vfunc_map();
}
vfunc_clicked() {
this._weatherClient.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
}
_getInfos() {
let info = this._weatherClient.info;
let forecasts = info.get_forecast_list();
@@ -386,27 +333,23 @@ class WeatherSection extends St.Button {
}
_sync() {
this.visible = this._weatherClient.available;
this.actor.visible = this._weatherClient.available;
if (!this.visible)
if (!this.actor.visible)
return;
this._titleLocation.visible = this._weatherClient.hasLocation;
this._updateForecasts();
}
});
};
var MessagesIndicator = GObject.registerClass(
class MessagesIndicator extends St.Icon {
_init() {
super._init({
icon_name: 'message-indicator-symbolic',
var MessagesIndicator = class MessagesIndicator {
constructor() {
this.actor = new St.Icon({ icon_name: 'message-indicator-symbolic',
icon_size: 16,
visible: false,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER
});
visible: false, y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
this._sources = [];
@@ -419,7 +362,7 @@ class MessagesIndicator extends St.Icon {
}
_onSourceAdded(tray, source) {
source.connect('notify::count', this._updateCount.bind(this));
source.connect('count-updated', this._updateCount.bind(this));
this._sources.push(source);
this._updateCount();
}
@@ -431,12 +374,12 @@ class MessagesIndicator extends St.Icon {
_updateCount() {
let count = 0;
this._sources.forEach(source => (count += source.unseenCount));
this._sources.forEach(source => count += source.unseenCount);
count -= Main.messageTray.queueCount;
this.visible = (count > 0);
this.actor.visible = (count > 0);
}
});
};
var IndicatorPad = GObject.registerClass(
class IndicatorPad extends St.Widget {
@@ -529,9 +472,9 @@ class DateMenuButton extends PanelMenu.Button {
this._indicator = new MessagesIndicator();
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._indicator);
box.add_actor(this._indicator.actor);
this.label_actor = this._clockDisplay;
this.add_actor(box);
@@ -547,8 +490,8 @@ class DateMenuButton extends PanelMenu.Button {
bin.add_actor(hbox);
this._calendar = new Calendar.Calendar();
this._calendar.connect('selected-date-changed', (_calendar, datetime) => {
let date = _gDateTimeToDate(datetime);
this._calendar.connect('selected-date-changed',
(calendar, date) => {
layout.frozen = !_isToday(date);
this._messageList.setDate(date);
});
@@ -565,19 +508,19 @@ class DateMenuButton extends PanelMenu.Button {
// Fill up the first column
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
let boxLayout = new CalendarColumnLayout(this._calendar);
let boxLayout = new CalendarColumnLayout(this._calendar.actor);
vbox = new St.Widget({ style_class: 'datemenu-calendar-column',
layout_manager: boxLayout });
boxLayout.hookup_style(vbox);
hbox.add(vbox);
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',
x_expand: true, x_fill: true,
@@ -590,10 +533,10 @@ class DateMenuButton extends PanelMenu.Button {
this._displaysSection.add_actor(displaysBox);
this._clocksItem = new WorldClocksSection();
displaysBox.add(this._clocksItem, { x_fill: true });
displaysBox.add(this._clocksItem.actor, { x_fill: true });
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

View File

@@ -6,13 +6,14 @@ const Signals = imports.signals;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
// 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
var SNAP_BACK_ANIMATION_TIME = 250;
var SNAP_BACK_ANIMATION_TIME = 0.25;
// Time to animate to original position on success
var REVERT_ANIMATION_TIME = 750;
var REVERT_ANIMATION_TIME = 0.75;
var DragMotionResult = {
NO_DROP: 0,
@@ -111,6 +112,9 @@ var _Draggable = class _Draggable {
if (event.get_button() != 1)
return Clutter.EVENT_PROPAGATE;
if (Tweener.getTweenCount(actor))
return Clutter.EVENT_PROPAGATE;
this._buttonDown = true;
this._grabActor(event.get_device());
@@ -136,6 +140,9 @@ var _Draggable = class _Draggable {
!global.display.is_pointer_emulating_sequence(event.get_event_sequence()))
return Clutter.EVENT_PROPAGATE;
if (Tweener.getTweenCount(actor))
return Clutter.EVENT_PROPAGATE;
this._buttonDown = true;
this._grabActor(event.get_device(), event.get_event_sequence());
@@ -422,22 +429,19 @@ var _Draggable = class _Draggable {
// to the final position because that tween would
// fight with updates as the user continues dragging
// the mouse; instead we do the position computations in
// a ::new-frame handler.
this._dragActor.ease({
scale_x: scale * origScale,
// an onUpdate() function.
Tweener.addTween(this._dragActor,
{ scale_x: scale * origScale,
scale_y: scale * origScale,
duration: SCALE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
this._dragActor.get_transition('scale-x').connect('new-frame', () => {
time: SCALE_ANIMATION_TIME,
transition: 'easeOutQuad',
onUpdate: () => {
let currentScale = this._dragActor.scale_x / origScale;
this._dragOffsetX = currentScale * origDragOffsetX;
this._dragOffsetY = currentScale * origDragOffsetY;
this._dragActor.set_position(
this._dragX + this._dragOffsetX,
this._dragActor.set_position(this._dragX + this._dragOffsetX,
this._dragY + this._dragOffsetY);
});
} });
}
}
}
@@ -573,15 +577,11 @@ var _Draggable = class _Draggable {
while (target) {
if (target._delegate && target._delegate.acceptDrop) {
let [r_, targX, targY] = target.transform_stage_point(dropX, dropY);
let accepted = false;
try {
accepted = target._delegate.acceptDrop(this.actor._delegate,
this._dragActor, targX, targY, event.get_time());
} catch (e) {
// On error, skip this target
logError(e, "Skipping drag target");
}
if (accepted) {
if (target._delegate.acceptDrop(this.actor._delegate,
this._dragActor,
targX,
targY,
event.get_time())) {
// If it accepted the drop without taking the actor,
// handle it ourselves.
if (this._dragActor && this._dragActor.get_parent() == Main.uiGroup) {
@@ -615,7 +615,7 @@ var _Draggable = class _Draggable {
// Snap the clone back to its source
[x, y] = this._dragActorSource.get_transformed_position();
let [sourceScaledWidth] = this._dragActorSource.get_transformed_size();
scale = sourceScaledWidth ? sourceScaledWidth / this._dragActor.width : 0;
scale = sourceScaledWidth ? this._dragActor.width / sourceScaledWidth : 0;
} else if (this._dragOrigParent) {
// Snap the actor back to its original position within
// its parent, adjusting for the fact that the parent
@@ -658,12 +658,12 @@ var _Draggable = class _Draggable {
let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
this._animateDragEnd(eventTime, {
x: snapBackX,
this._animateDragEnd(eventTime,
{ x: snapBackX,
y: snapBackY,
scale_x: snapBackScale,
scale_y: snapBackScale,
duration: SNAP_BACK_ANIMATION_TIME
time: SNAP_BACK_ANIMATION_TIME,
});
}
@@ -676,22 +676,21 @@ var _Draggable = class _Draggable {
this._dragActor.set_scale(restoreScale, restoreScale);
this._dragActor.opacity = 0;
this._animateDragEnd(eventTime, {
duration: REVERT_ANIMATION_TIME
});
this._animateDragEnd(eventTime,
{ time: REVERT_ANIMATION_TIME });
}
_animateDragEnd(eventTime, params) {
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
this._dragActor.ease(Object.assign(params, {
opacity: this._dragOrigOpacity,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._onAnimationComplete(this._dragActor, eventTime);
}
}));
Tweener.addTween(this._dragActor, params);
}
_finishAnimation() {

View File

@@ -17,6 +17,8 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
const Mainloop = imports.mainloop;
const { AccountsService, Clutter, Gio,
GLib, GObject, Pango, Polkit, Shell, St } = imports.gi;
@@ -207,10 +209,10 @@ function _setCheckBoxLabel(checkBox, text) {
if (text) {
label.set_text(text);
checkBox.show();
checkBox.actor.show();
} else {
label.set_text('');
checkBox.hide();
checkBox.actor.hide();
}
}
@@ -297,8 +299,8 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
y_align: St.Align.START });
this._checkBox = new CheckBox.CheckBox();
this._checkBox.connect('clicked', this._sync.bind(this));
messageLayout.add(this._checkBox);
this._checkBox.actor.connect('clicked', this._sync.bind(this));
messageLayout.add(this._checkBox.actor);
this._batteryWarning = new St.Label({ style_class: 'end-session-dialog-warning',
text: _("Running on battery power: please plug in before installing updates.") });
@@ -350,15 +352,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
}
// 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);
this._updatesPermission = Polkit.Permission.new_sync(
'org.freedesktop.packagekit.trigger-offline-update', null, null);
} catch (e) {
log(`No permission to trigger offline updates: ${e}`);
log('No permission to trigger offline updates: %s'.format(e.toString()));
}
});
}
_onDestroy() {
@@ -376,12 +375,12 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let subject = dialogContent.subject;
// Use different title when we are installing updates
if (dialogContent.subjectWithUpdates && this._checkBox.checked)
if (dialogContent.subjectWithUpdates && this._checkBox.actor.checked)
subject = dialogContent.subjectWithUpdates;
if (dialogContent.showBatteryWarning) {
// 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;
else
this._batteryWarning.opacity = 0;
@@ -429,7 +428,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let avatarWidget = new UserWidget.Avatar(this._user,
{ iconSize: _DIALOG_ICON_SIZE,
styleClass: dialogContent.iconStyleClass });
this._iconBin.child = avatarWidget;
this._iconBin.child = avatarWidget.actor;
avatarWidget.update();
}
@@ -449,16 +448,14 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
for (let i = 0; i < dialogContent.confirmButtons.length; i++) {
let signal = dialogContent.confirmButtons[i].signal;
let label = dialogContent.confirmButtons[i].label;
buttons.push({
action: () => {
buttons.push({ action: () => {
this.close(true);
let signalId = this.connect('closed', () => {
this.disconnect(signalId);
this._confirm(signal);
});
},
label: label,
});
label: label });
}
this.setButtons(buttons);
@@ -485,13 +482,13 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
};
// Offline update not available; just emit the signal
if (!this._checkBox.visible) {
if (!this._checkBox.actor.visible) {
callback();
return;
}
// Trigger the offline update as requested
if (this._checkBox.checked) {
if (this._checkBox.actor.checked) {
switch (signal) {
case "ConfirmedReboot":
this._triggerOfflineUpdateReboot(callback);
@@ -565,7 +562,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let startTime = GLib.get_monotonic_time();
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 secondsElapsed = ((currentTime - startTime) / 1000000);
@@ -587,7 +584,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
_stopTimer() {
if (this._timerId > 0) {
GLib.source_remove(this._timerId);
Mainloop.source_remove(this._timerId);
this._timerId = 0;
}
@@ -656,7 +653,7 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let actor = new St.BoxLayout({ style_class: 'end-session-dialog-session-list-item',
can_focus: true });
actor.add(avatar);
actor.add(avatar.actor);
let nameLabel = new St.Label({ text: userLabelText,
style_class: 'end-session-dialog-session-list-item-name',
@@ -754,14 +751,14 @@ class EndSessionDialog extends ModalDialog.ModalDialog {
let updatesAllowed = this._updatesPermission && this._updatesPermission.allowed;
_setCheckBoxLabel(this._checkBox, dialogContent.checkBoxText || '');
this._checkBox.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
this._checkBox.checked = (updatePrepared && updateTriggered);
this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
this._checkBox.actor.checked = (updatePrepared && updateTriggered);
// We show the warning either together with the checkbox, or when
// updates have already been triggered, but the user doesn't have
// enough permissions to cancel them.
this._batteryWarning.visible = (dialogContent.showBatteryWarning &&
(this._checkBox.visible || updatePrepared && updateTriggered && !updatesAllowed));
(this._checkBox.actor.visible || updatePrepared && updateTriggered && !updatesAllowed));
this._updateButtons();

View File

@@ -10,7 +10,7 @@ imports.gi.versions.Gtk = '3.0';
imports.gi.versions.TelepathyGLib = '0.12';
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;
// We can't import shell JS modules yet, because they may have
@@ -58,154 +58,6 @@ function _patchLayoutClass(layoutClass, styleProps) {
};
}
function _makeEaseCallback(params, cleanup) {
let onComplete = params.onComplete;
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";
@@ -242,27 +94,6 @@ function init() {
column_spacing: 'spacing-columns' });
_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() {
return St.describe_actor(this);
};
@@ -314,17 +145,3 @@ function init() {
Tweener.init();
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

@@ -186,14 +186,13 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
this._info = info;
this._invocation = invocation;
this.setButtons([{
label: _("Cancel"),
this.setButtons([{ label: _("Cancel"),
action: this._onCancelButtonPressed.bind(this),
key: Clutter.Escape,
}, {
label: _("Install"),
key: Clutter.Escape
},
{ label: _("Install"),
action: this._onInstallButtonPressed.bind(this),
default: true,
default: true
}]);
let content = new Dialog.MessageDialogContent({

View File

@@ -17,7 +17,7 @@ const EXTENSION_DISABLE_VERSION_CHECK_KEY = 'disable-extension-version-validatio
var ExtensionManager = class {
constructor() {
this._initialized = false;
this._initted = false;
this._enabled = false;
this._extensions = new Map();
@@ -98,9 +98,6 @@ var ExtensionManager = class {
}
_callExtensionEnable(uuid) {
if (!Main.sessionMode.allowExtensions)
return;
let extension = this.lookup(uuid);
if (!extension)
return;
@@ -111,6 +108,8 @@ var ExtensionManager = class {
if (extension.state != ExtensionState.DISABLED)
return;
this._extensionOrder.push(uuid);
let stylesheetNames = [`${global.session_mode}.css`, 'stylesheet.css'];
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
for (let i = 0; i < stylesheetNames.length; i++) {
@@ -122,7 +121,7 @@ var ExtensionManager = class {
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
continue; // not an error
this.logExtensionError(uuid, e);
log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
return;
}
}
@@ -130,14 +129,15 @@ var ExtensionManager = class {
try {
extension.stateObj.enable();
extension.state = ExtensionState.ENABLED;
this._extensionOrder.push(uuid);
this.emit('extension-state-changed', extension);
return;
} catch (e) {
if (extension.stylesheet) {
theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet;
}
this.logExtensionError(uuid, e);
return;
}
}
@@ -194,7 +194,7 @@ var ExtensionManager = class {
extension.errors = [];
extension.errors.push(message);
logError(error, `Extension ${uuid}`);
log('Extension "%s" had error: %s'.format(uuid, message));
this.emit('extension-state-changed', extension);
}
@@ -286,7 +286,7 @@ var ExtensionManager = class {
reloadExtension(oldExtension) {
// Grab the things we'll need to pass to createExtensionObject
// to reload it.
let { uuid, dir, type } = oldExtension;
let { uuid: uuid, dir: dir, type: type } = oldExtension;
// Then unload the old extension.
this.unloadExtension(oldExtension);
@@ -304,14 +304,12 @@ var ExtensionManager = class {
}
_callExtensionInit(uuid) {
if (!Main.sessionMode.allowExtensions)
return false;
let extension = this.lookup(uuid);
if (!extension)
throw new Error("Extension was not properly created. Call createExtensionObject first");
let dir = extension.dir;
if (!extension)
throw new Error("Extension was not properly created. Call loadExtension first");
let extensionJs = dir.get_child('extension.js');
if (!extensionJs.query_exists(null)) {
this.logExtensionError(uuid, new Error('Missing extension.js'));
@@ -390,6 +388,9 @@ var ExtensionManager = class {
_onEnabledExtensionsChanged() {
let newEnabledExtensions = this._getEnabledExtensions();
if (!this._enabled)
return;
// Find and enable all the newly enabled extensions: UUIDs found in the
// new setting, but not in the old one.
newEnabledExtensions.filter(
@@ -400,9 +401,9 @@ var ExtensionManager = class {
// Find and disable all the newly disabled extensions: UUIDs found in the
// old setting, but not in the new one.
this._extensionOrder.filter(
uuid => !newEnabledExtensions.includes(uuid)
).reverse().forEach(uuid => {
this._enabledExtensions.filter(
item => !newEnabledExtensions.includes(item)
).forEach(uuid => {
this._callExtensionDisable(uuid);
});
@@ -417,19 +418,22 @@ var ExtensionManager = class {
}
_onVersionValidationChanged() {
// Disabling extensions modifies the order array, so use a copy
let extensionOrder = this._extensionOrder.slice();
// we want to reload all extensions, but only enable
// extensions when allowed by the sessionMode, so
// temporarily disable them all
this._enabledExtensions = [];
// Disable enabled extensions in the reverse order first to avoid
// the "rebasing" done in _callExtensionDisable...
extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
// The loop modifies the extensions map, so iterate over a copy
let extensions = [...this._extensions.values()];
for (let extension of extensions)
this.reloadExtension(extension);
this._enabledExtensions = this._getEnabledExtensions();
if (Main.sessionMode.allowExtensions) {
this._enabledExtensions.forEach(uuid => {
this._callExtensionEnable(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() {
@@ -478,9 +482,9 @@ var ExtensionManager = class {
if (this._enabled)
return;
if (!this._initialized) {
if (!this._initted) {
this._loadExtensions();
this._initialized = true;
this._initted = true;
} else {
this._enabledExtensions.forEach(uuid => {
this._callExtensionEnable(uuid);
@@ -493,7 +497,7 @@ var ExtensionManager = class {
if (!this._enabled)
return;
if (this._initialized) {
if (this._initted) {
this._extensionOrder.slice().reverse().forEach(uuid => {
this._callExtensionDisable(uuid);
});
@@ -508,8 +512,8 @@ var ExtensionManager = class {
// property; it might make sense to make enabledExtensions independent
// from allowExtensions in the future
if (Main.sessionMode.allowExtensions) {
// Take care of added or removed sessionMode extensions
this._onEnabledExtensionsChanged();
if (this._initted)
this._enabledExtensions = this._getEnabledExtensions();
this._enableAllExtensions();
} else {
this._disableAllExtensions();

View File

@@ -1,7 +1,8 @@
// -*- 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 Main = imports.ui.main;
@@ -11,23 +12,11 @@ var MAX_CANDIDATES_PER_PAGE = 16;
var DEFAULT_INDEX_LABELS = ['1', '2', '3', '4', '5', '6', '7', '8',
'9', '0', 'a', 'b', 'c', 'd', 'e', 'f'];
var CandidateArea = GObject.registerClass({
Signals: {
'candidate-clicked': { param_types: [GObject.TYPE_UINT,
GObject.TYPE_UINT,
Clutter.ModifierType.$gtype] },
'cursor-down': {},
'cursor-up': {},
'next-page': {},
'previous-page': {},
}
}, class CandidateArea extends St.BoxLayout {
_init() {
super._init({
vertical: true,
var CandidateArea = class CandidateArea {
constructor() {
this.actor = new St.BoxLayout({ vertical: true,
reactive: true,
visible: false
});
visible: false });
this._candidateBoxes = [];
for (let i = 0; i < MAX_CANDIDATES_PER_PAGE; ++i) {
let box = new St.BoxLayout({ style_class: 'candidate-box',
@@ -38,7 +27,7 @@ var CandidateArea = GObject.registerClass({
box.add(box._indexLabel, { y_fill: false });
box.add(box._candidateLabel, { y_fill: false });
this._candidateBoxes.push(box);
this.add(box);
this.actor.add(box);
let j = i;
box.connect('button-release-event', (actor, event) => {
@@ -47,6 +36,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._previousButton = new St.Button({ style_class: 'candidate-page-button candidate-page-button-previous button' });
@@ -57,7 +59,7 @@ var CandidateArea = GObject.registerClass({
this._nextButton.child = new St.Icon({ style_class: 'candidate-page-button-icon' });
this._buttonBox.add(this._nextButton, { expand: true });
this.add(this._buttonBox);
this.actor.add(this._buttonBox);
this._previousButton.connect('clicked', () => {
this.emit('previous-page');
@@ -70,18 +72,6 @@ var CandidateArea = GObject.registerClass({
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) {
if (this._orientation == orientation)
return;
@@ -89,15 +79,15 @@ var CandidateArea = GObject.registerClass({
this._orientation = orientation;
if (this._orientation == IBus.Orientation.HORIZONTAL) {
this.vertical = false;
this.remove_style_class_name('vertical');
this.add_style_class_name('horizontal');
this.actor.vertical = false;
this.actor.remove_style_class_name('vertical');
this.actor.add_style_class_name('horizontal');
this._previousButton.child.icon_name = 'go-previous-symbolic';
this._nextButton.child.icon_name = 'go-next-symbolic';
} else { // VERTICAL || SYSTEM
this.vertical = true;
this.add_style_class_name('vertical');
this.remove_style_class_name('horizontal');
this.actor.vertical = true;
this.actor.add_style_class_name('vertical');
this.actor.remove_style_class_name('horizontal');
this._previousButton.child.icon_name = 'go-up-symbolic';
this._nextButton.child.icon_name = 'go-down-symbolic';
}
@@ -131,23 +121,19 @@ var CandidateArea = GObject.registerClass({
this._previousButton.reactive = wrapsAround || page > 0;
this._nextButton.reactive = wrapsAround || page < nPages - 1;
}
});
};
Signals.addSignalMethods(CandidateArea.prototype);
var CandidatePopup = GObject.registerClass(
class IbusCandidatePopup extends BoxPointer.BoxPointer {
_init() {
super._init(St.Side.TOP);
this.visible = false;
this.style_class = 'candidate-popup-boxpointer';
this._dummyCursor = new St.Widget({ opacity: 0 });
Main.layoutManager.uiGroup.add_actor(this._dummyCursor);
Main.layoutManager.addChrome(this);
var CandidatePopup = class CandidatePopup {
constructor() {
this._boxPointer = new BoxPointer.BoxPointer(St.Side.TOP);
this._boxPointer.visible = false;
this._boxPointer.style_class = 'candidate-popup-boxpointer';
Main.layoutManager.addChrome(this._boxPointer);
let box = new St.BoxLayout({ style_class: 'candidate-popup-content',
vertical: true });
this.bin.set_child(box);
this._boxPointer.bin.set_child(box);
this._preeditText = new St.Label({ style_class: 'candidate-popup-text',
visible: false });
@@ -158,7 +144,7 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
box.add(this._auxText);
this._candidateArea = new CandidateArea();
box.add(this._candidateArea);
box.add(this._candidateArea.actor);
this._candidateArea.connect('previous-page', () => {
this._panelService.page_up();
@@ -236,7 +222,7 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
this._updateVisibility();
});
panelService.connect('update-lookup-table', (_ps, lookupTable, visible) => {
this._candidateArea.visible = visible;
this._candidateArea.actor.visible = visible;
this._updateVisibility();
let nCandidates = lookupTable.get_number_of_candidates();
@@ -272,39 +258,37 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
this._candidateArea.updateButtons(lookupTable.is_round(), page, nPages);
});
panelService.connect('show-lookup-table', () => {
this._candidateArea.show();
this._candidateArea.actor.show();
this._updateVisibility();
});
panelService.connect('hide-lookup-table', () => {
this._candidateArea.hide();
this._candidateArea.actor.hide();
this._updateVisibility();
});
panelService.connect('focus-out', () => {
this.close(BoxPointer.PopupAnimation.NONE);
this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
Main.keyboard.resetSuggestions();
});
}
_setDummyCursorGeometry(x, y, w, h) {
this._dummyCursor.set_position(Math.round(x), Math.round(y));
this._dummyCursor.set_size(Math.round(w), Math.round(h));
if (this.visible)
this.setPosition(this._dummyCursor, 0);
Main.layoutManager.setDummyCursorGeometry(x, y, w, h);
if (this._boxPointer.visible)
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
}
_updateVisibility() {
let isVisible = (!Main.keyboard.visible &&
(this._preeditText.visible ||
this._auxText.visible ||
this._candidateArea.visible));
this._candidateArea.actor.visible));
if (isVisible) {
this.setPosition(this._dummyCursor, 0);
this.open(BoxPointer.PopupAnimation.NONE);
this.raise_top();
this._boxPointer.setPosition(Main.layoutManager.dummyCursor, 0);
this._boxPointer.open(BoxPointer.PopupAnimation.NONE);
this._boxPointer.raise_top();
} else {
this.close(BoxPointer.PopupAnimation.NONE);
this._boxPointer.close(BoxPointer.PopupAnimation.NONE);
}
}
@@ -314,4 +298,4 @@ class IbusCandidatePopup extends BoxPointer.BoxPointer {
if (attr.get_attr_type() == IBus.AttrType.BACKGROUND)
clutterText.set_selection(attr.get_start_index(), attr.get_end_index());
}
});
};

View File

@@ -1,17 +1,18 @@
// -*- 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, GLib, GObject, Meta, St } = imports.gi;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
var ICON_SIZE = 96;
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_MAX_DELAY_FOR_ITEM = 2 / 3 * ANIMATION_TIME_IN;
var ANIMATION_BASE_DELAY_FOR_ITEM = 1 / 4 * ANIMATION_MAX_DELAY_FOR_ITEM;
@@ -26,7 +27,28 @@ var AnimationDirection = {
};
var APPICON_ANIMATION_OUT_SCALE = 3;
var APPICON_ANIMATION_OUT_TIME = 250;
var APPICON_ANIMATION_OUT_TIME = 0.25;
const LEFT_DIVIDER_LEEWAY = 30;
const RIGHT_DIVIDER_LEEWAY = 30;
const NUDGE_ANIMATION_TYPE = Clutter.AnimationMode.EASE_OUT_ELASTIC;
const NUDGE_DURATION = 800;
const NUDGE_RETURN_ANIMATION_TYPE = Clutter.AnimationMode.EASE_OUT_QUINT;
const NUDGE_RETURN_DURATION = 300;
const NUDGE_FACTOR = 0.33;
const ICON_POSITION_DELAY = 25;
var DragLocation = {
DEFAULT: 0,
ON_ICON: 1,
START_EDGE: 2,
END_EDGE: 3,
EMPTY_AREA: 4,
}
var BaseIcon = GObject.registerClass(
class BaseIcon extends St.Bin {
@@ -142,10 +164,6 @@ class BaseIcon extends St.Bin {
zoomOutActor(this.child);
}
animateZoomOutAtPos(x, y) {
zoomOutActorAtPos(this.child, x, y);
}
update() {
this._createIconTexture(this.iconSize);
}
@@ -156,15 +174,10 @@ function clamp(value, min, max) {
}
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,
reactive: false });
let [width, height] = actor.get_transformed_size();
let [x, y] = actor.get_transformed_position();
actorClone.set_size(width, height);
actorClone.set_position(x, y);
actorClone.opacity = 255;
@@ -181,15 +194,17 @@ function zoomOutActorAtPos(actor, x, y) {
let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth);
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_y: APPICON_ANIMATION_OUT_SCALE,
translation_x: containedX - scaledX,
translation_y: containedY - scaledY,
opacity: 0,
duration: APPICON_ANIMATION_OUT_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => actorClone.destroy()
transition: 'easeOutQuad',
onComplete() {
actorClone.destroy();
}
});
}
@@ -231,18 +246,18 @@ var IconGrid = GObject.registerClass({
this._fixedHItemSize = this._fixedVItemSize = undefined;
this.connect('style-changed', this._onStyleChanged.bind(this));
// Cancel animations when hiding the overview, to avoid icons
// swarming into the void ...
this.connect('notify::mapped', () => {
if (!this.mapped)
this._cancelAnimation();
});
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
// swarming into the void ...
this._resetAnimationActors();
super.vfunc_unmap();
}
_onDestroy() {
if (this._updateIconSizesLaterId) {
Meta.later_remove (this._updateIconSizesLaterId);
@@ -256,23 +271,10 @@ var IconGrid = GObject.registerClass({
_childAdded(grid, child) {
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) {
child.disconnect(child._iconGridKeyFocusInId);
delete child._iconGridKeyFocusInId;
child.disconnect(child._opacityChangedId);
delete child._opacityChangedId;
delete child._paintVisible;
}
vfunc_get_preferred_width(_forHeight) {
@@ -282,8 +284,8 @@ var IconGrid = GObject.registerClass({
return [0, 0];
let nChildren = this.get_n_children();
let nColumns = this._colLimit
? Math.min(this._colLimit, nChildren)
let nColumns = this._colLimit ? Math.min(this._colLimit,
nChildren)
: nChildren;
let totalSpacing = Math.max(0, nColumns - 1) * this._getSpacing();
// Kind of a lie, but not really an issue right now. If
@@ -365,6 +367,7 @@ var IconGrid = GObject.registerClass({
let y = box.y1 + this.topPadding;
let columnIndex = 0;
let rowIndex = 0;
let nChanged = 0;
for (let i = 0; i < children.length; i++) {
let childBox = this._calculateChildBox(children[i], x, y, box);
@@ -374,7 +377,16 @@ var IconGrid = GObject.registerClass({
} else {
if (!animating)
children[i].opacity = 255;
// Figure out how much delay to apply
if (!childBox.equal(children[i].get_allocation_box()))
nChanged++;
children[i].save_easing_state();
children[i].set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD);
children[i].set_easing_delay(ICON_POSITION_DELAY * nChanged);
children[i].allocate(childBox, flags);
children[i].restore_easing_state();
}
columnIndex++;
@@ -402,7 +414,7 @@ var IconGrid = GObject.registerClass({
let allocationBox = this.get_allocation_box();
let paintBox = themeNode.get_paint_box(allocationBox);
let origin = new Graphene.Point3D();
let origin = new Clutter.Vertex();
origin.x = paintBox.x1 - allocationBox.x1;
origin.y = paintBox.y1 - allocationBox.y1;
origin.z = 0.0;
@@ -436,20 +448,21 @@ var IconGrid = GObject.registerClass({
* set of items to be animated.
*/
_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 => {
clone.source.reactive = true;
clone.source.opacity = 255;
clone.destroy();
});
this._clonesAnimating = [];
}
_animationDone() {
this._resetAnimationActors();
this.emit('animation-done');
}
@@ -458,7 +471,7 @@ var IconGrid = GObject.registerClass({
throw new GObject.NotImplementedError("Pulse animation only implements " +
"'in' animation direction");
this._resetAnimationActors();
this._cancelAnimation();
let actors = this._getChildrenToAnimate();
if (actors.length == 0) {
@@ -481,23 +494,21 @@ var IconGrid = GObject.registerClass({
let delay = index / actors.length * maxDelay;
let bounceUpTime = ANIMATION_TIME_IN / 4;
let isLastItem = index == actors.length - 1;
actor.ease({
Tweener.addTween(actor,
{ time: bounceUpTime,
transition: 'easeInOutQuad',
delay: delay,
scale_x: ANIMATION_BOUNCE_ICON_SCALE,
scale_y: ANIMATION_BOUNCE_ICON_SCALE,
duration: bounceUpTime,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay: delay,
onComplete: () => {
let duration = ANIMATION_TIME_IN - bounceUpTime;
actor.ease({
Tweener.addTween(actor,
{ time: ANIMATION_TIME_IN - bounceUpTime,
transition: 'easeInOutQuad',
scale_x: 1,
scale_y: 1,
duration,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
onComplete: () => {
if (isLastItem)
this._animationDone();
actor.reactive = true;
}
});
}
@@ -506,7 +517,7 @@ var IconGrid = GObject.registerClass({
}
animateSpring(animationDirection, sourceActor) {
this._resetAnimationActors();
this._cancelAnimation();
let actors = this._getChildrenToAnimate();
if (actors.length == 0) {
@@ -560,25 +571,21 @@ var IconGrid = GObject.registerClass({
let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM;
let [finalX, finalY] = actor._transformedPosition;
movementParams = {
movementParams = { time: ANIMATION_TIME_IN,
transition: 'easeInOutQuad',
delay: delay,
x: finalX,
y: finalY,
scale_x: 1,
scale_y: 1,
duration: ANIMATION_TIME_IN,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay
};
onComplete: () => {
if (isLastItem)
movementParams.onComplete = this._animationDone.bind(this);
fadeParams = {
opacity: 255,
duration: ANIMATION_FADE_IN_TIME_FOR_ITEM,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay
};
this._animationDone();
} };
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad',
delay: delay,
opacity: 255 };
} else {
let isLastItem = actor._distance == maxDist;
@@ -586,29 +593,26 @@ var IconGrid = GObject.registerClass({
actorClone.set_position(startX, startY);
let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM;
movementParams = {
movementParams = { time: ANIMATION_TIME_OUT,
transition: 'easeInOutQuad',
delay: delay,
x: adjustedSourcePositionX,
y: adjustedSourcePositionY,
scale_x: scaleX,
scale_y: scaleY,
duration: ANIMATION_TIME_OUT,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay
};
onComplete: () => {
if (isLastItem)
movementParams.onComplete = this._animationDone.bind(this);
fadeParams = {
opacity: 0,
duration: ANIMATION_FADE_IN_TIME_FOR_ITEM,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM
};
this._animationDone();
} };
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad',
delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM,
opacity: 0 };
}
actorClone.ease(movementParams);
actorClone.ease(fadeParams);
Tweener.addTween(actorClone, movementParams);
Tweener.addTween(actorClone, fadeParams);
}
}
@@ -717,13 +721,29 @@ var IconGrid = GObject.registerClass({
this._items.push(item);
if (index !== undefined)
this.insert_child_at_index(item, index);
this.insert_child_at_index(item.actor, index);
else
this.add_actor(item);
this.add_actor(item.actor);
}
moveItem(item, newPosition) {
if (!this.contains(item.actor)) {
log('Cannot move item not contained by the IconGrid');
return;
}
let children = this.get_children();
let visibleChildren = children.filter(c => c.is_visible());
let visibleChildAtPosition = visibleChildren[newPosition];
let realPosition = children.indexOf(visibleChildAtPosition);
this.set_child_at_index(item.actor, realPosition);
return realPosition;
}
removeItem(item) {
this.remove_child(item);
this.remove_child(item.actor);
}
getItemAtIndex(index) {
@@ -796,8 +816,7 @@ var IconGrid = GObject.registerClass({
let neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth;
let neededHeight = this.usedHeightForNRows(this._minRows) - availHeight;
let neededSpacePerItem = (neededWidth > neededHeight)
? Math.ceil(neededWidth / this._minColumns)
let neededSpacePerItem = (neededWidth > neededHeight) ? Math.ceil(neededWidth / this._minColumns)
: Math.ceil(neededHeight / this._minRows);
this._fixedHItemSize = Math.max(this._hItemSize - neededSpacePerItem, MIN_ICON_SIZE);
this._fixedVItemSize = Math.max(this._vItemSize - neededSpacePerItem, MIN_ICON_SIZE);
@@ -819,6 +838,223 @@ var IconGrid = GObject.registerClass({
}
return GLib.SOURCE_REMOVE;
}
// Drag n' Drop methods
nudgeItemsAtIndex(index, dragLocation) {
// No nudging when the cursor is in an empty area
if (dragLocation == DragLocation.EMPTY_AREA || dragLocation == DragLocation.ON_ICON)
return;
let children = this.get_children().filter(c => c.is_visible());
let nudgeIndex = index;
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
if (dragLocation != DragLocation.START_EDGE) {
let leftItem = children[nudgeIndex - 1];
let offset = rtl ? Math.floor(this._hItemSize * NUDGE_FACTOR) : Math.floor(-this._hItemSize * NUDGE_FACTOR);
this._animateNudge(leftItem, NUDGE_ANIMATION_TYPE, NUDGE_DURATION, offset);
}
// Nudge the icon to the right if we are the first item or not at the
// end of row
if (dragLocation != DragLocation.END_EDGE) {
let rightItem = children[nudgeIndex];
let offset = rtl ? Math.floor(-this._hItemSize * NUDGE_FACTOR) : Math.floor(this._hItemSize * NUDGE_FACTOR);
this._animateNudge(rightItem, NUDGE_ANIMATION_TYPE, NUDGE_DURATION, offset);
}
}
removeNudges() {
let children = this.get_children().filter(c => c.is_visible());
for (let index = 0; index < children.length; index++) {
this._animateNudge(children[index],
NUDGE_RETURN_ANIMATION_TYPE,
NUDGE_RETURN_DURATION,
0);
}
}
_animateNudge(item, animationType, duration, offset) {
if (!item)
return;
item.save_easing_state();
item.set_easing_mode(animationType);
item.set_easing_duration(duration);
item.translation_x = offset;
item.restore_easing_state();
}
// This function is overriden by the PaginatedIconGrid subclass so we can
// take into account the extra space when dragging from a folder
_calculateDndRow(y) {
let rowHeight = this._getVItemSize() + this._getSpacing();
return Math.floor(y / rowHeight);
}
// Returns the drop point index or -1 if we can't drop there
canDropAt(x, y) {
// This is an complex calculation, but in essence, we divide the grid
// as:
//
// left empty space
// | left padding right padding
// | | width without padding |
// +--------+---+---------------------------------------+-----+
// | | | | | | | |
// | | | | | | | |
// | | |--------+-----------+----------+-------| |
// | | | | | | | |
// | | | | | | | |
// | | |--------+-----------+----------+-------| |
// | | | | | | | |
// | | | | | | | |
// | | |--------+-----------+----------+-------| |
// | | | | | | | |
// | | | | | | | |
// +--------+---+---------------------------------------+-----+
//
// The left empty space is immediately discarded, and ignored in all
// calculations.
//
// The width (with paddings) is used to determine if we're dragging
// over the left or right padding, and which column is being dragged
// on.
//
// Finally, the width without padding is used to figure out where in
// the icon (start edge, end edge, on it, etc) the cursor is.
let [nColumns, usedWidth] = this._computeLayout(this.width);
let leftEmptySpace;
switch (this._xAlign) {
case St.Align.START:
leftEmptySpace = 0;
break;
case St.Align.MIDDLE:
leftEmptySpace = Math.floor((this.width - usedWidth) / 2);
break;
case St.Align.END:
leftEmptySpace = availWidth - usedWidth;
}
x -= leftEmptySpace;
y -= this.topPadding;
let row = this._calculateDndRow(y);
// Correct sx to handle the left padding to correctly calculate
// the column
let rtl = (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL);
let gridX = x - this.leftPadding;
let widthWithoutPadding = usedWidth - this.leftPadding - this.rightPadding;
let columnWidth = widthWithoutPadding / nColumns;
let column;
if (x < this.leftPadding)
column = 0;
else if (x > usedWidth - this.rightPadding)
column = nColumns - 1;
else
column = Math.floor(gridX / columnWidth);
let isFirstIcon = column == 0;
let isLastIcon = column == nColumns - 1;
// If we're outside of the grid, we are in an invalid drop location
if (x < 0 || x > usedWidth)
return [-1, DragLocation.DEFAULT];
let children = this.get_children().filter(c => c.is_visible());
let childIndex = Math.min((row * nColumns) + column, children.length);
// If we're above the grid vertically, we are in an invalid
// drop location
if (childIndex < 0)
return [-1, DragLocation.DEFAULT];
// If we're past the last visible element in the grid,
// we might be allowed to drop there.
if (childIndex >= children.length)
return [children.length, DragLocation.EMPTY_AREA];
let child = children[childIndex];
let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight] = child.get_preferred_size();
// This is the width of the cell that contains the icon
// (excluding spacing between cells)
let childIconWidth = Math.max(this._getHItemSize(), childNaturalWidth);
// Calculate the original position of the child icon (prior to nudging)
let childX;
if (rtl)
childX = widthWithoutPadding - (column * columnWidth) - childIconWidth;
else
childX = column * columnWidth;
let iconLeftX = childX + LEFT_DIVIDER_LEEWAY;
let iconRightX = childX + childIconWidth - RIGHT_DIVIDER_LEEWAY
let dropIndex;
let dragLocation;
x -= this.leftPadding;
if (x < iconLeftX) {
// We are to the left of the icon target
if (isFirstIcon || x < 0) {
// We are before the leftmost icon on the grid
if (rtl) {
dropIndex = childIndex + 1;
dragLocation = DragLocation.END_EDGE;
} else {
dropIndex = childIndex;
dragLocation = DragLocation.START_EDGE;
}
} else {
// We are between the previous icon (next in RTL) and this one
if (rtl)
dropIndex = childIndex + 1;
else
dropIndex = childIndex;
dragLocation = DragLocation.DEFAULT;
}
} else if (x >= iconRightX) {
// We are to the right of the icon target
if (childIndex >= children.length) {
// We are beyond the last valid icon
// (to the right of the app store / trash can, if present)
dropIndex = -1;
dragLocation = DragLocation.DEFAULT;
} else if (isLastIcon || x >= widthWithoutPadding) {
// We are beyond the rightmost icon on the grid
if (rtl) {
dropIndex = childIndex;
dragLocation = DragLocation.START_EDGE;
} else {
dropIndex = childIndex + 1;
dragLocation = DragLocation.END_EDGE;
}
} else {
// We are between this icon and the next one (previous in RTL)
if (rtl)
dropIndex = childIndex;
else
dropIndex = childIndex + 1;
dragLocation = DragLocation.DEFAULT;
}
} else {
// We are over the icon target area
dropIndex = childIndex;
dragLocation = DragLocation.ON_ICON;
}
return [dropIndex, dragLocation];
}
});
var PaginatedIconGrid = GObject.registerClass({
@@ -871,10 +1107,21 @@ var PaginatedIconGrid = GObject.registerClass({
let x = box.x1 + leftEmptySpace + this.leftPadding;
let y = box.y1 + this.topPadding;
let columnIndex = 0;
let nChanged = 0;
for (let i = 0; i < children.length; i++) {
let childBox = this._calculateChildBox(children[i], x, y, box);
// Figure out how much delay to apply
if (!childBox.equal(children[i].get_allocation_box()))
nChanged++;
children[i].save_easing_state();
children[i].set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD);
children[i].set_easing_delay(ICON_POSITION_DELAY * nChanged);
children[i].allocate(childBox, flags);
children[i].restore_easing_state();
children[i].show();
columnIndex++;
@@ -893,8 +1140,25 @@ var PaginatedIconGrid = GObject.registerClass({
}
// Overridden from IconGrid
_calculateDndRow(y) {
let row = super._calculateDndRow(y);
// If there's no extra space, just return the current value and maintain
// the same behavior when without a folder opened.
if (!this._extraSpaceData)
return row;
let [ baseRow, nRowsUp, nRowsDown ] = this._extraSpaceData;
let newRow = row + nRowsUp;
if (row > baseRow)
newRow -= nRowsDown;
return newRow;
}
_getChildrenToAnimate() {
let children = super._getChildrenToAnimate();
let children = this._getVisibleChildren();
let firstIndex = this._childrenPerPage * this.currentPage;
let lastIndex = firstIndex + this._childrenPerPage;
@@ -963,7 +1227,7 @@ var PaginatedIconGrid = GObject.registerClass({
*/
openExtraSpace(sourceItem, side, nRows) {
let children = this._getVisibleChildren();
let index = children.indexOf(sourceItem);
let index = children.indexOf(sourceItem.actor);
if (index == -1)
throw new Error('Item not found.');
@@ -973,7 +1237,8 @@ var PaginatedIconGrid = GObject.registerClass({
let childrenPerRow = this._childrenPerPage / this._rowsPerPage;
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 nRowsUp, nRowsDown;
@@ -1013,14 +1278,13 @@ var PaginatedIconGrid = GObject.registerClass({
for (let i = 0; i < children.length; i++) {
children[i].translation_y = 0;
let params = {
translation_y: translationY,
duration: EXTRA_SPACE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD
let params = { translation_y: translationY,
time: EXTRA_SPACE_ANIMATION_TIME,
transition: 'easeInOutQuad'
};
if (i == (children.length - 1))
params.onComplete = () => this.emit('space-opened');
children[i].ease(params);
Tweener.addTween(children[i], params);
}
}
@@ -1033,10 +1297,10 @@ var PaginatedIconGrid = GObject.registerClass({
for (let i = 0; i < this._translatedChildren.length; i++) {
if (!this._translatedChildren[i].translation_y)
continue;
this._translatedChildren[i].ease({
translation_y: 0,
duration: EXTRA_SPACE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
Tweener.addTween(this._translatedChildren[i],
{ translation_y: 0,
time: EXTRA_SPACE_ANIMATION_TIME,
transition: 'easeInOutQuad',
onComplete: () => this.emit('space-closed')
});
}

View File

@@ -76,8 +76,7 @@ var InhibitShortcutsDialog = GObject.registerClass({
let name = this._app ? this._app.get_name() : this._window.title;
/* Translators: %s is an application name like "Settings" */
let title = name
? _("%s wants to inhibit shortcuts").format(name)
let title = name ? _("%s wants to inhibit shortcuts").format(name)
: _("Application wants to inhibit shortcuts");
let icon = new Gio.ThemedIcon({ name: 'dialog-warning-symbolic' });

View File

@@ -27,23 +27,23 @@ class KbdA11yDialog extends GObject.Object {
if (whatChanged & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) {
key = KEY_SLOW_KEYS_ENABLED;
enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) > 0;
title = enabled
? _("Slow Keys Turned On")
: _("Slow Keys Turned Off");
enabled = (newFlags & Clutter.KeyboardA11yFlags.SLOW_KEYS_ENABLED) ? true : false;
title = enabled ?
_("Slow Keys Turned On") :
_("Slow Keys Turned Off");
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.");
} else if (whatChanged & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) {
key = KEY_STICKY_KEYS_ENABLED;
enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) > 0;
title = enabled
? _("Sticky Keys Turned On")
: _("Sticky Keys Turned Off");
body = enabled
? _("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.")
: _("You just pressed two keys at once, or pressed the Shift key 5 times in a row. " +
enabled = (newFlags & Clutter.KeyboardA11yFlags.STICKY_KEYS_ENABLED) ? true : false;
title = enabled ?
_("Sticky Keys Turned On") :
_("Sticky Keys Turned Off");
body = enabled ?
_("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.") :
_("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.");
} else {
return;

View File

@@ -1,5 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported KeyboardManager */
/* exported Keyboard */
const { Clutter, Gio, GLib, GObject, Meta, St } = imports.gi;
const Signals = imports.signals;
@@ -11,10 +11,11 @@ const Layout = imports.ui.layout;
const Main = imports.ui.main;
const PageIndicators = imports.ui.pageIndicators;
const PopupMenu = imports.ui.popupMenu;
const Tweener = imports.ui.tweener;
var KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2;
var KEYBOARD_REST_TIME = Layout.KEYBOARD_ANIMATION_TIME * 2 * 1000;
var KEY_LONG_PRESS_TIME = 250;
var PANEL_SWITCH_ANIMATION_TIME = 500;
var PANEL_SWITCH_ANIMATION_TIME = 0.5;
var PANEL_SWITCH_RELATIVE_DISTANCE = 1 / 3; /* A third of the actor width */
const A11Y_APPLICATIONS_SCHEMA = 'org.gnome.desktop.a11y.applications';
@@ -89,11 +90,8 @@ class KeyContainer extends St.Widget {
let gridLayout = new Clutter.GridLayout({ orientation: Clutter.Orientation.HORIZONTAL,
column_homogeneous: true,
row_homogeneous: true });
super._init({
layout_manager: gridLayout,
x_expand: true,
y_expand: true
});
super._init({ layout_manager: gridLayout,
x_expand: true, y_expand: true });
this._gridLayout = gridLayout;
this._currentRow = 0;
this._currentCol = 0;
@@ -107,10 +105,9 @@ class KeyContainer extends St.Widget {
this._currentRow++;
this._currentCol = 0;
let row = {
keys: [],
width: 0,
};
let row = new Object();
row.keys = [];
row.width = 0;
this._rows.push(row);
}
@@ -164,23 +161,24 @@ class KeyContainer extends St.Widget {
}
});
var Suggestions = GObject.registerClass(
class Suggestions extends St.BoxLayout {
_init() {
super._init({ style_class: 'word-suggestions', vertical: false });
this.show();
var Suggestions = class {
constructor() {
this.actor = new St.BoxLayout({ style_class: 'word-suggestions',
vertical: false });
this.actor.show();
}
add(word, callback) {
let button = new St.Button({ label: word });
button.connect('clicked', callback);
this.add(button);
this.actor.add(button);
}
clear() {
this.remove_all_children();
this.actor.remove_all_children();
}
});
};
Signals.addSignalMethods(Suggestions.prototype);
var LanguageSelectionPopup = class extends PopupMenu.PopupMenu {
constructor(actor) {
@@ -196,12 +194,12 @@ var LanguageSelectionPopup = class extends PopupMenu.PopupMenu {
item = this.addAction(is.displayName, () => {
inputSourceManager.activateInputSource(is, true);
});
item.can_focus = false;
item.actor.can_focus = false;
}
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
item = this.addSettingsAction(_("Region & Language Settings"), 'gnome-region-panel.desktop');
item.can_focus = false;
item.actor.can_focus = false;
this._capturedEventId = 0;
@@ -245,25 +243,17 @@ var LanguageSelectionPopup = class extends PopupMenu.PopupMenu {
}
};
var Key = GObject.registerClass({
Signals: {
'activated': {},
'long-press': {},
'pressed': { param_types: [GObject.TYPE_UINT, GObject.TYPE_STRING] },
'released': { param_types: [GObject.TYPE_UINT, GObject.TYPE_STRING] },
}
}, class Key extends St.BoxLayout {
_init(key, extendedKeys) {
super._init({ style_class: 'key-container' });
var Key = class Key {
constructor(key, extendedKeys) {
this.key = key || "";
this.keyButton = this._makeKey(this.key);
/* Add the key in a container, so keys can be padded without losing
* logical proportions between those.
*/
this.add(this.keyButton, { expand: true, x_fill: true });
this.connect('destroy', this._onDestroy.bind(this));
this.actor = new St.BoxLayout ({ style_class: 'key-container' });
this.actor.add(this.keyButton, { expand: true, x_fill: true });
this.actor.connect('destroy', this._onDestroy.bind(this));
this._extended_keys = extendedKeys;
this._extended_keyboard = null;
@@ -471,7 +461,8 @@ var Key = GObject.registerClass({
else
this.keyButton.remove_style_pseudo_class('latched');
}
});
};
Signals.addSignalMethods(Key.prototype);
var KeyboardModel = class {
constructor(groupName) {
@@ -579,26 +570,11 @@ var FocusTracker = class {
};
Signals.addSignalMethods(FocusTracker.prototype);
var EmojiPager = GObject.registerClass({
Properties: {
'delta': GObject.ParamSpec.int(
'delta', 'delta', 'delta',
GObject.ParamFlags.READWRITE,
GLib.MININT32, GLib.MAXINT32, 0)
},
Signals: {
'emoji': { param_types: [GObject.TYPE_STRING] },
'page-changed': {
param_types: [GObject.TYPE_INT, GObject.TYPE_INT, GObject.TYPE_INT]
}
}
}, class EmojiPager extends St.Widget {
_init(sections, nCols, nRows) {
super._init({
layout_manager: new Clutter.BinLayout(),
var EmojiPager = class EmojiPager {
constructor(sections, nCols, nRows) {
this.actor = new St.Widget({ layout_manager: new Clutter.BinLayout(),
reactive: true,
clip_to_allocation: true
});
clip_to_allocation: true });
this._sections = sections;
this._nCols = nCols;
this._nRows = nRows;
@@ -620,7 +596,7 @@ var EmojiPager = GObject.registerClass({
panAction.connect('gesture-cancel', this._onPanCancel.bind(this));
panAction.connect('gesture-end', this._onPanEnd.bind(this));
this._panAction = panAction;
this.add_action(panAction);
this.actor.add_action(panAction);
}
get delta() {
@@ -633,11 +609,7 @@ var EmojiPager = GObject.registerClass({
else if (value < -this._width)
value = -this._width;
if (this._delta == value)
return;
this._delta = value;
this.notify('delta');
if (value == 0)
return;
@@ -654,8 +626,8 @@ var EmojiPager = GObject.registerClass({
if (followingPage != null) {
this._followingPanel = this._generatePanel(followingPage);
this._followingPanel.set_pivot_point(0.5, 0.5);
this.add_child(this._followingPanel);
this.set_child_below_sibling(this._followingPanel, this._panel);
this.actor.add_child(this._followingPanel);
this.actor.set_child_below_sibling(this._followingPanel, this._panel);
}
this._followingPage = followingPage;
@@ -703,12 +675,12 @@ var EmojiPager = GObject.registerClass({
}
_onPanBegin() {
this._width = this.width;
this._width = this.actor.width;
return true;
}
_onPanEnd() {
if (Math.abs(this._delta) < this.width * PANEL_SWITCH_RELATIVE_DISTANCE) {
if (Math.abs(this._delta) < this.actor.width * PANEL_SWITCH_RELATIVE_DISTANCE) {
this._onPanCancel();
} else {
let value;
@@ -720,10 +692,12 @@ var EmojiPager = GObject.registerClass({
let relDelta = Math.abs(this._delta - value) / this._width;
let time = PANEL_SWITCH_ANIMATION_TIME * Math.abs(relDelta);
this.remove_all_transitions();
this.ease_property('delta', value, {
duration: time,
onComplete: () => {
Tweener.removeTweens(this);
Tweener.addTween(this,
{ delta: value,
time: time,
transition: 'easeInOutQuad',
onComplete() {
this.setCurrentPage(this.getFollowingPage());
}
});
@@ -731,12 +705,14 @@ var EmojiPager = GObject.registerClass({
}
_onPanCancel() {
let relDelta = Math.abs(this._delta) / this.width;
let relDelta = Math.abs(this._delta) / this.actor.width;
let time = PANEL_SWITCH_ANIMATION_TIME * Math.abs(relDelta);
this.remove_all_transitions();
this.ease_property('delta', 0, {
duration: time,
Tweener.removeTweens(this);
Tweener.addTween(this,
{ delta: 0,
time: time,
transition: 'easeInOutQuad',
});
}
@@ -809,7 +785,7 @@ var EmojiPager = GObject.registerClass({
this.emit('emoji', str);
});
gridLayout.attach(key, col, row, 1, 1);
gridLayout.attach(key.actor, col, row, 1, 1);
col++;
if (col >= this._nCols) {
@@ -847,11 +823,11 @@ var EmojiPager = GObject.registerClass({
if (!this._panel) {
this._panel = this._generatePanel(nPage);
this.add_child(this._panel);
this.actor.add_child(this._panel);
}
let page = this._pages[nPage];
this.emit('page-changed', page.section.label, page.page, page.nPages);
this.emit('page-changed', page.section, page.page, page.nPages);
}
setCurrentSection(section, nPage) {
@@ -864,23 +840,11 @@ var EmojiPager = GObject.registerClass({
}
}
}
});
var EmojiSelection = GObject.registerClass({
Signals: {
'emoji-selected': { param_types: [GObject.TYPE_STRING] },
'close-request': {},
'toggle': {},
}
}, class EmojiSelection extends St.BoxLayout {
_init() {
super._init({
style_class: 'emoji-panel',
x_expand: true,
y_expand: true,
vertical: true
});
};
Signals.addSignalMethods(EmojiPager.prototype);
var EmojiSelection = class EmojiSelection {
constructor() {
this._sections = [
{ first: 'grinning face', label: '🙂️' },
{ first: 'selfie', label: '👍️' },
@@ -895,44 +859,38 @@ var EmojiSelection = GObject.registerClass({
this._populateSections();
this.actor = new St.BoxLayout({ style_class: 'emoji-panel',
x_expand: true,
y_expand: true,
vertical: true });
this.actor.connect('notify::mapped', () => this._emojiPager.setCurrentPage(0));
this._emojiPager = new EmojiPager(this._sections, 11, 3);
this._emojiPager.connect('page-changed', (pager, sectionLabel, page, nPages) => {
this._onPageChanged(sectionLabel, page, nPages);
this._emojiPager.connect('page-changed', (pager, section, page, nPages) => {
this._onPageChanged(section, page, nPages);
});
this._emojiPager.connect('emoji', (pager, str) => {
this.emit('emoji-selected', str);
});
this.add(this._emojiPager, { expand: true });
this.actor.add(this._emojiPager.actor, { expand: true });
this._pageIndicator = new PageIndicators.PageIndicators(
Clutter.Orientation.HORIZONTAL
);
this.add(this._pageIndicator, { expand: true, x_fill: false, y_fill: false });
this._pageIndicator = new PageIndicators.PageIndicators(false);
this.actor.add(this._pageIndicator, { expand: true, x_fill: false, y_fill: false });
this._pageIndicator.setReactive(false);
let bottomRow = this._createBottomRow();
this.add(bottomRow, { expand: true, x_fill: false, y_fill: false });
this.actor.add(bottomRow, { expand: true, x_fill: false, y_fill: false });
this._emojiPager.setCurrentPage(0);
}
vfunc_map() {
this._emojiPager.setCurrentPage(0);
super.vfunc_map();
}
vfunc_unmap() {
super.vfunc_unmap();
this._emojiPager.setCurrentPage(0);
}
_onPageChanged(sectionLabel, page, nPages) {
_onPageChanged(section, page, nPages) {
this._pageIndicator.setNPages(nPages);
this._pageIndicator.setCurrentPage(page);
for (let i = 0; i < this._sections.length; i++) {
let sect = this._sections[i];
sect.button.setLatched(sectionLabel == sect.label);
sect.button.setLatched(section == sect);
}
}
@@ -988,14 +946,14 @@ var EmojiSelection = GObject.registerClass({
key = new Key('ABC', []);
key.keyButton.add_style_class_name('default-key');
key.connect('released', () => this.emit('toggle'));
row.appendKey(key, 1.5);
row.appendKey(key.actor, 1.5);
for (let i = 0; i < this._sections.length; i++) {
let section = this._sections[i];
key = new Key(section.label, []);
key.connect('released', () => this._emojiPager.setCurrentSection(section, 0));
row.appendKey(key);
row.appendKey(key.actor);
section.button = key;
}
@@ -1004,9 +962,9 @@ var EmojiSelection = GObject.registerClass({
key.keyButton.add_style_class_name('default-key');
key.keyButton.add_style_class_name('hide-key');
key.connect('released', () => {
this.emit('close-request');
this.emit('hide');
});
row.appendKey(key);
row.appendKey(key.actor);
row.layoutButtons();
let actor = new AspectContainer({ layout_manager: new Clutter.BinLayout(),
@@ -1020,14 +978,11 @@ var EmojiSelection = GObject.registerClass({
return actor;
}
});
};
Signals.addSignalMethods(EmojiSelection.prototype);
var Keypad = GObject.registerClass({
Signals: {
'keyval': { param_types: [GObject.TYPE_UINT] },
}
}, class Keypad extends AspectContainer {
_init() {
var Keypad = class Keypad {
constructor() {
let keys = [
{ label: '1', keyval: Clutter.KEY_1, left: 0, top: 0 },
{ label: '2', keyval: Clutter.KEY_2, left: 1, top: 0 },
@@ -1043,17 +998,14 @@ var Keypad = GObject.registerClass({
{ keyval: Clutter.KEY_Return, extraClassName: 'enter-key', left: 3, top: 1, height: 2 },
];
super._init({
layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true
});
this.actor = new AspectContainer({ layout_manager: new Clutter.BinLayout(),
x_expand: true, y_expand: true });
let gridLayout = new Clutter.GridLayout({ orientation: Clutter.Orientation.HORIZONTAL,
column_homogeneous: true,
row_homogeneous: true });
this._box = new St.Widget({ layout_manager: gridLayout, x_expand: true, y_expand: true });
this.add_child(this._box);
this.actor.add_child(this._box);
for (let i = 0; i < keys.length; i++) {
let cur = keys[i];
@@ -1065,32 +1017,86 @@ var Keypad = GObject.registerClass({
let w, h;
w = cur.width || 1;
h = cur.height || 1;
gridLayout.attach(key, cur.left, cur.top, w, h);
gridLayout.attach(key.actor, cur.left, cur.top, w, h);
key.connect('released', () => {
this.emit('keyval', cur.keyval);
});
}
}
});
};
Signals.addSignalMethods(Keypad.prototype);
var KeyboardManager = class KeyBoardManager {
var Keyboard = class Keyboard {
constructor() {
this._keyboard = null;
this.actor = null;
this._focusInExtendedKeys = false;
this._emojiActive = false;
this._languagePopup = null;
this._currentFocusWindow = null;
this._animFocusedWindow = null;
this._delayedAnimFocusWindow = null;
this._enableKeyboard = false; // a11y settings value
this._enabled = false; // enabled state (by setting or device type)
this._latched = false; // current level is latched
this._a11yApplicationsSettings = new Gio.Settings({ schema_id: A11Y_APPLICATIONS_SCHEMA });
this._a11yApplicationsSettings.connect('changed', this._syncEnabled.bind(this));
this._lastDeviceId = null;
Meta.get_backend().connect('last-device-changed', (backend, deviceId) => {
this._suggestions = null;
this._emojiKeyVisible = Meta.is_wayland_compositor();
this._focusTracker = new FocusTracker();
this._focusTracker.connect('position-changed', this._onFocusPositionChanged.bind(this));
this._focusTracker.connect('reset', () => {
this._delayedAnimFocusWindow = null;
this._animFocusedWindow = null;
this._oskFocusWindow = null;
});
this._focusTracker.connect('focus-changed', (tracker, focused) => {
// Valid only for X11
if (Meta.is_wayland_compositor())
return;
if (focused)
this.show(Main.layoutManager.focusIndex);
else
this.hide();
});
Meta.get_backend().connect('last-device-changed',
(backend, deviceId) => {
let manager = Clutter.DeviceManager.get_default();
let device = manager.get_device(deviceId);
if (device.get_device_name().indexOf('XTEST') < 0) {
if (!device.get_device_name().includes('XTEST')) {
this._lastDeviceId = deviceId;
this._syncEnabled();
}
});
this._syncEnabled();
this._showIdleId = 0;
this._keyboardVisible = false;
Main.layoutManager.connect('keyboard-visible-changed', (o, visible) => {
this._keyboardVisible = visible;
});
this._keyboardRequested = false;
this._keyboardRestingId = 0;
Main.layoutManager.connect('monitors-changed', this._relayout.bind(this));
}
get visible() {
return this._keyboardVisible;
}
_onFocusPositionChanged(focusTracker) {
let rect = focusTracker.getCurrentRect();
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
}
_lastDeviceIsTouchscreen() {
@@ -1107,143 +1113,38 @@ var KeyboardManager = class KeyBoardManager {
}
_syncEnabled() {
let enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
let enabled = enableKeyboard || this._lastDeviceIsTouchscreen();
if (!enabled && !this._keyboard)
let wasEnabled = this._enabled;
this._enableKeyboard = this._a11yApplicationsSettings.get_boolean(SHOW_KEYBOARD);
this._enabled = this._enableKeyboard || this._lastDeviceIsTouchscreen();
if (!this._enabled && !this._keyboardController)
return;
if (enabled && !this._keyboard) {
this._keyboard = new Keyboard();
} else if (!enabled && this._keyboard) {
this._keyboard.setCursorLocation(null);
Main.layoutManager.hideKeyboard(true);
this._keyboard.destroy();
this._keyboard = null;
}
}
get keyboardActor() {
return this._keyboard;
}
get visible() {
return this._keyboard && this._keyboard.visible;
}
open(monitor) {
if (this._keyboard)
this._keyboard.open(monitor);
}
close() {
if (this._keyboard)
this._keyboard.close();
}
addSuggestion(text, callback) {
if (this._keyboard)
this._keyboard.addSuggestion(text, callback);
}
resetSuggestions() {
if (this._keyboard)
this._keyboard.resetSuggestions();
}
shouldTakeEvent(event) {
if (!this._keyboard)
return false;
let actor = event.get_source();
return Main.layoutManager.keyboardBox.contains(actor) ||
!!actor._extended_keys || !!actor.extended_key;
}
};
var Keyboard = GObject.registerClass(
class Keyboard extends St.BoxLayout {
_init() {
super._init({ name: 'keyboard', vertical: true });
this._focusInExtendedKeys = false;
this._emojiActive = false;
this._languagePopup = null;
this._currentFocusWindow = null;
this._animFocusedWindow = null;
this._delayedAnimFocusWindow = null;
this._latched = false; // current level is latched
this._suggestions = null;
this._emojiKeyVisible = Meta.is_wayland_compositor();
this._focusTracker = new FocusTracker();
this._connectSignal(this._focusTracker, 'position-changed',
this._onFocusPositionChanged.bind(this));
this._connectSignal(this._focusTracker, 'reset', () => {
this._delayedAnimFocusWindow = null;
this._animFocusedWindow = null;
this._oskFocusWindow = null;
});
// Valid only for X11
if (!Meta.is_wayland_compositor()) {
this._connectSignal(this._focusTracker, 'focus-changed', (_tracker, focused) => {
if (focused)
this.open(Main.layoutManager.focusIndex);
else
this.close();
});
}
this._showIdleId = 0;
this._keyboardVisible = false;
this._connectSignal(Main.layoutManager, 'keyboard-visible-changed', (_lm, visible) => {
this._keyboardVisible = visible;
});
this._keyboardRequested = false;
this._keyboardRestingId = 0;
this._connectSignal(Main.layoutManager, 'monitors-changed', this._relayout.bind(this));
if (this._enabled && !this._keyboardController)
this._setupKeyboard();
else if (!this._enabled)
this.setCursorLocation(null);
this.connect('destroy', this._onDestroy.bind(this));
if (!this._enabled && wasEnabled)
Main.layoutManager.hideKeyboard(true);
}
_connectSignal(obj, signal, callback) {
if (!this._connectionsIDs)
this._connectionsIDs = [];
let id = obj.connect(signal, callback);
this._connectionsIDs.push([obj, id]);
return id;
}
get visible() {
return this._keyboardVisible && super.visible;
}
_onFocusPositionChanged(focusTracker) {
let rect = focusTracker.getCurrentRect();
this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
}
_onDestroy() {
for (let [obj, id] of this._connectionsIDs)
obj.disconnect(id);
delete this._connectionsIDs;
_destroyKeyboard() {
if (this._keyboardNotifyId)
this._keyboardController.disconnect(this._keyboardNotifyId);
if (this._keyboardGroupsChangedId)
this._keyboardController.disconnect(this._keyboardGroupsChangedId);
if (this._keyboardStateId)
this._keyboardController.disconnect(this._keyboardStateId);
if (this._emojiKeyVisibleId)
this._keyboardController.disconnect(this._emojiKeyVisibleId);
if (this._keypadVisibleId)
this._keyboardController.disconnect(this._keypadVisibleId);
if (this._focusNotifyId)
global.stage.disconnect(this._focusNotifyId);
this._clearShowIdle();
this._keyboardController = null;
this._suggestions = null;
this._aspectContainer = null;
this._emojiSelection = null;
this._keypad = null;
Main.layoutManager.untrackChrome(this);
Main.layoutManager.keyboardBox.remove_actor(this);
this._keyboard = null;
this.actor.destroy();
this.actor = null;
if (this._languagePopup) {
this._languagePopup.destroy();
@@ -1252,8 +1153,9 @@ class Keyboard extends St.BoxLayout {
}
_setupKeyboard() {
Main.layoutManager.keyboardBox.add_actor(this);
Main.layoutManager.trackChrome(this);
this.actor = new St.BoxLayout({ name: 'keyboard', vertical: true, reactive: true });
Main.layoutManager.keyboardBox.add_actor(this.actor);
Main.layoutManager.trackChrome(this.actor);
this._keyboardController = new KeyboardController();
@@ -1261,28 +1163,30 @@ class Keyboard extends St.BoxLayout {
this._currentPage = null;
this._suggestions = new Suggestions();
this.add(this._suggestions, { x_align: St.Align.MIDDLE, x_fill: false });
this.actor.add(this._suggestions.actor,
{ x_align: St.Align.MIDDLE,
x_fill: false });
this._aspectContainer = new AspectContainer({ layout_manager: new Clutter.BinLayout() });
this.add(this._aspectContainer, { expand: true });
this.actor.add(this._aspectContainer, { expand: true });
this._emojiSelection = new EmojiSelection();
this._emojiSelection.connect('toggle', this._toggleEmoji.bind(this));
this._emojiSelection.connect('close-request', () => this.close());
this._emojiSelection.connect('hide', () => this.hide());
this._emojiSelection.connect('emoji-selected', (selection, emoji) => {
this._keyboardController.commitString(emoji);
});
this._aspectContainer.add_child(this._emojiSelection);
this._emojiSelection.hide();
this._aspectContainer.add_child(this._emojiSelection.actor);
this._emojiSelection.actor.hide();
this._keypad = new Keypad();
this._connectSignal(this._keypad, 'keyval', (_keypad, keyval) => {
this._keypad.connect('keyval', (keypad, keyval) => {
this._keyboardController.keyvalPress(keyval);
this._keyboardController.keyvalRelease(keyval);
});
this._aspectContainer.add_child(this._keypad);
this._keypad.hide();
this._aspectContainer.add_child(this._keypad.actor);
this._keypad.actor.hide();
this._keypadVisible = false;
this._ensureKeysForGroup(this._keyboardController.getCurrentGroup());
@@ -1291,22 +1195,16 @@ class Keyboard extends St.BoxLayout {
// Keyboard models are defined in LTR, we must override
// the locale setting in order to avoid flipping the
// keyboard on RTL locales.
this.text_direction = Clutter.TextDirection.LTR;
this.actor.text_direction = Clutter.TextDirection.LTR;
this._connectSignal(this._keyboardController, 'active-group',
this._onGroupChanged.bind(this));
this._connectSignal(this._keyboardController, 'groups-changed',
this._onKeyboardGroupsChanged.bind(this));
this._connectSignal(this._keyboardController, 'panel-state',
this._onKeyboardStateChanged.bind(this));
this._connectSignal(this._keyboardController, 'keypad-visible',
this._onKeypadVisible.bind(this));
this._connectSignal(global.stage, 'notify::key-focus',
this._onKeyFocusChanged.bind(this));
this._keyboardNotifyId = this._keyboardController.connect('active-group', this._onGroupChanged.bind(this));
this._keyboardGroupsChangedId = this._keyboardController.connect('groups-changed', this._onKeyboardGroupsChanged.bind(this));
this._keyboardStateId = this._keyboardController.connect('panel-state', this._onKeyboardStateChanged.bind(this));
this._keypadVisibleId = this._keyboardController.connect('keypad-visible', this._onKeypadVisible.bind(this));
this._focusNotifyId = global.stage.connect('notify::key-focus', this._onKeyFocusChanged.bind(this));
if (Meta.is_wayland_compositor())
this._connectSignal(this._keyboardController, 'emoji-visible',
this._onEmojiKeyVisible.bind(this));
this._emojiKeyVisibleId = this._keyboardController.connect('emoji-visible', this._onEmojiKeyVisible.bind(this));
this._relayout();
}
@@ -1322,17 +1220,17 @@ class Keyboard extends St.BoxLayout {
return;
if (!(focus instanceof Clutter.Text)) {
this.close();
this.hide();
return;
}
if (!this._showIdleId) {
this._showIdleId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this.open(Main.layoutManager.focusIndex);
this.show(Main.layoutManager.focusIndex);
this._showIdleId = 0;
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._showIdleId, '[gnome-shell] this.open');
GLib.Source.set_name_by_id(this._showIdleId, '[gnome-shell] this.show');
}
}
@@ -1396,7 +1294,7 @@ class Keyboard extends St.BoxLayout {
this._setActiveLayer(0);
});
layout.appendKey(button, button.keyButton.keyWidth);
layout.appendKey(button.actor, button.keyButton.keyWidth);
}
}
@@ -1444,7 +1342,7 @@ class Keyboard extends St.BoxLayout {
if (keyval != null)
this._keyboardController.keyvalRelease(keyval);
else if (action == 'hide')
this.close();
this.hide();
else if (action == 'languageMenu')
this._popupLanguageMenu(actor);
else if (action == 'emoji')
@@ -1467,7 +1365,7 @@ class Keyboard extends St.BoxLayout {
/* Only hide the key actor, so the container still takes space */
extraButton.keyButton.hide();
} else {
extraButton.hide();
extraButton.actor.hide();
}
extraButton.setWidth(1.5);
} else if (key.right && numKeys > 8) {
@@ -1478,7 +1376,7 @@ class Keyboard extends St.BoxLayout {
extraButton.setWidth(1.5);
}
layout.appendKey(extraButton, extraButton.keyButton.keyWidth);
layout.appendKey(extraButton.actor, extraButton.keyButton.keyWidth);
}
}
@@ -1489,7 +1387,7 @@ class Keyboard extends St.BoxLayout {
_setEmojiActive(active) {
this._emojiActive = active;
this._emojiSelection.visible = this._emojiActive;
this._emojiSelection.actor.visible = this._emojiActive;
this._updateCurrentPageVisible();
}
@@ -1557,12 +1455,12 @@ class Keyboard extends St.BoxLayout {
_relayout() {
let monitor = Main.layoutManager.keyboardMonitor;
if (!monitor)
if (this.actor == null || monitor == null)
return;
let maxHeight = monitor.height / 3;
this.width = monitor.width;
this.height = maxHeight;
this.actor.width = monitor.width;
this.actor.height = maxHeight;
}
_onGroupChanged() {
@@ -1571,7 +1469,7 @@ class Keyboard extends St.BoxLayout {
}
_onKeyboardGroupsChanged() {
let nonGroupActors = [this._emojiSelection, this._keypad];
let nonGroupActors = [this._emojiSelection.actor, this._keypad.actor];
this._aspectContainer.get_children().filter(c => !nonGroupActors.includes(c)).forEach(c => {
c.destroy();
});
@@ -1585,7 +1483,7 @@ class Keyboard extends St.BoxLayout {
return;
this._keypadVisible = visible;
this._keypad.visible = this._keypadVisible;
this._keypad.actor.visible = this._keypadVisible;
this._updateCurrentPageVisible();
}
@@ -1610,9 +1508,9 @@ class Keyboard extends St.BoxLayout {
return;
if (enabled)
this.open(Main.layoutManager.focusIndex);
this.show(Main.layoutManager.focusIndex);
else
this.close();
this.hide();
}
_setActiveLayer(activeLevel) {
@@ -1639,6 +1537,12 @@ class Keyboard extends St.BoxLayout {
this._updateCurrentPageVisible();
}
shouldTakeEvent(event) {
let actor = event.get_source();
return Main.layoutManager.keyboardBox.contains(actor) ||
!!actor._extended_keys || !!actor.extended_key;
}
_clearKeyboardRestTimer() {
if (!this._keyboardRestingId)
return;
@@ -1646,7 +1550,10 @@ class Keyboard extends St.BoxLayout {
this._keyboardRestingId = 0;
}
open(monitor) {
show(monitor) {
if (!this._enabled)
return;
this._clearShowIdle();
this._keyboardRequested = true;
@@ -1663,13 +1570,13 @@ class Keyboard extends St.BoxLayout {
KEYBOARD_REST_TIME,
() => {
this._clearKeyboardRestTimer();
this._open(monitor);
this._show(monitor);
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._keyboardRestingId, '[gnome-shell] this._clearKeyboardRestTimer');
}
_open(monitor) {
_show(monitor) {
if (!this._keyboardRequested)
return;
@@ -1685,7 +1592,10 @@ class Keyboard extends St.BoxLayout {
}
}
close() {
hide() {
if (!this._enabled)
return;
this._clearShowIdle();
this._keyboardRequested = false;
@@ -1697,13 +1607,13 @@ class Keyboard extends St.BoxLayout {
KEYBOARD_REST_TIME,
() => {
this._clearKeyboardRestTimer();
this._close();
this._hide();
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._keyboardRestingId, '[gnome-shell] this._clearKeyboardRestTimer');
}
_close() {
_hide() {
if (this._keyboardRequested)
return;
@@ -1720,7 +1630,7 @@ class Keyboard extends St.BoxLayout {
if (!this._suggestions)
return;
this._suggestions.add(text, callback);
this._suggestions.show();
this._suggestions.actor.show();
}
_clearShowIdle() {
@@ -1744,23 +1654,19 @@ class Keyboard extends St.BoxLayout {
return;
if (show) {
windowActor.ease({
y: windowActor.y - deltaY,
duration: Layout.KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._windowSlideAnimationComplete(window, -deltaY);
}
});
Tweener.addTween(windowActor,
{ y: windowActor.y - deltaY,
time: Layout.KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._windowSlideAnimationComplete,
onCompleteParams: [window, -deltaY] });
} else {
windowActor.ease({
y: windowActor.y + deltaY,
duration: Layout.KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
onComplete: () => {
this._windowSlideAnimationComplete(window, deltaY);
}
});
Tweener.addTween(windowActor,
{ y: windowActor.y + deltaY,
time: Layout.KEYBOARD_ANIMATION_TIME,
transition: 'easeInQuad',
onComplete: this._windowSlideAnimationComplete,
onCompleteParams: [window, deltaY] });
}
}
@@ -1797,7 +1703,7 @@ class Keyboard extends St.BoxLayout {
this._oskFocusWindow = window;
}
});
};
var KeyboardController = class {
constructor() {

View File

@@ -11,11 +11,12 @@ const LoginManager = imports.misc.loginManager;
const DND = imports.ui.dnd;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Ripples = imports.ui.ripples;
var STARTUP_ANIMATION_TIME = 500;
var KEYBOARD_ANIMATION_TIME = 150;
var BACKGROUND_FADE_ANIMATION_TIME = 1000;
var STARTUP_ANIMATION_TIME = 0.5;
var KEYBOARD_ANIMATION_TIME = 0.15;
var BACKGROUND_FADE_ANIMATION_TIME = 1.0;
var HOT_CORNER_PRESSURE_THRESHOLD = 100; // pixels
var HOT_CORNER_PRESSURE_TIMEOUT = 1000; // ms
@@ -238,8 +239,7 @@ var LayoutManager = GObject.registerClass({
reactive: true });
this.addChrome(this.overviewGroup);
this.screenShieldGroup = new St.Widget({
name: 'screenShieldGroup',
this.screenShieldGroup = new St.Widget({ name: 'screenShieldGroup',
visible: false,
clip_to_allocation: true,
layout_manager: new Clutter.BinLayout(),
@@ -464,11 +464,10 @@ var LayoutManager = GObject.registerClass({
let backgroundActor = this._bgManagers[i].backgroundActor;
backgroundActor.show();
backgroundActor.opacity = 0;
backgroundActor.ease({
opacity: 255,
duration: BACKGROUND_FADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
Tweener.addTween(backgroundActor,
{ opacity: 255,
time: BACKGROUND_FADE_ANIMATION_TIME,
transition: 'easeOutQuad' });
}
}
}
@@ -606,17 +605,17 @@ var LayoutManager = GObject.registerClass({
return;
}
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,
coordinate: Clutter.BindCoordinate.ALL });
this._systemBackground.add_constraint(constraint);
this._systemBackground.actor.add_constraint(constraint);
let signalId = this._systemBackground.connect('loaded', () => {
this._systemBackground.disconnect(signalId);
this._systemBackground.show();
this._systemBackground.actor.show();
global.stage.show();
this._prepareStartupAnimation();
@@ -699,30 +698,30 @@ var LayoutManager = GObject.registerClass({
}
_startupAnimationGreeter() {
this.panelBox.ease({
translation_y: 0,
duration: STARTUP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._startupAnimationComplete()
});
Tweener.addTween(this.panelBox,
{ translation_y: 0,
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
onCompleteScope: this });
}
_startupAnimationSession() {
this.uiGroup.ease({
scale_x: 1,
Tweener.addTween(this.uiGroup,
{ scale_x: 1,
scale_y: 1,
opacity: 255,
duration: STARTUP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._startupAnimationComplete()
});
time: STARTUP_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._startupAnimationComplete,
onCompleteScope: this });
}
_startupAnimationComplete() {
this._coverPane.destroy();
this._coverPane = null;
this._systemBackground.destroy();
this._systemBackground.actor.destroy();
this._systemBackground = null;
this._startingUp = false;
@@ -741,14 +740,13 @@ var LayoutManager = GObject.registerClass({
showKeyboard() {
this.keyboardBox.show();
this.keyboardBox.ease({
anchor_y: this.keyboardBox.height,
Tweener.addTween(this.keyboardBox,
{ anchor_y: this.keyboardBox.height,
opacity: 255,
duration: KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._showKeyboardComplete();
}
time: KEYBOARD_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: this._showKeyboardComplete,
onCompleteScope: this
});
this.emit('keyboard-visible-changed', true);
}
@@ -768,14 +766,13 @@ var LayoutManager = GObject.registerClass({
this.keyboardBox.disconnect(this._keyboardHeightNotifyId);
this._keyboardHeightNotifyId = 0;
}
this.keyboardBox.ease({
anchor_y: 0,
Tweener.addTween(this.keyboardBox,
{ anchor_y: 0,
opacity: 0,
duration: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
onComplete: () => {
this._hideKeyboardComplete();
}
time: immediate ? 0 : KEYBOARD_ANIMATION_TIME,
transition: 'easeInQuad',
onComplete: this._hideKeyboardComplete,
onCompleteScope: this
});
this.emit('keyboard-visible-changed', false);
@@ -855,13 +852,12 @@ var LayoutManager = GObject.registerClass({
index = this._findActor(ancestor);
}
let ancestorData = ancestor
? this._trackedActors[index]
let ancestorData = ancestor ? this._trackedActors[index]
: defaultParams;
// We can't use Params.parse here because we want to drop
// the extra values like ancestorData.actor
for (let prop in defaultParams) {
if (!Object.prototype.hasOwnProperty.call(params, prop))
if (!params.hasOwnProperty(prop))
params[prop] = ancestorData[prop];
}
@@ -1015,6 +1011,11 @@ var LayoutManager = GObject.registerClass({
if (Main.modalCount > 0)
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 isPopupMenuVisible = global.top_window_group.get_children().some(isPopupMetaWindow);
let wantsInputRegion = !isPopupMenuVisible;
@@ -1070,17 +1071,16 @@ var LayoutManager = GObject.registerClass({
side = Meta.Side.RIGHT;
else
continue;
} else if (x1 <= monitor.x) {
} else if (x1 <= monitor.x)
side = Meta.Side.LEFT;
} else if (y1 <= monitor.y) {
else if (y1 <= monitor.y)
side = Meta.Side.TOP;
} else if (x2 >= monitor.x + monitor.width) {
else if (x2 >= monitor.x + monitor.width)
side = Meta.Side.RIGHT;
} else if (y2 >= monitor.y + monitor.height) {
else if (y2 >= monitor.y + monitor.height)
side = Meta.Side.BOTTOM;
} else {
else
continue;
}
let strutRect = new Meta.Rectangle({ x: x1, y: y1, width: x2 - x1, height: y2 - y1 });
let strut = new Meta.Strut({ rect: strutRect, side: side });
@@ -1112,11 +1112,8 @@ var LayoutManager = GObject.registerClass({
//
// This class manages a "hot corner" that can toggle switching to
// overview.
var HotCorner = GObject.registerClass(
class HotCorner extends Clutter.Actor {
_init(layoutManager, monitor, x, y) {
super._init();
var HotCorner = class HotCorner {
constructor(layoutManager, monitor, x, y) {
// 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
// guard area (the "environs"). This avoids triggering the hot corner
@@ -1145,8 +1142,6 @@ class HotCorner extends Clutter.Actor {
this._ripples = new Ripples.Ripples(px, py, 'ripple-box');
this._ripples.addTo(layoutManager.uiGroup);
this.connect('destroy', this._onDestroy.bind(this));
}
setBarrierSize(size) {
@@ -1186,14 +1181,11 @@ class HotCorner extends Clutter.Actor {
_setupFallbackCornerIfNeeded(layoutManager) {
if (!global.display.supports_extended_barriers()) {
this.set({
name: 'hot-corner-environs',
x: this._x,
y: this._y,
this.actor = new Clutter.Actor({ name: 'hot-corner-environs',
x: this._x, y: this._y,
width: 3,
height: 3,
reactive: true
});
reactive: true });
this._corner = new Clutter.Actor({ name: 'hot-corner',
width: 1,
@@ -1202,16 +1194,19 @@ class HotCorner extends Clutter.Actor {
reactive: true });
this._corner._delegate = this;
this.add_child(this._corner);
layoutManager.addChrome(this);
this.actor.add_child(this._corner);
layoutManager.addChrome(this.actor);
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) {
this._corner.set_position(this.width - this._corner.width, 0);
this.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
this._corner.set_position(this.actor.width - this._corner.width, 0);
this.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
} else {
this._corner.set_position(0, 0);
}
this.actor.connect('leave-event',
this._onEnvironsLeft.bind(this));
this._corner.connect('enter-event',
this._onCornerEntered.bind(this));
this._corner.connect('leave-event',
@@ -1219,12 +1214,13 @@ class HotCorner extends Clutter.Actor {
}
}
_onDestroy() {
destroy() {
this.setBarrierSize(0);
this._pressureBarrier.destroy();
this._pressureBarrier = null;
this._ripples.destroy();
if (this.actor)
this.actor.destroy();
}
_toggleOverview() {
@@ -1255,18 +1251,18 @@ class HotCorner extends Clutter.Actor {
}
_onCornerLeft(actor, event) {
if (event.get_related() != this)
if (event.get_related() != this.actor)
this._entered = false;
// Consume event, otherwise this will confuse onEnvironsLeft
return Clutter.EVENT_STOP;
}
vfunc_leave_event(crossingEvent) {
if (crossingEvent.related != this._corner)
_onEnvironsLeft(actor, event) {
if (event.get_related() != this._corner)
this._entered = false;
return Clutter.EVENT_PROPAGATE;
}
});
};
var PressureBarrier = class PressureBarrier {
constructor(threshold, timeout, actionMode) {

View File

@@ -2,8 +2,10 @@
/* exported Lightbox */
const { Clutter, GObject, Shell, St } = imports.gi;
const Signals = imports.signals;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
var DEFAULT_FADE_FACTOR = 0.4;
var VIGNETTE_BRIGHTNESS = 0.2;
@@ -22,31 +24,16 @@ t = clamp(t, 0.0, 1.0);\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);';
var RadialShaderEffect = GObject.registerClass({
Properties: {
'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 {
var RadialShaderEffect = GObject.registerClass(
class RadialShaderEffect extends Shell.GLSLEffect {
_init(params) {
this._brightness = undefined;
this._sharpness = undefined;
super._init(params);
this._brightnessLocation = this.get_uniform_location('brightness');
this._sharpnessLocation = this.get_uniform_location('vignette_sharpness');
this.brightness = 1.0;
this.sharpness = 0.0;
this.vignetteSharpness = 0.0;
}
vfunc_build_pipeline() {
@@ -59,25 +46,19 @@ var RadialShaderEffect = GObject.registerClass({
}
set brightness(v) {
if (this._brightness == v)
return;
this._brightness = v;
this.set_uniform_float(this._brightnessLocation,
1, [this._brightness]);
this.notify('brightness');
}
get sharpness() {
get vignetteSharpness() {
return this._sharpness;
}
set sharpness(v) {
if (this._sharpness == v)
return;
set vignetteSharpness(v) {
this._sharpness = v;
this.set_uniform_float(this._sharpnessLocation,
1, [this._sharpness]);
this.notify('sharpness');
}
});
@@ -88,8 +69,8 @@ var RadialShaderEffect = GObject.registerClass({
* - inhibitEvents: whether to inhibit events for @container
* - width: shade actor width
* - height: shade actor height
* - fadeFactor: fading opacity factor
* - radialEffect: whether to enable the GLSL radial effect
* - fadeInTime: seconds used to fade in
* - fadeOutTime: seconds used to fade out
*
* Lightbox creates a dark translucent "shade" actor to hide the
* contents of @container, and allows you to specify particular actors
@@ -105,49 +86,41 @@ var RadialShaderEffect = GObject.registerClass({
* @container and will track any changes in its size. You can override
* this by passing an explicit width and height in @params.
*/
var Lightbox = GObject.registerClass({
Properties: {
'active': GObject.ParamSpec.boolean(
'active', 'active', 'active', GObject.ParamFlags.READABLE, false),
}
}, class Lightbox extends St.Bin {
_init(container, params) {
params = Params.parse(params, {
inhibitEvents: false,
var Lightbox = class Lightbox {
constructor(container, params) {
params = Params.parse(params, { inhibitEvents: false,
width: null,
height: null,
fadeFactor: DEFAULT_FADE_FACTOR,
radialEffect: false,
});
super._init({
reactive: params.inhibitEvents,
width: params.width,
height: params.height,
visible: false
});
this._active = false;
this._container = container;
this._children = container.get_children();
this._fadeFactor = params.fadeFactor;
this._radialEffect = Clutter.feature_available(Clutter.FeatureFlags.SHADERS_GLSL) && params.radialEffect;
this.actor = new St.Bin({ reactive: params.inhibitEvents });
if (this._radialEffect)
this.add_effect(new RadialShaderEffect({ name: 'radial' }));
this.actor.add_effect(new RadialShaderEffect({ name: 'radial' }));
else
this.set({ opacity: 0, style_class: 'lightbox' });
this.actor.set({ opacity: 0, style_class: 'lightbox' });
container.add_actor(this);
this.raise_top();
container.add_actor(this.actor);
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) {
this.add_constraint(new Clutter.BindConstraint({
source: container,
coordinate: Clutter.BindCoordinate.ALL
}));
if (params.width && params.height) {
this.actor.width = params.width;
this.actor.height = params.height;
} 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));
@@ -156,20 +129,16 @@ var Lightbox = GObject.registerClass({
this._highlighted = null;
}
get active() {
return this._active;
}
_actorAdded(container, newChild) {
let children = this._container.get_children();
let myIndex = children.indexOf(this);
let myIndex = children.indexOf(this.actor);
let newChildIndex = children.indexOf(newChild);
if (newChildIndex > myIndex) {
// The child was added above the shade (presumably it was
// made the new top-most child). Move it below the shade,
// 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);
} else if (newChildIndex == 0) {
// Bottom of stack
@@ -182,55 +151,66 @@ var Lightbox = GObject.registerClass({
}
}
lightOn(fadeInTime) {
this.remove_all_transitions();
let easeProps = {
duration: fadeInTime || 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
};
let onComplete = () => {
this._active = true;
this.notify('active');
};
this.show();
show(fadeInTime) {
fadeInTime = fadeInTime || 0;
if (this._radialEffect) {
this.ease_property(
'@effects.radial.brightness', VIGNETTE_BRIGHTNESS, easeProps);
this.ease_property(
'@effects.radial.sharpness', VIGNETTE_SHARPNESS,
Object.assign({ onComplete }, easeProps));
let effect = this.actor.get_effect('radial');
Tweener.removeTweens(effect);
Tweener.addTween(effect,
{ brightness: VIGNETTE_BRIGHTNESS,
vignetteSharpness: VIGNETTE_SHARPNESS,
time: fadeInTime,
transition: 'easeOutQuad',
onComplete: () => {
this.shown = true;
this.emit('shown');
}
});
} else {
this.ease(Object.assign(easeProps, {
opacity: 255 * this._fadeFactor,
onComplete
}));
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor,
{ opacity: 255 * this._fadeFactor,
time: fadeInTime,
transition: 'easeOutQuad',
onComplete: () => {
this.shown = true;
this.emit('shown');
}
});
}
lightOff(fadeOutTime) {
this.remove_all_transitions();
this.actor.show();
}
this._active = false;
this.notify('active');
hide(fadeOutTime) {
fadeOutTime = fadeOutTime || 0;
let easeProps = {
duration: fadeOutTime || 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
};
let onComplete = () => this.hide();
this.shown = false;
if (this._radialEffect) {
this.ease_property(
'@effects.radial.brightness', 1.0, easeProps);
this.ease_property(
'@effects.radial.sharpness', 0.0, Object.assign({ onComplete }, easeProps));
let effect = this.actor.get_effect('radial');
Tweener.removeTweens(effect);
Tweener.addTween(effect,
{ brightness: 1.0,
vignetteSharpness: 0.0,
opacity: 0,
time: fadeOutTime,
transition: 'easeOutQuad',
onComplete: () => {
this.actor.hide();
}
});
} else {
this.ease(Object.assign(easeProps, { opacity: 0, onComplete }));
Tweener.removeTweens(this.actor);
Tweener.addTween(this.actor,
{ opacity: 0,
time: fadeOutTime,
transition: 'easeOutQuad',
onComplete: () => {
this.actor.hide();
}
});
}
}
@@ -261,7 +241,7 @@ var Lightbox = GObject.registerClass({
// case we may need to indicate some *other* actor as the new
// sibling of the to-be-lowered one.
let below = this;
let below = this.actor;
for (let i = this._children.length - 1; i >= 0; i--) {
if (this._children[i] == window)
this._children[i].raise_top();
@@ -274,6 +254,15 @@ var Lightbox = GObject.registerClass({
this._highlighted = window;
}
/**
* destroy:
*
* Destroys the lightbox.
*/
destroy() {
this.actor.destroy();
}
/**
* _onDestroy:
*
@@ -281,15 +270,10 @@ var Lightbox = GObject.registerClass({
* by destroying its container or by explicitly calling this.destroy().
*/
_onDestroy() {
if (this._actorAddedSignalId) {
this._container.disconnect(this._actorAddedSignalId);
this._actorAddedSignalId = 0;
}
if (this._actorRemovedSignalId) {
this._container.disconnect(this._actorRemovedSignalId);
this._actorRemovedSignalId = 0;
}
this.highlight(null);
}
});
};
Signals.addSignalMethods(Lightbox.prototype);

View File

@@ -11,26 +11,12 @@ const LOCATE_POINTER_SCHEMA = "org.gnome.desktop.interface";
var LocatePointer = class {
constructor() {
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.addTo(Main.uiGroup);
} else {
this._ripples.destroy();
this._ripples = null;
}
}
show() {
if (!this._ripples)
if (!this._settings.get_boolean(LOCATE_POINTER_KEY))
return;
let [x, y] = global.get_pointer();

View File

@@ -1,14 +1,16 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported LookingGlass */
const { Clutter, Cogl, Gio, GLib, GObject,
Graphene, Meta, Pango, Shell, St } = imports.gi;
const { Clutter, Cogl, Gio, GLib,
GObject, Meta, Pango, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const System = imports.system;
const History = imports.misc.history;
const ExtensionUtils = imports.misc.extensionUtils;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
const JsParse = imports.misc.jsParse;
@@ -19,6 +21,8 @@ const CHEVRON = '>>> ';
/* Imports...feel free to add here as needed */
var commandHeader = 'const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi; ' +
'const Main = imports.ui.main; ' +
'const Mainloop = imports.mainloop; ' +
'const Tweener = imports.ui.tweener; ' +
/* Utility functions...we should probably be able to use these
* in the shell core code too. */
'const stage = global.stage; ' +
@@ -30,11 +34,9 @@ var commandHeader = 'const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = im
const HISTORY_KEY = 'looking-glass-history';
// Time between tabs for them to count as a double-tab event
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();
const LG_ANIMATION_TIME = 500;
function _getAutoCompleteGlobalKeywords() {
const keywords = ['true', 'false', 'null', 'new'];
// Don't add the private properties of window (i.e., ones starting with '_')
@@ -110,11 +112,9 @@ var AutoComplete = class AutoComplete {
Signals.addSignalMethods(AutoComplete.prototype);
var Notebook = GObject.registerClass({
Signals: { 'selection': { param_types: [Clutter.Actor.$gtype] } },
}, class Notebook extends St.BoxLayout {
_init() {
super._init({ vertical: true });
var Notebook = class Notebook {
constructor() {
this.actor = new St.BoxLayout({ vertical: true });
this.tabControls = new St.BoxLayout({ style_class: 'labels' });
@@ -145,7 +145,7 @@ var Notebook = GObject.registerClass({
_scrollToBottom: false };
this._tabs.push(tabData);
scrollview.hide();
this.add(scrollview, { expand: true });
this.actor.add(scrollview, { expand: true });
let vAdjust = scrollview.vscroll.adjustment;
vAdjust.connect('changed', () => this._onAdjustScopeChanged(tabData));
@@ -176,7 +176,7 @@ var Notebook = GObject.registerClass({
// Focus the new tab before unmapping the old one
let tabData = this._tabs[index];
if (!tabData.scrollView.navigate_focus(null, St.DirectionType.TAB_FORWARD, false))
this.grab_key_focus();
this.actor.grab_key_focus();
this._unselect();
@@ -236,10 +236,11 @@ var Notebook = GObject.registerClass({
this.selectIndex(prevIndex);
}
});
};
Signals.addSignalMethods(Notebook.prototype);
function objectToString(o) {
if (typeof o == typeof objectToString) {
if (typeof(o) == typeof(objectToString)) {
// special case this since the default is way, way too verbose
return '<js function>';
} else {
@@ -247,64 +248,57 @@ function objectToString(o) {
}
}
var ObjLink = GObject.registerClass(
class ObjLink extends St.Button {
_init(lookingGlass, o, title) {
var ObjLink = class ObjLink {
constructor(lookingGlass, o, title) {
let text;
if (title)
text = title;
else
text = objectToString(o);
text = GLib.markup_escape_text(text, -1);
this._obj = o;
super._init({
reactive: true,
this.actor = new St.Button({ reactive: true,
track_hover: true,
style_class: 'shell-link',
label: text
});
this.get_child().single_line_mode = true;
label: text });
this.actor.get_child().single_line_mode = true;
this.actor.connect('clicked', this._onClicked.bind(this));
this._obj = o;
this._lookingGlass = lookingGlass;
}
vfunc_clicked() {
this._lookingGlass.inspectObject(this._obj, this);
_onClicked() {
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.o = o;
this.actor = new St.BoxLayout({ vertical: true });
this._lookingGlass = lookingGlass;
let cmdTxt = new St.Label({ text: command });
cmdTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
this.add(cmdTxt);
this.actor.add(cmdTxt);
let box = new St.BoxLayout({});
this.add(box);
this.actor.add(box);
let resultTxt = new St.Label({ text: `r(${index}) = ` });
resultTxt.clutter_text.ellipsize = Pango.EllipsizeMode.END;
box.add(resultTxt);
let objLink = new ObjLink(this._lookingGlass, o);
box.add(objLink);
box.add(objLink.actor);
}
});
};
var WindowList = GObject.registerClass({
GTypeName: 'LookingClass_WindowList'
}, class WindowList extends St.BoxLayout {
_init(lookingGlass) {
super._init({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
var WindowList = class WindowList {
constructor(lookingGlass) {
this.actor = new St.BoxLayout({ name: 'Windows', vertical: true, style: 'spacing: 8px' });
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));
tracker.connect('tracked-windows-changed', this._updateWindowList.bind(this));
@@ -312,10 +306,7 @@ var WindowList = GObject.registerClass({
}
_updateWindowList() {
if (!this._lookingGlass.isOpen)
return;
this.destroy_all_children();
this.actor.destroy_all_children();
let windows = global.get_window_actors();
let tracker = Shell.WindowTracker.get_default();
for (let i = 0; i < windows.length; i++) {
@@ -326,9 +317,9 @@ var WindowList = GObject.registerClass({
metaWindow._lookingGlassManaged = true;
}
let box = new St.BoxLayout({ vertical: true });
this.add(box);
this.actor.add(box);
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;' });
box.add(propsBox);
propsBox.add(new St.Label({ text: `wmclass: ${metaWindow.get_wm_class()}` }));
@@ -339,38 +330,30 @@ var WindowList = GObject.registerClass({
propsBox.add(propBox);
propBox.add(new St.Label({ text: 'app: ' }), { y_fill: false });
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 });
} else {
propsBox.add(new St.Label({ text: '<untracked>' }));
}
}
}
};
Signals.addSignalMethods(WindowList.prototype);
update() {
this._updateWindowList();
}
});
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
});
var ObjInspector = class ObjInspector {
constructor(lookingGlass) {
this._obj = null;
this._previousObj = null;
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',
style_class: 'lg-dialog',
vertical: true });
this.add_actor(this._container);
this.actor.add_actor(this._container);
this._lookingGlass = lookingGlass;
}
@@ -386,7 +369,7 @@ class ObjInspector extends St.ScrollView {
let hbox = new St.BoxLayout({ style_class: 'lg-obj-inspector-title' });
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)) });
label.single_line_mode = true;
hbox.add(label, { expand: true, y_fill: false });
@@ -404,7 +387,7 @@ class ObjInspector extends St.ScrollView {
button.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' }));
button.connect('clicked', this.close.bind(this));
hbox.add(button);
if (typeof obj == typeof {}) {
if (typeof(obj) == typeof({})) {
let properties = [];
for (let propName in obj) {
properties.push(propName);
@@ -416,7 +399,7 @@ class ObjInspector extends St.ScrollView {
let link;
try {
let prop = obj[propName];
link = new ObjLink(this._lookingGlass, prop);
link = new ObjLink(this._lookingGlass, prop).actor;
} catch (e) {
link = new St.Label({ text: '<error>' });
}
@@ -433,17 +416,14 @@ class ObjInspector extends St.ScrollView {
return;
this._previousObj = null;
this._open = true;
this.show();
this.actor.show();
if (sourceActor) {
this.set_scale(0, 0);
this.ease({
scale_x: 1,
scale_y: 1,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: 200
});
this.actor.set_scale(0, 0);
Tweener.addTween(this.actor, { scale_x: 1, scale_y: 1,
transition: 'easeOutQuad',
time: 0.2 });
} else {
this.set_scale(1, 1);
this.actor.set_scale(1, 1);
}
}
@@ -451,7 +431,7 @@ class ObjInspector extends St.ScrollView {
if (!this._open)
return;
this._open = false;
this.hide();
this.actor.hide();
this._previousObj = null;
this._obj = null;
}
@@ -465,7 +445,7 @@ class ObjInspector extends St.ScrollView {
_onBack() {
this.selectObject(this._previousObj, true);
}
});
};
var RedBorderEffect = GObject.registerClass(
class RedBorderEffect extends Clutter.Effect {
@@ -477,16 +457,16 @@ class RedBorderEffect extends Clutter.Effect {
color.init_from_4ub(0xff, 0, 0, 0xc4);
Cogl.set_source_color(color);
let alloc = actor.get_allocation_box();
let geom = actor.get_allocation_geometry();
let width = 2;
// clockwise order
Cogl.rectangle(0, 0, alloc.get_width(), width);
Cogl.rectangle(alloc.get_width() - width, width,
alloc.get_width(), alloc.get_height());
Cogl.rectangle(0, alloc.get_height(),
alloc.get_width() - width, alloc.get_height() - width);
Cogl.rectangle(0, alloc.get_height() - width,
Cogl.rectangle(0, 0, geom.width, width);
Cogl.rectangle(geom.width - width, width,
geom.width, geom.height);
Cogl.rectangle(0, geom.height,
geom.width - width, geom.height - width);
Cogl.rectangle(0, geom.height - width,
width, width);
}
});
@@ -496,7 +476,8 @@ var Inspector = GObject.registerClass({
'target': { param_types: [Clutter.Actor.$gtype, GObject.TYPE_DOUBLE, GObject.TYPE_DOUBLE] } },
}, class Inspector extends Clutter.Actor {
_init(lookingGlass) {
super._init({ width: 0, height: 0 });
super._init({ width: 0,
height: 0 });
Main.uiGroup.add_actor(this);
@@ -631,20 +612,18 @@ var Inspector = GObject.registerClass({
}
});
var Extensions = GObject.registerClass({
GTypeName: 'LookingClass_Extensions'
}, class Extensions extends St.BoxLayout {
_init(lookingGlass) {
super._init({ vertical: true, name: 'lookingGlassExtensions' });
var Extensions = class Extensions {
constructor(lookingGlass) {
this._lookingGlass = lookingGlass;
this.actor = new St.BoxLayout({ vertical: true,
name: 'lookingGlassExtensions' });
this._noExtensions = new St.Label({ style_class: 'lg-extensions-none',
text: _("No extensions installed") });
this._numExtensions = 0;
this._extensionsList = new St.BoxLayout({ vertical: true,
style_class: 'lg-extensions-list' });
this._extensionsList.add(this._noExtensions);
this.add(this._extensionsList);
this.actor.add(this._extensionsList);
Main.extensionManager.getUuids().forEach(uuid => {
this._loadExtension(null, uuid);
@@ -772,19 +751,10 @@ var Extensions = GObject.registerClass({
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._redBorderEffect = new RedBorderEffect();
@@ -792,18 +762,26 @@ class LookingGlass extends St.BoxLayout {
this._it = null;
this._offset = 0;
this._results = [];
// Sort of magic, but...eh.
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.connect('changed::monospace-font-name',
this._updateFont.bind(this));
this._updateFont();
// We want it to appear to slide out from underneath the panel
Main.uiGroup.add_actor(this);
Main.uiGroup.set_child_below_sibling(this,
Main.uiGroup.add_actor(this.actor);
Main.uiGroup.set_child_below_sibling(this.actor,
Main.layoutManager.panelBox);
Main.layoutManager.panelBox.connect('allocation-changed',
this._queueResize.bind(this));
@@ -811,11 +789,11 @@ class LookingGlass extends St.BoxLayout {
this._queueResize.bind(this));
this._objInspector = new ObjInspector(this);
Main.uiGroup.add_actor(this._objInspector);
this._objInspector.hide();
Main.uiGroup.add_actor(this._objInspector.actor);
this._objInspector.actor.hide();
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',
icon_size: 24 });
toolbar.add_actor(inspectIcon);
@@ -826,10 +804,10 @@ class LookingGlass extends St.BoxLayout {
this._pushResult(`inspect(${Math.round(stageX)}, ${Math.round(stageY)})`, target);
});
inspector.connect('closed', () => {
this.show();
this.actor.show();
global.stage.set_key_focus(this._entry);
});
this.hide();
this.actor.hide();
return Clutter.EVENT_STOP;
});
@@ -840,7 +818,7 @@ class LookingGlass extends St.BoxLayout {
gcIcon.connect('button-press-event', () => {
gcIcon.icon_name = 'user-trash';
System.gc();
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 500, () => {
this._timeoutId = Mainloop.timeout_add(500, () => {
gcIcon.icon_name = 'user-trash-full';
this._timeoutId = 0;
return GLib.SOURCE_REMOVE;
@@ -851,7 +829,7 @@ class LookingGlass extends St.BoxLayout {
let notebook = new Notebook();
this._notebook = notebook;
this.add(notebook, { expand: true });
this.actor.add(notebook.actor, { expand: true });
let emptyBox = new St.Bin();
toolbar.add(emptyBox, { expand: true });
@@ -874,10 +852,10 @@ class LookingGlass extends St.BoxLayout {
this._entryArea.add(this._entry, { expand: true });
this._windowList = new WindowList(this);
notebook.appendPage('Windows', this._windowList);
notebook.appendPage('Windows', this._windowList.actor);
this._extensions = new Extensions(this);
notebook.appendPage('Extensions', this._extensions);
notebook.appendPage('Extensions', this._extensions.actor);
this._entry.clutter_text.connect('activate', (o, _e) => {
// Hide any completions we are currently showing
@@ -919,7 +897,7 @@ class LookingGlass extends St.BoxLayout {
// monospace font to be bold/oblique/etc. Could easily be added here.
let size = fontDesc.get_size() / 1024.;
let unit = fontDesc.get_size_is_absolute() ? 'px' : 'pt';
this.style = `
this.actor.style = `
font-size: ${size}${unit};
font-family: "${fontDesc.get_family()}";`;
}
@@ -933,14 +911,17 @@ class LookingGlass extends St.BoxLayout {
}
_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);
this._resultsArea.add(result);
this._results.push(result);
this._resultsArea.add(result.actor);
if (obj instanceof Clutter.Actor)
this.setBorderPaintTarget(obj);
if (this._resultsArea.get_n_children() > this._maxItems) {
this._resultsArea.get_first_child().destroy();
let children = this._resultsArea.get_children();
if (children.length > this._maxItems) {
this._results.shift();
children[0].destroy();
this._offset++;
}
this._it = obj;
@@ -960,7 +941,7 @@ class LookingGlass extends St.BoxLayout {
this._completionActor.set_text(completions.join(', '));
// 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);
let [, naturalHeight] = this._completionActor.get_preferred_height(this._resultsArea.get_width());
@@ -969,14 +950,12 @@ class LookingGlass extends St.BoxLayout {
this._completionActor.height = naturalHeight;
} else {
let settings = St.Settings.get();
let duration = AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor;
this._completionActor.show();
this._completionActor.remove_all_transitions();
this._completionActor.ease({
Tweener.removeTweens(this._completionActor);
Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor,
transition: 'easeOutQuad',
height: naturalHeight,
opacity: 255,
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
opacity: 255
});
}
}
@@ -984,13 +963,11 @@ class LookingGlass extends St.BoxLayout {
_hideCompletions() {
if (this._completionActor) {
let settings = St.Settings.get();
let duration = AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor;
this._completionActor.remove_all_transitions();
this._completionActor.ease({
Tweener.removeTweens(this._completionActor);
Tweener.addTween(this._completionActor, { time: AUTO_COMPLETE_SHOW_COMPLETION_ANIMATION_DURATION / settings.slow_down_factor,
transition: 'easeOutQuad',
height: 0,
opacity: 0,
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._completionActor.hide();
}
@@ -1026,11 +1003,7 @@ class LookingGlass extends St.BoxLayout {
}
getResult(idx) {
try {
return this._resultsArea.get_child_at_index(idx - this._offset).o;
} catch (e) {
throw new Error(`Unknown result at index ${idx}`);
}
return this._results[idx - this._offset].o;
}
toggle() {
@@ -1052,14 +1025,14 @@ class LookingGlass extends St.BoxLayout {
let myWidth = primary.width * 0.7;
let availableHeight = primary.height - Main.layoutManager.keyboardBox.height;
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._targetY = this._hiddenY + myHeight;
this.y = this._hiddenY;
this.width = myWidth;
this.height = myHeight;
this._objInspector.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
this._objInspector.set_position(this.x + Math.floor(myWidth * 0.1),
this.actor.y = this._hiddenY;
this.actor.width = myWidth;
this.actor.height = myHeight;
this._objInspector.actor.set_size(Math.floor(myWidth * 0.8), Math.floor(myHeight * 0.8));
this._objInspector.actor.set_position(this.actor.x + Math.floor(myWidth * 0.1),
this._targetY + Math.floor(myHeight * 0.1));
}
@@ -1073,10 +1046,11 @@ class LookingGlass extends St.BoxLayout {
}
// Handle key events which are relevant for all tabs of the LookingGlass
vfunc_key_press_event(keyPressEvent) {
let symbol = keyPressEvent.keyval;
_globalKeyPressEvent(actor, event) {
let symbol = event.get_key_symbol();
let modifierState = event.get_state();
if (symbol == Clutter.Escape) {
if (this._objInspector.visible) {
if (this._objInspector.actor.visible) {
this._objInspector.close();
} else {
this.close();
@@ -1084,7 +1058,7 @@ class LookingGlass extends St.BoxLayout {
return Clutter.EVENT_STOP;
}
// 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) {
this._notebook.prevTab();
} else if (symbol == Clutter.KEY_Page_Down) {
@@ -1102,49 +1076,42 @@ class LookingGlass extends St.BoxLayout {
return;
this._notebook.selectIndex(0);
this.show();
this.actor.show();
this._open = true;
this._history.lastItem();
this.remove_all_transitions();
Tweener.removeTweens(this.actor);
// We inverse compensate for the slow-down so you can change the factor
// through LookingGlass without long waits.
let duration = LG_ANIMATION_TIME / St.Settings.get().slow_down_factor;
this.ease({
y: this._targetY,
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
let settings = St.Settings.get();
Tweener.addTween(this.actor, { time: 0.5 / settings.slow_down_factor,
transition: 'easeOutQuad',
y: this._targetY
});
this._windowList.update();
}
close() {
if (!this._open)
return;
this._objInspector.hide();
this._objInspector.actor.hide();
this._open = false;
this.remove_all_transitions();
Tweener.removeTweens(this.actor);
this.setBorderPaintTarget(null);
Main.popModal(this._entry);
let settings = St.Settings.get();
let duration = Math.min(LG_ANIMATION_TIME / settings.slow_down_factor,
LG_ANIMATION_TIME);
this.ease({
Tweener.addTween(this.actor, { time: Math.min(0.5 / settings.slow_down_factor, 0.5),
transition: 'easeOutQuad',
y: this._hiddenY,
duration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this.hide()
});
}
get isOpen() {
return this._open;
onComplete: () => {
this.actor.hide();
}
});
}
};
Signals.addSignalMethods(LookingGlass.prototype);

View File

@@ -2,6 +2,7 @@
const { Atspi, Clutter, GDesktopEnums,
Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Background = imports.ui.background;
@@ -264,7 +265,7 @@ var Magnifier = class Magnifier {
zoomRegion.setViewPort(viewPort);
// 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.height = viewPort.height / yMagFactor;
zoomRegion.setROI(fixedROI);
@@ -451,11 +452,15 @@ var Magnifier = class Magnifier {
* @clip: Flag to indicate whether to clip the crosshairs.
*/
setCrosshairsClip(clip) {
if (!this._crossHairs)
return;
// Setting no clipping on crosshairs means a zero sized clip rectangle.
this._crossHairs.setClip(clip ? CROSSHAIRS_CLIP_SIZE : [0, 0]);
if (clip) {
if (this._crossHairs)
this._crossHairs.setClip(CROSSHAIRS_CLIP_SIZE);
} else {
// Setting no clipping on crosshairs means a zero sized clip
// rectangle.
if (this._crossHairs)
this._crossHairs.setClip([0, 0]);
}
}
/**
@@ -1139,7 +1144,7 @@ var ZoomRegion = class ZoomRegion {
_clearScrollContentsTimer() {
if (this._scrollContentsTimerId != 0) {
GLib.source_remove(this._scrollContentsTimerId);
Mainloop.source_remove(this._scrollContentsTimerId);
this._scrollContentsTimerId = 0;
}
}
@@ -1151,7 +1156,7 @@ var ZoomRegion = class ZoomRegion {
}
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);
return GLib.SOURCE_REMOVE;
});
@@ -1290,7 +1295,7 @@ var ZoomRegion = class ZoomRegion {
// Add a background for when the magnified uiGroup is scrolled
// 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);
// Clone the group that contains all of UI on the screen. This is the
@@ -1587,9 +1592,8 @@ var ZoomRegion = class ZoomRegion {
}
};
var Crosshairs = GObject.registerClass(
class Crosshairs extends Clutter.Actor {
_init() {
var Crosshairs = class Crosshairs {
constructor() {
// Set the group containing the crosshairs to three times the desktop
// size in case the crosshairs need to appear to be infinite in
@@ -1597,7 +1601,7 @@ class Crosshairs extends Clutter.Actor {
let groupWidth = global.screen_width * 3;
let groupHeight = global.screen_height * 3;
super._init({
this._actor = new Clutter.Actor({
clip_to_allocation: false,
width: groupWidth,
height: groupHeight
@@ -1606,10 +1610,10 @@ class Crosshairs extends Clutter.Actor {
this._horizRightHair = new Clutter.Actor();
this._vertTopHair = new Clutter.Actor();
this._vertBottomHair = new Clutter.Actor();
this.add_actor(this._horizLeftHair);
this.add_actor(this._horizRightHair);
this.add_actor(this._vertTopHair);
this.add_actor(this._vertBottomHair);
this._actor.add_actor(this._horizLeftHair);
this._actor.add_actor(this._horizRightHair);
this._actor.add_actor(this._vertTopHair);
this._actor.add_actor(this._vertBottomHair);
this._clipSize = [0, 0];
this._clones = [];
this.reCenter();
@@ -1619,7 +1623,7 @@ class Crosshairs extends Clutter.Actor {
}
_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();
}
@@ -1640,15 +1644,12 @@ class Crosshairs extends Clutter.Actor {
if (zoomRegion && magnifiedMouse) {
let container = magnifiedMouse.get_parent();
if (container) {
crosshairsActor = this;
if (this.get_parent() != null) {
crosshairsActor = new Clutter.Clone({ source: this });
crosshairsActor = this._actor;
if (this._actor.get_parent() != null) {
crosshairsActor = new Clutter.Clone({ source: this._actor });
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.raise_child(magnifiedMouse, crosshairsActor);
@@ -1667,7 +1668,7 @@ class Crosshairs extends Clutter.Actor {
* child actor if it was just a clone of the crosshairs actor.
*/
removeFromParent(childActor) {
if (childActor == this)
if (childActor == this._actor)
childActor.get_parent().remove_actor(childActor);
else
childActor.destroy();
@@ -1777,6 +1778,28 @@ class Crosshairs extends Clutter.Actor {
}
}
/**
* 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:
* Reposition the horizontal and vertical hairs such that they cross at
@@ -1785,7 +1808,7 @@ class Crosshairs extends Clutter.Actor {
* @clipSize: Optional. If present, an array of the form [width, height].
*/
reCenter(clipSize) {
let [groupWidth, groupHeight] = this.get_size();
let [groupWidth, groupHeight] = this._actor.get_size();
let leftLength = this._horizLeftHair.get_width();
let topLength = this._vertTopHair.get_height();
let thickness = this._horizLeftHair.get_height();
@@ -1807,7 +1830,7 @@ class Crosshairs extends Clutter.Actor {
this._vertTopHair.set_position((groupWidth - thickness) / 2, top);
this._vertBottomHair.set_position((groupWidth - thickness) / 2, bottom);
}
});
};
var MagShaderEffects = class MagShaderEffects {
constructor(uiGroupClone) {

View File

@@ -9,6 +9,7 @@
initializeDeferredWork, getThemeStylesheet, setThemeStylesheet */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const AccessDialog = imports.ui.accessDialog;
const AudioDeviceSelection = imports.ui.audioDeviceSelection;
@@ -189,7 +190,7 @@ function _initializeUI() {
messageTray = new MessageTray.MessageTray();
panel = new Panel.Panel();
keyboard = new Keyboard.KeyboardManager();
keyboard = new Keyboard.Keyboard();
notificationDaemon = new NotificationDaemon.NotificationDaemon();
windowAttentionHandler = new WindowAttentionHandler.WindowAttentionHandler();
componentManager = new Components.ComponentManager();
@@ -229,11 +230,7 @@ function _initializeUI() {
EndSessionDialog.init();
// 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();
return GLib.SOURCE_REMOVE;
});
_startDate = new Date();
@@ -262,19 +259,6 @@ 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();
let perfModuleName = GLib.getenv("SHELL_PERF_MODULE");
@@ -403,7 +387,7 @@ function notify(msg, details) {
messageTray.add(source);
let notification = new MessageTray.Notification(source, msg, details);
notification.setTransient(true);
source.showNotification(notification);
source.notify(notification);
}
/**
@@ -636,7 +620,7 @@ function _runDeferredWork(workId) {
_deferredWorkQueue.splice(index, 1);
_deferredWorkData[workId].callback();
if (_deferredWorkQueue.length == 0 && _deferredTimeoutId > 0) {
GLib.source_remove(_deferredTimeoutId);
Mainloop.source_remove(_deferredTimeoutId);
_deferredTimeoutId = 0;
}
}
@@ -722,8 +706,9 @@ function queueDeferredWork(workId) {
_deferredWorkQueue.push(workId);
if (data.actor.mapped) {
_queueBeforeRedraw(workId);
return;
} else if (_deferredTimeoutId == 0) {
_deferredTimeoutId = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, DEFERRED_TIMEOUT_SECONDS, () => {
_deferredTimeoutId = Mainloop.timeout_add_seconds(DEFERRED_TIMEOUT_SECONDS, () => {
_runAllDeferredWork();
_deferredTimeoutId = 0;
return GLib.SOURCE_REMOVE;

View File

@@ -1,13 +1,13 @@
/* exported MessageListSection */
const { Atk, Clutter, Gio, GLib,
GObject, Graphene, Meta, Pango, St } = imports.gi;
const { Atk, Clutter, Gio, GLib, GObject, Meta, Pango, St } = imports.gi;
const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const Signals = imports.signals;
const Calendar = imports.ui.calendar;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
var MESSAGE_ANIMATION_TIME = 100;
var MESSAGE_ANIMATION_TIME = 0.1;
var DEFAULT_EXPAND_LINES = 6;
@@ -32,18 +32,13 @@ function _fixMarkup(text, allowMarkup) {
return GLib.markup_escape_text(text, -1);
}
var URLHighlighter = GObject.registerClass(
class URLHighlighter extends St.Label {
_init(text = '', lineWrap, allowMarkup) {
super._init({
reactive: true,
style_class: 'url-highlighter',
x_expand: true,
x_align: Clutter.ActorAlign.START
});
var URLHighlighter = class URLHighlighter {
constructor(text = '', lineWrap, allowMarkup) {
this.actor = new St.Label({ reactive: true, style_class: 'url-highlighter',
x_expand: true, x_align: Clutter.ActorAlign.START });
this._linkColor = '#ccccff';
this.connect('style-changed', () => {
let [hasColor, color] = this.get_theme_node().lookup_color('link-color', false);
this.actor.connect('style-changed', () => {
let [hasColor, color] = this.actor.get_theme_node().lookup_color('link-color', false);
if (hasColor) {
let linkColor = color.to_string().substr(0, 7);
if (linkColor != this._linkColor) {
@@ -52,47 +47,42 @@ class URLHighlighter extends St.Label {
}
}
});
this.clutter_text.line_wrap = lineWrap;
this.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
this.actor.clutter_text.line_wrap = lineWrap;
this.actor.clutter_text.line_wrap_mode = Pango.WrapMode.WORD_CHAR;
this.setMarkup(text, allowMarkup);
}
vfunc_button_press_event(buttonEvent) {
this.actor.connect('button-press-event', (actor, event) => {
// Don't try to URL highlight when invisible.
// The MessageTray doesn't actually hide us, so
// 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;
// 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
// handler, if an URL is clicked
return this._findUrlAtPos(buttonEvent) != -1;
}
vfunc_button_release_event(buttonEvent) {
if (!this.visible || this.get_paint_opacity() == 0)
return this._findUrlAtPos(event) != -1;
});
this.actor.connect('button-release-event', (actor, event) => {
if (!actor.visible || actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(buttonEvent);
let urlId = this._findUrlAtPos(event);
if (urlId != -1) {
let url = this._urls[urlId].url;
if (!url.includes(':'))
url = 'http://' + url;
Gio.app_info_launch_default_for_uri(
url, global.create_app_launch_context(0, -1));
Gio.app_info_launch_default_for_uri(url, global.create_app_launch_context(0, -1));
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
}
vfunc_motion_event(motionEvent) {
if (!this.visible || this.get_paint_opacity() == 0)
});
this.actor.connect('motion-event', (actor, event) => {
if (!actor.visible || actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE;
let urlId = this._findUrlAtPos(motionEvent);
let urlId = this._findUrlAtPos(event);
if (urlId != -1 && !this._cursorChanged) {
global.display.set_cursor(Meta.Cursor.POINTING_HAND);
this._cursorChanged = true;
@@ -101,26 +91,26 @@ class URLHighlighter extends St.Label {
this._cursorChanged = false;
}
return Clutter.EVENT_PROPAGATE;
}
vfunc_leave_event(crossingEvent) {
if (!this.visible || this.get_paint_opacity() == 0)
});
this.actor.connect('leave-event', () => {
if (!this.actor.visible || this.actor.get_paint_opacity() == 0)
return Clutter.EVENT_PROPAGATE;
if (this._cursorChanged) {
this._cursorChanged = false;
global.display.set_cursor(Meta.Cursor.DEFAULT);
}
return super.vfunc_leave_event(crossingEvent);
return Clutter.EVENT_PROPAGATE;
});
}
setMarkup(text, allowMarkup) {
text = text ? _fixMarkup(text, allowMarkup) : '';
this._text = text;
this.clutter_text.set_markup(text);
this.actor.clutter_text.set_markup(text);
/* 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();
}
@@ -136,15 +126,16 @@ class URLHighlighter extends St.Label {
pos = url.pos + url.url.length;
}
markup += this._text.substr(pos);
this.clutter_text.set_markup(markup);
this.actor.clutter_text.set_markup(markup);
}
_findUrlAtPos(event) {
let { x, y } = event;
[, x, y] = this.transform_stage_point(x, y);
let success_;
let [x, y] = event.get_coords();
[success_, x, y] = this.actor.transform_stage_point(x, y);
let findPos = -1;
for (let i = 0; i < this.clutter_text.text.length; i++) {
let [, px, py, lineHeight] = this.clutter_text.position_to_coords(i);
for (let i = 0; i < this.actor.clutter_text.text.length; i++) {
let [success_, px, py, lineHeight] = this.actor.clutter_text.position_to_coords(i);
if (py > y || py + lineHeight < y || x < px)
continue;
findPos = i;
@@ -157,7 +148,7 @@ class URLHighlighter extends St.Label {
}
return -1;
}
});
};
var ScaleLayout = GObject.registerClass(
class ScaleLayout extends Clutter.BinLayout {
@@ -293,29 +284,21 @@ var LabelExpanderLayout = GObject.registerClass({
}
});
var Message = GObject.registerClass({
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
});
var Message = class Message {
constructor(title, body) {
this.expanded = 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 });
this.set_child(vbox);
this.actor.set_child(vbox);
let hbox = new St.BoxLayout();
vbox.add_actor(hbox);
@@ -359,14 +342,15 @@ var Message = GObject.registerClass({
contentBox.add_actor(this._bodyStack);
this.bodyLabel = new URLHighlighter('', false, this._useBodyMarkup);
this.bodyLabel.add_style_class_name('message-body');
this._bodyStack.add_actor(this.bodyLabel);
this.bodyLabel.actor.add_style_class_name('message-body');
this._bodyStack.add_actor(this.bodyLabel.actor);
this.setBody(body);
this._closeButton.connect('clicked', this.close.bind(this));
let actorHoverId = this.connect('notify::hover', this._sync.bind(this));
this._closeButton.connect('destroy', this.disconnect.bind(this, actorHoverId));
this.connect('destroy', this._onDestroy.bind(this));
let actorHoverId = this.actor.connect('notify::hover', this._sync.bind(this));
this._closeButton.connect('destroy', this.actor.disconnect.bind(this.actor, actorHoverId));
this.actor.connect('clicked', this._onClicked.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
this._sync();
}
@@ -452,21 +436,19 @@ var Message = GObject.registerClass({
if (this._bodyStack.get_n_children() < 2) {
this._expandedLabel = new URLHighlighter(this._bodyText,
true, this._useBodyMarkup);
this.setExpandedBody(this._expandedLabel);
this.setExpandedBody(this._expandedLabel.actor);
}
if (animate) {
this._bodyStack.ease_property('@layout.expansion', 1, {
progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: MessageTray.ANIMATION_TIME,
});
Tweener.addTween(this._bodyStack.layout_manager,
{ expansion: 1,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad' });
this._actionBin.scale_y = 0;
this._actionBin.ease({
scale_y: 1,
duration: MessageTray.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
Tweener.addTween(this._actionBin,
{ scale_y: 1,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad' });
} else {
this._bodyStack.layout_manager.expansion = 1;
this._actionBin.scale_y = 1;
@@ -477,20 +459,18 @@ var Message = GObject.registerClass({
unexpand(animate) {
if (animate) {
this._bodyStack.ease_property('@layout.expansion', 0, {
progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: MessageTray.ANIMATION_TIME,
});
this._actionBin.ease({
scale_y: 0,
duration: MessageTray.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.addTween(this._bodyStack.layout_manager,
{ expansion: 0,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad' });
Tweener.addTween(this._actionBin,
{ scale_y: 0,
time: MessageTray.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this._actionBin.hide();
this.expanded = false;
}
});
} });
} else {
this._bodyStack.layout_manager.expansion = 0;
this._actionBin.scale_y = 0;
@@ -505,16 +485,19 @@ var Message = GObject.registerClass({
}
_sync() {
let visible = this.hover && this.canClose();
let visible = this.actor.hover && this.canClose();
this._closeButton.opacity = visible ? 255 : 0;
this._closeButton.reactive = visible;
}
_onClicked() {
}
_onDestroy() {
}
vfunc_key_press_event(keyEvent) {
let keysym = keyEvent.keyval;
_onKeyPressed(a, event) {
let keysym = event.get_key_symbol();
if (keysym == Clutter.KEY_Delete ||
keysym == Clutter.KEY_KP_Delete) {
@@ -523,66 +506,37 @@ var Message = GObject.registerClass({
}
return Clutter.EVENT_PROPAGATE;
}
});
};
Signals.addSignalMethods(Message.prototype);
var MessageListSection = GObject.registerClass({
Properties: {
'can-clear': GObject.ParamSpec.boolean(
'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',
var MessageListSection = class MessageListSection {
constructor() {
this.actor = new St.BoxLayout({ style_class: 'message-list-section',
clip_to_allocation: true,
vertical: true,
x_expand: true
});
x_expand: true, vertical: true });
this._list = new St.BoxLayout({ style_class: 'message-list-section-list',
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-removed', this._sync.bind(this));
let id = Main.sessionMode.connect('updated',
this._sync.bind(this));
this.connect('destroy', () => {
this.actor.connect('destroy', () => {
Main.sessionMode.disconnect(id);
});
this._messages = new Map();
this._date = new Date();
this._empty = true;
this._canClear = false;
this.empty = true;
this.canClear = false;
this._sync();
}
get empty() {
return this._empty;
}
get canClear() {
return this._canClear;
}
get _messages() {
return this._list.get_children().map(i => i.child);
}
_onKeyFocusIn(messageActor) {
this.emit('message-focused', messageActor);
_onKeyFocusIn(actor) {
this.emit('key-focus-in', actor);
}
get allowed() {
@@ -601,96 +555,85 @@ var MessageListSection = GObject.registerClass({
}
addMessageAtIndex(message, index, animate) {
if (this._messages.includes(message))
throw new Error('Message was already added previously');
let listItem = new St.Bin({
child: message,
x_fill: true,
y_fill: true,
layout_manager: new ScaleLayout(),
pivot_point: new Graphene.Point({ x: .5, y: .5 }),
let obj = {
container: null,
destroyId: 0,
keyFocusId: 0,
closeId: 0
};
let pivot = new Clutter.Point({ x: .5, y: .5 });
let scale = animate ? 0 : 1;
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 = [];
listItem._connectionsIds.push(message.connect('key-focus-in',
this._onKeyFocusIn.bind(this)));
listItem._connectionsIds.push(message.connect('close', () => {
obj.closeId = message.connect('close', () => {
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) {
if (!this._messages.includes(message))
throw new Error(`Impossible to move the untracked message ${message}`);
let listItem = message.get_parent();
let obj = this._messages.get(message);
if (!animate) {
this._list.set_child_at_index(listItem, index);
this._list.set_child_at_index(obj.container, index);
return;
}
let onComplete = () => {
this._list.set_child_at_index(listItem, index);
listItem.ease({
scale_x: 1,
this._list.set_child_at_index(obj.container, index);
Tweener.addTween(obj.container, { scale_x: 1,
scale_y: 1,
duration: MESSAGE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad' });
};
listItem.ease({
scale_x: 0,
Tweener.addTween(obj.container, { scale_x: 0,
scale_y: 0,
duration: MESSAGE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete
});
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: onComplete });
}
removeMessage(message, animate) {
if (!this._messages.includes(message))
throw new Error(`Impossible to remove the untracked message ${message}`);
let obj = this._messages.get(message);
let listItem = message.get_parent();
listItem._connectionsIds.forEach(id => message.disconnect(id));
message.actor.disconnect(obj.destroyId);
message.actor.disconnect(obj.keyFocusId);
message.disconnect(obj.closeId);
this._messages.delete(message);
if (animate) {
listItem.ease({
scale_x: 0,
scale_y: 0,
duration: MESSAGE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
listItem.destroy();
Tweener.addTween(obj.container, { scale_x: 0, scale_y: 0,
time: MESSAGE_ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete() {
obj.container.destroy();
global.sync_pointer();
}
});
} });
} else {
listItem.destroy();
obj.container.destroy();
global.sync_pointer();
}
}
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 (messages.length < 2) {
@@ -703,37 +646,47 @@ var MessageListSection = GObject.registerClass({
let delay = MESSAGE_ANIMATION_TIME / Math.max(messages.length, 5);
for (let i = 0; i < messages.length; i++) {
let message = messages[i];
message.get_parent().ease({
translation_x: this._list.width,
let obj = this._messages.get(message);
Tweener.addTween(obj.container,
{ anchor_x: this._list.width,
opacity: 0,
duration: MESSAGE_ANIMATION_TIME,
time: MESSAGE_ANIMATION_TIME,
delay: i * delay,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => message.close()
});
transition: 'easeOutQuad',
onComplete() {
message.close();
} });
}
}
}
_canClear() {
for (let message of this._messages.keys())
if (message.canClose())
return true;
return false;
}
_shouldShow() {
return !this.empty;
}
_sync() {
let messages = this._messages;
let empty = messages.length == 0;
let empty = this._list.get_n_children() == 0;
let changed = this.empty !== empty;
this.empty = empty;
if (this._empty != empty) {
this._empty = empty;
this.notify('empty');
}
if (changed)
this.emit('empty-changed');
let canClear = messages.some(m => m.canClose());
if (this._canClear != canClear) {
this._canClear = canClear;
this.notify('can-clear');
}
let canClear = this._canClear();
changed = this.canClear !== canClear;
this.canClear = canClear;
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

@@ -4,20 +4,23 @@
SystemNotificationSource, MessageTray */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Calendar = imports.ui.calendar;
const GnomeSession = imports.misc.gnomeSession;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
var ANIMATION_TIME = 200;
var NOTIFICATION_TIMEOUT = 4000;
var ANIMATION_TIME = 0.2;
var NOTIFICATION_TIMEOUT = 4;
var HIDE_TIMEOUT = 200;
var LONGER_HIDE_TIMEOUT = 600;
var HIDE_TIMEOUT = 0.2;
var LONGER_HIDE_TIMEOUT = 0.6;
var MAX_NOTIFICATIONS_IN_QUEUE = 3;
var MAX_NOTIFICATIONS_PER_SOURCE = 3;
@@ -133,84 +136,70 @@ var FocusGrabber = class FocusGrabber {
// source, such as whether to play sound or honour the critical bit.
//
// A notification without a policy object will inherit the default one.
var NotificationPolicy = GObject.registerClass({
GTypeName: 'MessageTray_NotificationPolicy',
Properties: {
'enable': GObject.ParamSpec.boolean(
'enable', 'enable', 'enable',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'enable-sound': GObject.ParamSpec.boolean(
'enable-sound', 'enable-sound', 'enable-sound',
GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY,
true),
'show-banners': GObject.ParamSpec.boolean(
'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),
var NotificationPolicy = class NotificationPolicy {
constructor(params) {
params = Params.parse(params, { enable: true,
enableSound: true,
showBanners: true,
forceExpanded: false,
showInLockScreen: true,
detailsInLockScreen: false
});
Object.getOwnPropertyNames(params).forEach(key => {
let desc = Object.getOwnPropertyDescriptor(params, key);
Object.defineProperty(this, `_${key}`, desc);
});
}
}, class NotificationPolicy extends GObject.Object {
// Do nothing for the default policy. These methods are only useful for the
// GSettings policy.
store() { }
destroy() { }
destroy() {
this.run_dispose();
get enable() {
return this._enable;
}
get enableSound() {
return this.enable_sound;
return this._enableSound;
}
get showBanners() {
return this.show_banners;
return this._showBanners;
}
get forceExpanded() {
return this.force_expanded;
return this._forceExpanded;
}
get showInLockScreen() {
return this.show_in_lock_screen;
return this._showInLockScreen;
}
get detailsInLockScreen() {
return this.details_in_lock_screen;
return this._detailsInLockScreen;
}
});
};
Signals.addSignalMethods(NotificationPolicy.prototype);
var NotificationGenericPolicy = GObject.registerClass({
GTypeName: 'MessageTray_NotificationGenericPolicy'
}, class NotificationGenericPolicy extends NotificationPolicy {
_init() {
super._init();
var NotificationGenericPolicy =
class NotificationGenericPolicy extends NotificationPolicy {
constructor() {
super();
this.id = 'generic';
this._masterSettings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications' });
this._masterSettings.connect('changed', this._changed.bind(this));
}
store() { }
destroy() {
this._masterSettings.run_dispose();
super.destroy();
}
_changed(settings, key) {
if (this.constructor.find_property(key))
this.notify(key);
this.emit('policy-changed', key);
}
get showBanners() {
@@ -220,13 +209,12 @@ var NotificationGenericPolicy = GObject.registerClass({
get showInLockScreen() {
return this._masterSettings.get_boolean('show-in-lock-screen');
}
});
};
var NotificationApplicationPolicy = GObject.registerClass({
GTypeName: 'MessageTray_NotificationApplicationPolicy'
}, class NotificationApplicationPolicy extends NotificationPolicy {
_init(id) {
super._init();
var NotificationApplicationPolicy =
class NotificationApplicationPolicy extends NotificationPolicy {
constructor(id) {
super();
this.id = id;
this._canonicalId = this._canonicalizeId(id);
@@ -252,13 +240,12 @@ var NotificationApplicationPolicy = GObject.registerClass({
destroy() {
this._masterSettings.run_dispose();
this._settings.run_dispose();
super.destroy();
}
_changed(settings, key) {
if (this.constructor.find_property(key))
this.notify(key);
this.emit('policy-changed', key);
if (key == 'enable')
this.emit('enable-changed');
}
_canonicalizeId(id) {
@@ -292,7 +279,7 @@ var NotificationApplicationPolicy = GObject.registerClass({
get detailsInLockScreen() {
return this._settings.get_boolean('details-in-lock-screen');
}
});
};
// Notification:
// @source: the notification's Source
@@ -349,26 +336,12 @@ var NotificationApplicationPolicy = GObject.registerClass({
// @source allows playing sounds).
//
// [1] https://developer.gnome.org/notification-spec/#markup
var Notification = GObject.registerClass({
GTypeName: 'MessageTray_Notification',
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();
var Notification = class Notification {
constructor(source, title, banner, params) {
this.source = source;
this.title = title;
this.urgency = Urgency.NORMAL;
this.resident = false;
// 'transient' is a reserved keyword in JS, so we have to use an alternate variable name
this.isTransient = false;
this.privacyScope = PrivacyScope.USER;
@@ -380,7 +353,6 @@ var Notification = GObject.registerClass({
this._soundFile = null;
this._soundPlayed = false;
this.actions = [];
this.setResident(false);
// If called with only one argument we assume the caller
// will call .update() later on. This is the case of
@@ -450,7 +422,7 @@ var Notification = GObject.registerClass({
if (this._acknowledged == v)
return;
this._acknowledged = v;
this.notify('acknowledged');
this.emit('acknowledged-changed');
}
setUrgency(urgency) {
@@ -459,15 +431,6 @@ var Notification = GObject.registerClass({
setResident(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) {
@@ -509,30 +472,23 @@ var Notification = GObject.registerClass({
activate() {
this.emit('activated');
if (!this.resident)
this.destroy();
}
destroy(reason = NotificationDestroyedReason.DISMISSED) {
if (this._activatedId) {
this.disconnect(this._activatedId);
delete this._activatedId;
}
this.emit('destroy', reason);
this.run_dispose();
}
});
};
Signals.addSignalMethods(Notification.prototype);
var NotificationBanner = GObject.registerClass({
Signals: {
'done-displaying': {},
'unfocused': {},
}
}, class NotificationBanner extends Calendar.NotificationMessage {
_init(notification) {
super._init(notification);
var NotificationBanner =
class NotificationBanner extends Calendar.NotificationMessage {
constructor(notification) {
super(notification);
this.can_focus = false;
this.add_style_class_name('notification-banner');
this.actor.can_focus = false;
this.actor.add_style_class_name('notification-banner');
this._buttonBox = null;
@@ -619,7 +575,7 @@ var NotificationBanner = GObject.registerClass({
return this.addButton(button, callback);
}
});
};
var SourceActor = GObject.registerClass(
class SourceActor extends St.Widget {
@@ -684,7 +640,7 @@ class SourceActorWithLabel extends SourceActor {
this.add_actor(this._counterBin);
this._countUpdatedId = this._source.connect('notify::count', this._updateCount.bind(this));
this._countUpdatedId = this._source.connect('count-updated', this._updateCount.bind(this));
this._updateCount();
this.connect('destroy', () => {
@@ -732,34 +688,11 @@ class SourceActorWithLabel extends SourceActor {
}
});
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 });
var Source = class Source {
constructor(title, iconName) {
this.SOURCE_ICON_SIZE = 48;
this.title = title;
this.iconName = iconName;
this.isChat = false;
@@ -794,7 +727,7 @@ var Source = GObject.registerClass({
}
countUpdated() {
super.notify('count');
this.emit('count-updated');
}
_createPolicy() {
@@ -802,17 +735,13 @@ var Source = GObject.registerClass({
}
get narrowestPrivacyScope() {
return this.notifications.every(n => n.privacyScope == PrivacyScope.SYSTEM)
? PrivacyScope.SYSTEM
return this.notifications.every(n => n.privacyScope == PrivacyScope.SYSTEM) ? PrivacyScope.SYSTEM
: PrivacyScope.USER;
}
setTitle(newTitle) {
if (this.title == newTitle)
return;
this.title = newTitle;
this.notify('title');
this.emit('title-changed');
}
createBanner(notification) {
@@ -837,10 +766,10 @@ var Source = GObject.registerClass({
return;
this.notifications.splice(index, 1);
this.countUpdated();
if (this.notifications.length == 0)
this.destroy();
this.countUpdated();
}
pushNotification(notification) {
@@ -851,39 +780,24 @@ var Source = GObject.registerClass({
this.notifications.shift().destroy(NotificationDestroyedReason.EXPIRED);
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.emit('notification-added', notification);
this.countUpdated();
}
showNotification(notification) {
notify(notification) {
notification.acknowledged = false;
this.pushNotification(notification);
if (this.policy.showBanners || notification.urgency == Urgency.CRITICAL) {
this.emit('notification-show', notification);
this.emit('notify', notification);
} else {
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) {
this.policy.destroy();
@@ -894,8 +808,6 @@ var Source = GObject.registerClass({
notifications[i].destroy(reason);
this.emit('destroy', reason);
this.run_dispose();
}
iconUpdated() {
@@ -910,23 +822,14 @@ var Source = GObject.registerClass({
for (let i = this.notifications.length - 1; i >= 0; i--)
if (!this.notifications[i].resident)
this.notifications[i].destroy();
}
});
var MessageTray = GObject.registerClass({
Signals: {
'queue-changed': {},
'source-added': { param_types: [Source.$gtype] },
'source-removed': { param_types: [Source.$gtype] },
this.countUpdated();
}
}, class MessageTray extends St.Widget {
_init() {
super._init({
visible: false,
clip_to_allocation: true,
layout_manager: new Clutter.BinLayout()
});
};
Signals.addSignalMethods(Source.prototype);
var MessageTray = class MessageTray {
constructor() {
this._presence = new GnomeSession.Presence((proxy, _error) => {
this._onStatusChanged(proxy.status);
});
@@ -943,15 +846,18 @@ var MessageTray = GObject.registerClass({
// so fix up Clutter's view of the pointer position in
// that case.
let related = ev.get_related();
if (!related || this.contains(related))
if (!related || this.actor.contains(related))
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 });
Main.layoutManager.panelBox.bind_property('visible',
constraint, 'work-area',
GObject.BindingFlags.SYNC_CREATE);
this.add_constraint(constraint);
this.actor.add_constraint(constraint);
this._bannerBin = new St.Widget({ name: 'notification-container',
reactive: true,
@@ -965,7 +871,7 @@ var MessageTray = GObject.registerClass({
this._onNotificationKeyRelease.bind(this));
this._bannerBin.connect('notify::hover',
this._onNotificationHoverChanged.bind(this));
this.add_actor(this._bannerBin);
this.actor.add_actor(this._bannerBin);
this._notificationFocusGrabber = new FocusGrabber(this._bannerBin);
this._notificationQueue = [];
@@ -994,7 +900,7 @@ var MessageTray = GObject.registerClass({
this._notificationTimeoutId = 0;
this._notificationRemoved = false;
Main.layoutManager.addChrome(this, { affectsInputRegion: false });
Main.layoutManager.addChrome(this.actor, { affectsInputRegion: false });
Main.layoutManager.trackChrome(this._bannerBin, { affectsInputRegion: true });
global.display.connect('in-fullscreen-changed', this._updateState.bind(this));
@@ -1037,11 +943,11 @@ var MessageTray = GObject.registerClass({
}
_onDragBegin() {
Shell.util_set_hidden_from_pick(this, true);
Shell.util_set_hidden_from_pick(this.actor, true);
}
_onDragEnd() {
Shell.util_set_hidden_from_pick(this, false);
Shell.util_set_hidden_from_pick(this.actor, false);
}
get bannerAlignment() {
@@ -1090,22 +996,23 @@ var MessageTray = GObject.registerClass({
// Register that we got a notification for this source
source.policy.store();
source.policy.connect('notify::enable', () => {
source.policy.connect('enable-changed', () => {
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);
}
_addSource(source) {
let obj = {
showId: 0,
source: source,
notifyId: 0,
destroyId: 0,
};
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));
this.emit('source-added', source);
@@ -1115,7 +1022,7 @@ var MessageTray = GObject.registerClass({
let obj = this._sources.get(source);
this._sources.delete(source);
source.disconnect(obj.showId);
source.disconnect(obj.notifyId);
source.disconnect(obj.destroyId);
this.emit('source-removed', source);
@@ -1156,7 +1063,7 @@ var MessageTray = GObject.registerClass({
}
}
_onNotificationShow(_source, notification) {
_onNotify(source, notification) {
if (this._notification == notification) {
// If a notification that is being shown is updated, we update
// how it is shown and extend the time until it auto-hides.
@@ -1185,7 +1092,7 @@ var MessageTray = GObject.registerClass({
_resetNotificationLeftTimeout() {
this._useLongerNotificationLeftTimeout = false;
if (this._notificationLeftTimeoutId) {
GLib.source_remove(this._notificationLeftTimeoutId);
Mainloop.source_remove(this._notificationLeftTimeoutId);
this._notificationLeftTimeoutId = 0;
this._notificationLeftMouseX = -1;
this._notificationLeftMouseY = -1;
@@ -1230,8 +1137,8 @@ var MessageTray = GObject.registerClass({
// 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.
// 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;
this._notificationLeftTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout, this._onNotificationLeftTimeout.bind(this));
let timeout = this._useLongerNotificationLeftTimeout ? LONGER_HIDE_TIMEOUT * 1000 : HIDE_TIMEOUT * 1000;
this._notificationLeftTimeoutId = Mainloop.timeout_add(timeout, this._onNotificationLeftTimeout.bind(this));
GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout');
}
}
@@ -1260,9 +1167,7 @@ var MessageTray = GObject.registerClass({
x < this._notificationLeftMouseX + MOUSE_LEFT_ACTOR_THRESHOLD &&
x > this._notificationLeftMouseX - MOUSE_LEFT_ACTOR_THRESHOLD) {
this._notificationLeftMouseX = -1;
this._notificationLeftTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
LONGER_HIDE_TIMEOUT,
this._notificationLeftTimeoutId = Mainloop.timeout_add(LONGER_HIDE_TIMEOUT * 1000,
this._onNotificationLeftTimeout.bind(this));
GLib.Source.set_name_by_id(this._notificationLeftTimeoutId, '[gnome-shell] this._onNotificationLeftTimeout');
} else {
@@ -1288,7 +1193,7 @@ var MessageTray = GObject.registerClass({
// at the present time.
_updateState() {
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)
return;
@@ -1344,6 +1249,34 @@ var MessageTray = GObject.registerClass({
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() {
this._userActiveWhileNotificationShown = true;
this._updateNotificationTimeout(2000);
@@ -1368,11 +1301,12 @@ var MessageTray = GObject.registerClass({
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.y = -this._banner.height;
this.show();
this._bannerBin.y = -this._banner.actor.height;
this.actor.show();
Meta.disable_unredirect_for_display(global.display);
this._updateShowingNotification();
@@ -1415,38 +1349,32 @@ var MessageTray = GObject.registerClass({
// We use this._showNotificationCompleted() onComplete callback to extend the time the updated
// notification is being shown.
this._notificationState = State.SHOWING;
this._bannerBin.remove_all_transitions();
this._bannerBin.ease({
opacity: 255,
duration: ANIMATION_TIME,
mode: Clutter.AnimationMode.LINEAR
});
this._bannerBin.ease({
y: 0,
duration: ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_BACK,
onComplete: () => {
this._notificationState = State.SHOWN;
this._showNotificationCompleted();
this._updateState();
}
});
let tweenParams = { y: 0,
_opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutBack',
onUpdate: this._clampOpacity,
onUpdateScope: this,
onComplete: this._showNotificationCompleted,
onCompleteScope: this
};
this._tween(this._bannerBin, '_notificationState', State.SHOWN, tweenParams);
}
_showNotificationCompleted() {
if (this._notification.urgency != Urgency.CRITICAL)
this._updateNotificationTimeout(NOTIFICATION_TIMEOUT);
this._updateNotificationTimeout(NOTIFICATION_TIMEOUT * 1000);
}
_updateNotificationTimeout(timeout) {
if (this._notificationTimeoutId) {
GLib.source_remove(this._notificationTimeoutId);
Mainloop.source_remove(this._notificationTimeoutId);
this._notificationTimeoutId = 0;
}
if (timeout > 0) {
this._notificationTimeoutId =
GLib.timeout_add(GLib.PRIORITY_DEFAULT, timeout,
Mainloop.timeout_add(timeout,
this._notificationTimeout.bind(this));
GLib.Source.set_name_by_id(this._notificationTimeoutId, '[gnome-shell] this._notificationTimeout');
}
@@ -1489,26 +1417,20 @@ var MessageTray = GObject.registerClass({
}
this._resetNotificationLeftTimeout();
this._bannerBin.remove_all_transitions();
if (animate) {
this._notificationState = State.HIDING;
this._bannerBin.ease({
opacity: 0,
duration: ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_BACK
});
this._bannerBin.ease({
y: -this._bannerBin.height,
duration: ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_BACK,
onComplete: () => {
this._notificationState = State.HIDDEN;
this._hideNotificationCompleted();
this._updateState();
}
this._tween(this._bannerBin, '_notificationState', State.HIDDEN,
{ y: -this._bannerBin.height,
_opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutBack',
onUpdate: this._clampOpacity,
onUpdateScope: this,
onComplete: this._hideNotificationCompleted,
onCompleteScope: this
});
} else {
Tweener.removeTweens(this._bannerBin);
this._bannerBin.y = -this._bannerBin.height;
this._bannerBin.opacity = 0;
this._notificationState = State.HIDDEN;
@@ -1519,16 +1441,16 @@ var MessageTray = GObject.registerClass({
_hideNotificationCompleted() {
let notification = this._notification;
this._notification = null;
if (!this._notificationRemoved && notification.isTransient)
if (notification.isTransient)
notification.destroy(NotificationDestroyedReason.EXPIRED);
this._pointerInNotification = false;
this._notificationRemoved = false;
Meta.enable_unredirect_for_display(global.display);
this._banner.destroy();
this._banner.actor.destroy();
this._banner = null;
this.hide();
this.actor.hide();
}
_expandActiveNotification() {
@@ -1550,15 +1472,15 @@ var MessageTray = GObject.registerClass({
_ensureBannerFocused() {
this._notificationFocusGrabber.grabFocus();
}
});
};
Signals.addSignalMethods(MessageTray.prototype);
var SystemNotificationSource = GObject.registerClass(
class SystemNotificationSource extends Source {
_init() {
super._init(_("System Information"), 'dialog-information-symbolic');
var SystemNotificationSource = class SystemNotificationSource extends Source {
constructor() {
super(_("System Information"), 'dialog-information-symbolic');
}
open() {
this.destroy();
}
});
};

View File

@@ -8,9 +8,10 @@ const Layout = imports.ui.layout;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
var OPEN_AND_CLOSE_TIME = 100;
var FADE_OUT_DIALOG_TIME = 1000;
var OPEN_AND_CLOSE_TIME = 0.1;
var FADE_OUT_DIALOG_TIME = 1.0;
var State = {
OPENED: 0,
@@ -121,13 +122,13 @@ var ModalDialog = GObject.registerClass({
this.dialogLayout.opacity = 255;
if (this._lightbox)
this._lightbox.lightOn();
this._lightbox.show();
this.opacity = 0;
this.show();
this.ease({
opacity: 255,
duration: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.addTween(this,
{ opacity: 255,
time: this._shouldFadeIn ? OPEN_AND_CLOSE_TIME : 0,
transition: 'easeOutQuad',
onComplete: () => {
this._setState(State.OPENED);
this.emit('opened');
@@ -175,17 +176,16 @@ var ModalDialog = GObject.registerClass({
this.popModal(timestamp);
this._savedKeyFocus = null;
if (this._shouldFadeOut) {
this.ease({
opacity: 0,
duration: OPEN_AND_CLOSE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._closeComplete()
if (this._shouldFadeOut)
Tweener.addTween(this,
{ opacity: 0,
time: OPEN_AND_CLOSE_TIME,
transition: 'easeOutQuad',
onComplete: this._closeComplete.bind(this)
});
} else {
else
this._closeComplete();
}
}
// Drop modal status without closing the dialog; this makes the
// dialog insensitive as well, so it needs to be followed shortly
@@ -249,11 +249,13 @@ var ModalDialog = GObject.registerClass({
return;
this.popModal(timestamp);
this.dialogLayout.ease({
opacity: 0,
duration: FADE_OUT_DIALOG_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (this.state = State.FADED_OUT)
Tweener.addTween(this.dialogLayout,
{ opacity: 0,
time: FADE_OUT_DIALOG_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this._setState(State.FADED_OUT);
}
});
}
});

View File

@@ -1,5 +1,5 @@
/* exported MediaSection */
const { Gio, GObject, Shell, St } = imports.gi;
const { Gio, Shell, St } = imports.gi;
const Signals = imports.signals;
const Calendar = imports.ui.calendar;
@@ -19,10 +19,9 @@ const MprisPlayerProxy = Gio.DBusProxy.makeProxyWrapper(MprisPlayerIface);
const MPRIS_PLAYER_PREFIX = 'org.mpris.MediaPlayer2.';
var MediaMessage = GObject.registerClass(
class MediaMessage extends MessageList.Message {
_init(player) {
super._init('', '');
var MediaMessage = class MediaMessage extends MessageList.Message {
constructor(player) {
super('', '');
this._player = player;
@@ -49,7 +48,7 @@ class MediaMessage extends MessageList.Message {
this._update();
}
vfunc_clicked() {
_onClicked() {
this._player.raise();
Main.panel.closeCalendar();
}
@@ -72,15 +71,14 @@ class MediaMessage extends MessageList.Message {
}
let isPlaying = this._player.status == 'Playing';
let iconName = isPlaying
? 'media-playback-pause-symbolic'
let iconName = isPlaying ? 'media-playback-pause-symbolic'
: 'media-playback-start-symbolic';
this._playPauseButton.child.icon_name = iconName;
this._updateNavButton(this._prevButton, this._player.canGoPrevious);
this._updateNavButton(this._nextButton, this._player.canGoNext);
}
});
};
var MprisPlayer = class MprisPlayer {
constructor(busName) {
@@ -195,10 +193,9 @@ var MprisPlayer = class MprisPlayer {
};
Signals.addSignalMethods(MprisPlayer.prototype);
var MediaSection = GObject.registerClass(
class MediaSection extends MessageList.MessageListSection {
_init() {
super._init();
var MediaSection = class MediaSection extends MessageList.MessageListSection {
constructor() {
super();
this._players = new Map();
@@ -249,4 +246,4 @@ class MediaSection extends MessageList.MessageListSection {
if (newOwner && !oldOwner)
this._addPlayer(name);
}
});
};

View File

@@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported NotificationDaemon */
const { GdkPixbuf, Gio, GLib, GObject, Shell, St } = imports.gi;
const { GdkPixbuf, Gio, GLib, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Config = imports.misc.config;
const Main = imports.ui.main;
@@ -170,7 +171,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
// Ignore replacesId since we already sent back a
// NotificationClosed for that id.
id = this._nextNotificationId++;
let idleId = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
let idleId = Mainloop.idle_add(() => {
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
return GLib.SOURCE_REMOVE;
});
@@ -346,8 +347,7 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
notification.setTransient(!!hints['transient']);
let privacyScope = (hints['x-gnome-privacy-scope'] || 'user');
notification.setPrivacyScope(privacyScope == 'system'
? MessageTray.PrivacyScope.SYSTEM
notification.setPrivacyScope(privacyScope == 'system' ? MessageTray.PrivacyScope.SYSTEM
: MessageTray.PrivacyScope.USER);
let sourceGIcon = source.useNotificationIcon ? gicon : null;
@@ -412,10 +412,10 @@ var FdoNotificationDaemon = class FdoNotificationDaemon {
}
};
var FdoNotificationDaemonSource = GObject.registerClass(
var FdoNotificationDaemonSource =
class FdoNotificationDaemonSource extends MessageTray.Source {
_init(title, pid, sender, appId) {
super._init(title);
constructor(title, pid, sender, appId) {
super(title);
this.pid = pid;
this.app = this._getApp(appId);
@@ -464,7 +464,7 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
if (notification.resident && this.app && tracker.focus_app == this.app)
this.pushNotification(notification);
else
this.showNotification(notification);
this.notify(notification);
}
_getApp(appId) {
@@ -526,7 +526,7 @@ class FdoNotificationDaemonSource extends MessageTray.Source {
return null;
}
}
});
};
const PRIORITY_URGENCY_MAP = {
low: MessageTray.Urgency.LOW,
@@ -535,28 +535,27 @@ const PRIORITY_URGENCY_MAP = {
urgent: MessageTray.Urgency.CRITICAL
};
var GtkNotificationDaemonNotification = GObject.registerClass(
var GtkNotificationDaemonNotification =
class GtkNotificationDaemonNotification extends MessageTray.Notification {
_init(source, notification) {
super._init(source);
constructor(source, notification) {
super(source);
this._serialized = GLib.Variant.new('a{sv}', notification);
let { title,
body,
icon: gicon,
urgent,
priority,
buttons,
let { "title": title,
"body": body,
"icon": gicon,
"urgent": urgent,
"priority": priority,
"buttons": buttons,
"default-action": defaultAction,
"default-action-target": defaultActionTarget,
timestamp: time } = notification;
"timestamp": time } = notification;
if (priority) {
let urgency = PRIORITY_URGENCY_MAP[priority.unpack()];
this.setUrgency(urgency != undefined ? urgency : MessageTray.Urgency.NORMAL);
} else if (urgent) {
this.setUrgency(urgent.unpack()
? MessageTray.Urgency.CRITICAL
this.setUrgency(urgent.unpack() ? MessageTray.Urgency.CRITICAL
: MessageTray.Urgency.NORMAL);
} else {
this.setUrgency(MessageTray.Urgency.NORMAL);
@@ -590,8 +589,8 @@ class GtkNotificationDaemonNotification extends MessageTray.Notification {
}
_onButtonClicked(button) {
let { action, target } = button;
this._activateAction(action.unpack(), target);
let { 'action': action, 'target': actionTarget } = button;
this._activateAction(action.unpack(), actionTarget);
}
activate() {
@@ -602,7 +601,7 @@ class GtkNotificationDaemonNotification extends MessageTray.Notification {
serialize() {
return this._serialized;
}
});
};
const FdoApplicationIface = loadInterfaceXML('org.freedesktop.Application');
const FdoApplicationProxy = Gio.DBusProxy.makeProxyWrapper(FdoApplicationIface);
@@ -618,9 +617,9 @@ function getPlatformData() {
function InvalidAppError() {}
var GtkNotificationDaemonAppSource = GObject.registerClass(
var GtkNotificationDaemonAppSource =
class GtkNotificationDaemonAppSource extends MessageTray.Source {
_init(appId) {
constructor(appId) {
let objectPath = objectPathFromAppId(appId);
if (!GLib.Variant.is_object_path(objectPath))
throw new InvalidAppError();
@@ -629,7 +628,7 @@ class GtkNotificationDaemonAppSource extends MessageTray.Source {
if (!app)
throw new InvalidAppError();
super._init(app.get_name());
super(app.get_name());
this._appId = appId;
this._app = app;
@@ -690,7 +689,7 @@ class GtkNotificationDaemonAppSource extends MessageTray.Source {
this._notifications[notificationId] = notification;
if (showBanner)
this.showNotification(notification);
this.notify(notification);
else
this.pushNotification(notification);
@@ -716,7 +715,7 @@ class GtkNotificationDaemonAppSource extends MessageTray.Source {
}
return [this._appId, notifications];
}
});
};
const GtkNotificationsIface = loadInterfaceXML('org.gtk.Notifications');
@@ -742,7 +741,7 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
delete this._sources[appId];
this._saveNotifications();
});
source.connect('notify::count', this._saveNotifications.bind(this));
source.connect('count-updated', this._saveNotifications.bind(this));
Main.messageTray.add(source);
this._sources[appId] = source;
return source;
@@ -751,7 +750,6 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
_loadNotifications() {
this._isLoading = true;
try {
let value = global.get_persistent_state('a(sa(sv))', 'notifications');
if (value) {
let sources = value.deep_unpack();
@@ -773,12 +771,9 @@ var GtkNotificationDaemon = class GtkNotificationDaemon {
});
});
}
} catch (e) {
logError(e, 'Failed to load saved notifications');
} finally {
this._isLoading = false;
}
}
_saveNotifications() {
if (this._isLoading)

View File

@@ -1,33 +1,30 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported OsdMonitorLabeler */
const { Clutter, Gio, GObject, Meta, St } = imports.gi;
const { Clutter, Gio, Meta, St } = imports.gi;
const Main = imports.ui.main;
var OsdMonitorLabel = GObject.registerClass(
class OsdMonitorLabel extends St.Widget {
_init(monitor, label) {
super._init({ x_expand: true, y_expand: true });
var OsdMonitorLabel = class {
constructor(monitor, label) {
this._actor = new St.Widget({ x_expand: true,
y_expand: true });
this._monitor = monitor;
this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true });
this.add_actor(this._box);
this._actor.add_actor(this._box);
this._label = new St.Label({ style_class: 'osd-monitor-label',
text: label });
this._box.add(this._label);
Main.uiGroup.add_child(this);
Main.uiGroup.set_child_above_sibling(this, null);
Main.uiGroup.add_child(this._actor);
Main.uiGroup.set_child_above_sibling(this._actor, null);
this._position();
Meta.disable_unredirect_for_display(global.display);
this.connect('destroy', () => {
Meta.enable_unredirect_for_display(global.display);
});
}
_position() {
@@ -40,7 +37,12 @@ class OsdMonitorLabel extends St.Widget {
this._box.y = workArea.y;
}
});
destroy() {
this._actor.destroy();
Meta.enable_unredirect_for_display(global.display);
}
};
var OsdMonitorLabeler = class {
constructor() {

View File

@@ -2,14 +2,16 @@
/* exported OsdWindowManager */
const { Clutter, GLib, GObject, Meta, St } = imports.gi;
const Mainloop = imports.mainloop;
const BarLevel = imports.ui.barLevel;
const Layout = imports.ui.layout;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var HIDE_TIMEOUT = 1500;
var FADE_TIME = 100;
var LEVEL_ANIMATION_TIME = 100;
var FADE_TIME = 0.1;
var LEVEL_ANIMATION_TIME = 0.1;
var OsdWindowConstraint = GObject.registerClass(
class OsdWindowConstraint extends Clutter.Constraint {
@@ -41,25 +43,22 @@ class OsdWindowConstraint extends Clutter.Constraint {
}
});
var OsdWindow = GObject.registerClass(
class OsdWindow extends St.Widget {
_init(monitorIndex) {
super._init({
x_expand: true,
var OsdWindow = class {
constructor(monitorIndex) {
this.actor = new St.Widget({ x_expand: true,
y_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER
});
y_align: Clutter.ActorAlign.CENTER });
this._monitorIndex = monitorIndex;
let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
this.add_constraint(constraint);
this.actor.add_constraint(constraint);
this._boxConstraint = new OsdWindowConstraint();
this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true });
this._box.add_constraint(this._boxConstraint);
this.add_actor(this._box);
this.actor.add_actor(this._box);
this._icon = new St.Icon();
this._box.add(this._icon, { expand: true });
@@ -67,16 +66,13 @@ class OsdWindow extends St.Widget {
this._label = new St.Label();
this._box.add(this._label);
this._level = new BarLevel.BarLevel({
style_class: 'level',
value: 0
});
this._box.add(this._level);
this._level = new BarLevel.BarLevel(0, { styleClass: 'level' });
this._box.add(this._level.actor);
this._hideTimeoutId = 0;
this._reset();
this.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
this._monitorsChangedId =
Main.layoutManager.connect('monitors-changed',
@@ -86,7 +82,7 @@ class OsdWindow extends St.Widget {
themeContext.connect('notify::scale-factor',
this._relayout.bind(this));
this._relayout();
Main.uiGroup.add_child(this);
Main.uiGroup.add_child(this.actor);
}
_onDestroy() {
@@ -111,13 +107,13 @@ class OsdWindow extends St.Widget {
}
setLevel(value) {
this._level.visible = (value != undefined);
this._level.actor.visible = (value != undefined);
if (value != undefined) {
if (this.visible)
this._level.ease_property('value', value, {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: LEVEL_ANIMATION_TIME
});
if (this.actor.visible)
Tweener.addTween(this._level,
{ value: value,
time: LEVEL_ANIMATION_TIME,
transition: 'easeOutQuad' });
else
this._level.value = value;
}
@@ -131,23 +127,22 @@ class OsdWindow extends St.Widget {
if (!this._icon.gicon)
return;
if (!this.visible) {
if (!this.actor.visible) {
Meta.disable_unredirect_for_display(global.display);
super.show();
this.opacity = 0;
this.get_parent().set_child_above_sibling(this, null);
this.actor.show();
this.actor.opacity = 0;
this.actor.get_parent().set_child_above_sibling(this.actor, null);
this.ease({
opacity: 255,
duration: FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
Tweener.addTween(this.actor,
{ opacity: 255,
time: FADE_TIME,
transition: 'easeOutQuad' });
}
if (this._hideTimeoutId)
GLib.source_remove(this._hideTimeoutId);
this._hideTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT, HIDE_TIMEOUT, this._hide.bind(this));
Mainloop.source_remove(this._hideTimeoutId);
this._hideTimeoutId = Mainloop.timeout_add(HIDE_TIMEOUT,
this._hide.bind(this));
GLib.Source.set_name_by_id(this._hideTimeoutId, '[gnome-shell] this._hide');
}
@@ -155,16 +150,16 @@ class OsdWindow extends St.Widget {
if (!this._hideTimeoutId)
return;
GLib.source_remove(this._hideTimeoutId);
Mainloop.source_remove(this._hideTimeoutId);
this._hide();
}
_hide() {
this._hideTimeoutId = 0;
this.ease({
opacity: 0,
duration: FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.addTween(this.actor,
{ opacity: 0,
time: FADE_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this._reset();
Meta.enable_unredirect_for_display(global.display);
@@ -174,7 +169,7 @@ class OsdWindow extends St.Widget {
}
_reset() {
super.hide();
this.actor.hide();
this.setLabel(null);
this.setMaxLevel(null);
this.setLevel(null);
@@ -196,7 +191,7 @@ class OsdWindow extends St.Widget {
this._box.translation_y = Math.round(monitor.height / 4);
this._boxConstraint.minSize = popupSize;
}
});
};
var OsdWindowManager = class {
constructor() {
@@ -213,7 +208,7 @@ var OsdWindowManager = class {
}
for (let i = Main.layoutManager.monitors.length; i < this._osdWindows.length; i++) {
this._osdWindows[i].destroy();
this._osdWindows[i].actor.destroy();
this._osdWindows[i] = null;
}

View File

@@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Overview */
const { Clutter, GLib, GObject, Meta, Shell, St } = imports.gi;
const { Clutter, GLib, Meta, Shell, St } = imports.gi;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const Background = imports.ui.background;
@@ -12,15 +13,16 @@ const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray;
const OverviewControls = imports.ui.overviewControls;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode
var ANIMATION_TIME = 250;
var ANIMATION_TIME = 0.25;
// Must be less than ANIMATION_TIME, since we switch to
// or from the overview completely after ANIMATION_TIME,
// and don't want the shading animation to get cut off
var SHADE_ANIMATION_TIME = 200;
var SHADE_ANIMATION_TIME = .20;
var DND_WINDOW_SWITCH_TIMEOUT = 750;
@@ -42,9 +44,8 @@ var ShellInfo = class {
}
setMessage(text, options) {
options = Params.parse(options, {
undoCallback: null,
forFeedback: false,
options = Params.parse(options, { undoCallback: null,
forFeedback: false
});
let undoCallback = options.undoCallback;
@@ -72,108 +73,36 @@ var ShellInfo = class {
if (undoCallback)
notification.addAction(_("Undo"), this._onUndoClicked.bind(this));
this._source.showNotification(notification);
this._source.notify(notification);
}
};
var OverviewActor = GObject.registerClass(
class OverviewActor extends St.BoxLayout {
_init() {
super._init({
name: 'overview',
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
accessible_name: _("Overview"),
vertical: true
});
this.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
// Add a clone of the panel to the overview so spacing and such is
// automatic
let panelGhost = new St.Bin({
child: new Clutter.Clone({ source: Main.panel }),
reactive: false,
opacity: 0
});
this.add_actor(panelGhost);
this._searchEntry = new St.Entry({
style_class: 'search-entry',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
characters. */
hint_text: _("Type to search…"),
track_hover: true,
can_focus: true
});
let searchEntryBin = new St.Bin({
child: this._searchEntry,
x_align: St.Align.MIDDLE
});
this.add_actor(searchEntryBin);
this._controls = new OverviewControls.ControlsManager(this._searchEntry);
// Add our same-line elements after the search entry
this.add(this._controls, { y_fill: true, expand: true });
}
get dash() {
return this._controls.dash;
}
get searchEntry() {
return this._searchEntry;
}
get viewSelector() {
return this._controls.viewSelector;
}
});
var Overview = class {
constructor() {
this._overviewCreated = false;
this._initCalled = false;
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
this._sessionUpdated();
}
get dash() {
return this._overview.dash;
}
get dashIconSize() {
logError(new Error('Usage of Overview.\'dashIconSize\' is deprecated, ' +
'use \'dash.iconSize\' property instead'));
return this.dash.iconSize;
}
get viewSelector() {
return this._overview.viewSelector;
}
get animationInProgress() {
return this._animationInProgress;
}
get visible() {
return this._visible;
}
get visibleTarget() {
return this._visibleTarget;
}
_createOverview() {
if (this._overview)
if (this._overviewCreated)
return;
if (this.isDummy)
return;
this._overviewCreated = true;
this._overview = new St.BoxLayout({ name: 'overview',
/* Translators: This is the main view to select
activities. See also note for "Activities" string. */
accessible_name: _("Overview"),
vertical: true });
this._overview.add_constraint(new LayoutManager.MonitorConstraint({ primary: true }));
this._overview._delegate = this;
// The main Background actors are inside global.window_group which are
// hidden when displaying the overview, so we create a new
// one. Instances of this class share a single CoglTexture behind the
@@ -188,11 +117,11 @@ var Overview = class {
this._activationTime = 0;
this._visible = false; // animating to overview, in overview, animating out
this.visible = false; // animating to overview, in overview, animating out
this._shown = false; // show() and not hide()
this._modal = false; // have a modal grab
this._animationInProgress = false;
this._visibleTarget = false;
this.animationInProgress = false;
this.visibleTarget = false;
// During transitions, we raise this to the top to avoid having the overview
// area be reactive; it causes too many issues such as double clicks on
@@ -201,6 +130,9 @@ var Overview = class {
reactive: true });
Main.layoutManager.overviewGroup.add_child(this._coverPane);
this._coverPane.connect('event', () => Clutter.EVENT_STOP);
Main.layoutManager.overviewGroup.add_child(this._overview);
this._coverPane.hide();
// XDND
@@ -242,13 +174,11 @@ var Overview = class {
_unshadeBackgrounds() {
let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) {
backgrounds[i].ease_property('brightness', 1.0, {
duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
backgrounds[i].ease_property('vignette-sharpness', 0.0, {
duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
Tweener.addTween(backgrounds[i],
{ brightness: 1.0,
vignette_sharpness: 0.0,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
}
@@ -256,13 +186,11 @@ var Overview = class {
_shadeBackgrounds() {
let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) {
backgrounds[i].ease_property('brightness', Lightbox.VIGNETTE_BRIGHTNESS, {
duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
backgrounds[i].ease_property('vignette-sharpness', Lightbox.VIGNETTE_SHARPNESS, {
duration: SHADE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
Tweener.addTween(backgrounds[i],
{ brightness: Lightbox.VIGNETTE_BRIGHTNESS,
vignette_sharpness: Lightbox.VIGNETTE_SHARPNESS,
time: SHADE_ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
}
@@ -282,12 +210,41 @@ var Overview = class {
if (this.isDummy)
return;
this._overview = new OverviewActor();
this._overview._delegate = this;
Main.layoutManager.overviewGroup.add_child(this._overview);
this._shellInfo = new ShellInfo();
// Add a clone of the panel to the overview so spacing and such is
// automatic
this._panelGhost = new St.Bin({ child: new Clutter.Clone({ source: Main.panel }),
reactive: false,
opacity: 0 });
this._overview.add_actor(this._panelGhost);
this._searchEntry = new St.Entry({ style_class: 'search-entry',
/* Translators: this is the text displayed
in the search entry when no search is
active; it should not exceed ~30
characters. */
hint_text: _("Type to search…"),
track_hover: true,
can_focus: true });
this._searchEntryBin = new St.Bin({ child: this._searchEntry,
x_align: St.Align.MIDDLE });
this._overview.add_actor(this._searchEntryBin);
// Create controls
this._controls = new OverviewControls.ControlsManager(this._searchEntry);
this._dash = this._controls.dash;
this.viewSelector = this._controls.viewSelector;
// Add our same-line elements after the search entry
this._overview.add(this._controls.actor, { y_fill: true, expand: true });
// TODO - recalculate everything when desktop size changes
this.dashIconSize = this._dash.iconSize;
this._dash.connect('icon-size-changed', () => {
this.dashIconSize = this._dash.iconSize;
});
Main.layoutManager.connect('monitors-changed', this._relayout.bind(this));
this._relayout();
}
@@ -340,7 +297,7 @@ var Overview = class {
_resetWindowSwitchTimeout() {
if (this._windowSwitchTimeoutId != 0) {
GLib.source_remove(this._windowSwitchTimeoutId);
Mainloop.source_remove(this._windowSwitchTimeoutId);
this._windowSwitchTimeoutId = 0;
}
}
@@ -363,9 +320,7 @@ var Overview = class {
if (targetIsWindow) {
this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
this._windowSwitchTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
DND_WINDOW_SWITCH_TIMEOUT,
this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
() => {
this._windowSwitchTimeoutId = 0;
Main.activateWindow(dragEvent.targetActor._delegate.metaWindow,
@@ -466,17 +421,16 @@ var Overview = class {
focusSearch() {
this.show();
this._overview.searchEntry.grab_key_focus();
this._searchEntry.grab_key_focus();
}
fadeInDesktop() {
this._desktopFade.opacity = 0;
this._desktopFade.show();
this._desktopFade.ease({
opacity: 255,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: ANIMATION_TIME
});
Tweener.addTween(this._desktopFade,
{ opacity: 255,
time: ANIMATION_TIME,
transition: 'easeOutQuad' });
}
fadeOutDesktop() {
@@ -490,10 +444,10 @@ var Overview = class {
this._desktopFade.opacity = 255;
this._desktopFade.show();
this._desktopFade.ease({
opacity: 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: ANIMATION_TIME
Tweener.addTween(this._desktopFade,
{ opacity: 0,
time: ANIMATION_TIME,
transition: 'easeOutQuad'
});
}
@@ -504,11 +458,11 @@ var Overview = class {
// the overview if the user both triggered the hot corner and
// clicked the Activities button.
shouldToggleByCornerOrButton() {
if (this._animationInProgress)
if (this.animationInProgress)
return false;
if (this._inItemDrag || this._inWindowDrag)
return false;
if (!this._activationTime ||
if (this._activationTime == 0 ||
GLib.get_monotonic_time() / GLib.USEC_PER_SEC - this._activationTime > OVERVIEW_ACTIVATION_TIMEOUT)
return true;
return false;
@@ -518,20 +472,22 @@ var Overview = class {
// We delay grab changes during animation so that when removing the
// overview we don't have a problem with the release of a press/release
// going to an application.
if (this._animationInProgress)
if (this.animationInProgress)
return true;
if (this._shown) {
let shouldBeModal = !this._inXdndDrag;
if (shouldBeModal && !this._modal) {
let actionMode = Shell.ActionMode.OVERVIEW;
if (Main.pushModal(this._overview, { actionMode })) {
if (shouldBeModal) {
if (!this._modal) {
if (Main.pushModal(this._overview,
{ actionMode: Shell.ActionMode.OVERVIEW })) {
this._modal = true;
} else {
this.hide();
return false;
}
}
}
} else {
if (this._modal) {
Main.popModal(this._overview);
@@ -560,23 +516,24 @@ var Overview = class {
_animateVisible() {
if (this._visible || this._animationInProgress)
if (this.visible || this.animationInProgress)
return;
this._visible = true;
this._animationInProgress = true;
this._visibleTarget = true;
this.visible = true;
this.animationInProgress = true;
this.visibleTarget = true;
this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC;
Meta.disable_unredirect_for_display(global.display);
this.viewSelector.show();
this._overview.opacity = 0;
this._overview.ease({
opacity: 255,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: ANIMATION_TIME,
onComplete: () => this._showDone()
Tweener.addTween(this._overview,
{ opacity: 255,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._showDone,
onCompleteScope: this
});
this._shadeBackgrounds();
@@ -586,7 +543,7 @@ var Overview = class {
}
_showDone() {
this._animationInProgress = false;
this.animationInProgress = false;
this._desktopFade.hide();
this._coverPane.hide();
@@ -626,20 +583,21 @@ var Overview = class {
}
_animateNotVisible() {
if (!this._visible || this._animationInProgress)
if (!this.visible || this.animationInProgress)
return;
this._animationInProgress = true;
this._visibleTarget = false;
this.animationInProgress = true;
this.visibleTarget = false;
this.viewSelector.animateFromOverview();
// Make other elements fade out.
this._overview.ease({
opacity: 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: ANIMATION_TIME,
onComplete: () => this._hideDone()
Tweener.addTween(this._overview,
{ opacity: 0,
transition: 'easeOutQuad',
time: ANIMATION_TIME,
onComplete: this._hideDone,
onCompleteScope: this
});
this._unshadeBackgrounds();
@@ -656,8 +614,8 @@ var Overview = class {
this._desktopFade.hide();
this._coverPane.hide();
this._visible = false;
this._animationInProgress = false;
this.visible = false;
this.animationInProgress = false;
this.emit('hidden');
// Handle any calls to show* while we were hiding
@@ -673,17 +631,14 @@ var Overview = class {
if (this.isDummy)
return;
if (this._visible)
if (this.visible)
this.hide();
else
this.show();
}
getShowAppsButton() {
logError(new Error('Usage of Overview.\'getShowAppsButton\' is deprecated, ' +
'use \'dash.showAppsButton\' property instead'));
return this.dash.showAppsButton;
return this._dash.showAppsButton;
}
};
Signals.addSignalMethods(Overview.prototype);

View File

@@ -6,16 +6,17 @@ const { Clutter, GObject, Meta, St } = imports.gi;
const Dash = imports.ui.dash;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const ViewSelector = imports.ui.viewSelector;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
var SIDE_CONTROLS_ANIMATION_TIME = 160;
var SIDE_CONTROLS_ANIMATION_TIME = 0.16;
function getRtlSlideDirection(direction, actor) {
let rtl = (actor.text_direction == Clutter.TextDirection.RTL);
if (rtl)
direction = (direction == SlideDirection.LEFT)
? SlideDirection.RIGHT : SlideDirection.LEFT;
direction = (direction == SlideDirection.LEFT) ?
SlideDirection.RIGHT : SlideDirection.LEFT;
return direction;
}
@@ -25,21 +26,11 @@ var SlideDirection = {
RIGHT: 1
};
var SlideLayout = GObject.registerClass({
Properties: {
'slide-x': GObject.ParamSpec.double(
'slide-x', 'slide-x', 'slide-x',
GObject.ParamFlags.READWRITE,
0, 1, 1),
'translation-x': GObject.ParamSpec.double(
'translation-x', 'translation-x', 'translation-x',
GObject.ParamFlags.READWRITE,
-Infinity, Infinity, 0)
}
}, class SlideLayout extends Clutter.FixedLayout {
var SlideLayout = GObject.registerClass(
class SlideLayout extends Clutter.FixedLayout {
_init(params) {
this._slideX = 1;
this._translationX = 0;
this._translationX = undefined;
this._direction = SlideDirection.LEFT;
super._init(params);
@@ -67,9 +58,8 @@ var SlideLayout = GObject.registerClass({
// flags only determine what to do if the allocated box is bigger
// than the actor's box.
let realDirection = getRtlSlideDirection(this._direction, child);
let alignX = (realDirection == SlideDirection.LEFT)
? availWidth - natWidth
: availWidth - natWidth * this._slideX;
let alignX = (realDirection == SlideDirection.LEFT) ? (availWidth - natWidth)
: (availWidth - natWidth * this._slideX);
let actorBox = new Clutter.ActorBox();
actorBox.x1 = box.x1 + alignX + this._translationX;
@@ -80,17 +70,12 @@ var SlideLayout = GObject.registerClass({
child.allocate(actorBox, flags);
}
// eslint-disable-next-line camelcase
set slide_x(value) {
if (this._slideX == value)
return;
set slideX(value) {
this._slideX = value;
this.notify('slide-x');
this.layout_changed();
}
// eslint-disable-next-line camelcase
get slide_x() {
get slideX() {
return this._slideX;
}
@@ -103,37 +88,29 @@ var SlideLayout = GObject.registerClass({
return this._direction;
}
// eslint-disable-next-line camelcase
set translation_x(value) {
if (this._translationX == value)
return;
set translationX(value) {
this._translationX = value;
this.notify('translation-x');
this.layout_changed();
}
// eslint-disable-next-line camelcase
get translation_x() {
get translationX() {
return this._translationX;
}
});
var SlidingControl = GObject.registerClass(
class SlidingControl extends St.Widget {
_init(params) {
var SlidingControl = class {
constructor(params) {
params = Params.parse(params, { slideDirection: SlideDirection.LEFT });
this.layout = new SlideLayout();
this.layout.slideDirection = params.slideDirection;
super._init({
layout_manager: this.layout,
style_class: 'overview-controls',
clip_to_allocation: true
});
this._visible = true;
this._inDrag = false;
this.layout = new SlideLayout();
this.layout.slideDirection = params.slideDirection;
this.actor = new St.Widget({ layout_manager: this.layout,
style_class: 'overview-controls',
clip_to_allocation: true });
Main.overview.connect('hiding', this._onOverviewHiding.bind(this));
Main.overview.connect('item-drag-begin', this._onDragBegin.bind(this));
@@ -150,20 +127,19 @@ class SlidingControl extends St.Widget {
}
_updateSlide() {
this.ease_property('@layout.slide-x', this._getSlide(), {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: SIDE_CONTROLS_ANIMATION_TIME,
});
Tweener.addTween(this.layout, { slideX: this._getSlide(),
time: SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad' });
}
getVisibleWidth() {
let child = this.get_first_child();
let child = this.actor.get_first_child();
let [, , natWidth] = child.get_preferred_size();
return natWidth;
}
_getTranslation() {
let child = this.get_first_child();
let child = this.actor.get_first_child();
let direction = getRtlSlideDirection(this.layout.slideDirection, child);
let visibleWidth = this.getVisibleWidth();
@@ -185,14 +161,13 @@ class SlidingControl extends St.Widget {
translationEnd = translation;
}
if (this.layout.translation_x == translationEnd)
if (this.layout.translationX == translationEnd)
return;
this.layout.translation_x = translationStart;
this.ease_property('@layout.translation-x', translationEnd, {
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: SIDE_CONTROLS_ANIMATION_TIME,
});
this.layout.translationX = translationStart;
Tweener.addTween(this.layout, { translationX: translationEnd,
time: SIDE_CONTROLS_ANIMATION_TIME,
transition: 'easeOutQuad' });
}
_onOverviewHiding() {
@@ -221,30 +196,28 @@ class SlidingControl extends St.Widget {
}
fadeIn() {
this.ease({
opacity: 255,
duration: SIDE_CONTROLS_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_IN_QUAD
Tweener.addTween(this.actor, { opacity: 255,
time: SIDE_CONTROLS_ANIMATION_TIME / 2,
transition: 'easeInQuad'
});
}
fadeHalf() {
this.ease({
opacity: 128,
duration: SIDE_CONTROLS_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
Tweener.addTween(this.actor, { opacity: 128,
time: SIDE_CONTROLS_ANIMATION_TIME / 2,
transition: 'easeOutQuad'
});
}
slideIn() {
this._visible = true;
// we will update slide_x and the translation from pageEmpty
// we will update slideX and the translation from pageEmpty
}
slideOut() {
this._visible = false;
this._updateTranslation();
// we will update slide_x from pageEmpty
// we will update slideX from pageEmpty
}
pageEmpty() {
@@ -252,38 +225,36 @@ class SlidingControl extends St.Widget {
// selector; this means we can now safely set the full slide for
// the next page, since slideIn or slideOut might have been called,
// changing the visiblity
this.remove_transition('@layout.slide-x');
this.layout.slide_x = this._getSlide();
this.layout.slideX = this._getSlide();
this._updateTranslation();
}
});
};
var ThumbnailsSlider = GObject.registerClass(
class ThumbnailsSlider extends SlidingControl {
_init(thumbnailsBox) {
super._init({ slideDirection: SlideDirection.RIGHT });
var ThumbnailsSlider = class extends SlidingControl {
constructor(thumbnailsBox) {
super({ slideDirection: SlideDirection.RIGHT });
this._thumbnailsBox = thumbnailsBox;
this.request_mode = Clutter.RequestMode.WIDTH_FOR_HEIGHT;
this.reactive = true;
this.track_hover = true;
this.add_actor(this._thumbnailsBox);
this.actor.request_mode = Clutter.RequestMode.WIDTH_FOR_HEIGHT;
this.actor.reactive = true;
this.actor.track_hover = true;
this.actor.add_actor(this._thumbnailsBox);
Main.layoutManager.connect('monitors-changed', this._updateSlide.bind(this));
global.workspace_manager.connect('active-workspace-changed',
this._updateSlide.bind(this));
global.workspace_manager.connect('notify::n-workspaces',
this._updateSlide.bind(this));
this.connect('notify::hover', this._updateSlide.bind(this));
this._thumbnailsBox.bind_property('visible', this, 'visible', GObject.BindingFlags.SYNC_CREATE);
this.actor.connect('notify::hover', this._updateSlide.bind(this));
this._thumbnailsBox.bind_property('visible', this.actor, 'visible', GObject.BindingFlags.SYNC_CREATE);
}
_getAlwaysZoomOut() {
// Always show the pager on hover, during a drag, or if workspaces are
// actually used, e.g. there are windows on any non-active workspace
let workspaceManager = global.workspace_manager;
let alwaysZoomOut = this.hover ||
let alwaysZoomOut = this.actor.hover ||
this._inDrag ||
!Meta.prefs_get_dynamic_workspaces() ||
workspaceManager.n_workspaces > 2 ||
@@ -308,12 +279,12 @@ class ThumbnailsSlider extends SlidingControl {
}
getNonExpandedWidth() {
let child = this.get_first_child();
let child = this.actor.get_first_child();
return child.get_theme_node().get_length('visible-width');
}
_onDragEnd() {
this.sync_hover();
this.actor.sync_hover();
super._onDragEnd();
}
@@ -325,7 +296,7 @@ class ThumbnailsSlider extends SlidingControl {
if (alwaysZoomOut)
return 1;
let child = this.get_first_child();
let child = this.actor.get_first_child();
let preferredHeight = child.get_preferred_height(-1)[1];
let expandedWidth = child.get_preferred_width(preferredHeight)[1];
@@ -339,25 +310,24 @@ class ThumbnailsSlider extends SlidingControl {
else
return this.getNonExpandedWidth();
}
});
};
var DashSlider = GObject.registerClass(
class DashSlider extends SlidingControl {
_init(dash) {
super._init({ slideDirection: SlideDirection.LEFT });
var DashSlider = class extends SlidingControl {
constructor(dash) {
super({ slideDirection: SlideDirection.LEFT });
this._dash = dash;
// SlideLayout reads the actor's expand flags to decide
// whether to allocate the natural size to its child, or the whole
// available allocation
this._dash.x_expand = true;
this._dash.actor.x_expand = true;
this.x_expand = true;
this.x_align = Clutter.ActorAlign.START;
this.y_expand = true;
this.actor.x_expand = true;
this.actor.x_align = Clutter.ActorAlign.START;
this.actor.y_expand = true;
this.add_actor(this._dash);
this.actor.add_actor(this._dash.actor);
this._dash.connect('icon-size-changed', this._updateSlide.bind(this));
}
@@ -376,7 +346,7 @@ class DashSlider extends SlidingControl {
_onWindowDragEnd() {
this.fadeIn();
}
});
};
var DashSpacer = GObject.registerClass(
class DashSpacer extends St.Widget {
@@ -421,21 +391,12 @@ var ControlsLayout = GObject.registerClass({
}
});
var ControlsManager = GObject.registerClass(
class ControlsManager extends St.Widget {
_init(searchEntry) {
let layout = new ControlsLayout();
super._init({
layout_manager: layout,
x_expand: true,
y_expand: true,
clip_to_allocation: true
});
var ControlsManager = class {
constructor(searchEntry) {
this.dash = new Dash.Dash();
this._dashSlider = new DashSlider(this.dash);
this._dashSpacer = new DashSpacer();
this._dashSpacer.setDashActor(this._dashSlider);
this._dashSpacer.setDashActor(this._dashSlider.actor);
this._thumbnailsBox = new WorkspaceThumbnail.ThumbnailsBox();
this._thumbnailsSlider = new ThumbnailsSlider(this._thumbnailsBox);
@@ -445,15 +406,20 @@ class ControlsManager extends St.Widget {
this.viewSelector.connect('page-changed', this._setVisibility.bind(this));
this.viewSelector.connect('page-empty', this._onPageEmpty.bind(this));
let layout = new ControlsLayout();
this.actor = new St.Widget({ layout_manager: layout,
x_expand: true, y_expand: true,
clip_to_allocation: true });
this._group = new St.BoxLayout({ name: 'overview-group',
x_expand: true, y_expand: true });
this.add_actor(this._group);
this.actor.add_actor(this._group);
this.add_actor(this._dashSlider);
this.actor.add_actor(this._dashSlider.actor);
this._group.add_actor(this._dashSpacer);
this._group.add(this.viewSelector, { x_fill: true, expand: true });
this._group.add_actor(this._thumbnailsSlider);
this._group.add(this.viewSelector.actor, { x_fill: true,
expand: true });
this._group.add_actor(this._thumbnailsSlider.actor);
layout.connect('allocation-changed', this._updateWorkspacesGeometry.bind(this));
@@ -461,18 +427,18 @@ class ControlsManager extends St.Widget {
}
_updateWorkspacesGeometry() {
let [x, y] = this.get_transformed_position();
let [width, height] = this.get_transformed_size();
let [x, y] = this.actor.get_transformed_position();
let [width, height] = this.actor.get_transformed_size();
let geometry = { x: x, y: y, width: width, height: height };
let spacing = this.get_theme_node().get_length('spacing');
let spacing = this.actor.get_theme_node().get_length('spacing');
let dashWidth = this._dashSlider.getVisibleWidth() + spacing;
let thumbnailsWidth = this._thumbnailsSlider.getNonExpandedWidth() + spacing;
geometry.width -= dashWidth;
geometry.width -= thumbnailsWidth;
if (this.get_text_direction() == Clutter.TextDirection.LTR)
if (this.actor.get_text_direction() == Clutter.TextDirection.LTR)
geometry.x += dashWidth;
else
geometry.x += thumbnailsWidth;
@@ -519,4 +485,4 @@ class ControlsManager extends St.Widget {
this._updateSpacerVisibility();
}
});
};

View File

@@ -1,5 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported PadOsd, PadOsdService */
/* exported PadOsdService */
const { Atk, Clutter, GDesktopEnums, Gio,
GLib, GObject, Gtk, Meta, Rsvg, St } = imports.gi;
@@ -22,32 +22,26 @@ const CCW = 1;
const UP = 0;
const DOWN = 1;
var PadChooser = GObject.registerClass({
Signals: { 'pad-selected': { param_types: [Clutter.InputDevice.$gtype] } }
}, class PadChooser extends St.Button {
_init(device, groupDevices) {
super._init({
style_class: 'pad-chooser-button',
var PadChooser = class {
constructor(device, groupDevices) {
this.actor = new St.Button({ style_class: 'pad-chooser-button',
toggle_mode: true,
x_fill: false,
y_fill: false,
x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE
});
y_align: St.Align.MIDDLE });
this.currentDevice = device;
this._padChooserMenu = null;
let arrow = new St.Icon({ style_class: 'popup-menu-arrow',
icon_name: 'pan-down-symbolic',
accessible_role: Atk.Role.ARROW });
this.set_child(arrow);
this.actor.set_child(arrow);
this._ensureMenu(groupDevices);
this.connect('destroy', this._onDestroy.bind(this));
}
vfunc_clicked() {
if (this.get_checked()) {
this.actor.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('clicked', actor => {
if (actor.get_checked()) {
if (this._padChooserMenu != null)
this._padChooserMenu.open(true);
else
@@ -55,12 +49,13 @@ var PadChooser = GObject.registerClass({
} else {
this._padChooserMenu.close(true);
}
});
}
_ensureMenu(devices) {
this._padChooserMenu = new PopupMenu.PopupMenu(this, 0.5, St.Side.TOP);
this._padChooserMenu = new PopupMenu.PopupMenu(this.actor, 0.5, St.Side.TOP);
this._padChooserMenu.connect('menu-closed', () => {
this.set_checked(false);
this.actor.set_checked(false);
});
this._padChooserMenu.actor.hide();
Main.uiGroup.add_actor(this._padChooserMenu.actor);
@@ -83,20 +78,24 @@ var PadChooser = GObject.registerClass({
update(devices) {
if (this._padChooserMenu)
this._padChooserMenu.actor.destroy();
this.set_checked(false);
this.actor.set_checked(false);
this._ensureMenu(devices);
}
});
var KeybindingEntry = GObject.registerClass({
GTypeName: 'PadOsd_KeybindingEntry',
Signals: { 'keybinding-edited': {} }
}, class KeybindingEntry extends St.Entry {
_init() {
super._init({ hint_text: _("New shortcut…"), style: 'width: 10em' });
destroy() {
this.actor.destroy();
}
};
Signals.addSignalMethods(PadChooser.prototype);
var KeybindingEntry = class {
constructor() {
this.actor = new St.Entry({ hint_text: _("New shortcut…"),
style: 'width: 10em' });
this.actor.connect('captured-event', this._onCapturedEvent.bind(this));
}
vfunc_captured_event(event) {
_onCapturedEvent(actor, event) {
if (event.type() != Clutter.EventType.KEY_PRESS)
return Clutter.EVENT_PROPAGATE;
@@ -104,24 +103,23 @@ var KeybindingEntry = GObject.registerClass({
event.get_key_symbol(),
event.get_key_code(),
event.get_state());
this.set_text(str);
this.actor.set_text(str);
this.emit('keybinding-edited', str);
return Clutter.EVENT_STOP;
}
});
};
Signals.addSignalMethods(KeybindingEntry.prototype);
var ActionComboBox = GObject.registerClass({
GTypeName: 'PadOsd_ActionComboBox',
Signals: { 'action-selected': { param_types: [GObject.TYPE_INT] } }
}, class ActionComboBox extends St.Button {
_init() {
super._init({ style_class: 'button' });
this.set_toggle_mode(true);
var ActionComboBox = class {
constructor() {
this.actor = new St.Button({ style_class: 'button' });
this.actor.connect('clicked', this._onButtonClicked.bind(this));
this.actor.set_toggle_mode(true);
let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
spacing: 6 });
let box = new St.Widget({ layout_manager: boxLayout });
this.set_child(box);
this.actor.set_child(box);
this._label = new St.Label({ style_class: 'combo-box-label' });
box.add_child(this._label);
@@ -133,9 +131,9 @@ var ActionComboBox = GObject.registerClass({
y_align: Clutter.ActorAlign.CENTER });
box.add_child(arrow);
this._editMenu = new PopupMenu.PopupMenu(this, 0, St.Side.TOP);
this._editMenu = new PopupMenu.PopupMenu(this.actor, 0, St.Side.TOP);
this._editMenu.connect('menu-closed', () => {
this.set_checked(false);
this.actor.set_checked(false);
});
this._editMenu.actor.hide();
Main.uiGroup.add_actor(this._editMenu.actor);
@@ -181,8 +179,8 @@ var ActionComboBox = GObject.registerClass({
this._editMenu.close(true);
}
vfunc_clicked() {
if (this.get_checked())
_onButtonClicked() {
if (this.actor.get_checked())
this.popup();
else
this.popdown();
@@ -191,40 +189,38 @@ var ActionComboBox = GObject.registerClass({
setButtonActionsActive(active) {
this._buttonItems.forEach(item => item.setSensitive(active));
}
});
};
Signals.addSignalMethods(ActionComboBox.prototype);
var ActionEditor = GObject.registerClass({
GTypeName: 'PadOsd_ActionEditor',
Signals: { 'done': {} }
}, class ActionEditor extends St.Widget {
_init() {
var ActionEditor = class {
constructor() {
let boxLayout = new Clutter.BoxLayout({ orientation: Clutter.Orientation.HORIZONTAL,
spacing: 12 });
super._init({ layout_manager: boxLayout });
this.actor = new St.Widget({ layout_manager: boxLayout });
this._actionComboBox = new ActionComboBox();
this._actionComboBox.connect('action-selected', this._onActionSelected.bind(this));
this.add_actor(this._actionComboBox);
this.actor.add_actor(this._actionComboBox.actor);
this._keybindingEdit = new KeybindingEntry();
this._keybindingEdit.connect('keybinding-edited', this._onKeybindingEdited.bind(this));
this.add_actor(this._keybindingEdit);
this.actor.add_actor(this._keybindingEdit.actor);
this._doneButton = new St.Button({ label: _("Done"),
style_class: 'button',
x_expand: false });
this._doneButton.connect('clicked', this._onEditingDone.bind(this));
this.add_actor(this._doneButton);
this.actor.add_actor(this._doneButton);
}
_updateKeybindingEntryState() {
if (this._currentAction == GDesktopEnums.PadButtonAction.KEYBINDING) {
this._keybindingEdit.set_text(this._currentKeybinding);
this._keybindingEdit.show();
this._keybindingEdit.grab_key_focus();
this._keybindingEdit.actor.set_text(this._currentKeybinding);
this._keybindingEdit.actor.show();
this._keybindingEdit.actor.grab_key_focus();
} else {
this._keybindingEdit.hide();
this._keybindingEdit.actor.hide();
}
}
@@ -242,7 +238,7 @@ var ActionEditor = GObject.registerClass({
close() {
this._actionComboBox.popdown();
this.hide();
this.actor.hide();
}
_onKeybindingEdited(entry, keybinding) {
@@ -276,7 +272,8 @@ var ActionEditor = GObject.registerClass({
this.close();
this.emit('done');
}
});
};
Signals.addSignalMethods(ActionEditor.prototype);
var PadDiagram = GObject.registerClass({
Properties: {
@@ -618,18 +615,8 @@ var PadDiagram = GObject.registerClass({
}
});
var PadOsd = GObject.registerClass({
Signals: { 'pad-selected': { param_types: [Clutter.InputDevice.$gtype] } }
}, class PadOsd extends St.BoxLayout {
_init(padDevice, settings, imagePath, editionMode, monitorIndex) {
super._init({
style_class: 'pad-osd-window',
vertical: true,
x_expand: true,
y_expand: true,
reactive: true
});
var PadOsd = class {
constructor(padDevice, settings, imagePath, editionMode, monitorIndex) {
this.padDevice = padDevice;
this._groupPads = [padDevice];
this._settings = settings;
@@ -666,18 +653,23 @@ var PadOsd = GObject.registerClass({
this._groupPads.push(device);
});
this.connect('destroy', this._onDestroy.bind(this));
Main.uiGroup.add_actor(this);
this.actor = new St.BoxLayout({ style_class: 'pad-osd-window',
x_expand: true,
y_expand: true,
vertical: true,
reactive: true });
this.actor.connect('destroy', this._onDestroy.bind(this));
Main.uiGroup.add_actor(this.actor);
this._monitorIndex = monitorIndex;
let constraint = new Layout.MonitorConstraint({ index: monitorIndex });
this.add_constraint(constraint);
this.actor.add_constraint(constraint);
this._titleBox = new St.BoxLayout({ style_class: 'pad-osd-title-box',
vertical: false,
x_expand: false,
x_align: Clutter.ActorAlign.CENTER });
this.add_actor(this._titleBox);
this.actor.add_actor(this._titleBox);
let labelBox = new St.BoxLayout({ style_class: 'pad-osd-title-menu-box',
vertical: true });
@@ -698,10 +690,10 @@ var PadOsd = GObject.registerClass({
this._padDiagram = new PadDiagram({ image: this._imagePath,
left_handed: settings.get_boolean('left-handed'),
editor_actor: this._actionEditor,
editor_actor: this._actionEditor.actor,
x_expand: true,
y_expand: true });
this.add_actor(this._padDiagram);
this.actor.add_actor(this._padDiagram);
// FIXME: Fix num buttons.
let i = 0;
@@ -732,7 +724,7 @@ var PadOsd = GObject.registerClass({
x_expand: true,
x_align: Clutter.ActorAlign.CENTER,
y_align: Clutter.ActorAlign.CENTER });
this.add_actor(buttonBox);
this.actor.add_actor(buttonBox);
this._editButton = new St.Button({ label: _("Edit…"),
style_class: 'button',
x_align: Clutter.ActorAlign.CENTER,
@@ -743,7 +735,7 @@ var PadOsd = GObject.registerClass({
buttonBox.add_actor(this._editButton);
this._syncEditionMode();
Main.pushModal(this);
Main.pushModal(this.actor);
}
_updatePadChooser() {
@@ -753,7 +745,7 @@ var PadOsd = GObject.registerClass({
this._padChooser.connect('pad-selected', (chooser, pad) => {
this._requestForOtherPad(pad);
});
this._titleBox.add_child(this._padChooser);
this._titleBox.add_child(this._padChooser.actor);
} else {
this._padChooser.update(this._groupPads);
}
@@ -926,8 +918,12 @@ var PadOsd = GObject.registerClass({
this._syncEditionMode();
}
destroy() {
this.actor.destroy();
}
_onDestroy() {
Main.popModal(this);
Main.popModal(this.actor);
this._actionEditor.close();
let deviceManager = Clutter.DeviceManager.get_default();
@@ -945,9 +941,11 @@ var PadOsd = GObject.registerClass({
this._capturedEventId = 0;
}
this.actor = null;
this.emit('closed');
}
});
};
Signals.addSignalMethods(PadOsd.prototype);
const PadOsdIface = loadInterfaceXML('org.gnome.Shell.Wacom.PadOsd');

View File

@@ -1,36 +1,34 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported PageIndicators, AnimatedPageIndicators */
const { Clutter, GLib, GObject, Meta, St } = imports.gi;
const { Clutter, GObject, St } = imports.gi;
const Tweener = imports.ui.tweener;
const { ANIMATION_TIME_OUT, ANIMATION_MAX_DELAY_OUT_FOR_ITEM, AnimationDirection } = imports.ui.iconGrid;
var INDICATORS_BASE_TIME = 250;
var INDICATORS_BASE_TIME_OUT = 125;
var INDICATORS_ANIMATION_DELAY = 125;
var INDICATORS_ANIMATION_DELAY_OUT = 62.5;
var INDICATORS_ANIMATION_MAX_TIME = 750;
var SWITCH_TIME = 400;
var INDICATORS_BASE_TIME = 0.25;
var INDICATORS_BASE_TIME_OUT = 0.125;
var INDICATORS_ANIMATION_DELAY = 0.125;
var INDICATORS_ANIMATION_DELAY_OUT = 0.0625;
var INDICATORS_ANIMATION_MAX_TIME = 0.75;
var SWITCH_TIME = 0.4;
var INDICATORS_ANIMATION_MAX_TIME_OUT =
Math.min (SWITCH_TIME,
ANIMATION_TIME_OUT + ANIMATION_MAX_DELAY_OUT_FOR_ITEM);
var ANIMATION_DELAY = 100;
var ANIMATION_DELAY = 0.1;
var PageIndicators = GObject.registerClass({
Signals: { 'page-activated': { param_types: [GObject.TYPE_INT] } }
}, class PageIndicators extends St.BoxLayout {
_init(orientation = Clutter.Orientation.VERTICAL) {
let vertical = orientation == Clutter.Orientation.VERTICAL;
super._init({
style_class: 'page-indicators',
_init(vertical = true) {
super._init({ style_class: 'page-indicators',
vertical,
x_expand: true, y_expand: true,
x_align: vertical ? Clutter.ActorAlign.END : Clutter.ActorAlign.CENTER,
y_align: vertical ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.END,
reactive: true,
clip_to_allocation: true
});
clip_to_allocation: true });
this._nPages = 0;
this._currentPage = undefined;
this._reactive = true;
@@ -96,26 +94,10 @@ var PageIndicators = GObject.registerClass({
var AnimatedPageIndicators = GObject.registerClass(
class AnimatedPageIndicators extends PageIndicators {
_init() {
super._init();
this.connect('destroy', this._onDestroy.bind(this));
}
super._init(true);
_onDestroy() {
if (this.animateLater) {
Meta.later_remove(this.animateLater);
this.animateLater = 0;
}
}
vfunc_map() {
super.vfunc_map();
// Implicit animations are skipped for unmapped actors, and our
// children aren't mapped yet, so defer to a later handler
this.animateLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
this.animateLater = 0;
this.connect('notify::mapped', () => {
this.animateIndicators(AnimationDirection.IN);
return GLib.SOURCE_REMOVE;
});
}
@@ -128,7 +110,7 @@ class AnimatedPageIndicators extends PageIndicators {
return;
for (let i = 0; i < this._nPages; i++)
children[i].remove_all_transitions();
Tweener.removeTweens(children[i]);
let offset;
if (this.get_text_direction() == Clutter.TextDirection.RTL)
@@ -137,23 +119,21 @@ class AnimatedPageIndicators extends PageIndicators {
offset = children[0].width;
let isAnimationIn = animationDirection == AnimationDirection.IN;
let delay = isAnimationIn
? INDICATORS_ANIMATION_DELAY
: INDICATORS_ANIMATION_DELAY_OUT;
let delay = isAnimationIn ? INDICATORS_ANIMATION_DELAY :
INDICATORS_ANIMATION_DELAY_OUT;
let baseTime = isAnimationIn ? INDICATORS_BASE_TIME : INDICATORS_BASE_TIME_OUT;
let totalAnimationTime = baseTime + delay * this._nPages;
let maxTime = isAnimationIn
? INDICATORS_ANIMATION_MAX_TIME
: INDICATORS_ANIMATION_MAX_TIME_OUT;
let maxTime = isAnimationIn ? INDICATORS_ANIMATION_MAX_TIME :
INDICATORS_ANIMATION_MAX_TIME_OUT;
if (totalAnimationTime > maxTime)
delay -= (totalAnimationTime - maxTime) / this._nPages;
for (let i = 0; i < this._nPages; i++) {
children[i].translation_x = isAnimationIn ? offset : 0;
children[i].ease({
Tweener.addTween(children[i], {
translation_x: isAnimationIn ? 0 : offset,
duration: baseTime + delay * i,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
time: baseTime + delay * i,
transition: 'easeInOutQuad',
delay: isAnimationIn ? ANIMATION_DELAY : 0
});
}

View File

@@ -3,6 +3,7 @@
const { Atk, Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Cairo = imports.cairo;
const Mainloop = imports.mainloop;
const Animation = imports.ui.animation;
const Config = imports.misc.config;
@@ -12,6 +13,7 @@ const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
var PANEL_ICON_SIZE = 16;
var APP_MENU_ICON_MARGIN = 0;
@@ -235,7 +237,7 @@ var AppMenuButton = GObject.registerClass({
this._overviewShowingId = Main.overview.connect('showing', this._sync.bind(this));
this._spinner = new Animation.Spinner(PANEL_ICON_SIZE, true);
this._container.add_actor(this._spinner);
this._container.add_actor(this._spinner.actor);
let menu = new AppMenu(this);
this.setMenu(menu);
@@ -260,12 +262,11 @@ var AppMenuButton = GObject.registerClass({
this._visible = true;
this.reactive = true;
this.show();
this.remove_all_transitions();
this.ease({
opacity: 255,
duration: Overview.ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
Tweener.removeTweens(this);
Tweener.addTween(this,
{ opacity: 255,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad' });
}
fadeOut() {
@@ -274,13 +275,14 @@ var AppMenuButton = GObject.registerClass({
this._visible = false;
this.reactive = false;
this.remove_all_transitions();
this.ease({
opacity: 0,
mode: Clutter.Animation.EASE_OUT_QUAD,
duration: Overview.ANIMATION_TIME,
onComplete: () => this.hide()
});
Tweener.removeTweens(this);
Tweener.addTween(this,
{ opacity: 0,
time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this.hide();
} });
}
_syncIcon() {
@@ -430,6 +432,9 @@ class ActivitiesButton extends PanelMenu.Button {
this.label_actor = this._label;
this.connect('captured-event', this._onCapturedEvent.bind(this));
this.connect_after('key-release-event', this._onKeyRelease.bind(this));
Main.overview.connect('showing', () => {
this.add_style_pseudo_class('overview');
this.add_accessible_state (Atk.StateType.CHECKED);
@@ -447,8 +452,8 @@ class ActivitiesButton extends PanelMenu.Button {
return DND.DragMotionResult.CONTINUE;
if (this._xdndTimeOut != 0)
GLib.source_remove(this._xdndTimeOut);
this._xdndTimeOut = GLib.timeout_add(GLib.PRIORITY_DEFAULT, BUTTON_DND_ACTIVATION_TIMEOUT, () => {
Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT, () => {
this._xdndToggleOverview();
});
GLib.Source.set_name_by_id(this._xdndTimeOut, '[gnome-shell] this._xdndToggleOverview');
@@ -456,7 +461,7 @@ class ActivitiesButton extends PanelMenu.Button {
return DND.DragMotionResult.CONTINUE;
}
vfunc_captured_event(event) {
_onCapturedEvent(actor, event) {
if (event.type() == Clutter.EventType.BUTTON_PRESS ||
event.type() == Clutter.EventType.TOUCH_BEGIN) {
if (!Main.overview.shouldToggleByCornerOrButton())
@@ -465,7 +470,9 @@ class ActivitiesButton extends PanelMenu.Button {
return Clutter.EVENT_PROPAGATE;
}
vfunc_event(event) {
_onEvent(actor, event) {
super._onEvent(actor, event);
if (event.type() == Clutter.EventType.TOUCH_END ||
event.type() == Clutter.EventType.BUTTON_RELEASE)
if (Main.overview.shouldToggleByCornerOrButton())
@@ -474,16 +481,13 @@ class ActivitiesButton extends PanelMenu.Button {
return Clutter.EVENT_PROPAGATE;
}
vfunc_key_release_event(keyEvent) {
let ret = super.vfunc_key_release_event(keyEvent);
if (ret == Clutter.EVENT_PROPAGATE) {
let symbol = keyEvent.keyval;
_onKeyRelease(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
if (Main.overview.shouldToggleByCornerOrButton())
Main.overview.toggle();
}
}
return ret;
return Clutter.EVENT_PROPAGATE;
}
_xdndToggleOverview() {
@@ -493,18 +497,19 @@ class ActivitiesButton extends PanelMenu.Button {
if (pickedActor == this && Main.overview.shouldToggleByCornerOrButton())
Main.overview.toggle();
GLib.source_remove(this._xdndTimeOut);
Mainloop.source_remove(this._xdndTimeOut);
this._xdndTimeOut = 0;
return GLib.SOURCE_REMOVE;
}
});
var PanelCorner = GObject.registerClass(
class PanelCorner extends St.DrawingArea {
_init(side) {
var PanelCorner = class {
constructor(side) {
this._side = side;
super._init({ style_class: 'panel-corner' });
this.actor = new St.DrawingArea({ style_class: 'panel-corner' });
this.actor.connect('style-changed', this._styleChanged.bind(this));
this.actor.connect('repaint', this._repaint.bind(this));
}
_findRightmostButton(container) {
@@ -594,7 +599,7 @@ class PanelCorner extends St.DrawingArea {
this._buttonStyleChangedSignalId = button.connect('style-changed',
() => {
let pseudoClass = button.get_style_pseudo_class();
this.set_style_pseudo_class(pseudoClass);
this.actor.set_style_pseudo_class(pseudoClass);
});
// The corner doesn't support theme transitions, so override
@@ -603,8 +608,8 @@ class PanelCorner extends St.DrawingArea {
}
}
vfunc_repaint() {
let node = this.get_theme_node();
_repaint() {
let node = this.actor.get_theme_node();
let cornerRadius = node.get_length("-panel-corner-radius");
let borderWidth = node.get_length('-panel-corner-border-width');
@@ -615,7 +620,7 @@ class PanelCorner extends St.DrawingArea {
let overlap = borderColor.alpha != 0;
let offsetY = overlap ? 0 : borderWidth;
let cr = this.get_context();
let cr = this.actor.get_context();
cr.setOperator(Cairo.Operator.SOURCE);
cr.moveTo(0, offsetY);
@@ -651,17 +656,16 @@ class PanelCorner extends St.DrawingArea {
cr.$dispose();
}
vfunc_style_changed() {
super.vfunc_style_changed();
let node = this.get_theme_node();
_styleChanged() {
let node = this.actor.get_theme_node();
let cornerRadius = node.get_length("-panel-corner-radius");
let borderWidth = node.get_length('-panel-corner-border-width');
this.set_size(cornerRadius, borderWidth + cornerRadius);
this.set_anchor_point(0, borderWidth);
this.actor.set_size(cornerRadius, borderWidth + cornerRadius);
this.actor.set_anchor_point(0, borderWidth);
}
});
};
var AggregateLayout = GObject.registerClass(
class AggregateLayout extends Clutter.BoxLayout {
@@ -726,20 +730,20 @@ class AggregateMenu extends PanelMenu.Button {
this._nightLight = new imports.ui.status.nightLight.Indicator();
this._thunderbolt = new imports.ui.status.thunderbolt.Indicator();
this._indicators.add_child(this._thunderbolt);
this._indicators.add_child(this._screencast);
this._indicators.add_child(this._location);
this._indicators.add_child(this._nightLight);
this._indicators.add_child(this._thunderbolt.indicators);
this._indicators.add_child(this._screencast.indicators);
this._indicators.add_child(this._location.indicators);
this._indicators.add_child(this._nightLight.indicators);
if (this._network) {
this._indicators.add_child(this._network);
this._indicators.add_child(this._network.indicators);
}
if (this._bluetooth) {
this._indicators.add_child(this._bluetooth);
this._indicators.add_child(this._bluetooth.indicators);
}
this._indicators.add_child(this._remoteAccess);
this._indicators.add_child(this._rfkill);
this._indicators.add_child(this._volume);
this._indicators.add_child(this._power);
this._indicators.add_child(this._remoteAccess.indicators);
this._indicators.add_child(this._rfkill.indicators);
this._indicators.add_child(this._volume.indicators);
this._indicators.add_child(this._power.indicators);
this._indicators.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
this.menu.addMenuItem(this._volume.menu);
@@ -797,10 +801,14 @@ class Panel extends St.Widget {
this.add_child(this._rightBox);
this._leftCorner = new PanelCorner(St.Side.LEFT);
this.add_child(this._leftCorner);
this.add_child(this._leftCorner.actor);
this._rightCorner = new PanelCorner(St.Side.RIGHT);
this.add_child(this._rightCorner);
this.add_child(this._rightCorner.actor);
this.connect('button-press-event', this._onButtonPress.bind(this));
this.connect('touch-event', this._onButtonPress.bind(this));
this.connect('key-press-event', this._onKeyPress.bind(this));
Main.overview.connect('showing', () => {
this.add_style_pseudo_class('overview');
@@ -889,65 +897,62 @@ class Panel extends St.Widget {
let cornerWidth, cornerHeight;
[, cornerWidth] = this._leftCorner.get_preferred_width(-1);
[, cornerHeight] = this._leftCorner.get_preferred_height(-1);
[, cornerWidth] = this._leftCorner.actor.get_preferred_width(-1);
[, cornerHeight] = this._leftCorner.actor.get_preferred_height(-1);
childBox.x1 = 0;
childBox.x2 = cornerWidth;
childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight;
this._leftCorner.allocate(childBox, flags);
this._leftCorner.actor.allocate(childBox, flags);
[, cornerWidth] = this._rightCorner.get_preferred_width(-1);
[, cornerHeight] = this._rightCorner.get_preferred_height(-1);
[, cornerWidth] = this._rightCorner.actor.get_preferred_width(-1);
[, cornerHeight] = this._rightCorner.actor.get_preferred_height(-1);
childBox.x1 = allocWidth - cornerWidth;
childBox.x2 = allocWidth;
childBox.y1 = allocHeight;
childBox.y2 = allocHeight + cornerHeight;
this._rightCorner.allocate(childBox, flags);
this._rightCorner.actor.allocate(childBox, flags);
}
_tryDragWindow(event) {
_onButtonPress(actor, event) {
if (Main.modalCount > 0)
return Clutter.EVENT_PROPAGATE;
if (event.source != this)
if (event.get_source() != actor)
return Clutter.EVENT_PROPAGATE;
let { x, y } = event;
let dragWindow = this._getDraggableWindowForPosition(x);
let type = event.type();
let isPress = type == Clutter.EventType.BUTTON_PRESS;
if (!isPress && type != Clutter.EventType.TOUCH_BEGIN)
return Clutter.EVENT_PROPAGATE;
let button = isPress ? event.get_button() : -1;
if (isPress && button != 1)
return Clutter.EVENT_PROPAGATE;
let [stageX, stageY] = event.get_coords();
let dragWindow = this._getDraggableWindowForPosition(stageX);
if (!dragWindow)
return Clutter.EVENT_PROPAGATE;
return global.display.begin_grab_op(
dragWindow,
global.display.begin_grab_op(dragWindow,
Meta.GrabOp.MOVING,
false, /* pointer grab */
true, /* frame action */
event.button || -1,
event.modifier_state,
event.time,
x, y) ? Clutter.EVENT_STOP : Clutter.EVENT_PROPAGATE;
button,
event.get_state(),
event.get_time(),
stageX, stageY);
return Clutter.EVENT_STOP;
}
vfunc_button_press_event(buttonEvent) {
if (buttonEvent.button != 1)
return Clutter.EVENT_PROPAGATE;
return this._tryDragWindow(buttonEvent);
}
vfunc_touch_event(touchEvent) {
if (touchEvent.type != Clutter.EventType.TOUCH_BEGIN)
return Clutter.EVENT_PROPAGATE;
return this._tryDragWindow(touchEvent);
}
vfunc_key_press_event(keyEvent) {
let symbol = keyEvent.keyval;
_onKeyPress(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Escape) {
global.display.focus_default_window(keyEvent.time);
global.display.focus_default_window(event.get_time());
return Clutter.EVENT_STOP;
}
@@ -1111,14 +1116,14 @@ class Panel extends St.Widget {
_addStyleClassName(className) {
this.add_style_class_name(className);
this._rightCorner.add_style_class_name(className);
this._leftCorner.add_style_class_name(className);
this._rightCorner.actor.add_style_class_name(className);
this._leftCorner.actor.add_style_class_name(className);
}
_removeStyleClassName(className) {
this.remove_style_class_name(className);
this._rightCorner.remove_style_class_name(className);
this._leftCorner.remove_style_class_name(className);
this._rightCorner.actor.remove_style_class_name(className);
this._leftCorner.actor.remove_style_class_name(className);
}
_onMenuSet(indicator) {

View File

@@ -2,6 +2,7 @@
/* exported Button, SystemIndicator */
const { Atk, Clutter, GObject, St } = imports.gi;
const Signals = imports.signals;
const Main = imports.ui.main;
const Params = imports.misc.params;
@@ -100,6 +101,9 @@ var Button = GObject.registerClass({
accessible_name: nameText ? nameText : "",
accessible_role: Atk.Role.MENU });
this.connect('event', this._onEvent.bind(this));
this.connect('notify::visible', this._onVisibilityChanged.bind(this));
if (dontCreateMenu)
this.menu = new PopupMenu.PopupDummyMenu(this);
else
@@ -128,7 +132,7 @@ var Button = GObject.registerClass({
this.emit('menu-set');
}
vfunc_event(event) {
_onEvent(actor, event) {
if (this.menu &&
(event.type() == Clutter.EventType.TOUCH_BEGIN ||
event.type() == Clutter.EventType.BUTTON_PRESS))
@@ -137,10 +141,11 @@ var Button = GObject.registerClass({
return Clutter.EVENT_PROPAGATE;
}
vfunc_hide() {
super.vfunc_hide();
_onVisibilityChanged() {
if (!this.menu)
return;
if (this.menu)
if (!this.visible)
this.menu.close();
}
@@ -195,34 +200,24 @@ var Button = GObject.registerClass({
* of an icon and a menu section, which will be composed into the
* aggregate menu.
*/
var SystemIndicator = GObject.registerClass({
GTypeName: 'PanelMenu_SystemIndicator',
}, class SystemIndicator extends St.BoxLayout {
_init() {
super._init({
style_class: 'panel-status-indicators-box',
reactive: true,
visible: false
});
var SystemIndicator = class {
constructor() {
this.indicators = new St.BoxLayout({ style_class: 'panel-status-indicators-box',
reactive: true });
this.indicators.hide();
this.menu = new PopupMenu.PopupMenuSection();
}
get indicators() {
let klass = this.constructor.name;
let { stack } = new Error();
log(`Usage of indicator.indicators is deprecated for ${klass}\n${stack}`);
return this;
}
_syncIndicatorsVisible() {
this.visible = this.get_children().some(a => a.visible);
this.indicators.visible = this.indicators.get_children().some(a => a.visible);
}
_addIndicator() {
let icon = new St.Icon({ style_class: 'system-status-icon' });
this.add_actor(icon);
this.indicators.add_actor(icon);
icon.connect('notify::visible', this._syncIndicatorsVisible.bind(this));
this._syncIndicatorsVisible();
return icon;
}
});
};
Signals.addSignalMethods(SystemIndicator.prototype);

View File

@@ -1,42 +1,20 @@
/* exported PointerA11yTimeout */
const { Clutter, GObject, Meta, St } = imports.gi;
const { Clutter, GLib, GObject, Meta, St } = imports.gi;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main;
const Cairo = imports.cairo;
const SUCCESS_ZOOM_OUT_DURATION = 150;
var PieTimer = GObject.registerClass({
Properties: {
'angle': GObject.ParamSpec.double(
'angle', 'angle', 'angle',
GObject.ParamFlags.READWRITE,
0, 2 * Math.PI, 0)
}
}, class PieTimer extends St.DrawingArea {
var PieTimer = GObject.registerClass(
class PieTimer extends St.DrawingArea {
_init() {
this._angle = 0;
super._init({
style_class: 'pie-timer',
opacity: 0,
this._x = 0;
this._y = 0;
this._startTime = 0;
this._duration = 0;
super._init( { style_class: 'pie-timer',
visible: false,
can_focus: false,
reactive: false
});
this.set_pivot_point(0.5, 0.5);
}
get angle() {
return this._angle;
}
set angle(angle) {
if (this._angle == angle)
return;
this._angle = angle;
this.notify('angle');
this.queue_repaint();
reactive: false });
}
vfunc_repaint() {
@@ -47,22 +25,20 @@ var PieTimer = GObject.registerClass({
let [width, height] = this.get_surface_size();
let radius = Math.min(width / 2, height / 2);
let currentTime = GLib.get_monotonic_time() / 1000.0;
let ellapsed = currentTime - this._startTime;
let angle = (ellapsed / this._duration) * 2 * Math.PI;
let startAngle = 3 * Math.PI / 2;
let endAngle = startAngle + this._angle;
let endAngle = startAngle + angle;
let cr = this.get_context();
cr.setLineCap(Cairo.LineCap.ROUND);
cr.setLineJoin(Cairo.LineJoin.ROUND);
cr.translate(width / 2, height / 2);
if (this._angle < 2 * Math.PI)
cr.moveTo(0, 0);
cr.arc(0, 0, radius - borderWidth, startAngle, endAngle);
if (this._angle < 2 * Math.PI)
cr.lineTo(0, 0);
cr.closePath();
cr.setLineWidth(0);
@@ -77,56 +53,47 @@ var PieTimer = GObject.registerClass({
}
start(x, y, duration) {
Tweener.removeTweens(this);
this.x = x - this.width / 2;
this.y = y - this.height / 2;
this.show();
Main.uiGroup.set_child_above_sibling(this, null);
this.ease({
opacity: 255,
duration: duration / 4,
mode: Clutter.AnimationMode.EASE_IN_QUAD
});
this._startTime = GLib.get_monotonic_time() / 1000.0;
this._duration = duration;
this.ease_property('angle', 2 * Math.PI, {
duration,
mode: Clutter.AnimationMode.LINEAR,
onComplete: this._onTransitionComplete.bind(this)
Tweener.addTween(this,
{ opacity: 255,
time: duration / 1000,
transition: 'easeOutQuad',
onUpdate: () => this.queue_repaint(),
onComplete: () => this.stop()
});
}
_onTransitionComplete() {
this.ease({
scale_x: 2,
scale_y: 2,
opacity: 0,
duration: SUCCESS_ZOOM_OUT_DURATION,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onStopped: () => this.destroy()
});
stop() {
Tweener.removeTweens(this);
this.hide();
}
});
var PointerA11yTimeout = class PointerA11yTimeout {
constructor() {
let manager = Clutter.DeviceManager.get_default();
let pieTimer = new PieTimer();
Main.uiGroup.add_actor(pieTimer);
manager.connect('ptr-a11y-timeout-started', (manager, device, type, timeout) => {
let [x, y] = global.get_pointer();
this._pieTimer = new PieTimer();
Main.uiGroup.add_actor(this._pieTimer);
Main.uiGroup.set_child_above_sibling(this._pieTimer, null);
this._pieTimer.start(x, y, timeout);
pieTimer.start(x, y, timeout);
if (type == Clutter.PointerA11yTimeoutType.GESTURE)
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
});
manager.connect('ptr-a11y-timeout-stopped', (manager, device, type, clicked) => {
if (!clicked)
this._pieTimer.destroy();
manager.connect('ptr-a11y-timeout-stopped', (manager, device, type) => {
pieTimer.stop();
if (type == Clutter.PointerA11yTimeoutType.GESTURE)
global.display.set_cursor(Meta.Cursor.DEFAULT);
});

View File

@@ -2,6 +2,7 @@
/* exported getPointerWatcher */
const { GLib, Meta } = imports.gi;
const Mainloop = imports.mainloop;
// We stop polling if the user is idle for more than this amount of time
var IDLE_TIME = 1000;
@@ -86,7 +87,7 @@ var PointerWatcher = class {
_updateTimeout() {
if (this._timeoutId) {
GLib.source_remove(this._timeoutId);
Mainloop.source_remove(this._timeoutId);
this._timeoutId = 0;
}
@@ -97,7 +98,7 @@ var PointerWatcher = class {
for (let i = 1; i < this._watches.length; i++)
minInterval = Math.min(this._watches[i].interval, minInterval);
this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, minInterval,
this._timeoutId = Mainloop.timeout_add(minInterval,
this._onTimeout.bind(this));
GLib.Source.set_name_by_id(this._timeoutId, '[gnome-shell] this._onTimeout');
}

View File

@@ -3,19 +3,19 @@
PopupImageMenuItem, PopupMenu, PopupDummyMenu, PopupSubMenu,
PopupMenuSection, PopupSubMenuMenuItem, PopupMenuManager */
const { Atk, Clutter, Gio, GObject, Graphene, Shell, St } = imports.gi;
const { Atk, Clutter, Gio, GObject, Shell, St } = imports.gi;
const Signals = imports.signals;
const BoxPointer = imports.ui.boxpointer;
const GrabHelper = imports.ui.grabHelper;
const Main = imports.ui.main;
const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
var Ornament = {
NONE: 0,
DOT: 1,
CHECK: 2,
HIDDEN: 3,
};
function isPopupMenuItemVisible(child) {
@@ -58,9 +58,11 @@ var PopupBaseMenuItem = GObject.registerClass({
Properties: {
'active': GObject.ParamSpec.boolean('active', 'active', 'active',
GObject.ParamFlags.READWRITE,
GObject.TYPE_BOOLEAN,
false),
'sensitive': GObject.ParamSpec.boolean('sensitive', 'sensitive', 'sensitive',
GObject.ParamFlags.READWRITE,
GObject.TYPE_BOOLEAN,
true),
},
Signals: {
@@ -68,12 +70,11 @@ var PopupBaseMenuItem = GObject.registerClass({
}
}, class PopupBaseMenuItem extends St.BoxLayout {
_init(params) {
params = Params.parse (params, {
reactive: true,
params = Params.parse (params, { reactive: true,
activate: true,
hover: true,
style_class: null,
can_focus: true,
can_focus: true
});
super._init({ style_class: 'popup-menu-item',
reactive: params.reactive,
@@ -97,6 +98,12 @@ var PopupBaseMenuItem = GObject.registerClass({
if (params.style_class)
this.add_style_class_name(params.style_class);
if (this._activatable) {
this.connect('button-press-event', this._onButtonPressEvent.bind(this));
this.connect('button-release-event', this._onButtonReleaseEvent.bind(this));
this.connect('touch-event', this._onTouchEvent.bind(this));
this.connect('key-press-event', this._onKeyPressEvent.bind(this));
}
if (params.reactive && params.hover)
this.bind_property('hover', this, 'active', GObject.BindingFlags.SYNC_CREATE);
}
@@ -118,44 +125,32 @@ var PopupBaseMenuItem = GObject.registerClass({
this._parent = parent;
}
vfunc_button_press_event(buttonEvent) {
if (!this._activatable)
return super.vfunc_button_press_event(buttonEvent);
_onButtonPressEvent() {
// This is the CSS active state
this.add_style_pseudo_class('active');
return Clutter.EVENT_PROPAGATE;
}
vfunc_button_release_event(buttonEvent) {
if (!this._activatable)
return super.vfunc_button_release_event(buttonEvent);
_onButtonReleaseEvent(actor, event) {
this.remove_style_pseudo_class('active');
this.activate(Clutter.get_current_event());
this.activate(event);
return Clutter.EVENT_STOP;
}
vfunc_touch_event(touchEvent) {
if (!this._activatable)
return super.vfunc_touch_event(touchEvent);
if (touchEvent.type == Clutter.EventType.TOUCH_END) {
_onTouchEvent(actor, event) {
if (event.type() == Clutter.EventType.TOUCH_END) {
this.remove_style_pseudo_class('active');
this.activate(Clutter.get_current_event());
this.activate(event);
return Clutter.EVENT_STOP;
} else if (touchEvent.type == Clutter.EventType.TOUCH_BEGIN) {
} else if (event.type() == Clutter.EventType.TOUCH_BEGIN) {
// This is the CSS active state
this.add_style_pseudo_class('active');
}
return Clutter.EVENT_PROPAGATE;
}
vfunc_key_press_event(keyEvent) {
if (!this._activatable)
return super.vfunc_key_press_event(keyEvent);
let state = keyEvent.modifier_state;
_onKeyPressEvent(actor, event) {
let state = event.get_state();
// if user has a modifier down (except capslock and numlock)
// then don't handle the key press here
@@ -166,9 +161,9 @@ var PopupBaseMenuItem = GObject.registerClass({
if (state)
return Clutter.EVENT_PROPAGATE;
let symbol = keyEvent.keyval;
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.activate(Clutter.get_current_event());
this.activate(event);
return Clutter.EVENT_STOP;
}
return Clutter.EVENT_PROPAGATE;
@@ -255,12 +250,10 @@ var PopupBaseMenuItem = GObject.registerClass({
} else if (ornament == Ornament.CHECK) {
this._ornamentLabel.text = '\u2713';
this.add_accessible_state(Atk.StateType.CHECKED);
} else if (ornament == Ornament.NONE || ornament == Ornament.HIDDEN) {
} else if (ornament == Ornament.NONE) {
this._ornamentLabel.text = '';
this.remove_accessible_state(Atk.StateType.CHECKED);
}
this._ornamentLabel.visible = ornament != Ornament.HIDDEN;
}
});
@@ -341,9 +334,8 @@ var PopupSwitchMenuItem = GObject.registerClass({
this._statusBin = new St.Bin({ x_align: St.Align.END });
this.add(this._statusBin, { expand: true, x_align: St.Align.END });
this._statusLabel = new St.Label({
text: '',
style_class: 'popup-status-menu-item',
this._statusLabel = new St.Label({ text: '',
style_class: 'popup-status-menu-item'
});
this._statusBin.child = this._switch;
}
@@ -434,7 +426,6 @@ var PopupMenuBase = class {
throw new TypeError(`Cannot instantiate abstract class ${this.constructor.name}`);
this.sourceActor = sourceActor;
this.focusActor = sourceActor;
this._parent = null;
if (styleClass !== undefined) {
@@ -559,7 +550,7 @@ var PopupMenuBase = class {
}
_connectItemSignals(menuItem) {
menuItem._activeChangeId = menuItem.connect('notify::active', menuItem => {
menuItem._activeChangeId = menuItem.connect('notify::active', (menuItem) => {
let active = menuItem.active;
if (active && this._activeMenuItem != menuItem) {
if (this._activeMenuItem)
@@ -623,8 +614,8 @@ var PopupMenuBase = class {
while (childBeforeIndex >= 0 && !isPopupMenuItemVisible(children[childBeforeIndex]))
childBeforeIndex--;
if (childBeforeIndex < 0 ||
children[childBeforeIndex]._delegate instanceof PopupSeparatorMenuItem) {
if (childBeforeIndex < 0
|| children[childBeforeIndex]._delegate instanceof PopupSeparatorMenuItem) {
menuItem.actor.hide();
return;
}
@@ -634,8 +625,8 @@ var PopupMenuBase = class {
while (childAfterIndex < children.length && !isPopupMenuItemVisible(children[childAfterIndex]))
childAfterIndex++;
if (childAfterIndex >= children.length ||
children[childAfterIndex]._delegate instanceof PopupSeparatorMenuItem) {
if (childAfterIndex >= children.length
|| children[childAfterIndex]._delegate instanceof PopupSeparatorMenuItem) {
menuItem.actor.hide();
return;
}
@@ -728,11 +719,10 @@ var PopupMenuBase = class {
this.disconnect(openStateChangeId);
menuItem.disconnect(destroyId);
});
} else if (menuItem instanceof PopupBaseMenuItem) {
} else if (menuItem instanceof PopupBaseMenuItem)
this._connectItemSignals(menuItem);
} else {
else
throw TypeError("Invalid argument to PopupMenuBase.addMenuItem()");
}
menuItem._setParent(this);
@@ -1023,16 +1013,17 @@ var PopupSubMenu = class extends PopupMenuBase {
if (animate) {
let [, naturalHeight] = this.actor.get_preferred_height(-1);
this.actor.height = 0;
this.actor.ease({
this.actor._arrowRotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrowRotation: targetAngle,
height: naturalHeight,
duration: 250,
mode: Clutter.AnimationMode.EASE_OUT_EXPO,
onComplete: () => this.actor.set_height(-1)
});
this._arrow.ease({
rotation_angle_z: targetAngle,
duration: 250,
mode: Clutter.AnimationMode.EASE_OUT_EXPO
time: 0.25,
onUpdate: () => {
this._arrow.rotation_angle_z = this.actor._arrowRotation;
},
onComplete: () => {
this.actor.set_height(-1);
}
});
} else {
this._arrow.rotation_angle_z = targetAngle;
@@ -1053,19 +1044,18 @@ var PopupSubMenu = class extends PopupMenuBase {
animate = false;
if (animate) {
this.actor.ease({
this.actor._arrowRotation = this._arrow.rotation_angle_z;
Tweener.addTween(this.actor,
{ _arrowRotation: 0,
height: 0,
duration: 250,
mode: Clutter.AnimationMode.EASE_OUT_EXPO,
time: 0.25,
onUpdate: () => {
this._arrow.rotation_angle_z = this.actor._arrowRotation;
},
onComplete: () => {
this.actor.hide();
this.actor.set_height(-1);
}
});
this._arrow.ease({
rotation_angle_z: 0,
duration: 250,
mode: Clutter.AnimationMode.EASE_OUT_EXPO
},
});
} else {
this._arrow.rotation_angle_z = 0;
@@ -1136,7 +1126,7 @@ class PopupSubMenuMenuItem extends PopupBaseMenuItem {
this.add(expander, { expand: true });
this._triangle = arrowIcon(St.Side.RIGHT);
this._triangle.pivot_point = new Graphene.Point({ x: 0.5, y: 0.6 });
this._triangle.pivot_point = new Clutter.Point({ x: 0.5, y: 0.6 });
this._triangleBin = new St.Widget({ y_expand: true,
y_align: Clutter.ActorAlign.CENTER });
@@ -1191,8 +1181,8 @@ class PopupSubMenuMenuItem extends PopupBaseMenuItem {
return this.menu.isOpen;
}
vfunc_key_press_event(keyPressEvent) {
let symbol = keyPressEvent.keyval;
_onKeyPressEvent(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Right) {
this._setOpenState(true);
@@ -1203,14 +1193,14 @@ class PopupSubMenuMenuItem extends PopupBaseMenuItem {
return Clutter.EVENT_STOP;
}
return super.vfunc_key_press_event(keyPressEvent);
return super._onKeyPressEvent(actor, event);
}
activate(_event) {
this._setOpenState(true);
}
vfunc_button_release_event() {
_onButtonReleaseEvent() {
// Since we override the parent, we need to manage what the parent does
// with the active style class
this.remove_style_pseudo_class('active');
@@ -1218,8 +1208,8 @@ class PopupSubMenuMenuItem extends PopupBaseMenuItem {
return Clutter.EVENT_PROPAGATE;
}
vfunc_touch_event(touchEvent) {
if (touchEvent.type == Clutter.EventType.TOUCH_END) {
_onTouchEvent(actor, event) {
if (event.type() == Clutter.EventType.TOUCH_END) {
// Since we override the parent, we need to manage what the parent does
// with the active style class
this.remove_style_pseudo_class('active');
@@ -1307,19 +1297,17 @@ var PopupMenuManager = class {
if (open) {
if (this.activeMenu)
this.activeMenu.close(BoxPointer.PopupAnimation.FADE);
this._grabHelper.grab({
actor: menu.actor,
focus: menu.focusActor,
onUngrab: isUser => this._closeMenu(isUser, menu),
});
this._grabHelper.grab({ actor: menu.actor, focus: menu.sourceActor,
onUngrab: isUser => {
this._closeMenu(isUser, menu);
} });
} else {
this._grabHelper.ungrab({ actor: menu.actor });
}
}
_changeMenu(newMenu) {
newMenu.open(this.activeMenu
? BoxPointer.PopupAnimation.FADE
newMenu.open(this.activeMenu ? BoxPointer.PopupAnimation.FADE
: BoxPointer.PopupAnimation.FULL);
}

View File

@@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Ripples */
const { Clutter, St } = imports.gi;
const { St } = imports.gi;
const Tweener = imports.ui.tweener;
// Shamelessly copied from the layout "hotcorner" ripples implementation
var Ripples = class Ripples {
@@ -34,41 +35,30 @@ var Ripples = class Ripples {
this._ripple3.set_pivot_point(px, py);
}
destroy() {
this._ripple1.destroy();
this._ripple2.destroy();
this._ripple3.destroy();
}
_animRipple(ripple, delay, duration, startScale, startOpacity, finalScale) {
_animRipple(ripple, delay, time, startScale, startOpacity, finalScale) {
// We draw a ripple by using a source image and animating it scaling
// outwards and fading away. We want the ripples to move linearly
// or it looks unrealistic, but if the opacity of the ripple goes
// linearly to zero it fades away too quickly, so we use a separate
// tween to give a non-linear curve to the fade-away and make
// linearly to zero it fades away too quickly, so we use Tweener's
// 'onUpdate' to give a non-linear curve to the fade-away and make
// it more visible in the middle section.
ripple.x = this._x;
ripple.y = this._y;
ripple._opacity = startOpacity;
ripple.visible = true;
ripple.opacity = 255 * Math.sqrt(startOpacity);
ripple.scale_x = ripple.scale_y = startScale;
ripple.set_translation( - this._px * ripple.width, - this._py * ripple.height, 0.0);
ripple.ease({
opacity: 0,
delay,
duration,
mode: Clutter.AnimationMode.EASE_IN_QUAD
});
ripple.ease({
Tweener.addTween(ripple, { _opacity: 0,
scale_x: finalScale,
scale_y: finalScale,
delay,
duration,
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => (ripple.visible = false)
});
delay: delay,
time: time,
transition: 'linear',
onUpdate: () => ripple.opacity = 255 * Math.sqrt(ripple._opacity),
onComplete: () => ripple.visible = false });
}
addTo(stage) {
@@ -97,8 +87,8 @@ var Ripples = class Ripples {
// for them to make perfect sense mathematically
// delay time scale opacity => scale
this._animRipple(this._ripple1, 0, 830, 0.25, 1.0, 1.5);
this._animRipple(this._ripple2, 50, 1000, 0.0, 0.7, 1.25);
this._animRipple(this._ripple3, 350, 1000, 0.0, 0.3, 1);
this._animRipple(this._ripple1, 0.0, 0.83, 0.25, 1.0, 1.5);
this._animRipple(this._ripple2, 0.05, 1.0, 0.0, 0.7, 1.25);
this._animRipple(this._ripple3, 0.35, 1.0, 0.0, 0.3, 1);
}
};

View File

@@ -6,6 +6,7 @@ const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const History = imports.misc.history;
@@ -18,7 +19,7 @@ const TERMINAL_SCHEMA = 'org.gnome.desktop.default-applications.terminal';
const EXEC_KEY = 'exec';
const EXEC_ARG_KEY = 'exec-arg';
var DIALOG_GROW_TIME = 100;
var DIALOG_GROW_TIME = 0.1;
var RunDialog = GObject.registerClass(
class RunDialog extends ModalDialog.ModalDialog {
@@ -94,17 +95,15 @@ class RunDialog extends ModalDialog.ModalDialog {
this._errorBox.hide();
this.setButtons([{
action: this.close.bind(this),
this.setButtons([{ action: this.close.bind(this),
label: _("Close"),
key: Clutter.Escape,
}]);
key: Clutter.Escape }]);
this._pathCompleter = new Gio.FilenameCompleter();
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entryText });
this._entryText.connect('activate', o => {
this._entryText.connect('activate', (o) => {
this.popModal();
this._run(o.get_text(),
Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK);
@@ -244,11 +243,10 @@ class RunDialog extends ModalDialog.ModalDialog {
let [, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
let parentActor = this._errorBox.get_parent();
let height = parentActor.height + errorBoxNaturalHeight;
parentActor.ease({
height,
duration: DIALOG_GROW_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.addTween(parentActor,
{ height: parentActor.height + errorBoxNaturalHeight,
time: DIALOG_GROW_TIME,
transition: 'easeOutQuad',
onComplete: () => {
parentActor.set_height(-1);
this._errorBox.show();

View File

@@ -1,9 +1,11 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const { AccountsService, Clutter, Cogl, Gio, GLib,
GnomeDesktop, GObject, Graphene, Meta, Shell, St } = imports.gi;
GnomeDesktop, GObject, Meta, Shell, St } = imports.gi;
const Cairo = imports.cairo;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const TweenerEquations = imports.tweener.equations;
const Background = imports.ui.background;
const GnomeSession = imports.misc.gnomeSession;
@@ -16,8 +18,7 @@ const Overview = imports.ui.overview;
const MessageTray = imports.ui.messageTray;
const ShellDBus = imports.ui.shellDBus;
const SmartcardManager = imports.misc.smartcardManager;
const { adjustAnimationTime } = imports.ui.environment;
const Tweener = imports.ui.tweener;
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
const LOCK_ENABLED_KEY = 'lock-enabled';
@@ -33,7 +34,7 @@ var ARROW_DRAG_THRESHOLD = 0.1;
// Parameters for the arrow animation
var N_ARROWS = 3;
var ARROW_ANIMATION_TIME = 600;
var ARROW_ANIMATION_TIME = 0.6;
var ARROW_ANIMATION_PEAK_OPACITY = 0.4;
var ARROW_IDLE_TIME = 30000; // ms
@@ -44,27 +45,25 @@ var SUMMARY_ICON_SIZE = 48;
// - MANUAL_FADE_TIME is used for lowering the shield when asked by the user,
// or when cancelling the dialog
// - CURTAIN_SLIDE_TIME is used when raising the shield before unlocking
var STANDARD_FADE_TIME = 10000;
var MANUAL_FADE_TIME = 300;
var CURTAIN_SLIDE_TIME = 300;
var STANDARD_FADE_TIME = 10;
var MANUAL_FADE_TIME = 0.3;
var CURTAIN_SLIDE_TIME = 0.3;
var Clock = GObject.registerClass(
class ScreenShieldClock extends St.BoxLayout {
_init() {
super._init({ style_class: 'screen-shield-clock', vertical: true });
var Clock = class {
constructor() {
this.actor = new St.BoxLayout({ style_class: 'screen-shield-clock',
vertical: true });
this._time = new St.Label({ style_class: 'screen-shield-clock-time' });
this._date = new St.Label({ style_class: 'screen-shield-clock-date' });
this.add(this._time, { x_align: St.Align.MIDDLE });
this.add(this._date, { x_align: St.Align.MIDDLE });
this.actor.add(this._time, { x_align: St.Align.MIDDLE });
this.actor.add(this._date, { x_align: St.Align.MIDDLE });
this._wallClock = new GnomeDesktop.WallClock({ time_only: true });
this._wallClock.connect('notify::clock', this._updateClock.bind(this));
this._updateClock();
this.connect('destroy', this._onDestroy.bind(this));
}
_updateClock() {
@@ -77,20 +76,17 @@ class ScreenShieldClock extends St.BoxLayout {
this._date.text = date.toLocaleFormat(dateFormat);
}
_onDestroy() {
destroy() {
this.actor.destroy();
this._wallClock.run_dispose();
}
});
};
var NotificationsBox = GObject.registerClass({
Signals: { 'wake-up-screen': {} }
}, class NotificationsBox extends St.BoxLayout {
_init() {
super._init({
vertical: true,
var NotificationsBox = class {
constructor() {
this.actor = new St.BoxLayout({ vertical: true,
name: 'screenShieldNotifications',
style_class: 'screen-shield-notifications-container'
});
style_class: 'screen-shield-notifications-container' });
this._scrollView = new St.ScrollView({ x_fill: false, x_align: St.Align.START,
hscrollbar_policy: St.PolicyType.NEVER });
@@ -98,7 +94,7 @@ var NotificationsBox = GObject.registerClass({
style_class: 'screen-shield-notifications-container' });
this._scrollView.add_actor(this._notificationBox);
this.add(this._scrollView, { x_fill: true, x_align: St.Align.START });
this.actor.add(this._scrollView, { x_fill: true, x_align: St.Align.START });
this._sources = new Map();
Main.messageTray.getSources().forEach(source => {
@@ -107,11 +103,9 @@ var NotificationsBox = GObject.registerClass({
this._updateVisibility();
this._sourceAddedId = Main.messageTray.connect('source-added', this._sourceAdded.bind(this));
this.connect('destroy', this._onDestroy.bind(this));
}
_onDestroy() {
destroy() {
if (this._sourceAddedId) {
Main.messageTray.disconnect(this._sourceAddedId);
this._sourceAddedId = 0;
@@ -121,13 +115,15 @@ var NotificationsBox = GObject.registerClass({
for (let [source, obj] of items) {
this._removeSource(source, obj);
}
this.actor.destroy();
}
_updateVisibility() {
this._notificationBox.visible =
this._notificationBox.get_children().some(a => a.visible);
this.visible = this._notificationBox.visible;
this.actor.visible = this._notificationBox.visible;
}
_makeNotificationCountText(count, isChat) {
@@ -180,8 +176,7 @@ var NotificationsBox = GObject.registerClass({
let body = '';
if (n.bannerBodyText) {
body = n.bannerBodyMarkup
? n.bannerBodyText
body = n.bannerBodyMarkup ? n.bannerBodyText
: GLib.markup_escape_text(n.bannerBodyText, -1);
}
@@ -229,14 +224,14 @@ var NotificationsBox = GObject.registerClass({
this._showSource(source, obj, obj.sourceBox);
this._notificationBox.add(obj.sourceBox, { x_fill: false, x_align: St.Align.START });
obj.sourceCountChangedId = source.connect('notify::count', source => {
obj.sourceCountChangedId = source.connect('count-updated', source => {
this._countChanged(source, obj);
});
obj.sourceTitleChangedId = source.connect('notify::title', source => {
obj.sourceTitleChangedId = source.connect('title-changed', source => {
this._titleChanged(source, obj);
});
obj.policyChangedId = source.policy.connect('notify', (policy, pspec) => {
if (pspec.name == 'show-in-lock-screen')
obj.policyChangedId = source.policy.connect('policy-changed', (policy, key) => {
if (key == 'show-in-lock-screen')
this._visibleChanged(source, obj);
else
this._detailedChanged(source, obj);
@@ -256,10 +251,10 @@ var NotificationsBox = GObject.registerClass({
let widget = obj.sourceBox;
let [, natHeight] = widget.get_preferred_height(-1);
widget.height = 0;
widget.ease({
height: natHeight,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
duration: 250,
Tweener.addTween(widget,
{ height: natHeight,
transition: 'easeOutQuad',
time: 0.25,
onComplete: () => {
this._scrollView.vscrollbar_policy = St.PolicyType.AUTOMATIC;
widget.set_height(-1);
@@ -343,7 +338,8 @@ var NotificationsBox = GObject.registerClass({
this._sources.delete(source);
}
});
};
Signals.addSignalMethods(NotificationsBox.prototype);
var Arrow = GObject.registerClass(
class ScreenShieldArrow extends St.Bin {
@@ -436,8 +432,7 @@ var ScreenShield = class {
this.actor = Main.layoutManager.screenShieldGroup;
this._lockScreenState = MessageTray.State.HIDDEN;
this._lockScreenGroup = new St.Widget({
x_expand: true,
this._lockScreenGroup = new St.Widget({ x_expand: true,
y_expand: true,
reactive: true,
can_focus: true,
@@ -492,7 +487,7 @@ var ScreenShield = class {
this._lockDialogGroup = new St.Widget({ x_expand: true,
y_expand: true,
reactive: true,
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
pivot_point: new Clutter.Point({ x: 0.5, y: 0.5 }),
name: 'lockDialogGroup' });
this.actor.add_actor(this._lockDialogGroup);
@@ -563,11 +558,11 @@ var ScreenShield = class {
this._longLightbox = new Lightbox.Lightbox(Main.uiGroup,
{ inhibitEvents: true,
fadeFactor: 1 });
this._longLightbox.connect('notify::active', this._onLongLightbox.bind(this));
this._longLightbox.connect('shown', this._onLongLightboxShown.bind(this));
this._shortLightbox = new Lightbox.Lightbox(Main.uiGroup,
{ inhibitEvents: true,
fadeFactor: 1 });
this._shortLightbox.connect('notify::active', this._onShortLightbox.bind(this));
this._shortLightbox.connect('shown', this._onShortLightboxShown.bind(this));
this.idleMonitor = Meta.IdleMonitor.get_core();
this._cursorTracker = Meta.CursorTracker.get_for_display(global.display);
@@ -740,17 +735,15 @@ var ScreenShield = class {
let maxOpacity = 255 * ARROW_ANIMATION_PEAK_OPACITY;
for (let i = 0; i < arrows.length; i++) {
arrows[i].opacity = 0;
arrows[i].ease({
opacity: maxOpacity,
Tweener.addTween(arrows[i],
{ opacity: 0,
delay: unitaryDelay * (N_ARROWS - (i + 1)),
duration: ARROW_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
arrows[i].ease({
opacity: 0,
duration: ARROW_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_IN_QUAD
});
time: ARROW_ANIMATION_TIME,
transition(t, b, c, d) {
if (t < d / 2)
return TweenerEquations.easeOutQuad(t, 0, maxOpacity, d / 2);
else
return TweenerEquations.easeInQuad(t - d / 2, maxOpacity, -maxOpacity, d / 2);
}
});
}
@@ -759,7 +752,7 @@ var ScreenShield = class {
}
_onDragBegin() {
this._lockScreenGroup.remove_all_transitions();
Tweener.removeTweens(this._lockScreenGroup);
this._lockScreenState = MessageTray.State.HIDING;
if (this._isLocked)
@@ -791,12 +784,12 @@ var ScreenShield = class {
// restore the lock screen to its original place
// try to use the same speed as the normal animation
let h = global.stage.height;
let duration = MANUAL_FADE_TIME * (-this._lockScreenGroup.y) / h;
this._lockScreenGroup.remove_all_transitions();
this._lockScreenGroup.ease({
y: 0,
duration,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
let time = MANUAL_FADE_TIME * (-this._lockScreenGroup.y) / h;
Tweener.removeTweens(this._lockScreenGroup);
Tweener.addTween(this._lockScreenGroup,
{ y: 0,
time: time,
transition: 'easeInQuad',
onComplete: () => {
this._lockScreenGroup.fixed_position_set = false;
this._lockScreenState = MessageTray.State.SHOWN;
@@ -813,7 +806,7 @@ var ScreenShield = class {
this._maybeCancelDialog();
if (this._longLightbox.visible) {
if (this._longLightbox.actor.visible) {
// We're in the process of showing.
return;
}
@@ -837,12 +830,8 @@ var ScreenShield = class {
let shouldLock = this._settings.get_boolean(LOCK_ENABLED_KEY) && !this._isLocked;
if (shouldLock) {
let lockTimeout = Math.max(
adjustAnimationTime(STANDARD_FADE_TIME),
this._settings.get_uint(LOCK_DELAY_KEY) * 1000);
this._lockTimeoutId = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
lockTimeout,
let lockTimeout = Math.max(STANDARD_FADE_TIME, this._settings.get_uint(LOCK_DELAY_KEY));
this._lockTimeoutId = Mainloop.timeout_add(lockTimeout * 1000,
() => {
this._lockTimeoutId = 0;
this.lock(false);
@@ -855,8 +844,8 @@ var ScreenShield = class {
}
_activateFade(lightbox, time) {
Main.uiGroup.set_child_above_sibling(lightbox, null);
lightbox.lightOn(time);
Main.uiGroup.set_child_above_sibling(lightbox.actor, null);
lightbox.show(time);
if (this._becameActiveId == 0)
this._becameActiveId = this.idleMonitor.add_user_active_watch(this._onUserBecameActive.bind(this));
@@ -885,20 +874,18 @@ var ScreenShield = class {
this._becameActiveId = 0;
if (this._isActive || this._isLocked) {
this._longLightbox.lightOff();
this._shortLightbox.lightOff();
this._longLightbox.hide();
this._shortLightbox.hide();
} else {
this.deactivate(false);
}
}
_onLongLightbox(lightBox) {
if (lightBox.active)
_onLongLightboxShown() {
this.activate(false);
}
_onShortLightbox(lightBox) {
if (lightBox.active)
_onShortLightboxShown() {
this._completeLockScreenShown();
}
@@ -924,8 +911,8 @@ var ScreenShield = class {
this._lockScreenGroup.hide();
if (this._dialog) {
this._dialog.grab_key_focus();
this._dialog.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
this._dialog.actor.grab_key_focus();
this._dialog.actor.navigate_focus(null, St.DirectionType.TAB_FORWARD, false);
}
}
@@ -935,7 +922,7 @@ var ScreenShield = class {
this._lockScreenState = MessageTray.State.HIDING;
this._lockScreenGroup.remove_all_transitions();
Tweener.removeTweens(this._lockScreenGroup);
if (animate) {
// Tween the lock screen out of screen
@@ -944,16 +931,16 @@ var ScreenShield = class {
// if velocity is specified, it's in pixels per milliseconds
let h = global.stage.height;
let delta = (h + this._lockScreenGroup.y);
let minVelocity = global.stage.height / CURTAIN_SLIDE_TIME;
let minVelocity = global.stage.height / (CURTAIN_SLIDE_TIME * 1000);
velocity = Math.max(minVelocity, velocity);
let duration = delta / velocity;
let time = (delta / velocity) / 1000;
this._lockScreenGroup.ease({
y: -h,
duration,
mode: Clutter.AnimationMode.EASE_IN_QUAD,
onComplete: () => this._hideLockScreenComplete()
Tweener.addTween(this._lockScreenGroup,
{ y: -h,
time: time,
transition: 'easeInQuad',
onComplete: this._hideLockScreenComplete.bind(this),
});
} else {
this._hideLockScreenComplete();
@@ -973,6 +960,7 @@ var ScreenShield = class {
this._dialog = new constructor(this._lockDialogGroup);
let time = global.get_current_time();
if (!this._dialog.open(time, onPrimary)) {
// This is kind of an impossible error: we're already modal
@@ -1013,13 +1001,14 @@ var ScreenShield = class {
if (params.animateLockScreen) {
this._lockScreenGroup.y = -global.screen_height;
this._lockScreenGroup.remove_all_transitions();
this._lockScreenGroup.ease({
y: 0,
duration: MANUAL_FADE_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
Tweener.removeTweens(this._lockScreenGroup);
Tweener.addTween(this._lockScreenGroup,
{ y: 0,
time: MANUAL_FADE_TIME,
transition: 'easeOutQuad',
onComplete: () => {
this._lockScreenShown({ fadeToBlack, animateFade: true });
this._lockScreenShown({ fadeToBlack: fadeToBlack,
animateFade: true });
}
});
} else {
@@ -1038,7 +1027,7 @@ var ScreenShield = class {
this._arrowActiveWatchId = 0;
if (!this._arrowAnimationId) {
this._arrowAnimationId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 6000, this._animateArrows.bind(this));
this._arrowAnimationId = Mainloop.timeout_add(6000, this._animateArrows.bind(this));
GLib.Source.set_name_by_id(this._arrowAnimationId, '[gnome-shell] this._animateArrows');
this._animateArrows();
}
@@ -1050,7 +1039,7 @@ var ScreenShield = class {
_pauseArrowAnimation() {
if (this._arrowAnimationId) {
GLib.source_remove(this._arrowAnimationId);
Mainloop.source_remove(this._arrowAnimationId);
this._arrowAnimationId = 0;
}
@@ -1060,7 +1049,7 @@ var ScreenShield = class {
_stopArrowAnimation() {
if (this._arrowAnimationId) {
GLib.source_remove(this._arrowAnimationId);
Mainloop.source_remove(this._arrowAnimationId);
this._arrowAnimationId = 0;
}
if (this._arrowActiveWatchId) {
@@ -1107,7 +1096,7 @@ var ScreenShield = class {
if (params.fadeToBlack && params.animateFade) {
// Take a beat
let id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, MANUAL_FADE_TIME, () => {
let id = Mainloop.timeout_add(1000 * MANUAL_FADE_TIME, () => {
this._activateFade(this._shortLightbox, MANUAL_FADE_TIME);
return GLib.SOURCE_REMOVE;
});
@@ -1138,20 +1127,16 @@ var ScreenShield = class {
vertical: true,
style_class: 'screen-shield-contents-box' });
this._clock = new Clock();
this._lockScreenContentsBox.add(this._clock, {
x_fill: true,
y_fill: true
});
this._lockScreenContentsBox.add(this._clock.actor, { x_fill: true,
y_fill: true });
this._lockScreenContents.add_actor(this._lockScreenContentsBox);
this._notificationsBox = new NotificationsBox();
this._wakeUpScreenId = this._notificationsBox.connect('wake-up-screen', this._wakeUpScreen.bind(this));
this._lockScreenContentsBox.add(this._notificationsBox, {
x_fill: true,
this._lockScreenContentsBox.add(this._notificationsBox.actor, { x_fill: true,
y_fill: true,
expand: true
});
expand: true });
this._hasLockScreen = true;
}
@@ -1229,12 +1214,13 @@ var ScreenShield = class {
this._isModal = false;
}
this._lockDialogGroup.ease({
Tweener.addTween(this._lockDialogGroup, {
scale_x: 0,
scale_y: 0,
duration: animate ? Overview.ANIMATION_TIME : 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._completeDeactivate()
time: animate ? Overview.ANIMATION_TIME : 0,
transition: 'easeOutQuad',
onComplete: this._completeDeactivate.bind(this),
onCompleteScope: this
});
}
@@ -1244,8 +1230,8 @@ var ScreenShield = class {
this._dialog = null;
}
this._longLightbox.lightOff();
this._shortLightbox.lightOff();
this._longLightbox.hide();
this._shortLightbox.hide();
this.actor.hide();
if (this._becameActiveId != 0) {
@@ -1254,7 +1240,7 @@ var ScreenShield = class {
}
if (this._lockTimeoutId != 0) {
GLib.source_remove(this._lockTimeoutId);
Mainloop.source_remove(this._lockTimeoutId);
this._lockTimeoutId = 0;
}

View File

@@ -1,11 +1,13 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported ScreenshotService */
const { Clutter, Graphene, Gio, GObject, GLib, Meta, Shell, St } = imports.gi;
const { Clutter, Gio, GLib, Meta, Shell, St } = imports.gi;
const Signals = imports.signals;
const GrabHelper = imports.ui.grabHelper;
const Lightbox = imports.ui.lightbox;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const { loadInterfaceXML } = imports.misc.fileUtils;
@@ -115,8 +117,8 @@ var ScreenshotService = class {
try {
let [result, area, filenameUsed] =
screenshot.screenshot_area_finish(res);
this._onScreenshotComplete(
result, area, filenameUsed, flash, invocation);
this._onScreenshotComplete(result, area, filenameUsed,
flash, invocation);
} catch (e) {
invocation.return_gerror (e);
}
@@ -133,8 +135,8 @@ var ScreenshotService = class {
try {
let [result, area, filenameUsed] =
screenshot.screenshot_window_finish(res);
this._onScreenshotComplete(
result, area, filenameUsed, flash, invocation);
this._onScreenshotComplete(result, area, filenameUsed,
flash, invocation);
} catch (e) {
invocation.return_gerror (e);
}
@@ -151,8 +153,8 @@ var ScreenshotService = class {
try {
let [result, area, filenameUsed] =
screenshot.screenshot_finish(res);
this._onScreenshotComplete(
result, area, filenameUsed, flash, invocation);
this._onScreenshotComplete(result, area, filenameUsed,
flash, invocation);
} catch (e) {
invocation.return_gerror (e);
}
@@ -197,7 +199,7 @@ var ScreenshotService = class {
let screenshot = this._createScreenshot(invocation, false);
if (!screenshot)
return;
screenshot.pick_color(coords.x, coords.y, (_o, res) => {
screenshot.pick_color(...coords, (o, res) => {
let [success_, color] = screenshot.pick_color_finish(res);
let { red, green, blue } = color;
let retval = GLib.Variant.new('(a{sv})', [{
@@ -218,62 +220,62 @@ var ScreenshotService = class {
}
};
var SelectArea = GObject.registerClass({
GTypeName: 'Screenshot_SelectArea',
Signals: { 'finished': { param_types: [Meta.Rectangle.$gtype] } }
}, class SelectArea extends St.Widget {
_init() {
var SelectArea = class {
constructor() {
this._startX = -1;
this._startY = -1;
this._lastX = 0;
this._lastY = 0;
this._result = null;
super._init({
visible: false,
this._group = new St.Widget({ visible: false,
reactive: true,
x: 0,
y: 0
});
Main.uiGroup.add_actor(this);
y: 0 });
Main.uiGroup.add_actor(this._group);
this._grabHelper = new GrabHelper.GrabHelper(this);
this._grabHelper = new GrabHelper.GrabHelper(this._group);
this._group.connect('button-press-event',
this._onButtonPress.bind(this));
this._group.connect('button-release-event',
this._onButtonRelease.bind(this));
this._group.connect('motion-event',
this._onMotionEvent.bind(this));
let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.ALL });
this.add_constraint(constraint);
this._group.add_constraint(constraint);
this._rubberband = new St.Widget({
style_class: 'select-area-rubberband',
visible: false
});
this.add_actor(this._rubberband);
this._group.add_actor(this._rubberband);
}
vfunc_show() {
if (!this._grabHelper.grab({ actor: this,
show() {
if (!this._grabHelper.grab({ actor: this._group,
onUngrab: this._onUngrab.bind(this) }))
return;
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
Main.uiGroup.set_child_above_sibling(this, null);
super.vfunc_show();
Main.uiGroup.set_child_above_sibling(this._group, null);
this._group.visible = true;
}
_getGeometry() {
return new Meta.Rectangle({
x: Math.min(this._startX, this._lastX),
return { x: Math.min(this._startX, this._lastX),
y: Math.min(this._startY, this._lastY),
width: Math.abs(this._startX - this._lastX) + 1,
height: Math.abs(this._startY - this._lastY) + 1
});
height: Math.abs(this._startY - this._lastY) + 1 };
}
vfunc_motion_event(motionEvent) {
if (this._startX == -1 || this._startY == -1 || this._result)
_onMotionEvent(actor, event) {
if (this._startX == -1 || this._startY == -1)
return Clutter.EVENT_PROPAGATE;
[this._lastX, this._lastY] = [motionEvent.x, motionEvent.y];
[this._lastX, this._lastY] = event.get_coords();
this._lastX = Math.floor(this._lastX);
this._lastY = Math.floor(this._lastY);
let geometry = this._getGeometry();
@@ -285,8 +287,8 @@ var SelectArea = GObject.registerClass({
return Clutter.EVENT_PROPAGATE;
}
vfunc_button_press_event(buttonEvent) {
[this._startX, this._startY] = [buttonEvent.x, buttonEvent.y];
_onButtonPress(actor, event) {
[this._startX, this._startY] = event.get_coords();
this._startX = Math.floor(this._startX);
this._startY = Math.floor(this._startY);
this._rubberband.set_position(this._startX, this._startY);
@@ -294,13 +296,15 @@ var SelectArea = GObject.registerClass({
return Clutter.EVENT_PROPAGATE;
}
vfunc_button_release_event() {
_onButtonRelease() {
this._result = this._getGeometry();
this.ease({
opacity: 0,
duration: 200,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => this._grabHelper.ungrab()
Tweener.addTween(this._group,
{ opacity: 0,
time: 0.2,
transition: 'easeOutQuad',
onComplete: () => {
this._grabHelper.ungrab();
}
});
return Clutter.EVENT_PROPAGATE;
}
@@ -310,43 +314,43 @@ var SelectArea = GObject.registerClass({
this.emit('finished', this._result);
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.destroy();
this._group.destroy();
return GLib.SOURCE_REMOVE;
});
}
});
var PickPixel = GObject.registerClass({
GTypeName: 'Screenshot_PickPixel',
Signals: { 'finished': { param_types: [Graphene.Point.$gtype] } }
}, class PickPixel extends St.Widget {
_init() {
super._init({ visible: false, reactive: true });
};
Signals.addSignalMethods(SelectArea.prototype);
var PickPixel = class {
constructor() {
this._result = null;
Main.uiGroup.add_actor(this);
this._group = new St.Widget({ visible: false,
reactive: true });
Main.uiGroup.add_actor(this._group);
this._grabHelper = new GrabHelper.GrabHelper(this);
this._grabHelper = new GrabHelper.GrabHelper(this._group);
this._group.connect('button-release-event',
this._onButtonRelease.bind(this));
let constraint = new Clutter.BindConstraint({ source: global.stage,
coordinate: Clutter.BindCoordinate.ALL });
this.add_constraint(constraint);
this._group.add_constraint(constraint);
}
vfunc_show() {
if (!this._grabHelper.grab({ actor: this,
show() {
if (!this._grabHelper.grab({ actor: this._group,
onUngrab: this._onUngrab.bind(this) }))
return;
global.display.set_cursor(Meta.Cursor.CROSSHAIR);
Main.uiGroup.set_child_above_sibling(this, null);
super.vfunc_show();
Main.uiGroup.set_child_above_sibling(this._group, null);
this._group.visible = true;
}
vfunc_button_release_event(buttonEvent) {
let { x, y } = buttonEvent;
this._result = new Graphene.Point({ x, y });
_onButtonRelease(actor, event) {
this._result = event.get_coords();
this._grabHelper.ungrab();
return Clutter.EVENT_PROPAGATE;
}
@@ -356,32 +360,32 @@ var PickPixel = GObject.registerClass({
this.emit('finished', this._result);
GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
this.destroy();
this._group.destroy();
return GLib.SOURCE_REMOVE;
});
}
});
};
Signals.addSignalMethods(PickPixel.prototype);
var FLASHSPOT_ANIMATION_OUT_TIME = 500; // milliseconds
var FLASHSPOT_ANIMATION_OUT_TIME = 0.5; // seconds
var Flashspot = GObject.registerClass(
class Flashspot extends Lightbox.Lightbox {
_init(area) {
super._init(Main.uiGroup, {
inhibitEvents: true,
var Flashspot = class extends Lightbox.Lightbox {
constructor(area) {
super(Main.uiGroup, { inhibitEvents: true,
width: area.width,
height: area.height
});
this.style_class = 'flashspot';
this.set_position(area.x, area.y);
height: area.height });
this.actor.style_class = 'flashspot';
this.actor.set_position(area.x, area.y);
}
fire(doneCallback) {
this.set({ visible: true, opacity: 255 });
this.ease({
opacity: 0,
duration: FLASHSPOT_ANIMATION_OUT_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
this.actor.show();
this.actor.opacity = 255;
Tweener.addTween(this.actor,
{ opacity: 0,
time: FLASHSPOT_ANIMATION_OUT_TIME,
transition: 'easeOutQuad',
onComplete: () => {
if (doneCallback)
doneCallback();
@@ -389,4 +393,4 @@ class Flashspot extends Lightbox.Lightbox {
}
});
}
});
};

View File

@@ -4,6 +4,7 @@
collectStatistics, runPerfScript */
const { Gio, GLib, Meta, Shell } = imports.gi;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const Params = imports.misc.params;
@@ -40,7 +41,7 @@ const { loadInterfaceXML } = imports.misc.fileUtils;
*/
function sleep(milliseconds) {
return new Promise(resolve => {
let id = GLib.timeout_add(GLib.PRIORITY_DEFAULT, milliseconds, () => {
let id = Mainloop.timeout_add(milliseconds, () => {
resolve();
return GLib.SOURCE_REMOVE;
});
@@ -317,7 +318,7 @@ async function runPerfScript(scriptModule, outputFile) {
for (let step of scriptModule.run()) {
try {
await step; // eslint-disable-line no-await-in-loop
await step;
} catch (err) {
log(`Script failed: ${err}\n${err.stack}`);
Meta.exit(Meta.ExitCode.ERROR);

View File

@@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported SearchResultsView */
const { Clutter, Gio, GLib, GObject, Meta, Shell, St } = imports.gi;
const { Clutter, Gio, GLib, GObject, Shell, St } = imports.gi;
const Signals = imports.signals;
const AppDisplay = imports.ui.appDisplay;
const IconGrid = imports.ui.iconGrid;
@@ -32,47 +32,39 @@ class MaxWidthBox extends St.BoxLayout {
}
});
var SearchResult = GObject.registerClass(
class SearchResult extends St.Button {
_init(provider, metaInfo, resultsView) {
var SearchResult = class {
constructor(provider, metaInfo, resultsView) {
this.provider = provider;
this.metaInfo = metaInfo;
this._resultsView = resultsView;
super._init({
reactive: true,
this.actor = new St.Button({ reactive: true,
can_focus: true,
track_hover: true,
x_align: St.Align.START,
y_fill: true
});
}
y_fill: true });
vfunc_clicked() {
this.activate();
this.actor._delegate = this;
this.actor.connect('clicked', this.activate.bind(this));
}
activate() {
this.provider.activateResult(this.metaInfo.id, this._resultsView.terms);
if (this.metaInfo.clipboardText)
St.Clipboard.get_default().set_text(
St.ClipboardType.CLIPBOARD, this.metaInfo.clipboardText);
Main.overview.toggle();
this.emit('activate', this.metaInfo.id);
}
});
};
Signals.addSignalMethods(SearchResult.prototype);
var ListSearchResult = GObject.registerClass(
class ListSearchResult extends SearchResult {
_init(provider, metaInfo, resultsView) {
super._init(provider, metaInfo, resultsView);
var ListSearchResult = class extends SearchResult {
this.style_class = 'list-search-result';
this.x_fill = true;
constructor(provider, metaInfo, resultsView) {
super(provider, metaInfo, resultsView);
this.actor.style_class = 'list-search-result';
this.actor.x_fill = true;
let content = new St.BoxLayout({ style_class: 'list-search-result-content',
vertical: false });
this.set_child(content);
this.actor.set_child(content);
this._termsChangedId = 0;
@@ -95,7 +87,7 @@ class ListSearchResult extends SearchResult {
x_align: St.Align.START,
y_align: St.Align.MIDDLE });
this.label_actor = title;
this.actor.label_actor = title;
if (this.metaInfo['description']) {
this._descriptionLabel = new St.Label({ style_class: 'list-search-result-description' });
@@ -111,7 +103,7 @@ class ListSearchResult extends SearchResult {
this._highlightTerms();
}
this.connect('destroy', this._onDestroy.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this));
}
get ICON_SIZE() {
@@ -128,56 +120,48 @@ class ListSearchResult extends SearchResult {
this._resultsView.disconnect(this._termsChangedId);
this._termsChangedId = 0;
}
});
};
var GridSearchResult = GObject.registerClass(
class GridSearchResult extends SearchResult {
_init(provider, metaInfo, resultsView) {
super._init(provider, metaInfo, resultsView);
var GridSearchResult = class extends SearchResult {
constructor(provider, metaInfo, resultsView) {
super(provider, metaInfo, resultsView);
this.style_class = 'grid-search-result';
this.actor.style_class = 'grid-search-result';
this.icon = new IconGrid.BaseIcon(this.metaInfo['name'],
{ createIcon: this.metaInfo['createIcon'] });
let content = new St.Bin({ child: this.icon });
this.set_child(content);
this.label_actor = this.icon.label;
this.actor.set_child(content);
this.actor.label_actor = this.icon.label;
}
});
var SearchResultsBase = GObject.registerClass({
GTypeFlags: GObject.TypeFlags.ABSTRACT,
Properties: {
'focus-child': GObject.ParamSpec.object(
'focus-child', 'focus-child', 'focus-child',
GObject.ParamFlags.READABLE,
Clutter.Actor.$gtype),
}
}, class SearchResultsBase extends St.BoxLayout {
_init(provider, resultsView) {
super._init({ style_class: 'search-section', vertical: true });
};
var SearchResultsBase = class {
constructor(provider, resultsView) {
this.provider = provider;
this._resultsView = resultsView;
this._terms = [];
this._focusChild = null;
this.actor = new St.BoxLayout({ style_class: 'search-section',
vertical: true });
this._resultDisplayBin = new St.Bin({ x_fill: true,
y_fill: true });
this.add(this._resultDisplayBin, { expand: true });
this.actor.add(this._resultDisplayBin, { expand: true });
let separator = new St.Widget({ style_class: 'search-section-separator' });
this.add(separator);
this.actor.add(separator);
this._resultDisplays = {};
this._cancellable = new Gio.Cancellable();
this._clipboard = St.Clipboard.get_default();
this.connect('destroy', this._onDestroy.bind(this));
this._cancellable = new Gio.Cancellable();
}
_onDestroy() {
destroy() {
this.actor.destroy();
this._terms = [];
}
@@ -191,21 +175,21 @@ var SearchResultsBase = GObject.registerClass({
clear() {
this._cancellable.cancel();
for (let resultId in this._resultDisplays)
this._resultDisplays[resultId].destroy();
this._resultDisplays[resultId].actor.destroy();
this._resultDisplays = {};
this._clearResultDisplay();
this.hide();
}
get focusChild() {
return this._focusChild;
this.actor.hide();
}
_keyFocusIn(actor) {
if (this._focusChild == actor)
return;
this._focusChild = actor;
this.notify('focus-child');
this.emit('key-focus-in', actor);
}
_activateResult(result, id) {
this.provider.activateResult(id, this._terms);
if (result.metaInfo.clipboardText)
this._clipboard.set_text(St.ClipboardType.CLIPBOARD, result.metaInfo.clipboardText);
Main.overview.toggle();
}
_setMoreCount(_count) {
@@ -244,7 +228,8 @@ var SearchResultsBase = GObject.registerClass({
metasNeeded.forEach((resultId, i) => {
let meta = metas[i];
let display = this._createResultDisplay(meta);
display.connect('key-focus-in', this._keyFocusIn.bind(this));
display.connect('activate', this._activateResult.bind(this));
display.actor.connect('key-focus-in', this._keyFocusIn.bind(this));
this._resultDisplays[resultId] = display;
});
callback(true);
@@ -256,13 +241,11 @@ var SearchResultsBase = GObject.registerClass({
this._terms = terms;
if (providerResults.length == 0) {
this._clearResultDisplay();
this.hide();
this.actor.hide();
callback();
} else {
let maxResults = this._getMaxDisplayedResults();
let results = maxResults > -1
? this.provider.filterResults(providerResults, maxResults)
: providerResults;
let results = this.provider.filterResults(providerResults, maxResults);
let moreCount = Math.max(providerResults.length - results.length, 0);
this._ensureResultActors(results, successful => {
@@ -275,23 +258,22 @@ var SearchResultsBase = GObject.registerClass({
// To avoid CSS transitions causing flickering when
// the first search result stays the same, we hide the
// content while filling in the results.
this.hide();
this.actor.hide();
this._clearResultDisplay();
results.forEach(resultId => {
this._addItem(this._resultDisplays[resultId]);
});
this._setMoreCount(this.provider.canLaunchSearch ? moreCount : 0);
this.show();
this.actor.show();
callback();
});
}
}
});
};
var ListSearchResults = GObject.registerClass(
class ListSearchResults extends SearchResultsBase {
_init(provider, resultsView) {
super._init(provider, resultsView);
var ListSearchResults = class extends SearchResultsBase {
constructor(provider, resultsView) {
super(provider, resultsView);
this._container = new St.BoxLayout({ style_class: 'search-section-content' });
this.providerInfo = new ProviderInfo(provider);
@@ -332,21 +314,21 @@ class ListSearchResults extends SearchResultsBase {
}
_addItem(display) {
this._content.add_actor(display);
this._content.add_actor(display.actor);
}
getFirstResult() {
if (this._content.get_n_children() > 0)
return this._content.get_child_at_index(0);
return this._content.get_child_at_index(0)._delegate;
else
return null;
}
});
};
Signals.addSignalMethods(ListSearchResults.prototype);
var GridSearchResults = GObject.registerClass(
class GridSearchResults extends SearchResultsBase {
_init(provider, resultsView) {
super._init(provider, resultsView);
var GridSearchResults = class extends SearchResultsBase {
constructor(provider, resultsView) {
super(provider, resultsView);
this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS,
xAlign: St.Align.START });
@@ -357,44 +339,22 @@ class GridSearchResults extends SearchResultsBase {
this._resultDisplayBin.set_child(this._bin);
}
_onDestroy() {
if (this._updateSearchLater) {
Meta.later_remove(this._updateSearchLater);
delete this._updateSearchLater;
}
super._onDestroy();
}
updateSearch(...args) {
if (this._notifyAllocationId)
this.disconnect(this._notifyAllocationId);
if (this._updateSearchLater) {
Meta.later_remove(this._updateSearchLater);
delete this._updateSearchLater;
}
this.actor.disconnect(this._notifyAllocationId);
// Make sure the maximum number of results calculated by
// _getMaxDisplayedResults() is updated after width changes.
this._notifyAllocationId = this.connect('notify::allocation', () => {
if (this._updateSearchLater)
return;
this._updateSearchLater = Meta.later_add(Meta.LaterType.BEFORE_REDRAW, () => {
delete this._updateSearchLater;
this._notifyAllocationId = this.actor.connect('notify::allocation', () => {
super.updateSearch(...args);
return GLib.SOURCE_REMOVE;
});
});
super.updateSearch(...args);
}
_getMaxDisplayedResults() {
let width = this.allocation.get_width();
if (width == 0)
return -1;
let nCols = this._grid.columnsForWidth(width);
let allocation = this.actor.allocation;
let nCols = this._grid.columnsForWidth(allocation.x2 - allocation.x1);
return nCols * this._grid.getRowLimit();
}
@@ -413,17 +373,17 @@ class GridSearchResults extends SearchResultsBase {
getFirstResult() {
if (this._grid.visibleItemsCount() > 0)
return this._grid.getItemAtIndex(0);
return this._grid.getItemAtIndex(0)._delegate;
else
return null;
}
});
};
Signals.addSignalMethods(GridSearchResults.prototype);
var SearchResultsView = GObject.registerClass({
Signals: { 'terms-changed': {} }
}, class SearchResultsView extends St.BoxLayout {
_init() {
super._init({ name: 'searchResults', vertical: true });
var SearchResults = class {
constructor() {
this.actor = new St.BoxLayout({ name: 'searchResults',
vertical: true });
this._content = new MaxWidthBox({ name: 'searchResultsContent',
vertical: true });
@@ -439,18 +399,16 @@ var SearchResultsView = GObject.registerClass({
action.connect('pan', this._onPan.bind(this));
this._scrollView.add_action(action);
this.add(this._scrollView, {
x_fill: true,
this.actor.add(this._scrollView, { x_fill: true,
y_fill: true,
expand: true,
x_align: St.Align.START,
y_align: St.Align.STAR
});
y_align: St.Align.START });
this._statusText = new St.Label({ style_class: 'search-statustext' });
this._statusBin = new St.Bin({ x_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE });
this.add(this._statusBin, { expand: true });
this.actor.add(this._statusBin, { expand: true });
this._statusBin.add_actor(this._statusText);
this._highlightDefault = false;
@@ -480,10 +438,6 @@ var SearchResultsView = GObject.registerClass({
this._reloadRemoteProviders();
}
get terms() {
return this._terms;
}
_reloadRemoteProviders() {
let remoteProviders = this._providers.filter(p => p.isRemoteProvider);
remoteProviders.forEach(provider => {
@@ -608,12 +562,12 @@ var SearchResultsView = GObject.registerClass({
_onPan(action) {
let [dist_, dx_, dy] = action.get_motion_delta(0);
let adjustment = this._scrollView.vscroll.adjustment;
adjustment.value -= (dy / this.height) * adjustment.page_size;
adjustment.value -= (dy / this.actor.height) * adjustment.page_size;
return false;
}
_focusChildChanged(provider) {
Util.ensureActorVisibleInScrollView(this._scrollView, provider.focusChild);
_keyFocusIn(provider, actor) {
Util.ensureActorVisibleInScrollView(this._scrollView, actor);
}
_ensureProviderDisplay(provider) {
@@ -626,9 +580,9 @@ var SearchResultsView = GObject.registerClass({
else
providerDisplay = new GridSearchResults(provider, this);
providerDisplay.connect('notify::focus-child', this._focusChildChanged.bind(this));
providerDisplay.hide();
this._content.add(providerDisplay);
providerDisplay.connect('key-focus-in', this._keyFocusIn.bind(this));
providerDisplay.actor.hide();
this._content.add(providerDisplay.actor);
provider.display = providerDisplay;
}
@@ -646,7 +600,7 @@ var SearchResultsView = GObject.registerClass({
let provider = providers[i];
let display = provider.display;
if (!display.visible)
if (!display.actor.visible)
continue;
let firstResult = display.getFirstResult();
@@ -721,22 +675,21 @@ var SearchResultsView = GObject.registerClass({
this._doSearch();
if (this._defaultResult)
this._defaultResult.popup_menu();
this._defaultResult.actor.popup_menu();
}
navigateFocus(direction) {
let rtl = this.get_text_direction() == Clutter.TextDirection.RTL;
let rtl = this.actor.get_text_direction() == Clutter.TextDirection.RTL;
if (direction == St.DirectionType.TAB_BACKWARD ||
direction == (rtl
? St.DirectionType.RIGHT
direction == (rtl ? St.DirectionType.RIGHT
: St.DirectionType.LEFT) ||
direction == St.DirectionType.UP) {
this.navigate_focus(null, direction, false);
this.actor.navigate_focus(null, direction, false);
return;
}
let from = this._defaultResult ? this._defaultResult : null;
this.navigate_focus(from, direction, false);
let from = this._defaultResult ? this._defaultResult.actor : null;
this.actor.navigate_focus(from, direction, false);
}
_setSelected(result, selected) {
@@ -744,10 +697,10 @@ var SearchResultsView = GObject.registerClass({
return;
if (selected) {
result.add_style_pseudo_class('selected');
Util.ensureActorVisibleInScrollView(this._scrollView, result);
result.actor.add_style_pseudo_class('selected');
Util.ensureActorVisibleInScrollView(this._scrollView, result.actor);
} else {
result.remove_style_pseudo_class('selected');
result.actor.remove_style_pseudo_class('selected');
}
}
@@ -760,7 +713,8 @@ var SearchResultsView = GObject.registerClass({
return description.replace(this._highlightRegex, '<b>$1</b>');
}
});
};
Signals.addSignalMethods(SearchResults.prototype);
var ProviderInfo = GObject.registerClass(
class ProviderInfo extends St.Button {

View File

@@ -2,6 +2,7 @@
/* exported SessionMode, listModes */
const GLib = imports.gi.GLib;
const Mainloop = imports.mainloop;
const Signals = imports.signals;
const FileUtils = imports.misc.fileUtils;
@@ -92,10 +93,10 @@ const _modes = {
isLocked: false,
isPrimary: true,
unlockDialog: imports.ui.unlockDialog.UnlockDialog,
components: Config.HAVE_NETWORKMANAGER
? ['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager']
: ['polkitAgent', 'telepathyClient',
components: Config.HAVE_NETWORKMANAGER ?
['networkAgent', 'polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'] :
['polkitAgent', 'telepathyClient',
'keyring', 'autorunManager', 'automountManager'],
panel: {
@@ -111,7 +112,7 @@ function _loadMode(file, info) {
let suffix = name.indexOf('.json');
let modeName = suffix == -1 ? name : name.slice(name, suffix);
if (Object.prototype.hasOwnProperty.call(_modes, modeName))
if (_modes.hasOwnProperty(modeName))
return;
let fileContent, success_, newMode;
@@ -140,16 +141,15 @@ function _loadModes() {
function listModes() {
_loadModes();
let loop = new GLib.MainLoop(null, false);
let id = GLib.idle_add(GLib.PRIORITY_DEFAULT, () => {
let id = Mainloop.idle_add(() => {
let names = Object.getOwnPropertyNames(_modes);
for (let i = 0; i < names.length; i++)
if (_modes[names[i]].isPrimary)
print(names[i]);
loop.quit();
Mainloop.quit('listModes');
});
GLib.Source.set_name_by_id(id, '[gnome-shell] listModes');
loop.run();
Mainloop.run('listModes');
}
var SessionMode = class {

View File

@@ -151,13 +151,9 @@ var GnomeShell = class {
let connection = this._dbusImpl.get_connection();
let info = this._dbusImpl.get_info();
let params = { 'device-id': GLib.Variant.new('u', device.get_device_id()),
'device-node': GLib.Variant.new('s', device.get_device_node()),
'timestamp': GLib.Variant.new('u', timestamp),
'action-mode': GLib.Variant.new('u', Main.actionMode) };
let deviceNode = device.get_device_node();
if (deviceNode)
params['device-node'] = GLib.Variant.new('s', deviceNode);
connection.emit_signal(destination,
this._dbusImpl.get_object_path(),
info ? info.name : null,

View File

@@ -2,6 +2,7 @@
/* exported ShellMountOperation, GnomeShellMountOpHandler */
const { Clutter, Gio, GLib, GObject, Pango, Shell, St } = imports.gi;
const Signals = imports.signals;
const Animation = imports.ui.animation;
const CheckBox = imports.ui.checkBox;
@@ -25,9 +26,8 @@ function _setButtonsForChoices(dialog, choices) {
for (let idx = 0; idx < choices.length; idx++) {
let button = idx;
buttons.unshift({
label: choices[idx],
action: () => dialog.emit('response', button),
buttons.unshift({ label: choices[idx],
action: () => dialog.emit('response', button)
});
}
@@ -43,22 +43,18 @@ function _setLabelsForMessage(content, message) {
/* -------------------------------------------------------- */
var ListItem = GObject.registerClass({
GTypeName: 'ShellMountOperation_ListItem',
Signals: { 'activate': {} }
}, class ListItem extends St.Button {
_init(app) {
var ListItem = class {
constructor(app) {
this._app = app;
let layout = new St.BoxLayout({ vertical: false });
super._init({
style_class: 'mount-dialog-app-list-item',
this.actor = new St.Button({ style_class: 'mount-dialog-app-list-item',
can_focus: true,
child: layout,
reactive: true,
x_align: St.Align.START,
x_fill: true
});
this._app = app;
x_fill: true });
this._icon = this._app.create_icon_texture(LIST_ITEM_ICON_SIZE);
@@ -71,13 +67,16 @@ var ListItem = GObject.registerClass({
let labelBin = new St.Bin({ y_align: St.Align.MIDDLE,
child: this._nameLabel });
layout.add(labelBin);
this.actor.connect('clicked', this._onClicked.bind(this));
}
vfunc_clicked() {
_onClicked() {
this.emit('activate');
this._app.activate();
}
});
};
Signals.addSignalMethods(ListItem.prototype);
var ShellMountOperation = class {
constructor(source, params) {
@@ -219,10 +218,9 @@ var ShellMountOperation = class {
}
};
var ShellUnmountNotifier = GObject.registerClass(
class ShellUnmountNotifier extends MessageTray.Source {
_init() {
super._init('', 'media-removable');
var ShellUnmountNotifier = class extends MessageTray.Source {
constructor() {
super('', 'media-removable');
this._notification = null;
Main.messageTray.add(this);
@@ -239,7 +237,7 @@ class ShellUnmountNotifier extends MessageTray.Source {
this._notification.update(header, text);
}
this.showNotification(this._notification);
this.notify(this._notification);
}
done(message) {
@@ -252,10 +250,10 @@ class ShellUnmountNotifier extends MessageTray.Source {
let notification = new MessageTray.Notification(this, message, null);
notification.setTransient(true);
this.showNotification(notification);
this.notify(notification);
}
}
});
};
var ShellMountQuestionDialog = GObject.registerClass({
Signals: { 'response': { param_types: [GObject.TYPE_INT] } }
@@ -304,14 +302,14 @@ var ShellMountPasswordDialog = GObject.registerClass({
visible: false }));
this._hiddenVolume = new CheckBox.CheckBox(_("Hidden Volume"));
content.messageBox.add(this._hiddenVolume);
content.messageBox.add(this._hiddenVolume.actor);
this._systemVolume = new CheckBox.CheckBox(_("Windows System Volume"));
content.messageBox.add(this._systemVolume);
content.messageBox.add(this._systemVolume.actor);
this._keyfilesCheckbox = new CheckBox.CheckBox(_("Uses Keyfiles"));
this._keyfilesCheckbox.connect("clicked", this._onKeyfilesCheckboxClicked.bind(this));
content.messageBox.add(this._keyfilesCheckbox);
this._keyfilesCheckbox.actor.connect("clicked", this._onKeyfilesCheckboxClicked.bind(this));
content.messageBox.add(this._keyfilesCheckbox.actor);
this._keyfilesLabel.clutter_text.set_markup(
/* Translators: %s is the Disks application */
@@ -361,7 +359,7 @@ var ShellMountPasswordDialog = GObject.registerClass({
ShellEntry.addContextMenu(this._passwordEntry, { isPassword: true });
this.setInitialKeyFocus(this._passwordEntry);
this._workSpinner = new Animation.Spinner(WORK_SPINNER_ICON_SIZE, true);
this._passwordEntry.secondary_icon = this._workSpinner;
this._passwordEntry.secondary_icon = this._workSpinner.actor;
if (rtl) {
layout.attach(this._passwordEntry, 0, 1, 1, 1);
@@ -382,32 +380,30 @@ var ShellMountPasswordDialog = GObject.registerClass({
if (flags & Gio.AskPasswordFlags.SAVING_SUPPORTED) {
this._rememberChoice = new CheckBox.CheckBox(_("Remember Password"));
this._rememberChoice.checked =
this._rememberChoice.actor.checked =
global.settings.get_boolean(REMEMBER_MOUNT_PASSWORD_KEY);
content.messageBox.add(this._rememberChoice);
content.messageBox.add(this._rememberChoice.actor);
} else {
this._rememberChoice = null;
}
this._defaultButtons = [{
label: _("Cancel"),
this._defaultButtons = [{ label: _("Cancel"),
action: this._onCancelButton.bind(this),
key: Clutter.Escape,
}, {
label: _("Unlock"),
key: Clutter.Escape
},
{ label: _("Unlock"),
action: this._onUnlockButton.bind(this),
default: true,
default: true
}];
this._usesKeyfilesButtons = [{
label: _("Cancel"),
this._usesKeyfilesButtons = [{ label: _("Cancel"),
action: this._onCancelButton.bind(this),
key: Clutter.Escape,
}, {
/* Translators: %s is the Disks application */
key: Clutter.Escape
},
{ /* Translators: %s is the Disks application */
label: _("Open %s").format(disksApp.get_name()),
action: this._onOpenDisksButton.bind(this),
default: true,
default: true
}];
this.setButtons(this._defaultButtons);
@@ -440,22 +436,22 @@ var ShellMountPasswordDialog = GObject.registerClass({
}
global.settings.set_boolean(REMEMBER_MOUNT_PASSWORD_KEY,
this._rememberChoice && this._rememberChoice.checked);
this._rememberChoice && this._rememberChoice.actor.checked);
this._workSpinner.play();
this.emit('response', 1,
this._passwordEntry.get_text(),
this._rememberChoice &&
this._rememberChoice.checked,
this._rememberChoice.actor.checked,
this._hiddenVolume &&
this._hiddenVolume.checked,
this._hiddenVolume.actor.checked,
this._systemVolume &&
this._systemVolume.checked,
this._systemVolume.actor.checked,
parseInt(pim));
}
_onKeyfilesCheckboxClicked() {
let useKeyfiles = this._keyfilesCheckbox.checked;
let useKeyfiles = this._keyfilesCheckbox.actor.checked;
this._passwordEntry.reactive = !useKeyfiles;
this._passwordEntry.can_focus = !useKeyfiles;
this._passwordEntry.clutter_text.editable = !useKeyfiles;
@@ -464,8 +460,8 @@ var ShellMountPasswordDialog = GObject.registerClass({
this._pimEntry.can_focus = !useKeyfiles;
this._pimEntry.clutter_text.editable = !useKeyfiles;
this._pimEntry.clutter_text.selectable = !useKeyfiles;
this._rememberChoice.reactive = !useKeyfiles;
this._rememberChoice.can_focus = !useKeyfiles;
this._rememberChoice.actor.reactive = !useKeyfiles;
this._rememberChoice.actor.can_focus = !useKeyfiles;
this._keyfilesLabel.visible = useKeyfiles;
this.setButtons(useKeyfiles ? this._usesKeyfilesButtons : this._defaultButtons);
}
@@ -528,7 +524,7 @@ var ShellProcessesDialog = GObject.registerClass({
return;
let item = new ListItem(app);
this._applicationList.add(item, { x_fill: true });
this._applicationList.add(item.actor, { x_fill: true });
item.connect('activate', () => {
// use -1 to indicate Cancel

View File

@@ -1,40 +1,41 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
/* exported Slider */
const { Atk, Clutter, GObject } = imports.gi;
const { Atk, Clutter } = imports.gi;
const Signals = imports.signals;
const BarLevel = imports.ui.barLevel;
var SLIDER_SCROLL_STEP = 0.02; /* Slider scrolling step in % */
var Slider = GObject.registerClass({
Signals: {
'drag-begin': {},
'drag-end': {}
}
}, class Slider extends BarLevel.BarLevel {
_init(value) {
super._init({
value,
style_class: 'slider',
can_focus: true,
var Slider = class extends BarLevel.BarLevel {
constructor(value) {
let params = {
styleClass: 'slider',
canFocus: true,
reactive: true,
accessible_role: Atk.Role.SLIDER
});
accessibleRole: Atk.Role.SLIDER,
};
super(value, params);
this._releaseId = 0;
this.actor.connect('button-press-event', this._startDragging.bind(this));
this.actor.connect('touch-event', this._touchDragging.bind(this));
this.actor.connect('scroll-event', this._onScrollEvent.bind(this));
this.actor.connect('key-press-event', this.onKeyPressEvent.bind(this));
this._releaseId = this._motionId = 0;
this._dragging = false;
this._customAccessible.connect('get-minimum-increment', this._getMinimumIncrement.bind(this));
}
vfunc_repaint() {
super.vfunc_repaint();
_barLevelRepaint(area) {
super._barLevelRepaint(area);
// Add handle
let cr = this.get_context();
let themeNode = this.get_theme_node();
let [width, height] = this.get_surface_size();
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let handleRadius = themeNode.get_length('-slider-handle-radius');
@@ -57,8 +58,8 @@ var Slider = GObject.registerClass({
cr.$dispose();
}
vfunc_button_press_event() {
return this.startDragging(Clutter.get_current_event());
_startDragging(actor, event) {
return this.startDragging(event);
}
startDragging(event) {
@@ -71,15 +72,20 @@ var Slider = GObject.registerClass({
let sequence = event.get_event_sequence();
if (sequence != null)
device.sequence_grab(sequence, this);
device.sequence_grab(sequence, this.actor);
else
device.grab(this);
device.grab(this.actor);
this._grabbedDevice = device;
this._grabbedSequence = sequence;
if (sequence == null) {
this._releaseId = this.actor.connect('button-release-event', this._endDragging.bind(this));
this._motionId = this.actor.connect('motion-event', this._motionEvent.bind(this));
}
// We need to emit 'drag-begin' before moving the handle to make
// sure that no 'notify::value' signal is emitted before this one.
// sure that no 'value-changed' signal is emitted before this one.
this.emit('drag-begin');
let absX, absY;
@@ -90,10 +96,10 @@ var Slider = GObject.registerClass({
_endDragging() {
if (this._dragging) {
if (this._releaseId) {
this.disconnect(this._releaseId);
this._releaseId = 0;
}
if (this._releaseId)
this.actor.disconnect(this._releaseId);
if (this._motionId)
this.actor.disconnect(this._motionId);
if (this._grabbedSequence != null)
this._grabbedDevice.sequence_ungrab(this._grabbedSequence);
@@ -109,15 +115,7 @@ var Slider = GObject.registerClass({
return Clutter.EVENT_STOP;
}
vfunc_button_release_event() {
if (this._dragging && !this._grabbedSequence)
return this._endDragging();
return Clutter.EVENT_PROPAGATE;
}
vfunc_touch_event() {
let event = Clutter.get_current_event();
_touchDragging(actor, event) {
let device = event.get_device();
let sequence = event.get_event_sequence();
@@ -125,9 +123,9 @@ var Slider = GObject.registerClass({
event.type() == Clutter.EventType.TOUCH_BEGIN) {
this.startDragging(event);
return Clutter.EVENT_STOP;
} else if (device.sequence_get_grabbed_actor(sequence) == this) {
} else if (device.sequence_get_grabbed_actor(sequence) == actor) {
if (event.type() == Clutter.EventType.TOUCH_UPDATE)
return this._motionEvent(this, event);
return this._motionEvent(actor, event);
else if (event.type() == Clutter.EventType.TOUCH_END)
return this._endDragging();
}
@@ -153,20 +151,15 @@ var Slider = GObject.registerClass({
delta = -dy * SLIDER_SCROLL_STEP;
}
this.value = Math.min(Math.max(0, this._value + delta), this._maxValue);
this._value = Math.min(Math.max(0, this._value + delta), this._maxValue);
this.actor.queue_repaint();
this.emit('value-changed', this._value);
return Clutter.EVENT_STOP;
}
vfunc_scroll_event() {
return this.scroll(Clutter.get_current_event());
}
vfunc_motion_event() {
if (this._dragging && !this._grabbedSequence)
return this._motionEvent(this, Clutter.get_current_event());
return Clutter.EVENT_PROPAGATE;
_onScrollEvent(actor, event) {
return this.scroll(event);
}
_motionEvent(actor, event) {
@@ -176,12 +169,14 @@ var Slider = GObject.registerClass({
return Clutter.EVENT_STOP;
}
vfunc_key_press_event(keyPressEvent) {
let key = keyPressEvent.keyval;
onKeyPressEvent(actor, event) {
let key = event.get_key_symbol();
if (key == Clutter.KEY_Right || key == Clutter.KEY_Left) {
let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
this._value = Math.max(0, Math.min(this._value + delta, this._maxValue));
this.actor.queue_repaint();
this.emit('drag-begin');
this.value = Math.max(0, Math.min(this._value + delta, this._maxValue));
this.emit('value-changed', this._value);
this.emit('drag-end');
return Clutter.EVENT_STOP;
}
@@ -190,11 +185,11 @@ var Slider = GObject.registerClass({
_moveHandle(absX, _absY) {
let relX, sliderX;
[sliderX] = this.get_transformed_position();
[sliderX] = this.actor.get_transformed_position();
relX = absX - sliderX;
let width = this._barLevelWidth;
let handleRadius = this.get_theme_node().get_length('-slider-handle-radius');
let handleRadius = this.actor.get_theme_node().get_length('-slider-handle-radius');
let newvalue;
if (relX < handleRadius)
@@ -203,10 +198,13 @@ var Slider = GObject.registerClass({
newvalue = 1;
else
newvalue = (relX - handleRadius) / (width - 2 * handleRadius);
this.value = newvalue * this._maxValue;
this._value = newvalue * this._maxValue;
this.actor.queue_repaint();
this.emit('value-changed', this._value);
}
_getMinimumIncrement() {
return 0.1;
}
});
};
Signals.addSignalMethods(Slider.prototype);

View File

@@ -2,6 +2,7 @@
/* exported ATIndicator */
const { Gio, GLib, GObject, St } = imports.gi;
const Mainloop = imports.mainloop;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
@@ -95,14 +96,14 @@ class ATIndicator extends PanelMenu.Button {
if (this._syncMenuVisibilityIdle)
return;
this._syncMenuVisibilityIdle = GLib.idle_add(GLib.PRIORITY_DEFAULT, this._syncMenuVisibility.bind(this));
this._syncMenuVisibilityIdle = Mainloop.idle_add(this._syncMenuVisibility.bind(this));
GLib.Source.set_name_by_id(this._syncMenuVisibilityIdle, '[gnome-shell] this._syncMenuVisibility');
}
_buildItemExtended(string, initialValue, writable, onSet) {
let widget = new PopupMenu.PopupSwitchMenuItem(string, initialValue);
if (!writable)
widget.reactive = false;
widget.actor.reactive = false;
else
widget.connect('toggled', item => {
onSet(item.state);
@@ -179,8 +180,8 @@ class ATIndicator extends PanelMenu.Button {
settings.is_writable(KEY_TEXT_SCALING_FACTOR),
enabled => {
if (enabled)
settings.set_double(
KEY_TEXT_SCALING_FACTOR, DPI_FACTOR_LARGE);
settings.set_double(KEY_TEXT_SCALING_FACTOR,
DPI_FACTOR_LARGE);
else
settings.reset(KEY_TEXT_SCALING_FACTOR);
});

View File

@@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Indicator */
const { Gio, GnomeBluetooth, GObject } = imports.gi;
const { Gio, GnomeBluetooth } = imports.gi;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
@@ -17,11 +17,9 @@ const RfkillManagerProxy = Gio.DBusProxy.makeProxyWrapper(RfkillManagerInterface
const HAD_BLUETOOTH_DEVICES_SETUP = 'had-bluetooth-devices-setup';
var Indicator = GObject.registerClass({
GTypeName: 'Bluetooth_Indicator'
}, class Indicator extends PanelMenu.SystemIndicator {
_init() {
super._init();
var Indicator = class extends PanelMenu.SystemIndicator {
constructor() {
super();
this._indicator = this._addIndicator();
this._indicator.icon_name = 'bluetooth-active-symbolic';
@@ -135,4 +133,4 @@ var Indicator = GObject.registerClass({
this._toggleItem.label.text = this._proxy.BluetoothAirplaneMode ? _("Turn On") : _("Turn Off");
}
});
};

View File

@@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Indicator */
const { Gio, GObject, St } = imports.gi;
const { Gio, St } = imports.gi;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
@@ -15,11 +15,9 @@ const OBJECT_PATH = '/org/gnome/SettingsDaemon/Power';
const BrightnessInterface = loadInterfaceXML('org.gnome.SettingsDaemon.Power.Screen');
const BrightnessProxy = Gio.DBusProxy.makeProxyWrapper(BrightnessInterface);
var Indicator = GObject.registerClass({
GTypeName: 'Brightness_Indicator'
}, class Indicator extends PanelMenu.SystemIndicator {
_init() {
super._init();
var Indicator = class extends PanelMenu.SystemIndicator {
constructor() {
super('display-brightness-symbolic');
this._proxy = new BrightnessProxy(Gio.DBus.session, BUS_NAME, OBJECT_PATH,
(proxy, error) => {
if (error) {
@@ -35,38 +33,31 @@ var Indicator = GObject.registerClass({
this.menu.addMenuItem(this._item);
this._slider = new Slider.Slider(0);
this._sliderChangedId = this._slider.connect('notify::value',
this._sliderChanged.bind(this));
this._slider.accessible_name = _("Brightness");
this._slider.connect('value-changed', this._sliderChanged.bind(this));
this._slider.actor.accessible_name = _("Brightness");
let icon = new St.Icon({ icon_name: 'display-brightness-symbolic',
style_class: 'popup-menu-icon' });
this._item.add(icon);
this._item.add(this._slider, { expand: true });
this._item.add(this._slider.actor, { expand: true });
this._item.connect('button-press-event', (actor, event) => {
return this._slider.startDragging(event);
});
this._item.connect('key-press-event', (actor, event) => {
return this._slider.emit('key-press-event', event);
return this._slider.onKeyPressEvent(actor, event);
});
}
_sliderChanged() {
let percent = this._slider.value * 100;
_sliderChanged(slider, value) {
let percent = value * 100;
this._proxy.Brightness = percent;
}
_changeSlider(value) {
GObject.signal_handler_block(this._slider, this._sliderChangedId);
this._slider.value = value;
GObject.signal_handler_unblock(this._slider, this._sliderChangedId);
}
_sync() {
let visible = this._proxy.Brightness >= 0;
this._item.visible = visible;
if (visible)
this._changeSlider(this._proxy.Brightness / 100.0);
this._slider.value = this._proxy.Brightness / 100.0;
}
});
};

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