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

View File

@@ -16,14 +16,8 @@ run_eslint() {
ARGS_LEGACY='--config lint/eslintrc-legacy.json' ARGS_LEGACY='--config lint/eslintrc-legacy.json'
local extra_args=ARGS_$1 local extra_args=ARGS_$1
local output_var=OUTPUT_$1 local output=OUTPUT_$1
local output=${!output_var} eslint -f unix ${!extra_args} -o ${!output} js
# ensure output exists even if eslint doesn't report any errors
mkdir -p $(dirname $output)
touch $output
eslint -f unix ${!extra_args} -o $output js
} }
list_commit_range_additions() { list_commit_range_additions() {
@@ -72,17 +66,10 @@ create_common() {
rm $OUTPUT_FINAL.tmp rm $OUTPUT_FINAL.tmp
} }
# Disable MR handling for now. We aren't ready to enforce if [ "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME" ]; then
# non-legacy style just yet ... git fetch $CI_MERGE_REQUEST_PROJECT_URL.git $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
unset CI_MERGE_REQUEST_TARGET_BRANCH_NAME
REMOTE=${1:-$CI_MERGE_REQUEST_PROJECT_URL.git}
BRANCH_NAME=${2:-$CI_MERGE_REQUEST_TARGET_BRANCH_NAME}
if [ "$BRANCH_NAME" ]; then
git fetch $REMOTE $BRANCH_NAME
branch_point=$(git merge-base HEAD FETCH_HEAD) 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 list_commit_range_additions $commit_range > $LINE_CHANGES
@@ -99,16 +86,12 @@ run_eslint LEGACY
echo Done. echo Done.
create_common 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 # 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 exit 0
fi fi
copy_matched_lines $OUTPUT_REGULAR $LINE_CHANGES $OUTPUT_MR copy_matched_lines $OUTPUT_FINAL $LINE_CHANGES $OUTPUT_MR
cat $OUTPUT_MR cat $OUTPUT_MR
is_empty $OUTPUT_MR is_empty $OUTPUT_MR

View File

@@ -84,6 +84,7 @@ don't use.
const Main = imports.ui.main; const Main = imports.ui.main;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util; const Util = imports.misc.util;
``` ```
The alphabetical ordering should be done independently of the location of the The alphabetical ordering should be done independently of the location of the
@@ -186,27 +187,15 @@ and "double quotes" for strings that the user may see. This allows us to
quickly find untranslated or mistranslated strings by grepping through the quickly find untranslated or mistranslated strings by grepping through the
sources for double quotes without a gettext call around them. sources for double quotes without a gettext call around them.
## `actor` (deprecated) and `_delegate` ## `actor` and `_delegate`
gjs allows us to set so-called "expando properties" on introspected objects, gjs allows us to set so-called "expando properties" on introspected objects,
allowing us to treat them like any other. Because the Shell was built before allowing us to treat them like any other. Because the Shell was built before
you could inherit from GTypes natively in JS, in some cases we have a wrapper you could inherit from GTypes natively in JS, we usually have a wrapper class
class that has a property called `actor` (now deprecated). We call this that has a property called `actor`. We call this wrapper class the "delegate".
wrapper class the "delegate".
We sometimes use expando properties to set a property called `_delegate` on We sometimes use expando properties to set a property called `_delegate` on
the actor itself: the actor itself:
```javascript
var MyActor = GObject.registerClass(
class MyActor extends Clutter.Actor {
_init(params) {
super._init(params);
this._delegate = this;
}
});
```
Or using the deprecated `actor`:
```javascript ```javascript
var MyClass = class { var MyClass = class {
constructor() { constructor() {
@@ -227,7 +216,6 @@ delegate object from an associated actor. For instance, the drag and drop
system calls the `handleDragOver` function on the delegate of a "drop target" system calls the `handleDragOver` function on the delegate of a "drop target"
when the user drags an item over it. If you do not set the `_delegate` when the user drags an item over it. If you do not set the `_delegate`
property, your actor will not be able to be dropped onto. property, your actor will not be able to be dropped onto.
In case the class is an actor itself, the `_delegate` can be just set to `this`.
## Functional style ## Functional style
@@ -289,49 +277,34 @@ If your usage of an object is like a hash table (and thus conceptually the keys
can have special chars in them), don't use quotes, but use brackets: `{ bar: 42 can have special chars in them), don't use quotes, but use brackets: `{ bar: 42
}`, `foo['bar']`. }`, `foo['bar']`.
## Animations ## Getters, setters, and Tweener
Most objects that are animated are actors, and most properties used in animations
are animatable, which means they can use implicit animations:
Getters and setters should be used when you are dealing with an API that is
designed around setting properties, like Tweener. If you want to animate an
arbitrary property, create a getter and setter, and use Tweener to animate the
property.
```javascript ```javascript
moveActor(actor, x, y) { var ANIMATION_TIME = 2000;
actor.ease({
x, var MyClass = class {
y, constructor() {
duration: 500, // ms this.actor = new St.BoxLayout();
mode: Clutter.AnimationMode.EASE_OUT_QUAD this._position = 0;
}); }
}
``` get position() {
return this._position;
The above is a convenience wrapper around the actual Clutter API, and should generally }
be preferred over the more verbose:
set position(value) {
```javascript this._position = value;
moveActor(actor, x, y) { this.actor.set_position(value, value);
actor.save_easing_state(); }
};
actor.set_easing_duration(500);
actor.set_easing_mode(Clutter.AnimationMode.EASE_OUT_QUAD); let myThing = new MyClass();
actor.set({ Tweener.addTween(myThing,
x, { position: 100,
y time: ANIMATION_TIME,
}); transition: 'easeOutQuad' });
actor.restore_easing_state();
}
```
There is a similar convenience API around Clutter.PropertyTransition to animate
actor (or actor meta) properties that cannot use implicit animations:
```javascript
desaturateActor(actor, desaturate) {
let factor = desaturate ? 1.0 : 0.0;
actor.ease_property('@effects.desaturate.factor', factor, {
duration: 500, // ms
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
}
``` ```

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 3.33.4
====== ======
* Fix unintentional interference between gestures [Jonas; !598] * 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.SettingsDaemon.Wacom.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.AudioDeviceSelection.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.AudioDeviceSelection.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.CalendarServer.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.CalendarServer.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.ClocksIntegration.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.Extensions.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.Extensions.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.Introspect.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.Introspect.xml</file>
<file preprocess="xml-stripblanks">org.gnome.Shell.HotplugSniffer.xml</file> <file preprocess="xml-stripblanks">org.gnome.Shell.HotplugSniffer.xml</file>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -50,7 +50,7 @@
</description> </description>
</key> </key>
<key name="favorite-apps" type="as"> <key name="favorite-apps" type="as">
<default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'org.gnome.Shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default> <default>[ 'epiphany.desktop', 'evolution.desktop', 'rhythmbox.desktop', 'shotwell.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ]</default>
<summary>List of desktop file IDs for favorite applications</summary> <summary>List of desktop file IDs for favorite applications</summary>
<description> <description>
The applications corresponding to these identifiers The applications corresponding to these identifiers
@@ -109,6 +109,10 @@
the shell. the shell.
</description> </description>
</key> </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"/> <child name="keybindings" schema="org.gnome.shell.keybindings"/>
</schema> </schema>
@@ -150,6 +154,11 @@
Keybinding to focus the active notification. Keybinding to focus the active notification.
</description> </description>
</key> </key>
<key name="pause-resume-tweens" type="as">
<default>[]</default>
<summary>Keybinding that pauses and resumes all running tweens, for debugging purposes</summary>
<description></description>
</key>
<key name="switch-to-application-1" type="as"> <key name="switch-to-application-1" type="as">
<default>["&lt;Super&gt;1"]</default> <default>["&lt;Super&gt;1"]</default>
<summary>Switch to application 1</summary> <summary>Switch to application 1</summary>
@@ -228,17 +237,6 @@
</key> </key>
</schema> </schema>
<schema id="org.gnome.shell.world-clocks" path="/org/gnome/shell/world-clocks/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="locations" type="av">
<summary>Locations</summary>
<description>
The locations to show in world clocks
</description>
<default>[]</default>
</key>
</schema>
<schema id="org.gnome.shell.weather" path="/org/gnome/shell/weather/" <schema id="org.gnome.shell.weather" path="/org/gnome/shell/weather/"
gettext-domain="@GETTEXT_PACKAGE@"> gettext-domain="@GETTEXT_PACKAGE@">
<key name="automatic-location" type="b"> <key name="automatic-location" type="b">

View File

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

View File

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

View File

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

View File

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

View File

@@ -20,7 +20,7 @@
* In order for transformation animations to look good, they need to be * In order for transformation animations to look good, they need to be
* incremental and have some order to them (e.g., fade out hidden items, * incremental and have some order to them (e.g., fade out hidden items,
* then shrink to close the void left over). Chaining animations in this way can * then shrink to close the void left over). Chaining animations in this way can
* be error-prone and wordy using just ease() callbacks. * be error-prone and wordy using just Tweener callbacks.
* *
* The classes in this file help with this: * The classes in this file help with this:
* *
@@ -202,6 +202,7 @@ var ConsecutiveBatch = class extends Batch {
hold.disconnect(signalId); hold.disconnect(signalId);
this.nextTask(); this.nextTask();
}); });
return;
} else { } else {
// This task finished, process the next one // This task finished, process the next one
this.nextTask(); this.nextTask();

View File

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

View File

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

View File

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

View File

@@ -165,8 +165,8 @@ function versionCheck(required, current) {
let requiredArray = required[i].split('.'); let requiredArray = required[i].split('.');
if (requiredArray[0] == major && if (requiredArray[0] == major &&
requiredArray[1] == minor && requiredArray[1] == minor &&
((requiredArray[2] === undefined && parseInt(minor) % 2 == 0) || (requiredArray[2] == point ||
requiredArray[2] == point)) (requiredArray[2] == undefined && parseInt(minor) % 2 == 0)))
return true; return true;
} }
return false; return false;

View File

@@ -28,7 +28,7 @@ var HistoryManager = class {
this._entry = params.entry; this._entry = params.entry;
if (this._entry) { if (this._entry) {
this._entry.connect('key-press-event', this._entry.connect('key-press-event',
this._onEntryKeyPress.bind(this)); this._onEntryKeyPress.bind(this));
} }
} }

View File

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

View File

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

View File

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

View File

@@ -172,7 +172,7 @@ function getPropertyNamesFromExpression(expr, commandHeader = '') {
// Make sure propsUnique contains one key for every // Make sure propsUnique contains one key for every
// property so we end up with a unique list of properties // property so we end up with a unique list of properties
allProps.map(p => (propsUnique[p] = null)); allProps.map(p => propsUnique[p] = null);
} }
return Object.keys(propsUnique).sort(); return Object.keys(propsUnique).sort();
} }
@@ -217,7 +217,7 @@ function isUnsafeExpression(str) {
prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing prunedStr = prunedStr.replace(/[=!]==/g, ''); //replace === and !== with nothing
prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing prunedStr = prunedStr.replace(/[=<>!]=/g, ''); //replace ==, <=, >=, != with nothing
if (prunedStr.match(/[=]/)) { if (prunedStr.match(/=/)) {
return true; return true;
} else if (prunedStr.match(/;/)) { } else if (prunedStr.match(/;/)) {
// If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well // If we contain a semicolon not inside of a quote/regex, assume we're unsafe as well

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 // The following are not the complete interfaces, just the methods we need
@@ -182,9 +182,9 @@ var ModemCdma = class {
Signals.addSignalMethods(ModemCdma.prototype); Signals.addSignalMethods(ModemCdma.prototype);
// ------------------------------------------------------- // //------------------------------------------------------------------------------
// Support for the new ModemManager1 interface (MM >= 0.7) // // Support for the new ModemManager1 interface (MM >= 0.7)
// ------------------------------------------------------- // //------------------------------------------------------------------------------
const BroadbandModemInterface = loadInterfaceXML('org.freedesktop.ModemManager1.Modem'); const BroadbandModemInterface = loadInterfaceXML('org.freedesktop.ModemManager1.Modem');
const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface); const BroadbandModemProxy = Gio.DBusProxy.makeProxyWrapper(BroadbandModemInterface);

View File

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

View File

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

View File

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

View File

@@ -127,11 +127,11 @@ function *run() {
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true; Main.overview._dash.showAppsButton.checked = true;
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = false; Main.overview._dash.showAppsButton.checked = false;
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
} }
} }

View File

@@ -57,7 +57,7 @@ function waitAndDraw(milliseconds) {
cb(); cb();
}); });
return callback => (cb = callback); return callback => cb = callback;
} }
function waitSignal(object, signal) { function waitSignal(object, signal) {
@@ -69,7 +69,7 @@ function waitSignal(object, signal) {
cb(); cb();
}); });
return callback => (cb = callback); return callback => cb = callback;
} }
function extractBootTimestamp() { function extractBootTimestamp() {
@@ -127,7 +127,7 @@ function *run() {
Scripting.scriptEvent('applicationsShowStart'); Scripting.scriptEvent('applicationsShowStart');
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
Main.overview.dash.showAppsButton.checked = true; Main.overview._dash.showAppsButton.checked = true;
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
Scripting.scriptEvent('applicationsShowDone'); Scripting.scriptEvent('applicationsShowDone');
@@ -137,9 +137,9 @@ function *run() {
Main.overview.hide(); Main.overview.hide();
yield Scripting.waitLeisure(); yield Scripting.waitLeisure();
// --------------------- // ////////////////////////////////////////
// Tests of redraw speed // // Tests of redraw speed
// --------------------- // ////////////////////////////////////////
global.frame_timestamps = true; global.frame_timestamps = true;
global.frame_finish_timestamp = true; global.frame_finish_timestamp = true;
@@ -186,6 +186,8 @@ function *run() {
yield Scripting.sleep(1000); yield Scripting.sleep(1000);
////////////////////////////////////////
let appSys = Shell.AppSystem.get_default(); let appSys = Shell.AppSystem.get_default();
let app = appSys.lookup_app('org.gnome.gedit.desktop'); let app = appSys.lookup_app('org.gnome.gedit.desktop');

View File

@@ -56,8 +56,8 @@ class AccessDialog extends ModalDialog.ModalDialog {
let check = new CheckBox.CheckBox(); let check = new CheckBox.CheckBox();
check.getLabelActor().text = name; check.getLabelActor().text = name;
check.checked = selected == "true"; check.actor.checked = selected == "true";
content.insertBeforeBody(check); content.insertBeforeBody(check.actor);
this._choices.set(id, check); this._choices.set(id, check);
} }
@@ -99,7 +99,7 @@ class AccessDialog extends ModalDialog.ModalDialog {
let results = {}; let results = {};
if (response == DialogResponse.OK) { if (response == DialogResponse.OK) {
for (let [id, check] of this._choices) { for (let [id, check] of this._choices) {
let checked = check.checked ? 'true' : 'false'; let checked = check.actor.checked ? 'true' : 'false';
results[id] = new GLib.Variant('s', checked); results[id] = new GLib.Variant('s', checked);
} }
} }
@@ -147,7 +147,7 @@ var AccessDialogDBus = class {
subtitle, body, options); subtitle, body, options);
dialog.open(); dialog.open();
dialog.connect('closed', () => (this._accessDialog = null)); dialog.connect('closed', () => this._accessDialog = null);
this._accessDialog = dialog; this._accessDialog = dialog;
} }

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,6 +2,7 @@
/* exported Component */ /* exported Component */
const { Gio, GLib } = imports.gi; const { Gio, GLib } = imports.gi;
const Mainloop = imports.mainloop;
const Params = imports.misc.params; const Params = imports.misc.params;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
@@ -38,7 +39,7 @@ var AutomountManager = class {
this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', this._onDriveDisconnected.bind(this)); this._driveDisconnectedId = this._volumeMonitor.connect('drive-disconnected', this._onDriveDisconnected.bind(this));
this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', this._onDriveEjectButton.bind(this)); this._driveEjectButtonId = this._volumeMonitor.connect('drive-eject-button', this._onDriveEjectButton.bind(this));
this._mountAllId = GLib.idle_add(GLib.PRIORITY_DEFAULT, this._startupMountAll.bind(this)); this._mountAllId = Mainloop.idle_add(this._startupMountAll.bind(this));
GLib.Source.set_name_by_id(this._mountAllId, '[gnome-shell] this._startupMountAll'); GLib.Source.set_name_by_id(this._mountAllId, '[gnome-shell] this._startupMountAll');
} }
@@ -50,7 +51,7 @@ var AutomountManager = class {
this._volumeMonitor.disconnect(this._driveEjectButtonId); this._volumeMonitor.disconnect(this._driveEjectButtonId);
if (this._mountAllId > 0) { if (this._mountAllId > 0) {
GLib.source_remove(this._mountAllId); Mainloop.source_remove(this._mountAllId);
this._mountAllId = 0; this._mountAllId = 0;
} }
} }
@@ -156,7 +157,7 @@ var AutomountManager = class {
!volume.should_automount() || !volume.should_automount() ||
!volume.can_mount()) { !volume.can_mount()) {
// allow the autorun to run anyway; this can happen if the // allow the autorun to run anyway; this can happen if the
// mount gets added programmatically later, even if // mount gets added programmatically later, even if
// should_automount() or can_mount() are false, like for // should_automount() or can_mount() are false, like for
// blank optical media. // blank optical media.
this._allowAutorun(volume); this._allowAutorun(volume);
@@ -219,17 +220,17 @@ var AutomountManager = class {
_onVolumeRemoved(monitor, volume) { _onVolumeRemoved(monitor, volume) {
if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) { if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) {
GLib.source_remove(volume._allowAutorunExpireId); Mainloop.source_remove(volume._allowAutorunExpireId);
delete volume._allowAutorunExpireId; delete volume._allowAutorunExpireId;
} }
this._volumeQueue = this._volumeQueue =
this._volumeQueue.filter(element => (element != volume)); this._volumeQueue.filter(element => (element != volume));
} }
_reaskPassword(volume) { _reaskPassword(volume) {
let prevOperation = this._activeOperations.get(volume); let prevOperation = this._activeOperations.get(volume);
let existingDialog = prevOperation ? prevOperation.borrowDialog() : null; let existingDialog = prevOperation ? prevOperation.borrowDialog() : null;
let operation = let operation =
new ShellMountOperation.ShellMountOperation(volume, new ShellMountOperation.ShellMountOperation(volume,
{ existingDialog: existingDialog }); { existingDialog: existingDialog });
this._mountVolume(volume, operation); this._mountVolume(volume, operation);
@@ -248,7 +249,7 @@ var AutomountManager = class {
} }
_allowAutorunExpire(volume) { _allowAutorunExpire(volume) {
let id = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, AUTORUN_EXPIRE_TIMEOUT_SECS, () => { let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => {
volume.allowAutorun = false; volume.allowAutorun = false;
delete volume._allowAutorunExpireId; delete volume._allowAutorunExpireId;
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;

View File

@@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Component */ /* exported Component */
const { Gio, GObject, St } = imports.gi; const { Gio, St } = imports.gi;
const GnomeSession = imports.misc.gnomeSession; const GnomeSession = imports.misc.gnomeSession;
const Main = imports.ui.main; const Main = imports.ui.main;
@@ -63,7 +63,7 @@ function startAppForMount(app, mount) {
files.push(root); files.push(root);
try { try {
retval = app.launch(files, retval = app.launch(files,
global.create_app_launch_context(0, -1)); global.create_app_launch_context(0, -1));
} catch (e) { } catch (e) {
log(`Unable to launch the application ${app.get_name()}: ${e}`); log(`Unable to launch the application ${app.get_name()}: ${e}`);
@@ -72,6 +72,8 @@ function startAppForMount(app, mount) {
return retval; return retval;
} }
/******************************************/
const HotplugSnifferIface = loadInterfaceXML('org.gnome.Shell.HotplugSniffer'); const HotplugSnifferIface = loadInterfaceXML('org.gnome.Shell.HotplugSniffer');
const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface); const HotplugSnifferProxy = Gio.DBusProxy.makeProxyWrapper(HotplugSnifferIface);
function HotplugSniffer() { function HotplugSniffer() {
@@ -115,9 +117,9 @@ var ContentTypeDiscoverer = class {
let hotplugSniffer = new HotplugSniffer(); let hotplugSniffer = new HotplugSniffer();
hotplugSniffer.SniffURIRemote(root.get_uri(), hotplugSniffer.SniffURIRemote(root.get_uri(),
([contentTypes]) => { ([contentTypes]) => {
this._emitCallback(mount, contentTypes); this._emitCallback(mount, contentTypes);
}); });
} }
} }
@@ -213,11 +215,11 @@ var AutorunDispatcher = class {
} }
_addSource(mount, apps) { _addSource(mount, apps) {
// if we already have a source showing for this // if we already have a source showing for this
// mount, return // mount, return
if (this._getSourceForMount(mount)) if (this._getSourceForMount(mount))
return; return;
// add a new source // add a new source
this._sources.push(new AutorunSource(this._manager, mount, apps)); this._sources.push(new AutorunSource(this._manager, mount, apps));
} }
@@ -262,7 +264,7 @@ var AutorunDispatcher = class {
removeMount(mount) { removeMount(mount) {
let source = this._getSourceForMount(mount); let source = this._getSourceForMount(mount);
// if we aren't tracking this mount, don't do anything // if we aren't tracking this mount, don't do anything
if (!source) if (!source)
return; return;
@@ -272,10 +274,9 @@ var AutorunDispatcher = class {
} }
}; };
var AutorunSource = GObject.registerClass( var AutorunSource = class extends MessageTray.Source {
class AutorunSource extends MessageTray.Source { constructor(manager, mount, apps) {
_init(manager, mount, apps) { super(mount.get_name());
super._init(mount.get_name());
this._manager = manager; this._manager = manager;
this.mount = mount; this.mount = mount;
@@ -285,7 +286,7 @@ class AutorunSource extends MessageTray.Source {
// add ourselves as a source, and popup the notification // add ourselves as a source, and popup the notification
Main.messageTray.add(this); Main.messageTray.add(this);
this.showNotification(this._notification); this.notify(this._notification);
} }
getIcon() { getIcon() {
@@ -295,12 +296,11 @@ class AutorunSource extends MessageTray.Source {
_createPolicy() { _createPolicy() {
return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus'); return new MessageTray.NotificationApplicationPolicy('org.gnome.Nautilus');
} }
}); };
var AutorunNotification = GObject.registerClass( var AutorunNotification = class extends MessageTray.Notification {
class AutorunNotification extends MessageTray.Notification { constructor(manager, source) {
_init(manager, source) { super(source, source.title);
super._init(source, source.title);
this._manager = manager; this._manager = manager;
this._mount = source.mount; this._mount = source.mount;
@@ -325,10 +325,10 @@ class AutorunNotification extends MessageTray.Notification {
style_class: 'hotplug-notification-item-icon' }); style_class: 'hotplug-notification-item-icon' });
box.add(icon); box.add(icon);
let label = new St.Bin({ let label = new St.Bin({ y_align: St.Align.MIDDLE,
y_align: St.Align.MIDDLE, child: new St.Label
child: new St.Label({ text: _("Open with %s").format(app.get_name()) }), ({ text: _("Open with %s").format(app.get_name()) })
}); });
box.add(label); box.add(label);
let button = new St.Button({ child: box, let button = new St.Button({ child: box,
@@ -352,6 +352,6 @@ class AutorunNotification extends MessageTray.Notification {
let app = Gio.app_info_get_default_for_type('inode/directory', false); let app = Gio.app_info_get_default_for_type('inode/directory', false);
startAppForMount(app, this._mount); startAppForMount(app, this._mount);
} }
}); };
var Component = AutorunManager; var Component = AutorunManager;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,7 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported DateMenuButton */ /* exported DateMenuButton */
const { Clutter, Gio, GLib, GnomeDesktop, const { Clutter, GLib, GnomeDesktop,
GObject, GWeather, Shell, St } = imports.gi; GObject, GWeather, Shell, St } = imports.gi;
const Util = imports.misc.util; const Util = imports.misc.util;
@@ -11,13 +11,8 @@ const Calendar = imports.ui.calendar;
const Weather = imports.misc.weather; const Weather = imports.misc.weather;
const System = imports.system; const System = imports.system;
const { loadInterfaceXML } = imports.misc.fileUtils;
const MAX_FORECASTS = 5; const MAX_FORECASTS = 5;
const ClocksIntegrationIface = loadInterfaceXML('org.gnome.Shell.ClocksIntegration');
const ClocksProxy = Gio.DBusProxy.makeProxyWrapper(ClocksIntegrationIface);
function _isToday(date) { function _isToday(date) {
let now = new Date(); let now = new Date();
return now.getYear() == date.getYear() && return now.getYear() == date.getYear() &&
@@ -25,26 +20,22 @@ function _isToday(date) {
now.getDate() == date.getDate(); now.getDate() == date.getDate();
} }
function _gDateTimeToDate(datetime) { var TodayButton = class TodayButton {
return new Date(datetime.to_unix() * 1000 + datetime.get_microsecond() / 1000); constructor(calendar) {
}
var TodayButton = GObject.registerClass(
class TodayButton extends St.Button {
_init(calendar) {
// Having the ability to go to the current date if the user is already // Having the ability to go to the current date if the user is already
// on the current date can be confusing. So don't make the button reactive // on the current date can be confusing. So don't make the button reactive
// until the selected date changes. // until the selected date changes.
super._init({ this.actor = new St.Button({ style_class: 'datemenu-today-button',
style_class: 'datemenu-today-button', x_expand: true, x_align: St.Align.START,
x_align: St.Align.START, can_focus: true,
x_expand: true, reactive: false
can_focus: true, });
reactive: false this.actor.connect('clicked', () => {
this._calendar.setDate(new Date(), false);
}); });
let hbox = new St.BoxLayout({ vertical: true }); let hbox = new St.BoxLayout({ vertical: true });
this.add_actor(hbox); this.actor.add_actor(hbox);
this._dayLabel = new St.Label({ style_class: 'day-label', this._dayLabel = new St.Label({ style_class: 'day-label',
x_align: Clutter.ActorAlign.START }); x_align: Clutter.ActorAlign.START });
@@ -54,17 +45,13 @@ class TodayButton extends St.Button {
hbox.add_actor(this._dateLabel); hbox.add_actor(this._dateLabel);
this._calendar = calendar; this._calendar = calendar;
this._calendar.connect('selected-date-changed', (_calendar, datetime) => { this._calendar.connect('selected-date-changed', (calendar, date) => {
// Make the button reactive only if the selected date is not the // Make the button reactive only if the selected date is not the
// current date. // current date.
this.reactive = !_isToday(_gDateTimeToDate(datetime)); this.actor.reactive = !_isToday(date);
}); });
} }
vfunc_clicked() {
this._calendar.setDate(new Date(), false);
}
setDate(date) { setDate(date) {
this._dayLabel.set_text(date.toLocaleFormat('%A')); this._dayLabel.set_text(date.toLocaleFormat('%A'));
@@ -81,72 +68,57 @@ class TodayButton extends St.Button {
* date, e.g. "Tuesday February 17 2015". * date, e.g. "Tuesday February 17 2015".
*/ */
dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y")); dateFormat = Shell.util_translate_time_string (N_("%A %B %e %Y"));
this.accessible_name = date.toLocaleFormat(dateFormat); this.actor.accessible_name = date.toLocaleFormat(dateFormat);
} }
}); };
var WorldClocksSection = GObject.registerClass( var WorldClocksSection = class WorldClocksSection {
class WorldClocksSection extends St.Button { constructor() {
_init() {
super._init({
style_class: 'world-clocks-button',
x_fill: true,
can_focus: true
});
this._clock = new GnomeDesktop.WallClock(); this._clock = new GnomeDesktop.WallClock();
this._clockNotifyId = 0; this._clockNotifyId = 0;
this._locations = []; this._locations = [];
this.actor = new St.Button({ style_class: 'world-clocks-button',
x_fill: true,
can_focus: true });
this.actor.connect('clicked', () => {
this._clockAppMon.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
});
let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL }); let layout = new Clutter.GridLayout({ orientation: Clutter.Orientation.VERTICAL });
this._grid = new St.Widget({ style_class: 'world-clocks-grid', this._grid = new St.Widget({ style_class: 'world-clocks-grid',
layout_manager: layout }); layout_manager: layout });
layout.hookup_style(this._grid); layout.hookup_style(this._grid);
this.child = this._grid; this.actor.child = this._grid;
this._clocksApp = null; this._clockAppMon = new Util.AppSettingsMonitor('org.gnome.clocks.desktop',
this._clocksProxy = new ClocksProxy( 'org.gnome.clocks');
Gio.DBus.session, this._clockAppMon.connect('available-changed',
'org.gnome.clocks', this._sync.bind(this));
'/org/gnome/clocks', this._clockAppMon.watchSetting('world-clocks',
this._onProxyReady.bind(this), this._clocksChanged.bind(this));
null /* cancellable */,
Gio.DBusProxyFlags.DO_NOT_AUTO_START | Gio.DBusProxyFlags.GET_INVALIDATED_PROPERTIES);
this._settings = new Gio.Settings({
schema_id: 'org.gnome.shell.world-clocks'
});
this._settings.connect('changed', this._clocksChanged.bind(this));
this._clocksChanged();
this._appSystem = Shell.AppSystem.get_default();
this._appSystem.connect('installed-changed',
this._sync.bind(this));
this._sync(); this._sync();
} }
vfunc_clicked() {
if (this._clocksApp)
this._clocksApp.activate();
Main.overview.hide();
Main.panel.closeCalendar();
}
_sync() { _sync() {
this._clocksApp = this._appSystem.lookup_app('org.gnome.clocks.desktop'); this.actor.visible = this._clockAppMon.available;
this.visible = this._clocksApp != null;
} }
_clocksChanged() { _clocksChanged(settings) {
this._grid.destroy_all_children(); this._grid.destroy_all_children();
this._locations = []; this._locations = [];
let world = GWeather.Location.get_world(); let world = GWeather.Location.get_world();
let clocks = this._settings.get_value('locations').deep_unpack(); let clocks = settings.get_value('world-clocks').deep_unpack();
for (let i = 0; i < clocks.length; i++) { for (let i = 0; i < clocks.length; i++) {
let l = world.deserialize(clocks[i]); if (!clocks[i].location)
continue;
let l = world.deserialize(clocks[i].location);
if (l && l.get_timezone() != null) if (l && l.get_timezone() != null)
this._locations.push({ location: l }); this._locations.push({ location: l });
} }
@@ -157,14 +129,13 @@ class WorldClocksSection extends St.Button {
}); });
let layout = this._grid.layout_manager; let layout = this._grid.layout_manager;
let title = (this._locations.length == 0) let title = (this._locations.length == 0) ? _("Add world clocks…")
? _("Add world clocks") : _("World Clocks");
: _("World Clocks");
let header = new St.Label({ style_class: 'world-clocks-header', let header = new St.Label({ style_class: 'world-clocks-header',
x_align: Clutter.ActorAlign.START, x_align: Clutter.ActorAlign.START,
text: title }); text: title });
layout.attach(header, 0, 0, 2, 1); layout.attach(header, 0, 0, 2, 1);
this.label_actor = header; this.actor.label_actor = header;
let localOffset = GLib.DateTime.new_now_local().get_utc_offset(); let localOffset = GLib.DateTime.new_now_local().get_utc_offset();
@@ -226,42 +197,30 @@ class WorldClocksSection extends St.Button {
l.actor.text = Util.formatTime(now, { timeOnly: true }); l.actor.text = Util.formatTime(now, { timeOnly: true });
} }
} }
};
_onProxyReady(proxy, error) { var WeatherSection = class WeatherSection {
if (error) { constructor() {
log(`Failed to create GNOME Clocks proxy: ${error}`);
return;
}
this._clocksProxy.connect('g-properties-changed',
this._onClocksPropertiesChanged.bind(this));
this._onClocksPropertiesChanged();
}
_onClocksPropertiesChanged() {
if (this._clocksProxy.g_name_owner == null)
return;
this._settings.set_value('locations',
new GLib.Variant('av', this._clocksProxy.Locations));
}
});
var WeatherSection = GObject.registerClass(
class WeatherSection extends St.Button {
_init() {
super._init({
style_class: 'weather-button',
x_fill: true,
can_focus: true
});
this._weatherClient = new Weather.WeatherClient(); this._weatherClient = new Weather.WeatherClient();
this.actor = new St.Button({ style_class: 'weather-button',
x_fill: true,
can_focus: true });
this.actor.connect('clicked', () => {
this._weatherClient.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
});
this.actor.connect('notify::mapped', () => {
if (this.actor.mapped)
this._weatherClient.update();
});
let box = new St.BoxLayout({ style_class: 'weather-box', let box = new St.BoxLayout({ style_class: 'weather-box',
vertical: true }); vertical: true });
this.child = box; this.actor.child = box;
let titleBox = new St.BoxLayout(); let titleBox = new St.BoxLayout();
titleBox.add_child(new St.Label({ style_class: 'weather-header', titleBox.add_child(new St.Label({ style_class: 'weather-header',
@@ -284,18 +243,6 @@ class WeatherSection extends St.Button {
this._sync(); this._sync();
} }
vfunc_map() {
this._weatherClient.update();
super.vfunc_map();
}
vfunc_clicked() {
this._weatherClient.activateApp();
Main.overview.hide();
Main.panel.closeCalendar();
}
_getInfos() { _getInfos() {
let info = this._weatherClient.info; let info = this._weatherClient.info;
let forecasts = info.get_forecast_list(); let forecasts = info.get_forecast_list();
@@ -386,27 +333,23 @@ class WeatherSection extends St.Button {
} }
_sync() { _sync() {
this.visible = this._weatherClient.available; this.actor.visible = this._weatherClient.available;
if (!this.visible) if (!this.actor.visible)
return; return;
this._titleLocation.visible = this._weatherClient.hasLocation; this._titleLocation.visible = this._weatherClient.hasLocation;
this._updateForecasts(); this._updateForecasts();
} }
}); };
var MessagesIndicator = GObject.registerClass( var MessagesIndicator = class MessagesIndicator {
class MessagesIndicator extends St.Icon { constructor() {
_init() { this.actor = new St.Icon({ icon_name: 'message-indicator-symbolic',
super._init({ icon_size: 16,
icon_name: 'message-indicator-symbolic', visible: false, y_expand: true,
icon_size: 16, y_align: Clutter.ActorAlign.CENTER });
visible: false,
y_expand: true,
y_align: Clutter.ActorAlign.CENTER
});
this._sources = []; this._sources = [];
@@ -419,7 +362,7 @@ class MessagesIndicator extends St.Icon {
} }
_onSourceAdded(tray, source) { _onSourceAdded(tray, source) {
source.connect('notify::count', this._updateCount.bind(this)); source.connect('count-updated', this._updateCount.bind(this));
this._sources.push(source); this._sources.push(source);
this._updateCount(); this._updateCount();
} }
@@ -431,12 +374,12 @@ class MessagesIndicator extends St.Icon {
_updateCount() { _updateCount() {
let count = 0; let count = 0;
this._sources.forEach(source => (count += source.unseenCount)); this._sources.forEach(source => count += source.unseenCount);
count -= Main.messageTray.queueCount; count -= Main.messageTray.queueCount;
this.visible = (count > 0); this.actor.visible = (count > 0);
} }
}); };
var IndicatorPad = GObject.registerClass( var IndicatorPad = GObject.registerClass(
class IndicatorPad extends St.Widget { class IndicatorPad extends St.Widget {
@@ -529,9 +472,9 @@ class DateMenuButton extends PanelMenu.Button {
this._indicator = new MessagesIndicator(); this._indicator = new MessagesIndicator();
let box = new St.BoxLayout(); let box = new St.BoxLayout();
box.add_actor(new IndicatorPad(this._indicator)); box.add_actor(new IndicatorPad(this._indicator.actor));
box.add_actor(this._clockDisplay); box.add_actor(this._clockDisplay);
box.add_actor(this._indicator); box.add_actor(this._indicator.actor);
this.label_actor = this._clockDisplay; this.label_actor = this._clockDisplay;
this.add_actor(box); this.add_actor(box);
@@ -547,11 +490,11 @@ class DateMenuButton extends PanelMenu.Button {
bin.add_actor(hbox); bin.add_actor(hbox);
this._calendar = new Calendar.Calendar(); this._calendar = new Calendar.Calendar();
this._calendar.connect('selected-date-changed', (_calendar, datetime) => { this._calendar.connect('selected-date-changed',
let date = _gDateTimeToDate(datetime); (calendar, date) => {
layout.frozen = !_isToday(date); layout.frozen = !_isToday(date);
this._messageList.setDate(date); this._messageList.setDate(date);
}); });
this.menu.connect('open-state-changed', (menu, isOpen) => { this.menu.connect('open-state-changed', (menu, isOpen) => {
// Whenever the menu is opened, select today // Whenever the menu is opened, select today
@@ -565,19 +508,19 @@ class DateMenuButton extends PanelMenu.Button {
// Fill up the first column // Fill up the first column
this._messageList = new Calendar.CalendarMessageList(); this._messageList = new Calendar.CalendarMessageList();
hbox.add(this._messageList, { expand: true, y_fill: false, y_align: St.Align.START }); hbox.add(this._messageList.actor, { expand: true, y_fill: false, y_align: St.Align.START });
// Fill up the second column // Fill up the second column
let boxLayout = new CalendarColumnLayout(this._calendar); let boxLayout = new CalendarColumnLayout(this._calendar.actor);
vbox = new St.Widget({ style_class: 'datemenu-calendar-column', vbox = new St.Widget({ style_class: 'datemenu-calendar-column',
layout_manager: boxLayout }); layout_manager: boxLayout });
boxLayout.hookup_style(vbox); boxLayout.hookup_style(vbox);
hbox.add(vbox); hbox.add(vbox);
this._date = new TodayButton(this._calendar); this._date = new TodayButton(this._calendar);
vbox.add_actor(this._date); vbox.add_actor(this._date.actor);
vbox.add_actor(this._calendar); vbox.add_actor(this._calendar.actor);
this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade', this._displaysSection = new St.ScrollView({ style_class: 'datemenu-displays-section vfade',
x_expand: true, x_fill: true, x_expand: true, x_fill: true,
@@ -590,10 +533,10 @@ class DateMenuButton extends PanelMenu.Button {
this._displaysSection.add_actor(displaysBox); this._displaysSection.add_actor(displaysBox);
this._clocksItem = new WorldClocksSection(); this._clocksItem = new WorldClocksSection();
displaysBox.add(this._clocksItem, { x_fill: true }); displaysBox.add(this._clocksItem.actor, { x_fill: true });
this._weatherItem = new WeatherSection(); this._weatherItem = new WeatherSection();
displaysBox.add(this._weatherItem, { x_fill: true }); displaysBox.add(this._weatherItem.actor, { x_fill: true });
// Done with hbox for calendar and event list // Done with hbox for calendar and event list

View File

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

View File

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

View File

@@ -10,7 +10,7 @@ imports.gi.versions.Gtk = '3.0';
imports.gi.versions.TelepathyGLib = '0.12'; imports.gi.versions.TelepathyGLib = '0.12';
imports.gi.versions.TelepathyLogger = '0.2'; imports.gi.versions.TelepathyLogger = '0.2';
const { Clutter, GLib, Meta, Shell, St } = imports.gi; const { Clutter, GLib, Shell, St } = imports.gi;
const Gettext = imports.gettext; const Gettext = imports.gettext;
// We can't import shell JS modules yet, because they may have // We can't import shell JS modules yet, because they may have
@@ -58,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) { function _loggingFunc(...args) {
let fields = { 'MESSAGE': args.join(', ') }; let fields = { 'MESSAGE': args.join(', ') };
let domain = "GNOME Shell"; let domain = "GNOME Shell";
@@ -242,27 +94,6 @@ function init() {
column_spacing: 'spacing-columns' }); column_spacing: 'spacing-columns' });
_patchLayoutClass(Clutter.BoxLayout, { spacing: 'spacing' }); _patchLayoutClass(Clutter.BoxLayout, { spacing: 'spacing' });
let origSetEasingDuration = Clutter.Actor.prototype.set_easing_duration;
Clutter.Actor.prototype.set_easing_duration = function(msecs) {
origSetEasingDuration.call(this, adjustAnimationTime(msecs));
};
let origSetEasingDelay = Clutter.Actor.prototype.set_easing_delay;
Clutter.Actor.prototype.set_easing_delay = function(msecs) {
origSetEasingDelay.call(this, adjustAnimationTime(msecs));
};
Clutter.Actor.prototype.ease = function(props, easingParams) {
_easeActor(this, props, easingParams);
};
Clutter.Actor.prototype.ease_property = function(propName, target, params) {
_easeActorProperty(this, propName, target, params);
};
St.Adjustment.prototype.ease = function(target, params) {
// we're not an actor of course, but we implement the same
// transition API as Clutter.Actor, so this works anyway
_easeActorProperty(this, 'value', target, params);
};
Clutter.Actor.prototype.toString = function() { Clutter.Actor.prototype.toString = function() {
return St.describe_actor(this); return St.describe_actor(this);
}; };
@@ -314,17 +145,3 @@ function init() {
Tweener.init(); Tweener.init();
String.prototype.format = Format.format; String.prototype.format = Format.format;
} }
// adjustAnimationTime:
// @msecs: time in milliseconds
//
// Adjust @msecs to account for St's enable-animations
// and slow-down-factor settings
function adjustAnimationTime(msecs) {
let settings = St.Settings.get();
if (!settings.enable_animations)
return 1;
return settings.slow_down_factor * msecs;
}

View File

@@ -186,15 +186,14 @@ class InstallExtensionDialog extends ModalDialog.ModalDialog {
this._info = info; this._info = info;
this._invocation = invocation; this._invocation = invocation;
this.setButtons([{ this.setButtons([{ label: _("Cancel"),
label: _("Cancel"), action: this._onCancelButtonPressed.bind(this),
action: this._onCancelButtonPressed.bind(this), key: Clutter.Escape
key: Clutter.Escape, },
}, { { label: _("Install"),
label: _("Install"), action: this._onInstallButtonPressed.bind(this),
action: this._onInstallButtonPressed.bind(this), default: true
default: true, }]);
}]);
let content = new Dialog.MessageDialogContent({ let content = new Dialog.MessageDialogContent({
title: _("Download and install “%s” from extensions.gnome.org?").format(info.name), title: _("Download and install “%s” from extensions.gnome.org?").format(info.name),

View File

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

View File

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

View File

@@ -1,17 +1,18 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported BaseIcon, IconGrid, PaginatedIconGrid */ /* 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 Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const Main = imports.ui.main; const Main = imports.ui.main;
var ICON_SIZE = 96; var ICON_SIZE = 96;
var MIN_ICON_SIZE = 16; var MIN_ICON_SIZE = 16;
var EXTRA_SPACE_ANIMATION_TIME = 250; var EXTRA_SPACE_ANIMATION_TIME = 0.25;
var ANIMATION_TIME_IN = 350; var ANIMATION_TIME_IN = 0.350;
var ANIMATION_TIME_OUT = 1 / 2 * ANIMATION_TIME_IN; var ANIMATION_TIME_OUT = 1 / 2 * ANIMATION_TIME_IN;
var ANIMATION_MAX_DELAY_FOR_ITEM = 2 / 3 * ANIMATION_TIME_IN; var ANIMATION_MAX_DELAY_FOR_ITEM = 2 / 3 * ANIMATION_TIME_IN;
var ANIMATION_BASE_DELAY_FOR_ITEM = 1 / 4 * ANIMATION_MAX_DELAY_FOR_ITEM; var ANIMATION_BASE_DELAY_FOR_ITEM = 1 / 4 * ANIMATION_MAX_DELAY_FOR_ITEM;
@@ -26,7 +27,28 @@ var AnimationDirection = {
}; };
var APPICON_ANIMATION_OUT_SCALE = 3; var APPICON_ANIMATION_OUT_SCALE = 3;
var APPICON_ANIMATION_OUT_TIME = 250; var APPICON_ANIMATION_OUT_TIME = 0.25;
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( var BaseIcon = GObject.registerClass(
class BaseIcon extends St.Bin { class BaseIcon extends St.Bin {
@@ -142,10 +164,6 @@ class BaseIcon extends St.Bin {
zoomOutActor(this.child); zoomOutActor(this.child);
} }
animateZoomOutAtPos(x, y) {
zoomOutActorAtPos(this.child, x, y);
}
update() { update() {
this._createIconTexture(this.iconSize); this._createIconTexture(this.iconSize);
} }
@@ -156,15 +174,10 @@ function clamp(value, min, max) {
} }
function zoomOutActor(actor) { function zoomOutActor(actor) {
let [x, y] = actor.get_transformed_position();
zoomOutActorAtPos(actor, x, y);
}
function zoomOutActorAtPos(actor, x, y) {
let actorClone = new Clutter.Clone({ source: actor, let actorClone = new Clutter.Clone({ source: actor,
reactive: false }); reactive: false });
let [width, height] = actor.get_transformed_size(); let [width, height] = actor.get_transformed_size();
let [x, y] = actor.get_transformed_position();
actorClone.set_size(width, height); actorClone.set_size(width, height);
actorClone.set_position(x, y); actorClone.set_position(x, y);
actorClone.opacity = 255; actorClone.opacity = 255;
@@ -181,16 +194,18 @@ function zoomOutActorAtPos(actor, x, y) {
let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth); let containedX = clamp(scaledX, monitor.x, monitor.x + monitor.width - scaledWidth);
let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight); let containedY = clamp(scaledY, monitor.y, monitor.y + monitor.height - scaledHeight);
actorClone.ease({ Tweener.addTween(actorClone,
scale_x: APPICON_ANIMATION_OUT_SCALE, { time: APPICON_ANIMATION_OUT_TIME,
scale_y: APPICON_ANIMATION_OUT_SCALE, scale_x: APPICON_ANIMATION_OUT_SCALE,
translation_x: containedX - scaledX, scale_y: APPICON_ANIMATION_OUT_SCALE,
translation_y: containedY - scaledY, translation_x: containedX - scaledX,
opacity: 0, translation_y: containedY - scaledY,
duration: APPICON_ANIMATION_OUT_TIME, opacity: 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
onComplete: () => actorClone.destroy() onComplete() {
}); actorClone.destroy();
}
});
} }
var IconGrid = GObject.registerClass({ var IconGrid = GObject.registerClass({
@@ -231,18 +246,18 @@ var IconGrid = GObject.registerClass({
this._fixedHItemSize = this._fixedVItemSize = undefined; this._fixedHItemSize = this._fixedVItemSize = undefined;
this.connect('style-changed', this._onStyleChanged.bind(this)); this.connect('style-changed', this._onStyleChanged.bind(this));
// 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-added', this._childAdded.bind(this));
this.connect('actor-removed', this._childRemoved.bind(this)); this.connect('actor-removed', this._childRemoved.bind(this));
this.connect('destroy', this._onDestroy.bind(this)); 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() { _onDestroy() {
if (this._updateIconSizesLaterId) { if (this._updateIconSizesLaterId) {
Meta.later_remove (this._updateIconSizesLaterId); Meta.later_remove (this._updateIconSizesLaterId);
@@ -256,23 +271,10 @@ var IconGrid = GObject.registerClass({
_childAdded(grid, child) { _childAdded(grid, child) {
child._iconGridKeyFocusInId = child.connect('key-focus-in', this._keyFocusIn.bind(this)); child._iconGridKeyFocusInId = child.connect('key-focus-in', this._keyFocusIn.bind(this));
child._paintVisible = child.opacity > 0;
child._opacityChangedId = child.connect('notify::opacity', () => {
let paintVisible = child._paintVisible;
child._paintVisible = child.opacity > 0;
if (paintVisible !== child._paintVisible)
this.queue_relayout();
});
} }
_childRemoved(grid, child) { _childRemoved(grid, child) {
child.disconnect(child._iconGridKeyFocusInId); child.disconnect(child._iconGridKeyFocusInId);
delete child._iconGridKeyFocusInId;
child.disconnect(child._opacityChangedId);
delete child._opacityChangedId;
delete child._paintVisible;
} }
vfunc_get_preferred_width(_forHeight) { vfunc_get_preferred_width(_forHeight) {
@@ -282,9 +284,9 @@ var IconGrid = GObject.registerClass({
return [0, 0]; return [0, 0];
let nChildren = this.get_n_children(); let nChildren = this.get_n_children();
let nColumns = this._colLimit let nColumns = this._colLimit ? Math.min(this._colLimit,
? Math.min(this._colLimit, nChildren) nChildren)
: nChildren; : nChildren;
let totalSpacing = Math.max(0, nColumns - 1) * this._getSpacing(); let totalSpacing = Math.max(0, nColumns - 1) * this._getSpacing();
// Kind of a lie, but not really an issue right now. If // Kind of a lie, but not really an issue right now. If
// we wanted to support some sort of hidden/overflow that would // we wanted to support some sort of hidden/overflow that would
@@ -365,6 +367,7 @@ var IconGrid = GObject.registerClass({
let y = box.y1 + this.topPadding; let y = box.y1 + this.topPadding;
let columnIndex = 0; let columnIndex = 0;
let rowIndex = 0; let rowIndex = 0;
let nChanged = 0;
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
let childBox = this._calculateChildBox(children[i], x, y, box); let childBox = this._calculateChildBox(children[i], x, y, box);
@@ -374,7 +377,16 @@ var IconGrid = GObject.registerClass({
} else { } else {
if (!animating) if (!animating)
children[i].opacity = 255; 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].allocate(childBox, flags);
children[i].restore_easing_state();
} }
columnIndex++; columnIndex++;
@@ -402,7 +414,7 @@ var IconGrid = GObject.registerClass({
let allocationBox = this.get_allocation_box(); let allocationBox = this.get_allocation_box();
let paintBox = themeNode.get_paint_box(allocationBox); let paintBox = themeNode.get_paint_box(allocationBox);
let origin = new Graphene.Point3D(); let origin = new Clutter.Vertex();
origin.x = paintBox.x1 - allocationBox.x1; origin.x = paintBox.x1 - allocationBox.x1;
origin.y = paintBox.y1 - allocationBox.y1; origin.y = paintBox.y1 - allocationBox.y1;
origin.z = 0.0; origin.z = 0.0;
@@ -436,20 +448,21 @@ var IconGrid = GObject.registerClass({
* set of items to be animated. * set of items to be animated.
*/ */
_getChildrenToAnimate() { _getChildrenToAnimate() {
return this._getVisibleChildren().filter(child => child.opacity > 0); return this._getVisibleChildren();
} }
_resetAnimationActors() { _cancelAnimation() {
this._clonesAnimating.forEach(clone => clone.destroy());
this._clonesAnimating = [];
}
_animationDone() {
this._clonesAnimating.forEach(clone => { this._clonesAnimating.forEach(clone => {
clone.source.reactive = true; clone.source.reactive = true;
clone.source.opacity = 255; clone.source.opacity = 255;
clone.destroy(); clone.destroy();
}); });
this._clonesAnimating = []; this._clonesAnimating = [];
}
_animationDone() {
this._resetAnimationActors();
this.emit('animation-done'); this.emit('animation-done');
} }
@@ -458,7 +471,7 @@ var IconGrid = GObject.registerClass({
throw new GObject.NotImplementedError("Pulse animation only implements " + throw new GObject.NotImplementedError("Pulse animation only implements " +
"'in' animation direction"); "'in' animation direction");
this._resetAnimationActors(); this._cancelAnimation();
let actors = this._getChildrenToAnimate(); let actors = this._getChildrenToAnimate();
if (actors.length == 0) { if (actors.length == 0) {
@@ -481,32 +494,30 @@ var IconGrid = GObject.registerClass({
let delay = index / actors.length * maxDelay; let delay = index / actors.length * maxDelay;
let bounceUpTime = ANIMATION_TIME_IN / 4; let bounceUpTime = ANIMATION_TIME_IN / 4;
let isLastItem = index == actors.length - 1; let isLastItem = index == actors.length - 1;
actor.ease({ Tweener.addTween(actor,
scale_x: ANIMATION_BOUNCE_ICON_SCALE, { time: bounceUpTime,
scale_y: ANIMATION_BOUNCE_ICON_SCALE, transition: 'easeInOutQuad',
duration: bounceUpTime, delay: delay,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, scale_x: ANIMATION_BOUNCE_ICON_SCALE,
delay: delay, scale_y: ANIMATION_BOUNCE_ICON_SCALE,
onComplete: () => { onComplete: () => {
let duration = ANIMATION_TIME_IN - bounceUpTime; Tweener.addTween(actor,
actor.ease({ { time: ANIMATION_TIME_IN - bounceUpTime,
scale_x: 1, transition: 'easeInOutQuad',
scale_y: 1, scale_x: 1,
duration, scale_y: 1,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, onComplete: () => {
onComplete: () => { if (isLastItem)
if (isLastItem) this._animationDone();
this._animationDone(); }
actor.reactive = true; });
} }
}); });
}
});
} }
} }
animateSpring(animationDirection, sourceActor) { animateSpring(animationDirection, sourceActor) {
this._resetAnimationActors(); this._cancelAnimation();
let actors = this._getChildrenToAnimate(); let actors = this._getChildrenToAnimate();
if (actors.length == 0) { if (actors.length == 0) {
@@ -560,25 +571,21 @@ var IconGrid = GObject.registerClass({
let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM; let delay = (1 - (actor._distance - minDist) / normalization) * ANIMATION_MAX_DELAY_FOR_ITEM;
let [finalX, finalY] = actor._transformedPosition; let [finalX, finalY] = actor._transformedPosition;
movementParams = { movementParams = { time: ANIMATION_TIME_IN,
x: finalX, transition: 'easeInOutQuad',
y: finalY, delay: delay,
scale_x: 1, x: finalX,
scale_y: 1, y: finalY,
duration: ANIMATION_TIME_IN, scale_x: 1,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, scale_y: 1,
delay onComplete: () => {
}; if (isLastItem)
this._animationDone();
if (isLastItem) } };
movementParams.onComplete = this._animationDone.bind(this); fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad',
fadeParams = { delay: delay,
opacity: 255, opacity: 255 };
duration: ANIMATION_FADE_IN_TIME_FOR_ITEM,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
delay
};
} else { } else {
let isLastItem = actor._distance == maxDist; let isLastItem = actor._distance == maxDist;
@@ -586,29 +593,26 @@ var IconGrid = GObject.registerClass({
actorClone.set_position(startX, startY); actorClone.set_position(startX, startY);
let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM; let delay = (actor._distance - minDist) / normalization * ANIMATION_MAX_DELAY_OUT_FOR_ITEM;
movementParams = { movementParams = { time: ANIMATION_TIME_OUT,
x: adjustedSourcePositionX, transition: 'easeInOutQuad',
y: adjustedSourcePositionY, delay: delay,
scale_x: scaleX, x: adjustedSourcePositionX,
scale_y: scaleY, y: adjustedSourcePositionY,
duration: ANIMATION_TIME_OUT, scale_x: scaleX,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, scale_y: scaleY,
delay onComplete: () => {
}; if (isLastItem)
this._animationDone();
if (isLastItem) } };
movementParams.onComplete = this._animationDone.bind(this); fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad',
fadeParams = { delay: ANIMATION_TIME_OUT + delay - ANIMATION_FADE_IN_TIME_FOR_ITEM,
opacity: 0, 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
};
} }
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); this._items.push(item);
if (index !== undefined) if (index !== undefined)
this.insert_child_at_index(item, index); this.insert_child_at_index(item.actor, index);
else else
this.add_actor(item); this.add_actor(item.actor);
}
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) { removeItem(item) {
this.remove_child(item); this.remove_child(item.actor);
} }
getItemAtIndex(index) { getItemAtIndex(index) {
@@ -796,9 +816,8 @@ var IconGrid = GObject.registerClass({
let neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth; let neededWidth = this.usedWidthForNColumns(this._minColumns) - availWidth;
let neededHeight = this.usedHeightForNRows(this._minRows) - availHeight; let neededHeight = this.usedHeightForNRows(this._minRows) - availHeight;
let neededSpacePerItem = (neededWidth > neededHeight) let neededSpacePerItem = (neededWidth > neededHeight) ? Math.ceil(neededWidth / this._minColumns)
? Math.ceil(neededWidth / this._minColumns) : Math.ceil(neededHeight / this._minRows);
: Math.ceil(neededHeight / this._minRows);
this._fixedHItemSize = Math.max(this._hItemSize - neededSpacePerItem, MIN_ICON_SIZE); this._fixedHItemSize = Math.max(this._hItemSize - neededSpacePerItem, MIN_ICON_SIZE);
this._fixedVItemSize = Math.max(this._vItemSize - neededSpacePerItem, MIN_ICON_SIZE); this._fixedVItemSize = Math.max(this._vItemSize - neededSpacePerItem, MIN_ICON_SIZE);
@@ -819,6 +838,223 @@ var IconGrid = GObject.registerClass({
} }
return GLib.SOURCE_REMOVE; 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({ var PaginatedIconGrid = GObject.registerClass({
@@ -871,10 +1107,21 @@ var PaginatedIconGrid = GObject.registerClass({
let x = box.x1 + leftEmptySpace + this.leftPadding; let x = box.x1 + leftEmptySpace + this.leftPadding;
let y = box.y1 + this.topPadding; let y = box.y1 + this.topPadding;
let columnIndex = 0; let columnIndex = 0;
let nChanged = 0;
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
let childBox = this._calculateChildBox(children[i], x, y, box); let childBox = this._calculateChildBox(children[i], x, y, box);
// 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].allocate(childBox, flags);
children[i].restore_easing_state();
children[i].show(); children[i].show();
columnIndex++; columnIndex++;
@@ -893,8 +1140,25 @@ var PaginatedIconGrid = GObject.registerClass({
} }
// Overridden from IconGrid // 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() { _getChildrenToAnimate() {
let children = super._getChildrenToAnimate(); let children = this._getVisibleChildren();
let firstIndex = this._childrenPerPage * this.currentPage; let firstIndex = this._childrenPerPage * this.currentPage;
let lastIndex = firstIndex + this._childrenPerPage; let lastIndex = firstIndex + this._childrenPerPage;
@@ -963,7 +1227,7 @@ var PaginatedIconGrid = GObject.registerClass({
*/ */
openExtraSpace(sourceItem, side, nRows) { openExtraSpace(sourceItem, side, nRows) {
let children = this._getVisibleChildren(); let children = this._getVisibleChildren();
let index = children.indexOf(sourceItem); let index = children.indexOf(sourceItem.actor);
if (index == -1) if (index == -1)
throw new Error('Item not found.'); throw new Error('Item not found.');
@@ -973,7 +1237,8 @@ var PaginatedIconGrid = GObject.registerClass({
let childrenPerRow = this._childrenPerPage / this._rowsPerPage; let childrenPerRow = this._childrenPerPage / this._rowsPerPage;
let sourceRow = Math.floor((index - pageOffset) / childrenPerRow); let sourceRow = Math.floor((index - pageOffset) / childrenPerRow);
let nRowsAbove = (side == St.Side.TOP) ? sourceRow + 1 : sourceRow; let nRowsAbove = (side == St.Side.TOP) ? sourceRow + 1
: sourceRow;
let nRowsBelow = this._rowsPerPage - nRowsAbove; let nRowsBelow = this._rowsPerPage - nRowsAbove;
let nRowsUp, nRowsDown; let nRowsUp, nRowsDown;
@@ -1013,14 +1278,13 @@ var PaginatedIconGrid = GObject.registerClass({
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
children[i].translation_y = 0; children[i].translation_y = 0;
let params = { let params = { translation_y: translationY,
translation_y: translationY, time: EXTRA_SPACE_ANIMATION_TIME,
duration: EXTRA_SPACE_ANIMATION_TIME, transition: 'easeInOutQuad'
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD };
};
if (i == (children.length - 1)) if (i == (children.length - 1))
params.onComplete = () => this.emit('space-opened'); params.onComplete = () => this.emit('space-opened');
children[i].ease(params); Tweener.addTween(children[i], params);
} }
} }
@@ -1033,12 +1297,12 @@ var PaginatedIconGrid = GObject.registerClass({
for (let i = 0; i < this._translatedChildren.length; i++) { for (let i = 0; i < this._translatedChildren.length; i++) {
if (!this._translatedChildren[i].translation_y) if (!this._translatedChildren[i].translation_y)
continue; continue;
this._translatedChildren[i].ease({ Tweener.addTween(this._translatedChildren[i],
translation_y: 0, { translation_y: 0,
duration: EXTRA_SPACE_ANIMATION_TIME, time: EXTRA_SPACE_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD, transition: 'easeInOutQuad',
onComplete: () => this.emit('space-closed') onComplete: () => this.emit('space-closed')
}); });
} }
} }
}); });

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,26 +11,12 @@ const LOCATE_POINTER_SCHEMA = "org.gnome.desktop.interface";
var LocatePointer = class { var LocatePointer = class {
constructor() { constructor() {
this._settings = new Gio.Settings({ schema_id: LOCATE_POINTER_SCHEMA }); this._settings = new Gio.Settings({ schema_id: LOCATE_POINTER_SCHEMA });
this._settings.connect(`changed::${LOCATE_POINTER_KEY}`, () => this._syncEnabled()); this._ripples = new Ripples.Ripples(0.5, 0.5, 'ripple-pointer-location');
this._syncEnabled(); this._ripples.addTo(Main.uiGroup);
}
_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() { show() {
if (!this._ripples) if (!this._settings.get_boolean(LOCATE_POINTER_KEY))
return; return;
let [x, y] = global.get_pointer(); let [x, y] = global.get_pointer();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Overview */ /* 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 Signals = imports.signals;
const Background = imports.ui.background; const Background = imports.ui.background;
@@ -12,15 +13,16 @@ const Main = imports.ui.main;
const MessageTray = imports.ui.messageTray; const MessageTray = imports.ui.messageTray;
const OverviewControls = imports.ui.overviewControls; const OverviewControls = imports.ui.overviewControls;
const Params = imports.misc.params; const Params = imports.misc.params;
const Tweener = imports.ui.tweener;
const WorkspaceThumbnail = imports.ui.workspaceThumbnail; const WorkspaceThumbnail = imports.ui.workspaceThumbnail;
// Time for initial animation going into Overview mode // 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 // Must be less than ANIMATION_TIME, since we switch to
// or from the overview completely after ANIMATION_TIME, // or from the overview completely after ANIMATION_TIME,
// and don't want the shading animation to get cut off // 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; var DND_WINDOW_SWITCH_TIMEOUT = 750;
@@ -42,10 +44,9 @@ var ShellInfo = class {
} }
setMessage(text, options) { setMessage(text, options) {
options = Params.parse(options, { options = Params.parse(options, { undoCallback: null,
undoCallback: null, forFeedback: false
forFeedback: false, });
});
let undoCallback = options.undoCallback; let undoCallback = options.undoCallback;
let forFeedback = options.forFeedback; let forFeedback = options.forFeedback;
@@ -72,108 +73,36 @@ var ShellInfo = class {
if (undoCallback) if (undoCallback)
notification.addAction(_("Undo"), this._onUndoClicked.bind(this)); 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 { var Overview = class {
constructor() { constructor() {
this._overviewCreated = false;
this._initCalled = false; this._initCalled = false;
Main.sessionMode.connect('updated', this._sessionUpdated.bind(this)); Main.sessionMode.connect('updated', this._sessionUpdated.bind(this));
this._sessionUpdated(); 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() { _createOverview() {
if (this._overview) if (this._overviewCreated)
return; return;
if (this.isDummy) if (this.isDummy)
return; 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 // The main Background actors are inside global.window_group which are
// hidden when displaying the overview, so we create a new // hidden when displaying the overview, so we create a new
// one. Instances of this class share a single CoglTexture behind the // one. Instances of this class share a single CoglTexture behind the
@@ -188,11 +117,11 @@ var Overview = class {
this._activationTime = 0; 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._shown = false; // show() and not hide()
this._modal = false; // have a modal grab this._modal = false; // have a modal grab
this._animationInProgress = false; this.animationInProgress = false;
this._visibleTarget = false; this.visibleTarget = false;
// During transitions, we raise this to the top to avoid having the overview // 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 // area be reactive; it causes too many issues such as double clicks on
@@ -201,6 +130,9 @@ var Overview = class {
reactive: true }); reactive: true });
Main.layoutManager.overviewGroup.add_child(this._coverPane); Main.layoutManager.overviewGroup.add_child(this._coverPane);
this._coverPane.connect('event', () => Clutter.EVENT_STOP); this._coverPane.connect('event', () => Clutter.EVENT_STOP);
Main.layoutManager.overviewGroup.add_child(this._overview);
this._coverPane.hide(); this._coverPane.hide();
// XDND // XDND
@@ -242,28 +174,24 @@ var Overview = class {
_unshadeBackgrounds() { _unshadeBackgrounds() {
let backgrounds = this._backgroundGroup.get_children(); let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) { for (let i = 0; i < backgrounds.length; i++) {
backgrounds[i].ease_property('brightness', 1.0, { Tweener.addTween(backgrounds[i],
duration: SHADE_ANIMATION_TIME, { brightness: 1.0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD vignette_sharpness: 0.0,
}); time: SHADE_ANIMATION_TIME,
backgrounds[i].ease_property('vignette-sharpness', 0.0, { transition: 'easeOutQuad'
duration: SHADE_ANIMATION_TIME, });
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
} }
} }
_shadeBackgrounds() { _shadeBackgrounds() {
let backgrounds = this._backgroundGroup.get_children(); let backgrounds = this._backgroundGroup.get_children();
for (let i = 0; i < backgrounds.length; i++) { for (let i = 0; i < backgrounds.length; i++) {
backgrounds[i].ease_property('brightness', Lightbox.VIGNETTE_BRIGHTNESS, { Tweener.addTween(backgrounds[i],
duration: SHADE_ANIMATION_TIME, { brightness: Lightbox.VIGNETTE_BRIGHTNESS,
mode: Clutter.AnimationMode.EASE_OUT_QUAD vignette_sharpness: Lightbox.VIGNETTE_SHARPNESS,
}); time: SHADE_ANIMATION_TIME,
backgrounds[i].ease_property('vignette-sharpness', Lightbox.VIGNETTE_SHARPNESS, { transition: 'easeOutQuad'
duration: SHADE_ANIMATION_TIME, });
mode: Clutter.AnimationMode.EASE_OUT_QUAD
});
} }
} }
@@ -282,12 +210,41 @@ var Overview = class {
if (this.isDummy) if (this.isDummy)
return; return;
this._overview = new OverviewActor();
this._overview._delegate = this;
Main.layoutManager.overviewGroup.add_child(this._overview);
this._shellInfo = new ShellInfo(); 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)); Main.layoutManager.connect('monitors-changed', this._relayout.bind(this));
this._relayout(); this._relayout();
} }
@@ -340,7 +297,7 @@ var Overview = class {
_resetWindowSwitchTimeout() { _resetWindowSwitchTimeout() {
if (this._windowSwitchTimeoutId != 0) { if (this._windowSwitchTimeoutId != 0) {
GLib.source_remove(this._windowSwitchTimeoutId); Mainloop.source_remove(this._windowSwitchTimeoutId);
this._windowSwitchTimeoutId = 0; this._windowSwitchTimeoutId = 0;
} }
} }
@@ -363,9 +320,7 @@ var Overview = class {
if (targetIsWindow) { if (targetIsWindow) {
this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow; this._lastHoveredWindow = dragEvent.targetActor._delegate.metaWindow;
this._windowSwitchTimeoutId = GLib.timeout_add( this._windowSwitchTimeoutId = Mainloop.timeout_add(DND_WINDOW_SWITCH_TIMEOUT,
GLib.PRIORITY_DEFAULT,
DND_WINDOW_SWITCH_TIMEOUT,
() => { () => {
this._windowSwitchTimeoutId = 0; this._windowSwitchTimeoutId = 0;
Main.activateWindow(dragEvent.targetActor._delegate.metaWindow, Main.activateWindow(dragEvent.targetActor._delegate.metaWindow,
@@ -466,17 +421,16 @@ var Overview = class {
focusSearch() { focusSearch() {
this.show(); this.show();
this._overview.searchEntry.grab_key_focus(); this._searchEntry.grab_key_focus();
} }
fadeInDesktop() { fadeInDesktop() {
this._desktopFade.opacity = 0; this._desktopFade.opacity = 0;
this._desktopFade.show(); this._desktopFade.show();
this._desktopFade.ease({ Tweener.addTween(this._desktopFade,
opacity: 255, { opacity: 255,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, time: ANIMATION_TIME,
duration: ANIMATION_TIME transition: 'easeOutQuad' });
});
} }
fadeOutDesktop() { fadeOutDesktop() {
@@ -490,11 +444,11 @@ var Overview = class {
this._desktopFade.opacity = 255; this._desktopFade.opacity = 255;
this._desktopFade.show(); this._desktopFade.show();
this._desktopFade.ease({ Tweener.addTween(this._desktopFade,
opacity: 0, { opacity: 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, time: ANIMATION_TIME,
duration: ANIMATION_TIME transition: 'easeOutQuad'
}); });
} }
// Checks if the Activities button is currently sensitive to // Checks if the Activities button is currently sensitive to
@@ -504,11 +458,11 @@ var Overview = class {
// the overview if the user both triggered the hot corner and // the overview if the user both triggered the hot corner and
// clicked the Activities button. // clicked the Activities button.
shouldToggleByCornerOrButton() { shouldToggleByCornerOrButton() {
if (this._animationInProgress) if (this.animationInProgress)
return false; return false;
if (this._inItemDrag || this._inWindowDrag) if (this._inItemDrag || this._inWindowDrag)
return false; return false;
if (!this._activationTime || if (this._activationTime == 0 ||
GLib.get_monotonic_time() / GLib.USEC_PER_SEC - this._activationTime > OVERVIEW_ACTIVATION_TIMEOUT) GLib.get_monotonic_time() / GLib.USEC_PER_SEC - this._activationTime > OVERVIEW_ACTIVATION_TIMEOUT)
return true; return true;
return false; return false;
@@ -518,18 +472,20 @@ var Overview = class {
// We delay grab changes during animation so that when removing the // 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 // overview we don't have a problem with the release of a press/release
// going to an application. // going to an application.
if (this._animationInProgress) if (this.animationInProgress)
return true; return true;
if (this._shown) { if (this._shown) {
let shouldBeModal = !this._inXdndDrag; let shouldBeModal = !this._inXdndDrag;
if (shouldBeModal && !this._modal) { if (shouldBeModal) {
let actionMode = Shell.ActionMode.OVERVIEW; if (!this._modal) {
if (Main.pushModal(this._overview, { actionMode })) { if (Main.pushModal(this._overview,
this._modal = true; { actionMode: Shell.ActionMode.OVERVIEW })) {
} else { this._modal = true;
this.hide(); } else {
return false; this.hide();
return false;
}
} }
} }
} else { } else {
@@ -560,24 +516,25 @@ var Overview = class {
_animateVisible() { _animateVisible() {
if (this._visible || this._animationInProgress) if (this.visible || this.animationInProgress)
return; return;
this._visible = true; this.visible = true;
this._animationInProgress = true; this.animationInProgress = true;
this._visibleTarget = true; this.visibleTarget = true;
this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC; this._activationTime = GLib.get_monotonic_time() / GLib.USEC_PER_SEC;
Meta.disable_unredirect_for_display(global.display); Meta.disable_unredirect_for_display(global.display);
this.viewSelector.show(); this.viewSelector.show();
this._overview.opacity = 0; this._overview.opacity = 0;
this._overview.ease({ Tweener.addTween(this._overview,
opacity: 255, { opacity: 255,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
duration: ANIMATION_TIME, time: ANIMATION_TIME,
onComplete: () => this._showDone() onComplete: this._showDone,
}); onCompleteScope: this
});
this._shadeBackgrounds(); this._shadeBackgrounds();
this._coverPane.raise_top(); this._coverPane.raise_top();
@@ -586,7 +543,7 @@ var Overview = class {
} }
_showDone() { _showDone() {
this._animationInProgress = false; this.animationInProgress = false;
this._desktopFade.hide(); this._desktopFade.hide();
this._coverPane.hide(); this._coverPane.hide();
@@ -626,21 +583,22 @@ var Overview = class {
} }
_animateNotVisible() { _animateNotVisible() {
if (!this._visible || this._animationInProgress) if (!this.visible || this.animationInProgress)
return; return;
this._animationInProgress = true; this.animationInProgress = true;
this._visibleTarget = false; this.visibleTarget = false;
this.viewSelector.animateFromOverview(); this.viewSelector.animateFromOverview();
// Make other elements fade out. // Make other elements fade out.
this._overview.ease({ Tweener.addTween(this._overview,
opacity: 0, { opacity: 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD, transition: 'easeOutQuad',
duration: ANIMATION_TIME, time: ANIMATION_TIME,
onComplete: () => this._hideDone() onComplete: this._hideDone,
}); onCompleteScope: this
});
this._unshadeBackgrounds(); this._unshadeBackgrounds();
this._coverPane.raise_top(); this._coverPane.raise_top();
@@ -656,8 +614,8 @@ var Overview = class {
this._desktopFade.hide(); this._desktopFade.hide();
this._coverPane.hide(); this._coverPane.hide();
this._visible = false; this.visible = false;
this._animationInProgress = false; this.animationInProgress = false;
this.emit('hidden'); this.emit('hidden');
// Handle any calls to show* while we were hiding // Handle any calls to show* while we were hiding
@@ -673,17 +631,14 @@ var Overview = class {
if (this.isDummy) if (this.isDummy)
return; return;
if (this._visible) if (this.visible)
this.hide(); this.hide();
else else
this.show(); this.show();
} }
getShowAppsButton() { getShowAppsButton() {
logError(new Error('Usage of Overview.\'getShowAppsButton\' is deprecated, ' + return this._dash.showAppsButton;
'use \'dash.showAppsButton\' property instead'));
return this.dash.showAppsButton;
} }
}; };
Signals.addSignalMethods(Overview.prototype); Signals.addSignalMethods(Overview.prototype);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,7 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported Ripples */ /* exported Ripples */
const { Clutter, St } = imports.gi; const { St } = imports.gi;
const Tweener = imports.ui.tweener;
// Shamelessly copied from the layout "hotcorner" ripples implementation // Shamelessly copied from the layout "hotcorner" ripples implementation
var Ripples = class Ripples { var Ripples = class Ripples {
@@ -34,41 +35,30 @@ var Ripples = class Ripples {
this._ripple3.set_pivot_point(px, py); this._ripple3.set_pivot_point(px, py);
} }
destroy() { _animRipple(ripple, delay, time, startScale, startOpacity, finalScale) {
this._ripple1.destroy();
this._ripple2.destroy();
this._ripple3.destroy();
}
_animRipple(ripple, delay, duration, startScale, startOpacity, finalScale) {
// We draw a ripple by using a source image and animating it scaling // We draw a ripple by using a source image and animating it scaling
// outwards and fading away. We want the ripples to move linearly // outwards and fading away. We want the ripples to move linearly
// or it looks unrealistic, but if the opacity of the ripple goes // 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 // linearly to zero it fades away too quickly, so we use Tweener's
// tween to give a non-linear curve to the fade-away and make // 'onUpdate' to give a non-linear curve to the fade-away and make
// it more visible in the middle section. // it more visible in the middle section.
ripple.x = this._x; ripple.x = this._x;
ripple.y = this._y; ripple.y = this._y;
ripple._opacity = startOpacity;
ripple.visible = true; ripple.visible = true;
ripple.opacity = 255 * Math.sqrt(startOpacity); ripple.opacity = 255 * Math.sqrt(startOpacity);
ripple.scale_x = ripple.scale_y = startScale; ripple.scale_x = ripple.scale_y = startScale;
ripple.set_translation( - this._px * ripple.width, - this._py * ripple.height, 0.0); ripple.set_translation( - this._px * ripple.width, - this._py * ripple.height, 0.0);
ripple.ease({ Tweener.addTween(ripple, { _opacity: 0,
opacity: 0, scale_x: finalScale,
delay, scale_y: finalScale,
duration, delay: delay,
mode: Clutter.AnimationMode.EASE_IN_QUAD time: time,
}); transition: 'linear',
ripple.ease({ onUpdate: () => ripple.opacity = 255 * Math.sqrt(ripple._opacity),
scale_x: finalScale, onComplete: () => ripple.visible = false });
scale_y: finalScale,
delay,
duration,
mode: Clutter.AnimationMode.LINEAR,
onComplete: () => (ripple.visible = false)
});
} }
addTo(stage) { addTo(stage) {
@@ -96,9 +86,9 @@ var Ripples = class Ripples {
// parameters were found by trial and error, so don't look // parameters were found by trial and error, so don't look
// for them to make perfect sense mathematically // for them to make perfect sense mathematically
// delay time scale opacity => scale // delay time scale opacity => scale
this._animRipple(this._ripple1, 0, 830, 0.25, 1.0, 1.5); this._animRipple(this._ripple1, 0.0, 0.83, 0.25, 1.0, 1.5);
this._animRipple(this._ripple2, 50, 1000, 0.0, 0.7, 1.25); this._animRipple(this._ripple2, 0.05, 1.0, 0.0, 0.7, 1.25);
this._animRipple(this._ripple3, 350, 1000, 0.0, 0.3, 1); 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 Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog; const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry; const ShellEntry = imports.ui.shellEntry;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util; const Util = imports.misc.util;
const History = imports.misc.history; const History = imports.misc.history;
@@ -18,7 +19,7 @@ const TERMINAL_SCHEMA = 'org.gnome.desktop.default-applications.terminal';
const EXEC_KEY = 'exec'; const EXEC_KEY = 'exec';
const EXEC_ARG_KEY = 'exec-arg'; const EXEC_ARG_KEY = 'exec-arg';
var DIALOG_GROW_TIME = 100; var DIALOG_GROW_TIME = 0.1;
var RunDialog = GObject.registerClass( var RunDialog = GObject.registerClass(
class RunDialog extends ModalDialog.ModalDialog { class RunDialog extends ModalDialog.ModalDialog {
@@ -94,17 +95,15 @@ class RunDialog extends ModalDialog.ModalDialog {
this._errorBox.hide(); this._errorBox.hide();
this.setButtons([{ this.setButtons([{ action: this.close.bind(this),
action: this.close.bind(this), label: _("Close"),
label: _("Close"), key: Clutter.Escape }]);
key: Clutter.Escape,
}]);
this._pathCompleter = new Gio.FilenameCompleter(); this._pathCompleter = new Gio.FilenameCompleter();
this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY, this._history = new History.HistoryManager({ gsettingsKey: HISTORY_KEY,
entry: this._entryText }); entry: this._entryText });
this._entryText.connect('activate', o => { this._entryText.connect('activate', (o) => {
this.popModal(); this.popModal();
this._run(o.get_text(), this._run(o.get_text(),
Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK); Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK);
@@ -244,16 +243,15 @@ class RunDialog extends ModalDialog.ModalDialog {
let [, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1); let [, errorBoxNaturalHeight] = this._errorBox.get_preferred_height(-1);
let parentActor = this._errorBox.get_parent(); let parentActor = this._errorBox.get_parent();
let height = parentActor.height + errorBoxNaturalHeight; Tweener.addTween(parentActor,
parentActor.ease({ { height: parentActor.height + errorBoxNaturalHeight,
height, time: DIALOG_GROW_TIME,
duration: DIALOG_GROW_TIME, transition: 'easeOutQuad',
mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => {
onComplete: () => { parentActor.set_height(-1);
parentActor.set_height(-1); this._errorBox.show();
this._errorBox.show(); }
} });
});
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -151,13 +151,9 @@ var GnomeShell = class {
let connection = this._dbusImpl.get_connection(); let connection = this._dbusImpl.get_connection();
let info = this._dbusImpl.get_info(); let info = this._dbusImpl.get_info();
let params = { 'device-id': GLib.Variant.new('u', device.get_device_id()), 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), 'timestamp': GLib.Variant.new('u', timestamp),
'action-mode': GLib.Variant.new('u', Main.actionMode) }; '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, connection.emit_signal(destination,
this._dbusImpl.get_object_path(), this._dbusImpl.get_object_path(),
info ? info.name : null, info ? info.name : null,

View File

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

View File

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

View File

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

View File

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

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