Compare commits

...

88 Commits

Author SHA1 Message Date
Georges Basile Stavracas Neto
24cdcc56da st-bin: Destroy child in ClutterActor:destroy vfunc
According to Clutter documentation, "[…] actors implementing the
ClutterContainer interface should override the default implementation
of the class handler of this signal and call clutter_actor_destroy()
on their  children."

StBin was doing that in GObject:dispose() instead. Move the child
destruction to a new ClutterActor:destroy() vfunc override.


(cherry picked from commit b719744e75)
2019-01-16 00:05:59 +00:00
Takao Fujiwara
1b28cdfbf4 keyboard: Do not call KeyboardManager.holdKeyboard() with set-content-type
When gnome-shell receives the signal of 'set-content-type' from ibus,
gnome-shell calls KeyboardManager.holdKeyboard() and
KeyboardManager.releaseKeyboard() and the functions change the current
input focus in GNOME Xorg and it could result in closing a popup window
which has a password entry by focusing on the entry.
The solution is to stop to call the APIs on 'set-content-type' signal.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/391


(cherry picked from commit 551e827841)
2019-01-15 15:24:40 +00:00
Florian Müllner
a73294312f altSwitcher: Fix error when all alternatives are disabled
While we do consider the case that we don't have a child to show for the
visibility, we are still trying to move the click action unconditionally.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/783

(cherry picked from commit e77463b875)
2019-01-11 11:30:27 +00:00
Florian Müllner
5e7a7e31a1 messageTray: Re-enable unredirection when banner is destroyed
The intention of commit 4dc20398 was to disable unredirection while
banners are shown, but the ::done-displaying signal currently used for
re-enabling unredirection is only emitted under some circumstances, so
it's possible that unredirection is left disabled indefinitely, whoops.

Fix this by tying disabling unredirection explicitly to the lifetime
of the banner actor.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/799

(cherry picked from commit e5ce3d541e)
2019-01-11 11:30:27 +00:00
Florian Müllner
8111286463 messageTray: Disable unredirection while showing banners
We don't usually show notification banners while the monitor is in
fullscreen, but when we do - the notification is urgent - we should
actually show the banner, even if the top-most window is unredirected.
To achieve that, disable unredirection while the banner is showing.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/430

(cherry picked from commit 4dc2039859)
2019-01-11 11:30:26 +00:00
Will Thompson
06c6ecc15b workspacesView: initialize self._restackedNotifyId
This attribute was previously only assigned in show(). hide() compares
this attribute to 0. If hide() is called before show() is first called,
the comparison would give the correct result (undefined > 0 is false)
but log a warning:

    JS WARNING: [resource:///org/gnome/shell/ui/workspacesView.js 529]:
    reference to undefined property "_restackedNotifyId"

Initialize this attribute in _init(), alongside _scrollEventId and
_keyPressEventId which are also used in hide().

(cherry picked from commit b2fabd9356)
2019-01-11 11:30:26 +00:00
Will Thompson
36f9dcd2bd endSessionDialog: squash "reference to undefined property" warning
dialogContent is set to one of the elements of the list DialogContent,
but not all of those have a checkBoxText property. When logging out (as
opposed to shutting down), this causes a warning:

    JS WARNING: [resource:///org/gnome/shell/ui/endSessionDialog.js
    763]: reference to undefined property "checkBoxText"

(The line number corresponds to this line in 3.28.3.)

The warning is apparently not triggered if the undefined property is
used as part of a boolean expression:

    gjs> var x = {};
    gjs> x.a;
    typein:2:1 strict warning: reference to undefined property "a"
    gjs> if (x.b) { log('oh no'); }
    gjs> x.c || ''
    ""
_setCheckBoxLabel() just checks the truthiness of its 'text' argument,
and the empty string is false-y, so passing '' rather than undefined has
no functional effect.

(cherry picked from commit 0892b5dcdb)
2019-01-11 11:30:26 +00:00
Andrea Azzarone
219118e633 viewSelector: Don't unfocus other modals on reset
Don't drop the key focus on Clutter's side if anything but the overview has
pushed a modal (e.g. system modals when activated using the overview).

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/618

(cherry picked from commit fffe58f829)
2019-01-11 11:30:26 +00:00
Florian Müllner
1e929357e0 panel: Also ignore hidden windows for proximity
We currently only ignore minimized windows, not windows that are
hidden for other reasons - namely on wayland windows are initially
hidden until they are placed.

This fixes a flicker in the transparent top bar on wayland when the
"position" of an unplaced window wrongly suggests the window is
overlapping the top bar.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/693

(cherry-picked from commit a0dc8dc7ef)
2019-01-11 11:30:26 +00:00
Marco Trevisan (Treviño)
e7463e38ca notificationDaemon: support file:// or icon theme names for image-path
While this sounds counter-intuitive, the image-path hint value might also
be used with URIs or icon names.

As per freedesktop standard:
  The "app_icon" parameter and "image-path" hint should be either an URI
  (file:// is the only URI schema supported right now) or a name in a
  freedesktop.org-compliant icon theme (not a GTK+ stock ID).

Thus the image-path hint should also be parsed as it happens for the
app_icon.

Reuse same logic, by falling back on _iconForNotificationData with the
hint value.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/285

(cherry picked from commit 33b8537bf5)
2019-01-11 11:30:26 +00:00
Andrea Azzarone
420c1cbfd1 dash: destroy items's child before tooltip
Destroy the DashItemContainer's child from the same handler as the tooltip. This
will prevent invalid reads when the item is destroyed while its quicklist is
still open.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/781

(cherry picked from commit ff2fbf5ae4)
2019-01-11 11:30:26 +00:00
Cosimo Cecchi
d53bd98532 StWidget: don't forget to invalidate the paint state if not on stage
If the actor is not on the stage yet (i.e. does not have a theme
node), but has a paint state cached, we currently fail to invalidate
it, which will lead to the actor painting with old contents once it
gets onto the stage.

This commit fixes the issue by changing our invalidation strategy;
previously we were looking at the widget's own theme node to determine
if it should be invalidated or not.
Now we look at the theme nodes of our cached paint states. When the
widget is mapped on stage, those are the same as the widget's own
theme node, but when the widget is not on the stage, we'll still be
able to invalidate them.

As part of this, we move the invalidation API to StThemeNodePaintState,
which is a more natural place for our use case.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/314

(cherry picked from commit 6743c18fdf)
2019-01-11 11:30:26 +00:00
Cosimo Cecchi
128a501b9a StTextureCache: use right event to detect file changes
StTextureCache installs file monitors that invalidate caches when
contents of the underlying file change.
At the moment, the cache uses the Gio.FileMonitorEvent.CHANGED event
type to make that determination.

However, that is suboptimal for at least two reasons:
- while a file is being written to disk, many CHANGED events will be
  emitted in sequence. That will cause needless cache invalidations,
  and we will risk loading the file before it's fully loaded.
- if an existing file is replaced, e.g. with g_file_replace(), we may
  not get a CHANGED event but a CREATED one instead, so the cache ends
  up never getting invalidated.

The good news is that in both of those cases GFileMonitor will send a
CHANGES_DONE_HINT event after changes have settled, or after the file
is replaced.

This commit fixes both cases by switching from the CHANGED event to
CHANGES_DONE_HINT to determine that a file has in fact changed.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/286

(cherry picked from commit ca3f4cfb41)
2019-01-11 11:30:26 +00:00
Florian Müllner
b29e243fec st: Avoid integer overflow on unpremultiply
When computing the effective border color, we operate on colors with
premultiplied alpha to simplify the calculations, then unpremultiply
the result. However we miss a bounds check in the last check, so any
color component can overflow the allowed maximum of 0xff and shift the
result in unexpected ways.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/305

(cherry picked from commit 925a25da17)
2019-01-11 11:30:26 +00:00
Jonas Ådahl
fa2ddcc52f dnd: Repick target actor if destroyed mid iteration
The picked target actor may be destroyed (e.g. hover style change
resulting in the ClutterTexture to be destroyed). If we don't handle
this, GJS will abort when it sees the exception caused by Javascript
code trying to access the destroyed target actor.

To handle it, listen on the 'destroy' signal on the target actor, and
repick, so a valid actor is passed to the next motion callback.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/632

(cherry picked from commit 4259676f6e)
2019-01-11 11:30:26 +00:00
Marco Trevisan (Treviño)
fbf194f6a1 st-button: Ignore pointer emulated touch events
In X11, pointer emulated touch events are replicated with normal PRESS, RELEASE
pair events which are generated by the server. Thus for a single tap we get:
 - TOUCH_BEGIN -> TOUCH_END, PRESS -> RELEASE

This will cause st-button to send two "clicked" signals, instead of just one,
breaking extensions (like dash-to-dock) that show buttons in the main stage
which will be checked two times or that will receive the same signal two times.


(cherry picked from commit 4c11d15a07)
2018-11-26 21:22:10 +00:00
Daniel van Vugt
5610a2435d iconGrid: Defer and group animation cleanup
The `reactive` property of icon actors was being restored 24 times over
the course of the spring animation, all at slightly different times as
each icon finished animating at different times.

The problem is that toggling `reactive` on an `StWidget` incurs a style
change of the `insensitive` pseudo class, and style changes would quickly
queue relayouts incurring full stage reallocation. This occurred many times
during a spring animation hogging the CPU and limiting the frame rate.

The solution is defer and batch the cleanup for all icons until after the
last icon has finished animating. This way the CPU impact of the style
change and stage relayout isn't felt during the animation so the frame
rate remains higher and smoother. The overall CPU usage of the animation
is also reduced as the remaining relayouts are much more likely to be
grouped into a single frame.

Icon spring animation performance on an i7-7700:
Before: 83% CPU and 47 FPS
After : 78% CPU and 54 FPS
which is about a 22% increase in performance per clock (FPS/CPU).

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/253


(cherry picked from commit a5e6dd52d2)
2018-11-20 19:52:16 +00:00
Florian Müllner
a5b36fc7f4 osdWindow: Disconnect signals on destroy
Since we started to show OSD windows on all monitors, OSD windows are
destroyed when the corresponding monitor is disconnected. We shouldn't
leave any signal handlers around in that case - they prevent the object
from being garbage collected, and trigger warnings for accessing proper-
ties of invalidated GObjects.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/602
2018-10-30 13:13:50 +01:00
Marek Černocký
923d80bba8 Updated Czech translation 2018-10-07 14:32:30 +02:00
Florian Müllner
9e196d2765 workspace: Avoid setting an undefined width
Since commit c04289853f the `width` parameter may be undefined, but
it is still set unconditionally, whoops.
2018-09-04 17:30:56 +02:00
Florian Müllner
94897492be calendar: chain up to parent on _onDestroy
(cherry picked from commit 5bca4a884e)
2018-09-03 23:39:40 +00:00
Marco Trevisan (Treviño)
6baf82eb83 messageList: stop syncing if closeButton has been destroyed
The _sync function for Message only updates the close button visibility,
so we can safely stop doing that if the close button get get destroyed earlier
(as it happens when clicking on it).

https://bugzilla.gnome.org/show_bug.cgi?id=791233


(cherry picked from commit 87da623d86)
2018-09-03 23:38:47 +00:00
Marco Trevisan (Treviño)
65d27aaa43 automountManager: remove allowAutorun expire timeout on volume removal
If the volume is removed before AUTORUN_EXPIRE_TIMEOUT_SECS seconds, we can stop
the timeout earlier as there's nothing to unset, while the volume instance
won't be valid anymore.

https://bugzilla.gnome.org/show_bug.cgi?id=791233


(cherry picked from commit 9c41736a81)
2018-09-03 23:38:17 +00:00
Marco Trevisan (Treviño)
176aaa4a97 extensionSystem: Unset stylesheet file reference when unloaded
We must remove the GFile reference from the representing object when an
extension has been unloaded as this won't be used anymore later (e.g. as cached
ref).


(cherry picked from commit 72f5802be9)
2018-09-03 23:36:00 +00:00
Marco Trevisan (Treviño)
5ae5811155 js/main: Throw error if no valid default stylesheet is found
Throw an error using an informative message in case a mode uses a stylesheet
that can't be loaded, instead of crashing later because the theming can't be
properly computed, and thus the minimum size of the actors.


(cherry picked from commit 30cb2127a1)
2018-09-03 23:35:30 +00:00
Marco Trevisan (Treviño)
e027af9548 extensionSystem: Unload stylesheet if extension is not loaded
We should not keep any reference to an extension custom stylesheet in case we
got an error while enabling that


(cherry picked from commit 3aea290adc)
2018-09-03 23:34:54 +00:00
Marco Trevisan (Treviño)
73649a0d6a extensionSystem: Don't load an extension with invalid stylesheet
We currently assign the stylesheet to an extension whenever the file exists,
regardless of whether it actually loaded successfully or not.
And thus we load an extension that ships a stylesheet even if that file can't
be used.

There is no point in trying to load an extension if its stylesheet wasn't
loaded in the first place, so make sure this happens only on success.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/188


(cherry picked from commit 5b3ff7184e)
2018-09-03 23:34:26 +00:00
Iain Lane
7dbcd26619 network: Don't assume the active connection has been processed first
`NMConnectionDevice._sync()` is responsible for setting up the active
connection that we'll end up displaying. It expects the active
connection to already be in a map `_connectionItems`. If it isn't in
there, we get a null dereference and the indicator can get into a weird
state where it doesn't display devices / connections properly.

Let's change this expectation. If there is an active connection,
`_deviceAdded()` will eventually get to it and call `_sync()` to set up
the active connection state. We make `_sync()` tolerate there being no
active connection when it's called.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/140


(cherry picked from commit 5d61e2563d)
2018-09-03 23:34:07 +00:00
verdre
f30ec4a4c8 workspace: Don't initially hide the title of window overlays
To be able to read the properties of the title correctly during the
first relayout of the overlay, the title, just like the border, can't be
hidden. Otherwise the title can be misaligned some pixels to the left
sometimes.

This slighty worsens the issue that windows moved to a separate
workspace using DND will show an overlay when the workspace is shown in
the overview even though no window is pointed at. Before this commit,
only the border would be visible for windows moved to another workspace,
now the title also is.
2018-09-04 01:18:00 +02:00
verdre
c04289853f workspace: Avoid setting overlay title width
Avoid setting the width of the overlay title ourselves to keep the
default width of -1, this way StLabel will change its width by itself as
soon as the text is updated.

The width only needs to be changed if the window title changes, and we
don't animate it in this case anyway so there's no need to pass a width
to _animateOverlayActor().

Setting the title width to the preferred width on relayout is impossible
because get_preferred_width() will always return the width we set the
label to before. If the width is not set to -1, there's no way to get
the new preferred width without calculating it ourselves from the
underlying ClutterText instance.

https://bugzilla.gnome.org/show_bug.cgi?id=787260
2018-09-04 01:18:00 +02:00
Marco Trevisan (Treviño)
b72b773d87 search: Ignore search provider results metas if search is cancelled
When a search has been cancelled, it is expected that providers don't
return the requested number of results, so don't log a warning in that
case.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/205
2018-09-04 01:12:24 +02:00
Marco Trevisan (Treviño)
da7cd2807f search: Cancel search provider operations on clear
Ensure that the search provider operations (just getResultMetas requests
in the current implementation) in progress are properly cancelled when we
clear the UI, otherwise returned results might still be added when not
needed.

This is triggered for each provider by the SearchResults reset.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/205
2018-09-04 01:12:12 +02:00
Marco Trevisan (Treviño)
20373ba64e viewSelector: Cancel search on overview hidden
Currently when the overview is hidden, any pending search is kept alive,
not only at remote search provider level (as per issue #183), but even
the shell providers proxies continue to get and process data. This happens
even if this is not needed anymore, while the UI reset is performed only
next time that the overview is shown (causing some more computation
presentation time).

In order to stop this to happen, when the overview is hidden, we have to
unset the search entry to an empty value as this would make SearchResults
to have empty terms list and that would make the proxies cancellable to
be triggered (without causing any further search to start).

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/205
2018-09-04 01:12:04 +02:00
Ray Strode
025f6eb68e objectManager: correct other invalid index code in onNameVanished
The object manager tries to synthesize interface removal
events if the bus name of a remote object drops off the bus.

The code had bad typos in it, though: it reuses the `i`
index variable in its inner loop, where it should be using
the `j` index variable.

This commit corrects the i/j confusion.
2018-09-04 01:11:40 +02:00
Ray Strode
dc5df5c4c9 objectManager: correct invalid index code in onNameVanished
The object manager tries to synthesize interface removal
events if the bus name of a remote object drops off the bus.

The code has a bad typo in it, though: it confuses `objectPaths`
(the list of all object paths) and `objectPath` (the object
currently being processed this iteration of the loop).

That leads to a failure to synthesize the interface removal
events, and spew in the log.

This commit corrects the objectPath/objectPaths confusion.
2018-09-04 01:11:40 +02:00
Marco Trevisan (Treviño)
81db908339 layoutManager: Return null monitor if focusIndex is invalid
https://bugzilla.gnome.org/show_bug.cgi?id=788882


(cherry picked from commit 996dd74157)
2018-08-31 14:40:35 +00:00
Marco Trevisan (Treviño)
706a2259b8 windowManager: Don't animate unmanaged windows on (un)minimization
(cherry picked from commit 878946962d)
2018-08-31 14:40:01 +00:00
Sam Spilsbury
e94af71430 keyboard: Handle case where keyboardMonitor is unset
This may be the case where keyboardIndex is -1, which may be the
case where either the keyboard monitor hasn't been set yet, or
the keyboard is being unmanaged and meta_window_get_monitor
returns -1

https://bugzilla.gnome.org/show_bug.cgi?id=788882


(cherry picked from commit 19e864ed3b)
2018-08-31 14:39:12 +00:00
Sam Spilsbury
a662e7bb87 windowMenu: Check if monitorIndex is valid before using it
Calling meta_window_get_monitor on an unmanaged window may return
-1, so we need to check the return value.

https://bugzilla.gnome.org/show_bug.cgi?id=788882


(cherry picked from commit c9bf72c5c4)
2018-08-31 14:38:54 +00:00
Florian Müllner
0b82388c49 overviewControls: Sync hover after drag operations
During global grabs, actors miss enter and leave events required
for correct hover tracking. This can cause the workspace switcher
to get stuck while slid out, so ensure the actor's hover state is
synced after drag operations.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/161


(cherry picked from commit 328c63bf64)
2018-08-31 14:28:11 +00:00
Carlos Garnacho
b359b937e9 layout: Mark chrome container as NO_LAYOUT
Showing and hiding children does not affect the allocation of the uiGroup
nor its other children. We can avoid full relayout/redraw in those
situations.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/197


(cherry picked from commit 73d8c82640)
2018-08-31 14:27:15 +00:00
Carlos Garnacho
98fb7c33f2 windowManager: Declare variables
Fixes warnings from GJS.


(cherry picked from commit 2f76951658)
2018-08-31 14:22:21 +00:00
Jasper St. Pierre
4dfc2e0fd1 st-texture-cache: Obey cache policy in st_texture_cache_load
https://bugzilla.gnome.org/show_bug.cgi?id=663461


(cherry picked from commit 50e849a186)
2018-08-31 14:15:30 +00:00
Carlos Garnacho
9152d3a286 st-box-layout: Queue relayout on adjustment changes
The actor allocation doesn't change per-se, but apply_transform()
will practically transform it. In order to have the paint volume
update accordingly, queue a relayout.


(cherry picked from commit ab4c72d758)
2018-08-31 14:11:58 +00:00
Carlos Garnacho
ba33a05dd2 st: Clip StEntry to allocation
The default get_paint_volume() implementation will do the union
of children, and the child ClutterText paint volume may expand
beyond StEntry size when text overflows.

We actually want all content to be clipped to the StEntry, so
implement get_paint_volume() and tell it so.


(cherry picked from commit 86a520b880)
2018-08-31 14:11:05 +00:00
Carlos Garnacho
ddb309815c st: Make StScrollables' paint volume reflect the unconstrained view
And constrain it in StScrollView instead (instead of falling back to an
infinite paint volume, as the actor as paint/pick impls, but no
corresponding get_paint_volume one).

Fixes artifacts with the AppView (and possibly other places) when paint
volumes are aggressively cached.


(cherry picked from commit 4bf033a885)
2018-08-31 14:08:57 +00:00
Florian Müllner
6a796675bd keyboard: Handle no-window case in FocusTracker
For windows, the cursor location needs to be adjusted by the frame
offsets. However we cannot assume that there is a window, as the
shell itself can have the key focus.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/414


(cherry picked from commit 0dee82fb9f)
2018-08-31 13:48:21 +00:00
verdre
d08497414f workspace: Fix infinite loop when finding parent window of dialogs
When a dialog is added to a window while the overview is shown, we get
its parent using get_transient_for() so we can add it to the right
window clone.

If we have multiple layers of dialogs we have to do this recursively
until we find the root ancestor. This case currently results in an
infinite loop: Since parent is always set to the same window, the
while-condition will always be true.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/180


(cherry picked from commit 52cbc299a7)
2018-08-30 02:39:37 +00:00
verdre
82886b7ee8 overview: Use whole stage size for cover pane
We show a cover pane on top of the overview during transitions to
prevent issues caused by clicks and mouseover events when the overview
is not ready. Right now, this pane is only being shown on the primary
monitor, which obviosly allows interactions to happen before the
animations are finished on the secondary monitors.

To fix this, use the size of the whole stage for the cover pane.


(cherry picked from commit 02d06bb1f3)
2018-08-30 02:37:28 +00:00
Carlos Garnacho
dca43c7b24 st: Use ClutterClickAction on StEntry primary/secondary icons
This makes them work on touchscreens as well.

Closes: #116


(cherry picked from commit dd59212d3f)
2018-08-19 21:12:22 +00:00
Carlos Garnacho
af50a7829f runDialog: Use ClutterText::activate for enter handling
Instead of consuming the event in front of the input method. Enter
is sometimes overriden by those, so it seems better to let the IM
handle the key event, and react later to it if it got propagated
anyway. That is what ::activate does, so use this signal.

This used to work before ClutterInputMethod/InputFocus because the
IM received the events directly from stage captured events. This
is not the case anymore.

Closes: #440


(cherry picked from commit 3ab9e9e8ad)
2018-08-19 21:11:37 +00:00
Florian Müllner
67cb02d46a Revert "workspaceThumbnail: rebuild thumbnails if workareas size changed"
It is unclear what the change was supposed to be fixing, but it
broke animations of workspace additions and removals, as those
events trigger the ::workareas-changed signal.

This reverts commit c29bd46e7a.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/162
2018-08-19 15:12:28 +02:00
Florian Müllner
721ce54037 panel: Allow restoring maximized/tiled windows by touch
Maximized and tiled windows can be restored with a drag gesture,
not only from their titlebars, but also from any non-reactive
parts of the top bar above the window. Currently this only works
for actual pointer devices, extend the behavior to handle touch
as well.

https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/112


(cherry picked from commit 905801b178)
2018-07-31 00:17:49 +00:00
Andrea Azzarone
445eed40a7 popupMenu: Don't handle key presses directly if there are modifiers
Key events involved in a keyboard shortcut are not completely consumed by
Mutter. That means that if the popupMenu is bound to a shortcut (e.g.
Alt<Space>) and the user keeps the keys pressed, the same key-event will be
delivered to the popupMenu. We can workaround this issue filtering out all the
events where a a modifier is down (except capslock).

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/372


(cherry picked from commit 2e90c5fa4b)
2018-07-31 00:14:53 +00:00
Marco Trevisan (Treviño)
fddd122956 gdm, util: Always allow to retry login in unlock mode
When in lockscreen mode there's no point of resetting the auth login as there's
no welcome screen, and that would just cause the UI to freeze, with no reason.
This could have been useful if we were stopping the user to login for a given
time after ALLOWED_FAILURES attempts, but this is not the case yet.


(cherry picked from commit cf69fe4b18)
2018-07-25 20:38:58 +00:00
Marco Trevisan (Treviño)
df1b46eee2 authPrompt: Do not enable sensitivity if retries are disallowed
Set the sensitivity of the UI according to the canRetry parameter and thus
if no more logins are allowed don't take any input.

Fixes #311


(cherry picked from commit 8f848925f6)
2018-07-25 20:37:42 +00:00
Marco Trevisan (Treviño)
bf318df7f3 authPrompt: Unset preemptiveAnswer on reset
When we get a reset signal the preemptiveAnswer should be also unset or it will
be used next time the user authPrompt will be activated, even without any further
user interaction.

Fixes #311


(cherry picked from commit d21657fe61)
2018-07-25 20:37:20 +00:00
Marco Trevisan (Treviño)
2a2f3c981e workspaceThumbnail: Sync clone position changes with actor
We need to update the clone position if window actor (not the meta window)
position changed.

https://bugzilla.gnome.org/show_bug.cgi?id=776588
2018-07-24 13:11:39 +02:00
Marco Trevisan (Treviño)
8e5eab0498 workspace: Recompute bounding box on window 'position-changed'
We need to update the clone position if window size changed
also, rename meta window 'size-changed' callback accordingly.

https://bugzilla.gnome.org/show_bug.cgi?id=792681
2018-07-24 13:11:39 +02:00
Florian Müllner
6ed21e1ce0 Bump version to 3.28.3
Update NEWS.
2018-07-18 22:53:05 +02:00
Florian Müllner
9c51c87d8c events: Re-use event messages where possible
Destroying and recreating the entire events list on every change is not only
wasteful, it also breaks the clear functionality as messages scheduled for
removal are replaced with "new" messages after the first message has been
removed.

Address both issues by keeping track of all messages and re-use them
whenever possible.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/325
2018-07-13 23:03:42 +02:00
Florian Müllner
db2245d60b workspaceThumbnail: Don't keep stale clones in list
If a clone gets destroyed before the corresponding MetaWindow is
removed from the workspace, we will still find it in the list of
clones and try to destroy it again. Avoid the resulting warnings
by updating the list of clones immediately when a clone is destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2018-07-13 15:11:43 +02:00
Florian Müllner
f26cc3ac23 workspace: Don't keep stale clones in list
If a clone gets destroyed before the corresponding MetaWindow is
removed from the workspace, we will still find it in the list of
clones and try to destroy it again. Avoid the resulting warnings
by updating the list of clones immediately when a clone is destroyed.

https://bugzilla.gnome.org/show_bug.cgi?id=791233
2018-07-13 15:11:43 +02:00
Marco Trevisan (Treviño)
02c5b4b947 workspaceThumbnail: remove unused private win reference 2018-07-13 15:11:43 +02:00
Carlos Garnacho
df57829ea1 keyboard: Implement standalone FocusTracker
And stop using FocusCaretTracker for caret position purposes. This
new object uses 1) the text-input protocol in wayland and 2) Info
from IBusPanelService for X11 (which is meant to work for XIM too).

This drops the usage of AtspiEventListener for OSK purposes, which
is best to avoid.
2018-07-11 18:52:27 +02:00
Didier Roche
da96408098 ui: Theme lookup should respect XDG_DATA_DIRS
Modes, extensions and other GNOME Shell assets are searched in appropriate
subdirectories of each directory in XDG_DATA_DIRS, falling back
to global.datadir.
However, this isn't the case for themes, which are currently always expected
in global.datadir, even when referenced by a mode in a different XDG_DATA_DIR.

The fix is to have the theme finding pattern follow the same logic as other
elements.
Fixes #167.


(cherry picked from commit d6d09fd3c8)
2018-06-20 23:24:07 +00:00
Marco Trevisan (Treviño)
4b2e0247af st-texture-cache: Save cairo surfaces to a different map
The default keyed_surface is meant to handle CoglTextures thus we can't
add cairo surfaces to it, as the DestroyNotify function won't handle them.

Then the quicker way is to just add another Hash table for handling
such types of textures, with proper destroy function.


(cherry picked from commit 1f03599d1c)
2018-06-20 23:00:20 +00:00
Marco Trevisan (Treviño)
2c617e5a3a st-texture-cache: Don't add NULL textures to cache
This might cause a crash when cleaning up the cache as the hash table has
cogl_object_unref as DestroyNotify function but that assumes that
the passed object is a valid CoglObject.

Fixes: #210


(cherry picked from commit a24999b7a3)
2018-06-20 22:59:29 +00:00
Joe Rabinoff
4ff7e84c51 Change "const" to "var"
These variables are in fact used from other modules, so gjs complains about them
being const.


(cherry picked from commit 8237a1f6e0)
2018-06-20 22:30:17 +00:00
Daniel van Vugt
9f76b6e4a2 magnifier.js: Fix zoom juddering
Make Zoom respond to the mouse silky-smoothly.

It was previously hard-coded to: 1000/50 = 20 FPS.

https://bugzilla.gnome.org/show_bug.cgi?id=682013
https://launchpad.net/bugs/1691675


(cherry picked from commit 94101e8bb8)
2018-06-07 08:42:32 +00:00
Gun Chleoc
0ac0f7e85b Update Scottish Gaelic translation 2018-06-01 10:36:10 +00:00
Marco Trevisan (Treviño)
73b00ff1a7 st-label: Unset clutter text instance on disposal
The instance is owned by the actor (being its child), and thus when the
disposal happens for the parent the text is disposed too, thus it's just
safer to nullify its reference so that we won't try to access to invalid
objects later, and this might be the case since the JS objects could be kept
around until they aren't finalized.

https://bugzilla.gnome.org/show_bug.cgi?id=788931


(cherry picked from commit 44894262f4)
2018-05-29 09:57:50 +00:00
Pieter Schalk Schoeman
a52597ac5b Update Afrikaans translation 2018-05-19 20:59:51 +00:00
Mario Sanchez Prada
9a2597f80b network: Update the icon in the panel whenever NM's state changes
Similar to what it's done when the main connection changes, we need
to make sure that the icon in the panel gets updated before calling
_syncConnectivity(), so that the icon gets always updated if needed,
regardless of whether there's an active connection or not.

This is needed because there's at least one case when an icon should
be shown when the computer is not connected to any network: when a
hotspot has been enabled, which can be useful even if there's not
an internet connection to share (e.g. to easily allow connecting
other devices to the computer.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/214


(cherry picked from commit d8b9e23502)
2018-05-17 20:28:26 +00:00
Florian Müllner
e1ed4b25e1 networkAgent: Fix fallout from libnm port
While the libnm-glib version of the function returns a GByteArray*
that gjs can directly cast to the required gutf8*, the libnm function
returns GBytes* from which we need to explicitly fetch the data.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/136


(cherry picked from commit c0a453f64f)
2018-05-09 14:53:15 +00:00
Florian Müllner
c70b18764b Bump version to 3.28.2
Update NEWS.
2018-05-08 22:18:02 +02:00
Florian Müllner
4398516520 build: Include Cally in St introspection
CallyActor is exposed indirectly via StAccessible's parent type,
so add the dependency to shut up a gjs warning.

https://bugzilla.gnome.org/show_bug.cgi?id=781471
2018-05-08 22:02:11 +02:00
Florian Müllner
220514d10e remoteSearch: Actually return icons
Since commit 3b1330880f, a remote search result's createIcon() method
no longer returns the created icon, whoops ...

https://gitlab.gnome.org/GNOME/gnome-shell/issues/249
2018-05-08 22:02:11 +02:00
Silvère Latchurié
18312d9ccd osdWindow: Fix blurriness at certain resolutions
The y position wasn't rounded, leading to some blurriness at vertical
resolutions that aren't a multiple of 4 (e.g. 1050).

https://bugzilla.gnome.org/show_bug.cgi?id=782011
2018-05-08 22:02:11 +02:00
Ray Strode
234b1441e4 keyboardManager: take group index into account when preserving keymap
commit 642107a2 attempts to avoid resetting the current keymap on
spurious input source changes.

It does this by checking if the current layout id is found in
the new list of layouts and resetting the current layout to the
associated match in the list. By not nullifying the current
layout, it won't get subsequently reset.

Unfortunately, if the order of the list changes, resetting the
current keymap is still necessary, since the order corresponds
with the index of the activated group.

This commit changes the code to nullify the current layout if
its group index changes.

https://bugzilla.redhat.com/show_bug.cgi?id=1573923
2018-05-08 13:56:55 -04:00
Rafael Fontenelle
e909db5848 Update Brazilian Portuguese translation 2018-05-02 18:46:32 +00:00
Carlos Garnacho
702338bc7d keyboardManager: Preserve current keymap across reloads
The IM can pretty much update the input sources anytime (even if
to set the same ones). That ends up triggering rebuilding all user
defined keymaps, and losing modifier state if we are unfortunate
enough that this caught us while pressing one.

One common situation seems to be password entries, resulting in
the wrong character being printed if the first character happens
to require the shift key.

If the current keymap is not found in the newly loaded list,
this._current will end up null, with the same behavior as we get
currently (immediate keymap reload).

https://bugzilla.redhat.com/show_bug.cgi?id=1569211

https://gitlab.gnome.org/GNOME/gnome-shell/issues/240

Closes: #240
2018-04-29 17:52:56 +02:00
Florian Müllner
7c9dbc66d9 polkitAgent: Guard against repeated close() calls
We use the close() method to disconnect signal handlers set up in
init(), however the handler ID is only valid in the first call in
case the method is called more than once.

https://gitlab.gnome.org/GNOME/gnome-shell/issues/221
2018-04-21 22:39:15 +02:00
Stas Solovey
0d031dc20f Update Russian translation 2018-04-19 20:32:53 +00:00
Marco Trevisan (Treviño)
b476e851b7 workspaceThumbnail: only update _porthole if the overview is visible
Otherwise it happens that porthole is computed again after that the
overlay is hidden (triggered by a layout reallocation) and thus not
regenerated again afterwards.

https://bugzilla.gnome.org/show_bug.cgi?id=792687


(cherry picked from commit 5fcf40b973)
2018-04-18 00:35:42 +00:00
Marco Trevisan (Treviño)
a27be6a540 workspaceThumbnail: rebuild thumbnails if workareas size changed
https://bugzilla.gnome.org/show_bug.cgi?id=792687


(cherry picked from commit c29bd46e7a)
2018-04-18 00:34:45 +00:00
Marco Trevisan (Treviño)
4b6a57fabe workspaceThumbnail: initialize porthole based on workArea
https://bugzilla.gnome.org/show_bug.cgi?id=792687


(cherry picked from commit b99e304f1e)
2018-04-18 00:33:39 +00:00
Mario Sanchez Prada
92758890bb popupMenu: Fix wrong call to clutter_actor_add_child()
Specify the horizontal alignment via the x_align property when creating
the StIcon, since this function expects one argument, not two.


(cherry picked from commit cdbc99e992)
2018-04-18 00:32:37 +00:00
56 changed files with 1982 additions and 1324 deletions

28
NEWS
View File

@ -1,3 +1,31 @@
3.28.3
======
* Fix lagging pointer when zoomed [Daniel; #682013]
* Fix "Clear All" for calendar events [Florian; #325]
* Misc. bug fixes [Florian, Mario, Marco; #136, #214, #788931, #791233]
Contributors:
Carlos Garnacho, Florian Müllner, Mario Sanchez Prada, Joe Rabinoff,
Didier Roche, Marco Trevisan (Treviño), Daniel van Vugt
Translators:
Pieter Schalk Schoeman [af], Gun Chleoc [gd]
3.28.2
======
* Fix lock-up on cancelling polkit dialog [Florian; #221]
* Guard against untimely keyboard map changes [Carlos; #240]
* Fix blurriness of OSD under some resolutions [Silvère; #782011]
* Fix icons in search provider results [Florian; #249]
* Misc. bug fixes [Marco, Florian; #792687, #781471]
Contributors:
Carlos Garnacho, Silvère Latchurié, Florian Müllner, Mario Sanchez Prada,
Ray Strode, Marco Trevisan (Treviño)
Translators:
Stas Solovey [ru], Rafael Fontenelle [pt_BR]
3.28.1 3.28.1
====== ======
* Fix compose characters in shell entries [Carlos; #115] * Fix compose characters in shell entries [Carlos; #115]

View File

@ -242,11 +242,11 @@ var AuthPrompt = new Lang.Class({
this.emit('prompted'); this.emit('prompted');
}, },
_onVerificationFailed() { _onVerificationFailed(userVerifier, canRetry) {
this._queryingService = null; this._queryingService = null;
this.clear(); this.clear();
this.updateSensitivity(true); this.updateSensitivity(canRetry);
this.setActorInDefaultButtonWell(null); this.setActorInDefaultButtonWell(null);
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED; this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
}, },
@ -439,6 +439,7 @@ var AuthPrompt = new Lang.Class({
this.verificationStatus = AuthPromptStatus.NOT_VERIFYING; this.verificationStatus = AuthPromptStatus.NOT_VERIFYING;
this.cancelButton.reactive = true; this.cancelButton.reactive = true;
this.nextButton.label = _("Next"); this.nextButton.label = _("Next");
this._preemptiveAnswer = null;
if (this._userVerifier) if (this._userVerifier)
this._userVerifier.cancel(); this._userVerifier.cancel();

View File

@ -534,12 +534,13 @@ var ShellUserVerifier = new Lang.Class({
_verificationFailed(retry) { _verificationFailed(retry) {
// For Not Listed / enterprise logins, immediately reset // For Not Listed / enterprise logins, immediately reset
// the dialog // the dialog
// Otherwise, we allow ALLOWED_FAILURES attempts. After that, we // Otherwise, when in login mode we allow ALLOWED_FAILURES attempts.
// go back to the welcome screen. // After that, we go back to the welcome screen.
this._failCounter++; this._failCounter++;
let canRetry = retry && this._userName && let canRetry = retry && this._userName &&
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY); (this._reauthOnly ||
this._failCounter < this._settings.get_int(ALLOWED_FAILURES_KEY));
if (canRetry) { if (canRetry) {
if (!this.hasPendingMessages) { if (!this.hasPendingMessages) {
@ -562,7 +563,7 @@ var ShellUserVerifier = new Lang.Class({
} }
} }
this.emit('verification-failed'); this.emit('verification-failed', canRetry);
}, },
_onConversationStopped(client, serviceName) { _onConversationStopped(client, serviceName) {

View File

@ -115,6 +115,11 @@ var IBusManager = new Lang.Class({
object_path: IBus.PATH_PANEL }); object_path: IBus.PATH_PANEL });
this._candidatePopup.setPanelService(this._panelService); this._candidatePopup.setPanelService(this._panelService);
this._panelService.connect('update-property', this._updateProperty.bind(this)); this._panelService.connect('update-property', this._updateProperty.bind(this));
this._panelService.connect('set-cursor-location', (ps, x, y, w, h) => {
let cursorLocation = { x, y, width: w, height: h };
this.emit('set-cursor-location', cursorLocation);
});
try { try {
// IBus versions older than 1.5.10 have a bug which // IBus versions older than 1.5.10 have a bug which
// causes spurious set-content-type emissions when // causes spurious set-content-type emissions when

View File

@ -89,6 +89,8 @@ var KeyboardManager = new Lang.Class({
}, },
setUserLayouts(ids) { setUserLayouts(ids) {
let currentId = this._current ? this._current.id : null;
let currentGroupIndex = this._current ? this._current.groupIndex : null;
this._current = null; this._current = null;
this._layoutInfos = {}; this._layoutInfos = {};
@ -115,6 +117,9 @@ var KeyboardManager = new Lang.Class({
info.group = group; info.group = group;
info.groupIndex = groupIndex; info.groupIndex = groupIndex;
if (currentId == id && currentGroupIndex == groupIndex)
this._current = info;
i += 1; i += 1;
} }
}, },

View File

@ -236,11 +236,12 @@ var ObjectManager = new Lang.Class({
_onNameVanished() { _onNameVanished() {
let objectPaths = Object.keys(this._objects); let objectPaths = Object.keys(this._objects);
for (let i = 0; i < objectPaths.length; i++) { for (let i = 0; i < objectPaths.length; i++) {
let object = this._objects[objectPaths]; let objectPath = objectPaths[i];
let object = this._objects[objectPath];
let interfaceNames = Object.keys(object); let interfaceNames = Object.keys(object);
for (let j = 0; i < interfaceNames.length; i++) { for (let j = 0; j < interfaceNames.length; j++) {
let interfaceName = interfaceNames[i]; let interfaceName = interfaceNames[j];
if (object[interfaceName]) if (object[interfaceName])
this._removeInterface(objectPath, interfaceName); this._removeInterface(objectPath, interfaceName);

View File

@ -802,6 +802,8 @@ var NotificationMessage = new Lang.Class({
}, },
_onDestroy() { _onDestroy() {
this.parent();
if (this._updatedId) if (this._updatedId)
this.notification.disconnect(this._updatedId); this.notification.disconnect(this._updatedId);
this._updatedId = 0; this._updatedId = 0;
@ -821,6 +823,8 @@ var EventsSection = new Lang.Class({
this._desktopSettings.connect('changed', this._reloadEvents.bind(this)); this._desktopSettings.connect('changed', this._reloadEvents.bind(this));
this._eventSource = new EmptyEventSource(); this._eventSource = new EmptyEventSource();
this._messageById = new Map();
this.parent(); this.parent();
this._title = new St.Button({ style_class: 'events-section-title', this._title = new St.Button({ style_class: 'events-section-title',
@ -875,20 +879,32 @@ var EventsSection = new Lang.Class({
this._reloading = true; this._reloading = true;
this._list.destroy_all_children();
let periodBegin = _getBeginningOfDay(this._date); let periodBegin = _getBeginningOfDay(this._date);
let periodEnd = _getEndOfDay(this._date); let periodEnd = _getEndOfDay(this._date);
let events = this._eventSource.getEvents(periodBegin, periodEnd); let events = this._eventSource.getEvents(periodBegin, periodEnd);
let ids = events.map(e => e.id);
this._messageById.forEach((message, id) => {
if (ids.includes(id))
return;
this._messageById.delete(id);
this.removeMessage(message);
});
for (let i = 0; i < events.length; i++) { for (let i = 0; i < events.length; i++) {
let event = events[i]; let event = events[i];
let message = new EventMessage(event, this._date); let message = this._messageById.get(event.id);
message.connect('close', () => { if (!message) {
this._ignoreEvent(event); message = new EventMessage(event, this._date);
}); message.connect('close', () => {
this.addMessage(message, false); this._ignoreEvent(event);
});
this._messageById.set(event.id, message);
this.addMessage(message, false);
} else {
this.moveMessage(message, i, false);
}
} }
this._reloading = false; this._reloading = false;

View File

@ -210,6 +210,10 @@ var AutomountManager = new Lang.Class({
}, },
_onVolumeRemoved(monitor, volume) { _onVolumeRemoved(monitor, volume) {
if (volume._allowAutorunExpireId && volume._allowAutorunExpireId > 0) {
Mainloop.source_remove(volume._allowAutorunExpireId);
delete volume._allowAutorunExpireId;
}
this._volumeQueue = this._volumeQueue =
this._volumeQueue.filter(element => (element != volume)); this._volumeQueue.filter(element => (element != volume));
}, },
@ -234,8 +238,10 @@ var AutomountManager = new Lang.Class({
_allowAutorunExpire(volume) { _allowAutorunExpire(volume) {
let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => { let id = Mainloop.timeout_add_seconds(AUTORUN_EXPIRE_TIMEOUT_SECS, () => {
volume.allowAutorun = false; volume.allowAutorun = false;
delete volume._allowAutorunExpireId;
return GLib.SOURCE_REMOVE; return GLib.SOURCE_REMOVE;
}); });
volume._allowAutorunExpireId = id;
GLib.Source.set_name_by_id(id, '[gnome-shell] volume.allowAutorun'); GLib.Source.set_name_by_id(id, '[gnome-shell] volume.allowAutorun');
} }
}); });

View File

@ -655,7 +655,7 @@ var NetworkAgent = new Lang.Class({
switch (connectionType) { switch (connectionType) {
case '802-11-wireless': case '802-11-wireless':
let wirelessSetting = connection.get_setting_wireless(); let wirelessSetting = connection.get_setting_wireless();
let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid()); let ssid = NM.utils_ssid_to_utf8(wirelessSetting.get_ssid().get_data());
title = _("Authentication required by wireless network"); title = _("Authentication required by wireless network");
body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid); body = _("Passwords or encryption keys are required to access the wireless network “%s”.").format(ssid);
break; break;

View File

@ -201,7 +201,9 @@ var AuthenticationDialog = new Lang.Class({
close(timestamp) { close(timestamp) {
this.parent(timestamp); this.parent(timestamp);
Main.sessionMode.disconnect(this._sessionUpdatedId); if (this._sessionUpdatedId)
Main.sessionMode.disconnect(this._sessionUpdatedId);
this._sessionUpdatedId = 0;
}, },
_ensureOpen() { _ensureOpen() {

View File

@ -52,6 +52,8 @@ var DashItemContainer = new Lang.Class({
this.animatingOut = false; this.animatingOut = false;
this.connect('destroy', () => { this.connect('destroy', () => {
if (this.child != null)
this.child.destroy();
this.label.destroy(); this.label.destroy();
}); });
}, },

View File

@ -396,10 +396,15 @@ var _Draggable = new Lang.Class({
return true; return true;
}, },
_pickTargetActor() {
return this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
this._dragX, this._dragY);
},
_updateDragHover() { _updateDragHover() {
this._updateHoverId = 0; this._updateHoverId = 0;
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL, let target = this._pickTargetActor();
this._dragX, this._dragY);
let dragEvent = { let dragEvent = {
x: this._dragX, x: this._dragX,
y: this._dragY, y: this._dragY,
@ -407,6 +412,18 @@ var _Draggable = new Lang.Class({
source: this.actor._delegate, source: this.actor._delegate,
targetActor: target targetActor: target
}; };
let targetActorDestroyHandlerId;
let handleTargetActorDestroyClosure;
handleTargetActorDestroyClosure = () => {
target = this._pickTargetActor();
dragEvent.targetActor = target;
targetActorDestroyHandlerId =
target.connect('destroy', handleTargetActorDestroyClosure);
};
targetActorDestroyHandlerId =
target.connect('destroy', handleTargetActorDestroyClosure);
for (let i = 0; i < dragMonitors.length; i++) { for (let i = 0; i < dragMonitors.length; i++) {
let motionFunc = dragMonitors[i].dragMotion; let motionFunc = dragMonitors[i].dragMotion;
if (motionFunc) { if (motionFunc) {
@ -417,6 +434,7 @@ var _Draggable = new Lang.Class({
} }
} }
} }
dragEvent.targetActor.disconnect(targetActorDestroyHandlerId);
while (target) { while (target) {
if (target._delegate && target._delegate.handleDragOver) { if (target._delegate && target._delegate.handleDragOver) {

View File

@ -760,7 +760,7 @@ var EndSessionDialog = new Lang.Class({
let updatePrepared = this._pkOfflineProxy.UpdatePrepared; let updatePrepared = this._pkOfflineProxy.UpdatePrepared;
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.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed); this._checkBox.actor.visible = (dialogContent.checkBoxText && updatePrepared && updatesAllowed);
this._checkBox.actor.checked = (updatePrepared && updateTriggered); this._checkBox.actor.checked = (updatePrepared && updateTriggered);

View File

@ -76,6 +76,7 @@ function disableExtension(uuid) {
if (extension.stylesheet) { if (extension.stylesheet) {
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme(); let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.unload_stylesheet(extension.stylesheet); theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet;
} }
try { try {
@ -115,13 +116,18 @@ function enableExtension(uuid) {
extensionOrder.push(uuid); 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();
for (let i = 0; i < stylesheetNames.length; i++) { for (let i = 0; i < stylesheetNames.length; i++) {
let stylesheetFile = extension.dir.get_child(stylesheetNames[i]); try {
if (stylesheetFile.query_exists(null)) { let stylesheetFile = extension.dir.get_child(stylesheetNames[i]);
let theme = St.ThemeContext.get_for_stage(global.stage).get_theme();
theme.load_stylesheet(stylesheetFile); theme.load_stylesheet(stylesheetFile);
extension.stylesheet = stylesheetFile; extension.stylesheet = stylesheetFile;
break; break;
} catch (e) {
if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND))
continue; // not an error
log(`Failed to load stylesheet for extension ${uuid}: ${e.message}`);
return;
} }
} }
@ -131,6 +137,10 @@ function enableExtension(uuid) {
_signals.emit('extension-state-changed', extension); _signals.emit('extension-state-changed', extension);
return; return;
} catch(e) { } catch(e) {
if (extension.stylesheet) {
theme.unload_stylesheet(extension.stylesheet);
delete extension.stylesheet;
}
logExtensionError(uuid, e); logExtensionError(uuid, e);
return; return;
} }

View File

@ -418,6 +418,11 @@ var IconGrid = new Lang.Class({
}, },
_animationDone() { _animationDone() {
this._clonesAnimating.forEach(clone => {
clone.source.reactive = true;
clone.source.opacity = 255;
clone.destroy();
});
this._clonesAnimating = []; this._clonesAnimating = [];
this.emit('animation-done'); this.emit('animation-done');
}, },
@ -538,10 +543,6 @@ var IconGrid = new Lang.Class({
onComplete: () => { onComplete: () => {
if (isLastItem) if (isLastItem)
this._animationDone(); this._animationDone();
actor.opacity = 255;
actor.reactive = true;
actorClone.destroy();
}}; }};
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM, fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad', transition: 'easeInOutQuad',
@ -562,12 +563,8 @@ var IconGrid = new Lang.Class({
scale_x: scaleX, scale_x: scaleX,
scale_y: scaleY, scale_y: scaleY,
onComplete: () => { onComplete: () => {
if (isLastItem) { if (isLastItem)
this._animationDone(); this._animationDone();
this._restoreItemsOpacity();
}
actor.reactive = true;
actorClone.destroy();
}}; }};
fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM, fadeParams = { time: ANIMATION_FADE_IN_TIME_FOR_ITEM,
transition: 'easeInOutQuad', transition: 'easeInOutQuad',
@ -581,12 +578,6 @@ var IconGrid = new Lang.Class({
} }
}, },
_restoreItemsOpacity() {
for (let index = 0; index < this._items.length; index++) {
this._items[index].actor.opacity = 255;
}
},
_getAllocatedChildSizeAndSpacing(child) { _getAllocatedChildSizeAndSpacing(child) {
let [,, natWidth, natHeight] = child.get_preferred_size(); let [,, natWidth, natHeight] = child.get_preferred_size();
let width = Math.min(this._getHItemSize(), natWidth); let width = Math.min(this._getHItemSize(), natWidth);

View File

@ -1,6 +1,5 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const FocusCaretTracker = imports.ui.focusCaretTracker;
const Atspi = imports.gi.Atspi; const Atspi = imports.gi.Atspi;
const Clutter = imports.gi.Clutter; const Clutter = imports.gi.Clutter;
const Gdk = imports.gi.Gdk; const Gdk = imports.gi.Gdk;
@ -13,6 +12,7 @@ const Signals = imports.signals;
const St = imports.gi.St; const St = imports.gi.St;
const InputSourceManager = imports.ui.status.keyboard; const InputSourceManager = imports.ui.status.keyboard;
const IBusManager = imports.misc.ibusManager;
const BoxPointer = imports.ui.boxpointer; const BoxPointer = imports.ui.boxpointer;
const Layout = imports.ui.layout; const Layout = imports.ui.layout;
const Main = imports.ui.main; const Main = imports.ui.main;
@ -261,6 +261,7 @@ var Key = new Lang.Class({
this._extended_keyboard = null; this._extended_keyboard = null;
this._pressTimeoutId = 0; this._pressTimeoutId = 0;
this._capturedPress = false; this._capturedPress = false;
this._capturedEventId = 0; this._capturedEventId = 0;
this._unmapId = 0; this._unmapId = 0;
this._longPress = false; this._longPress = false;
@ -484,6 +485,79 @@ var KeyboardModel = new Lang.Class({
} }
}); });
var FocusTracker = new Lang.Class({
Name: 'FocusTracker',
_init() {
this._currentWindow = null;
this._currentWindowPositionId = 0;
global.screen.get_display().connect('notify::focus-window', () => {
this._setCurrentWindow(global.screen.get_display().focus_window);
this.emit('window-changed', this._currentWindow);
});
/* Valid for wayland clients */
Main.inputMethod.connect('cursor-location-changed', (o, rect) => {
let newRect = { x: rect.get_x(), y: rect.get_y(), width: rect.get_width(), height: rect.get_height() };
this._setCurrentRect(newRect);
});
this._ibusManager = IBusManager.getIBusManager();
this._ibusManager.connect('set-cursor-location', (manager, rect) => {
/* Valid for X11 clients only */
if (Main.inputMethod.currentFocus)
return;
this._setCurrentRect(rect);
});
},
get currentWindow() {
return this._currentWindow;
},
_setCurrentWindow(window) {
if (this._currentWindow)
this._currentWindow.disconnect(this._currentWindowPositionId);
this._currentWindow = window;
if (window) {
this._currentWindowPositionId = this._currentWindow.connect('position-changed', () => {
if (global.display.get_grab_op() == Meta.GrabOp.NONE)
this.emit('position-changed');
else
this.emit('reset');
});
}
},
_setCurrentRect(rect) {
if (this._currentWindow) {
let frameRect = this._currentWindow.get_frame_rect();
rect.x -= frameRect.x;
rect.y -= frameRect.y;
}
this._rect = rect;
this.emit('position-changed');
},
getCurrentRect() {
let rect = { x: this._rect.x, y: this._rect.y,
width: this._rect.width, height: this._rect.height };
if (this._currentWindow) {
let frameRect = this._currentWindow.get_frame_rect();
rect.x += frameRect.x;
rect.y += frameRect.y;
}
return rect;
}
});
Signals.addSignalMethods(FocusTracker.prototype);
var Keyboard = new Lang.Class({ var Keyboard = new Lang.Class({
Name: 'Keyboard', Name: 'Keyboard',
@ -491,15 +565,10 @@ var Keyboard = new Lang.Class({
this.actor = null; this.actor = null;
this._focusInExtendedKeys = false; this._focusInExtendedKeys = false;
this._focusCaretTracker = new FocusCaretTracker.FocusCaretTracker();
this._focusCaretTracker.connect('focus-changed', this._onFocusChanged.bind(this));
this._focusCaretTracker.connect('caret-moved', this._onCaretMoved.bind(this));
this._languagePopup = null; this._languagePopup = null;
this._currentAccessible = null;
this._caretTrackingEnabled = false;
this._updateCaretPositionId = 0;
this._currentFocusWindow = null; this._currentFocusWindow = null;
this._originalWindowY = null; this._animFocusedWindow = null;
this._delayedAnimFocusWindow = null;
this._enableKeyboard = false; // a11y settings value this._enableKeyboard = false; // a11y settings value
this._enabled = false; // enabled state (by setting or device type) this._enabled = false; // enabled state (by setting or device type)
@ -510,6 +579,14 @@ var Keyboard = new Lang.Class({
this._lastDeviceId = null; this._lastDeviceId = null;
this._suggestions = null; this._suggestions = null;
this._focusTracker = new FocusTracker();
this._focusTracker.connect('position-changed', this._onFocusPositionChanged.bind(this));
this._focusTracker.connect('reset', () => {
this._delayedAnimFocusWindow = null;
this._animFocusedWindow = null;
this._oskFocusWindow = null;
});
Meta.get_backend().connect('last-device-changed', Meta.get_backend().connect('last-device-changed',
(backend, deviceId) => { (backend, deviceId) => {
let manager = Clutter.DeviceManager.get_default(); let manager = Clutter.DeviceManager.get_default();
@ -532,102 +609,15 @@ var Keyboard = new Lang.Class({
this._keyboardRestingId = 0; this._keyboardRestingId = 0;
Main.layoutManager.connect('monitors-changed', this._relayout.bind(this)); Main.layoutManager.connect('monitors-changed', this._relayout.bind(this));
//Main.inputMethod.connect('cursor-location-changed', (o, rect) => {
// if (this._keyboardVisible) {
// let currentWindow = global.screen.get_display().focus_window;
// this.setCursorLocation(currentWindow, rect.get_x(), rect.get_y(),
// rect.get_width(), rect.get_height());
// }
//});
}, },
get visible() { get visible() {
return this._keyboardVisible; return this._keyboardVisible;
}, },
_setCaretTrackerEnabled(enabled) { _onFocusPositionChanged(focusTracker) {
if (this._caretTrackingEnabled == enabled) let rect = focusTracker.getCurrentRect();
return; this.setCursorLocation(focusTracker.currentWindow, rect.x, rect.y, rect.width, rect.height);
this._caretTrackingEnabled = enabled;
if (enabled) {
this._focusCaretTracker.registerFocusListener();
this._focusCaretTracker.registerCaretListener();
} else {
this._focusCaretTracker.deregisterFocusListener();
this._focusCaretTracker.deregisterCaretListener();
}
},
_updateCaretPosition(accessible) {
if (this._updateCaretPositionId)
GLib.source_remove(this._updateCaretPositionId);
if (!this._keyboardRequested)
return;
this._updateCaretPositionId = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
this._updateCaretPositionId = 0;
let currentWindow = global.screen.get_display().focus_window;
if (!currentWindow) {
this.setCursorLocation(null);
return GLib.SOURCE_REMOVE;
}
let windowRect = currentWindow.get_frame_rect();
let text = accessible.get_text_iface();
let component = accessible.get_component_iface();
try {
let caretOffset = text.get_caret_offset();
let caretRect = text.get_character_extents(caretOffset, Atspi.CoordType.WINDOW);
let focusRect = component.get_extents(Atspi.CoordType.WINDOW);
if (caretRect.width == 0 && caretRect.height == 0)
caretRect = focusRect;
this.setCursorLocation(currentWindow, caretRect.x, caretRect.y, caretRect.width, caretRect.height);
} catch (e) {
log('Error updating caret position for OSK: ' + e.message);
}
return GLib.SOURCE_REMOVE;
});
GLib.Source.set_name_by_id(this._updateCaretPositionId, '[gnome-shell] this._updateCaretPosition');
},
_focusIsTextEntry(accessible) {
try {
let role = accessible.get_role();
let stateSet = accessible.get_state_set();
return stateSet.contains(Atspi.StateType.EDITABLE) || role == Atspi.Role.TERMINAL;
} catch (e) {
log('Error determining accessible role: ' + e.message);
return false;
}
},
_onFocusChanged(caretTracker, event) {
let accessible = event.source;
if (!this._focusIsTextEntry(accessible))
return;
let focused = event.detail1 != 0;
if (focused) {
this._currentAccessible = accessible;
this._updateCaretPosition(accessible);
this.show(Main.layoutManager.focusIndex);
} else if (this._currentAccessible == accessible) {
this._currentAccessible = null;
this.hide();
}
},
_onCaretMoved(caretTracker, event) {
let accessible = event.source;
if (this._currentAccessible == accessible)
this._updateCaretPosition(accessible);
}, },
_lastDeviceIsTouchscreen() { _lastDeviceIsTouchscreen() {
@ -650,8 +640,6 @@ var Keyboard = new Lang.Class({
if (!this._enabled && !this._keyboardController) if (!this._enabled && !this._keyboardController)
return; return;
this._setCaretTrackerEnabled(this._enabled);
if (this._enabled && !this._keyboardController) if (this._enabled && !this._keyboardController)
this._setupKeyboard(); this._setupKeyboard();
else if (!this._enabled) else if (!this._enabled)
@ -936,9 +924,11 @@ var Keyboard = new Lang.Class({
}, },
_relayout() { _relayout() {
if (this.actor == null)
return;
let monitor = Main.layoutManager.keyboardMonitor; let monitor = Main.layoutManager.keyboardMonitor;
if (this.actor == null || monitor == null)
return;
let maxHeight = monitor.height / 3; let maxHeight = monitor.height / 3;
this.actor.width = monitor.width; this.actor.width = monitor.width;
this.actor.height = maxHeight; this.actor.height = maxHeight;
@ -1027,11 +1017,14 @@ var Keyboard = new Lang.Class({
if (!this._keyboardRequested) if (!this._keyboardRequested)
return; return;
if (this._currentAccessible)
this._updateCaretPosition(this._currentAccessible);
Main.layoutManager.keyboardIndex = monitor; Main.layoutManager.keyboardIndex = monitor;
this._relayout(); this._relayout();
Main.layoutManager.showKeyboard(); Main.layoutManager.showKeyboard();
if (this._delayedAnimFocusWindow) {
this._setAnimationWindow(this._delayedAnimFocusWindow);
this._delayedAnimFocusWindow = null;
}
}, },
hide() { hide() {
@ -1102,8 +1095,9 @@ var Keyboard = new Lang.Class({
window.move_frame(true, frameRect.x, frameRect.y); window.move_frame(true, frameRect.x, frameRect.y);
}, },
_animateWindow(window, show, deltaY) { _animateWindow(window, show) {
let windowActor = window.get_compositor_private(); let windowActor = window.get_compositor_private();
let deltaY = Main.layoutManager.keyboardBox.height;
if (!windowActor) if (!windowActor)
return; return;
@ -1124,35 +1118,39 @@ var Keyboard = new Lang.Class({
} }
}, },
setCursorLocation(window, x, y , w, h) { _setAnimationWindow(window) {
if (window == this._oskFocusWindow) if (this._animFocusedWindow == window)
return; return;
if (this._oskFocusWindow) { if (this._animFocusedWindow)
let display = global.screen.get_display(); this._animateWindow(this._animFocusedWindow, false);
if (window)
this._animateWindow(window, true);
if (display.get_grab_op() == Meta.GrabOp.NONE || this._animFocusedWindow = window;
display.get_focus_window() != this._oskFocusWindow) },
this._animateWindow(this._oskFocusWindow, false, this._oskFocusWindowDelta);
this._oskFocusWindow = null; setCursorLocation(window, x, y , w, h) {
this._oskFocusWindowDelta = null; let monitor = Main.layoutManager.keyboardMonitor;
}
if (window) { if (window && monitor) {
let monitor = Main.layoutManager.keyboardMonitor;
let keyboardHeight = Main.layoutManager.keyboardBox.height; let keyboardHeight = Main.layoutManager.keyboardBox.height;
let frameRect = window.get_frame_rect(); let focusObscured = false;
let windowActor = window.get_compositor_private();
let delta = 0;
if (frameRect.y + y + h >= monitor.height - keyboardHeight) if (y + h >= monitor.y + monitor.height - keyboardHeight) {
delta = keyboardHeight; if (this._keyboardVisible)
this._setAnimationWindow(window);
this._animateWindow(window, true, delta); else
this._oskFocusWindow = window; this._delayedAnimFocusWindow = window;
this._oskFocusWindowDelta = delta; } else if (y < keyboardHeight) {
this._delayedAnimFocusWindow = null;
this._setAnimationWindow(null);
}
} else {
this._setAnimationWindow(null);
} }
this._oskFocusWindow = window;
}, },
}); });

View File

@ -203,6 +203,7 @@ var LayoutManager = new Lang.Class({
// Set up stage hierarchy to group all UI actors under one container. // Set up stage hierarchy to group all UI actors under one container.
this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' }); this.uiGroup = new Shell.GenericContainer({ name: 'uiGroup' });
this.uiGroup.set_flags(Clutter.ActorFlags.NO_LAYOUT);
this.uiGroup.connect('allocate', (actor, box, flags) => { this.uiGroup.connect('allocate', (actor, box, flags) => {
let children = actor.get_children(); let children = actor.get_children();
for (let i = 0; i < children.length; i++) for (let i = 0; i < children.length; i++)
@ -557,6 +558,8 @@ var LayoutManager = new Lang.Class({
}, },
get focusMonitor() { get focusMonitor() {
if (this.focusIndex < 0)
return null;
return this.monitors[this.focusIndex]; return this.monitors[this.focusIndex];
}, },

View File

@ -19,7 +19,6 @@ const MagnifierDBus = imports.ui.magnifierDBus;
const Params = imports.misc.params; const Params = imports.misc.params;
const PointerWatcher = imports.ui.pointerWatcher; const PointerWatcher = imports.ui.pointerWatcher;
var MOUSE_POLL_FREQUENCY = 50;
var CROSSHAIRS_CLIP_SIZE = [100, 100]; var CROSSHAIRS_CLIP_SIZE = [100, 100];
var NO_CHANGE = 0.0; var NO_CHANGE = 0.0;
@ -152,8 +151,10 @@ var Magnifier = new Lang.Class({
* Turn on mouse tracking, if not already doing so. * Turn on mouse tracking, if not already doing so.
*/ */
startTrackingMouse() { startTrackingMouse() {
if (!this._pointerWatch) if (!this._pointerWatch) {
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(MOUSE_POLL_FREQUENCY, this.scrollToMousePos.bind(this)); let interval = 1000 / Clutter.get_default_frame_rate();
this._pointerWatch = PointerWatcher.getPointerWatcher().addWatch(interval, this.scrollToMousePos.bind(this));
}
}, },
/** /**

View File

@ -256,6 +256,14 @@ function _getStylesheet(name) {
if (stylesheet.query_exists(null)) if (stylesheet.query_exists(null))
return stylesheet; return stylesheet;
let dataDirs = GLib.get_system_data_dirs();
for (let i = 0; i < dataDirs.length; i++) {
let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', 'theme', name]);
let stylesheet = Gio.file_new_for_path(path);
if (stylesheet.query_exists(null))
return stylesheet;
}
stylesheet = Gio.File.new_for_path(global.datadir + '/theme/' + name); stylesheet = Gio.File.new_for_path(global.datadir + '/theme/' + name);
if (stylesheet.query_exists(null)) if (stylesheet.query_exists(null))
return stylesheet; return stylesheet;
@ -335,6 +343,9 @@ function loadTheme() {
let theme = new St.Theme ({ application_stylesheet: _cssStylesheet, let theme = new St.Theme ({ application_stylesheet: _cssStylesheet,
default_stylesheet: _defaultCssStylesheet }); default_stylesheet: _defaultCssStylesheet });
if (theme.default_stylesheet == null)
throw new Error("No valid stylesheet found for '%s'".format(sessionMode.stylesheetName));
if (previousTheme) { if (previousTheme) {
let customStylesheets = previousTheme.get_custom_stylesheets(); let customStylesheets = previousTheme.get_custom_stylesheets();

View File

@ -362,7 +362,8 @@ var Message = new Lang.Class({
this.setBody(body); this.setBody(body);
this._closeButton.connect('clicked', this.close.bind(this)); this._closeButton.connect('clicked', this.close.bind(this));
this.actor.connect('notify::hover', this._sync.bind(this)); let actorHoverId = this.actor.connect('notify::hover', this._sync.bind(this));
this._closeButton.connect('destroy', this.actor.disconnect.bind(this.actor, actorHoverId));
this.actor.connect('clicked', this._onClicked.bind(this)); this.actor.connect('clicked', this._onClicked.bind(this));
this.actor.connect('destroy', this._onDestroy.bind(this)); this.actor.connect('destroy', this._onDestroy.bind(this));
this._sync(); this._sync();

View File

@ -1320,6 +1320,7 @@ var MessageTray = new Lang.Class({
this._bannerBin.y = -this._banner.actor.height; this._bannerBin.y = -this._banner.actor.height;
this.actor.show(); this.actor.show();
Meta.disable_unredirect_for_display(global.display);
this._updateShowingNotification(); this._updateShowingNotification();
let [x, y, mods] = global.get_pointer(); let [x, y, mods] = global.get_pointer();
@ -1457,6 +1458,7 @@ var MessageTray = new Lang.Class({
this._pointerInNotification = false; this._pointerInNotification = false;
this._notificationRemoved = false; this._notificationRemoved = false;
Meta.enable_unredirect_for_display(global.display);
this._banner.actor.destroy(); this._banner.actor.destroy();
this._banner = null; this._banner = null;

View File

@ -117,10 +117,8 @@ var FdoNotificationDaemon = new Lang.Class({
bitsPerSample, nChannels, data] = hints['image-data']; bitsPerSample, nChannels, data] = hints['image-data'];
return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha, return Shell.util_create_pixbuf_from_data(data, GdkPixbuf.Colorspace.RGB, hasAlpha,
bitsPerSample, width, height, rowStride); bitsPerSample, width, height, rowStride);
} else if (hints['image-path']) {
return new Gio.FileIcon({ file: Gio.File.new_for_path(hints['image-path']) });
} }
return null; return this._iconForNotificationData(hints['image-path']);
}, },
_fallbackIconForNotificationData(hints) { _fallbackIconForNotificationData(hints) {

View File

@ -108,15 +108,30 @@ var OsdWindow = new Lang.Class({
this._hideTimeoutId = 0; this._hideTimeoutId = 0;
this._reset(); this._reset();
Main.layoutManager.connect('monitors-changed', this.actor.connect('destroy', this._onDestroy.bind(this));
this._relayout.bind(this));
this._monitorsChangedId =
Main.layoutManager.connect('monitors-changed',
this._relayout.bind(this));
let themeContext = St.ThemeContext.get_for_stage(global.stage); let themeContext = St.ThemeContext.get_for_stage(global.stage);
themeContext.connect('notify::scale-factor', this._scaleChangedId =
this._relayout.bind(this)); themeContext.connect('notify::scale-factor',
this._relayout.bind(this));
this._relayout(); this._relayout();
Main.uiGroup.add_child(this.actor); Main.uiGroup.add_child(this.actor);
}, },
_onDestroy() {
if (this._monitorsChangedId)
Main.layoutManager.disconnect(this._monitorsChangedId);
this._monitorsChangedId = 0;
let themeContext = St.ThemeContext.get_for_stage(global.stage);
if (this._scaleChangedId)
themeContext.disconnect(this._scaleChangedId);
this._scaleChangedId = 0;
},
setIcon(icon) { setIcon(icon) {
this._icon.gicon = icon; this._icon.gicon = icon;
}, },
@ -204,7 +219,7 @@ var OsdWindow = new Lang.Class({
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
this._icon.icon_size = popupSize / (2 * scaleFactor); this._icon.icon_size = popupSize / (2 * scaleFactor);
this._box.translation_y = monitor.height / 4; this._box.translation_y = Math.round(monitor.height / 4);
this._boxConstraint.minSize = popupSize; this._boxConstraint.minSize = popupSize;
} }
}); });

View File

@ -393,10 +393,8 @@ var Overview = new Lang.Class({
if (!Main.layoutManager.primaryMonitor) if (!Main.layoutManager.primaryMonitor)
return; return;
let workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex); this._coverPane.set_position(0, 0);
this._coverPane.set_size(global.screen_width, global.screen_height);
this._coverPane.set_position(0, workArea.y);
this._coverPane.set_size(workArea.width, workArea.height);
this._updateBackgrounds(); this._updateBackgrounds();
}, },

View File

@ -284,6 +284,11 @@ var ThumbnailsSlider = new Lang.Class({
return child.get_theme_node().get_length('visible-width'); return child.get_theme_node().get_length('visible-width');
}, },
_onDragEnd() {
this.actor.sync_hover();
this.parent();
},
_getSlide() { _getSlide() {
if (!this._visible) if (!this._visible)
return 0; return 0;

View File

@ -796,6 +796,7 @@ var Panel = new Lang.Class({
this.actor.connect('get-preferred-height', this._getPreferredHeight.bind(this)); this.actor.connect('get-preferred-height', this._getPreferredHeight.bind(this));
this.actor.connect('allocate', this._allocate.bind(this)); this.actor.connect('allocate', this._allocate.bind(this));
this.actor.connect('button-press-event', this._onButtonPress.bind(this)); this.actor.connect('button-press-event', this._onButtonPress.bind(this));
this.actor.connect('touch-event', this._onButtonPress.bind(this));
this.actor.connect('key-press-event', this._onKeyPress.bind(this)); this.actor.connect('key-press-event', this._onKeyPress.bind(this));
Main.overview.connect('showing', () => { Main.overview.connect('showing', () => {
@ -939,8 +940,13 @@ var Panel = new Lang.Class({
if (event.get_source() != actor) if (event.get_source() != actor)
return Clutter.EVENT_PROPAGATE; return Clutter.EVENT_PROPAGATE;
let button = event.get_button(); let type = event.type();
if (button != 1) 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; return Clutter.EVENT_PROPAGATE;
let focusWindow = global.display.focus_window; let focusWindow = global.display.focus_window;
@ -1079,6 +1085,7 @@ var Panel = new Lang.Class({
let windows = activeWorkspace.list_windows().filter(metaWindow => { let windows = activeWorkspace.list_windows().filter(metaWindow => {
return metaWindow.is_on_primary_monitor() && return metaWindow.is_on_primary_monitor() &&
metaWindow.showing_on_its_workspace() && metaWindow.showing_on_its_workspace() &&
!metaWindow.is_hidden() &&
metaWindow.get_window_type() != Meta.WindowType.DESKTOP; metaWindow.get_window_type() != Meta.WindowType.DESKTOP;
}); });

View File

@ -141,8 +141,17 @@ var PopupBaseMenuItem = new Lang.Class({
}, },
_onKeyPressEvent(actor, event) { _onKeyPressEvent(actor, event) {
let symbol = event.get_key_symbol(); let state = event.get_state();
// if user has a modifier down (except capslock)
// then don't handle the key press here
state &= ~Clutter.ModifierType.LOCK_MASK;
state &= Clutter.ModifierType.MODIFIER_MASK;
if (state)
return Clutter.EVENT_PROPAGATE;
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(event); this.activate(event);
return Clutter.EVENT_STOP; return Clutter.EVENT_STOP;
@ -394,8 +403,9 @@ var PopupImageMenuItem = new Lang.Class({
_init(text, icon, params) { _init(text, icon, params) {
this.parent(params); this.parent(params);
this._icon = new St.Icon({ style_class: 'popup-menu-icon' }); this._icon = new St.Icon({ style_class: 'popup-menu-icon',
this.actor.add_child(this._icon, { align: St.Align.END }); x_align: Clutter.ActorAlign.END });
this.actor.add_child(this._icon);
this.label = new St.Label({ text: text }); this.label = new St.Label({ text: text });
this.actor.add_child(this.label); this.actor.add_child(this.label);
this.actor.label_actor = this.label; this.actor.label_actor = this.label;

View File

@ -295,7 +295,7 @@ var RemoteSearchProvider = new Lang.Class({
name: metas[i]['name'], name: metas[i]['name'],
description: metas[i]['description'], description: metas[i]['description'],
createIcon: size => { createIcon: size => {
this.createIcon(size, metas[i]); return this.createIcon(size, metas[i]);
}, },
clipboardText: metas[i]['clipboardText'] }); clipboardText: metas[i]['clipboardText'] });
} }

View File

@ -114,18 +114,16 @@ var RunDialog = new Lang.Class({
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.popModal();
this._run(o.get_text(),
Clutter.get_current_event().get_state() & Clutter.ModifierType.CONTROL_MASK);
if (!this._commandError ||
!this.pushModal())
this.close();
});
this._entryText.connect('key-press-event', (o, e) => { this._entryText.connect('key-press-event', (o, e) => {
let symbol = e.get_key_symbol(); let symbol = e.get_key_symbol();
if (symbol == Clutter.Return || symbol == Clutter.KP_Enter) {
this.popModal();
this._run(o.get_text(),
e.get_state() & Clutter.ModifierType.CONTROL_MASK);
if (!this._commandError ||
!this.pushModal())
this.close();
return Clutter.EVENT_STOP;
}
if (symbol == Clutter.Tab) { if (symbol == Clutter.Tab) {
let text = o.get_text(); let text = o.get_text();
let prefix; let prefix;

View File

@ -192,6 +192,7 @@ var SearchResultsBase = new Lang.Class({
}, },
clear() { clear() {
this._cancellable.cancel();
for (let resultId in this._resultDisplays) for (let resultId in this._resultDisplays)
this._resultDisplays[resultId].actor.destroy(); this._resultDisplays[resultId].actor.destroy();
this._resultDisplays = {}; this._resultDisplays = {};
@ -225,6 +226,12 @@ var SearchResultsBase = new Lang.Class({
this._cancellable.reset(); this._cancellable.reset();
this.provider.getResultMetas(metasNeeded, metas => { this.provider.getResultMetas(metasNeeded, metas => {
if (this._cancellable.is_cancelled()) {
if (metas.length > 0)
log(`Search provider ${this.provider.id} returned results after the request was canceled`);
callback(false);
return;
}
if (metas.length != metasNeeded.length) { if (metas.length != metasNeeded.length) {
log('Wrong number of result metas returned by search provider ' + this.provider.id + log('Wrong number of result metas returned by search provider ' + this.provider.id +
': expected ' + metasNeeded.length + ' but got ' + metas.length); ': expected ' + metasNeeded.length + ' but got ' + metas.length);

View File

@ -360,11 +360,14 @@ var InputSourceManager = new Lang.Class({
this._settings.connect('per-window-changed', this._sourcesPerWindowChanged.bind(this)); this._settings.connect('per-window-changed', this._sourcesPerWindowChanged.bind(this));
this._sourcesPerWindowChanged(); this._sourcesPerWindowChanged();
this._disableIBus = false; this._disableIBus = false;
this._reloading = false;
}, },
reload() { reload() {
this._reloading = true;
this._keyboardManager.setKeyboardOptions(this._settings.keyboardOptions); this._keyboardManager.setKeyboardOptions(this._settings.keyboardOptions);
this._inputSourcesChanged(); this._inputSourcesChanged();
this._reloading = false;
}, },
_ibusReadyCallback(im, ready) { _ibusReadyCallback(im, ready) {
@ -458,7 +461,15 @@ var InputSourceManager = new Lang.Class({
}, },
activateInputSource(is, interactive) { activateInputSource(is, interactive) {
KeyboardManager.holdKeyboard(); // The focus changes during holdKeyboard/releaseKeyboard may trick
// the client into hiding UI containing the currently focused entry.
// So holdKeyboard/releaseKeyboard are not called when
// 'set-content-type' signal is received.
// E.g. Focusing on a password entry in a popup in Xorg Firefox
// will emit 'set-content-type' signal.
// https://gitlab.gnome.org/GNOME/gnome-shell/issues/391
if (!this._reloading)
KeyboardManager.holdKeyboard();
this._keyboardManager.apply(is.xkbId); this._keyboardManager.apply(is.xkbId);
// All the "xkb:..." IBus engines simply "echo" back symbols, // All the "xkb:..." IBus engines simply "echo" back symbols,
@ -473,7 +484,10 @@ var InputSourceManager = new Lang.Class({
else else
engine = 'xkb:us::eng'; engine = 'xkb:us::eng';
this._ibusManager.setEngine(engine, KeyboardManager.releaseKeyboard); if (!this._reloading)
this._ibusManager.setEngine(engine, KeyboardManager.releaseKeyboard);
else
this._ibusManager.setEngine(engine);
this._currentInputSourceChanged(is); this._currentInputSourceChanged(is);
if (interactive) if (interactive)

View File

@ -419,12 +419,14 @@ var NMConnectionDevice = new Lang.Class({
this._deactivateItem.actor.visible = this._device.state > NM.DeviceState.DISCONNECTED; this._deactivateItem.actor.visible = this._device.state > NM.DeviceState.DISCONNECTED;
if (this._activeConnection == null) { if (this._activeConnection == null) {
this._activeConnection = this._device.active_connection; let activeConnection = this._device.active_connection;
if (activeConnection && activeConnection.connection) {
if (this._activeConnection) { let item = this._connectionItems.get(activeConnection.connection.get_uuid());
ensureActiveConnectionProps(this._activeConnection, this._client); if (item) {
let item = this._connectionItems.get(this._activeConnection.connection.get_uuid()); this._activeConnection = activeConnection;
item.setActiveConnection(this._activeConnection); ensureActiveConnectionProps(this._activeConnection, this._client);
item.setActiveConnection(this._activeConnection);
}
} }
} }
@ -1944,6 +1946,7 @@ var NMApplet = new Lang.Class({
this.indicators.visible = this._client.nm_running; this.indicators.visible = this._client.nm_running;
this.menu.actor.visible = this._client.networking_enabled; this.menu.actor.visible = this._client.networking_enabled;
this._updateIcon();
this._syncConnectivity(); this._syncConnectivity();
}, },

View File

@ -58,6 +58,9 @@ var AltSwitcher = new Lang.Class({
childToShow = this._standard; childToShow = this._standard;
} else if (this._alternate.visible) { } else if (this._alternate.visible) {
childToShow = this._alternate; childToShow = this._alternate;
} else {
this.actor.hide();
return;
} }
let childShown = this.actor.get_child(); let childShown = this.actor.get_child();
@ -79,7 +82,7 @@ var AltSwitcher = new Lang.Class({
global.sync_pointer(); global.sync_pointer();
} }
this.actor.visible = (childToShow != null); this.actor.show();
}, },
_onDestroy() { _onDestroy() {

View File

@ -311,6 +311,7 @@ var ViewSelector = new Lang.Class({
}, },
hide() { hide() {
this.reset();
this._workspacesDisplay.hide(); this._workspacesDisplay.hide();
}, },
@ -459,7 +460,11 @@ var ViewSelector = new Lang.Class({
}, },
reset() { reset() {
global.stage.set_key_focus(null); // Don't drop the key focus on Clutter's side if anything but the
// overview has pushed a modal (e.g. system modals when activated using
// the overview).
if (Main.modalCount <= 1)
global.stage.set_key_focus(null);
this._entry.text = ''; this._entry.text = '';

View File

@ -24,7 +24,7 @@ const EdgeDragAction = imports.ui.edgeDragAction;
const CloseDialog = imports.ui.closeDialog; const CloseDialog = imports.ui.closeDialog;
const SwitchMonitor = imports.ui.switchMonitor; const SwitchMonitor = imports.ui.switchMonitor;
const SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings'; var SHELL_KEYBINDINGS_SCHEMA = 'org.gnome.shell.keybindings';
var MINIMIZE_WINDOW_ANIMATION_TIME = 0.2; var MINIMIZE_WINDOW_ANIMATION_TIME = 0.2;
var SHOW_WINDOW_ANIMATION_TIME = 0.15; var SHOW_WINDOW_ANIMATION_TIME = 0.15;
var DIALOG_SHOW_WINDOW_ANIMATION_TIME = 0.1; var DIALOG_SHOW_WINDOW_ANIMATION_TIME = 0.1;
@ -627,8 +627,8 @@ var AppSwitchAction = new Lang.Class({
if (this.get_n_current_points() == 3) { if (this.get_n_current_points() == 3) {
for (let i = 0; i < this.get_n_current_points(); i++) { for (let i = 0; i < this.get_n_current_points(); i++) {
[startX, startY] = this.get_press_coords(i); let [startX, startY] = this.get_press_coords(i);
[x, y] = this.get_motion_coords(i); let [x, y] = this.get_motion_coords(i);
if (Math.abs(x - startX) > MOTION_THRESHOLD || if (Math.abs(x - startX) > MOTION_THRESHOLD ||
Math.abs(y - startY) > MOTION_THRESHOLD) Math.abs(y - startY) > MOTION_THRESHOLD)
@ -1173,6 +1173,10 @@ var WindowManager = new Lang.Class({
yScale = geom.height / actor.height; yScale = geom.height / actor.height;
} else { } else {
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()]; let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
if (!monitor) {
this._minimizeWindowDone();
return;
}
xDest = monitor.x; xDest = monitor.x;
yDest = monitor.y; yDest = monitor.y;
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
@ -1248,6 +1252,11 @@ var WindowManager = new Lang.Class({
geom.height / actor.height); geom.height / actor.height);
} else { } else {
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()]; let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
if (!monitor) {
actor.show();
this._unminimizeWindowDone();
return;
}
actor.set_position(monitor.x, monitor.y); actor.set_position(monitor.x, monitor.y);
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL) if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
actor.x += monitor.width; actor.x += monitor.width;

View File

@ -128,11 +128,10 @@ var WindowMenu = new Lang.Class({
let screen = global.screen; let screen = global.screen;
let nMonitors = screen.get_n_monitors(); let nMonitors = screen.get_n_monitors();
if (nMonitors > 1) { let monitorIndex = window.get_monitor();
if (nMonitors > 1 && monitorIndex >= 0) {
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
let monitorIndex = window.get_monitor();
let dir = Meta.ScreenDirection.UP; let dir = Meta.ScreenDirection.UP;
let upMonitorIndex = let upMonitorIndex =
screen.get_monitor_neighbor_index(monitorIndex, dir); screen.get_monitor_neighbor_index(monitorIndex, dir);

View File

@ -137,8 +137,10 @@ var WindowClone = new Lang.Class({
this._dragSlot = [0, 0, 0, 0]; this._dragSlot = [0, 0, 0, 0];
this._stackAbove = null; this._stackAbove = null;
this._windowClone._updateId = this.metaWindow.connect('size-changed', this._windowClone._sizeChangedId = this.metaWindow.connect('size-changed',
this._onRealWindowSizeChanged.bind(this)); this._onMetaWindowSizeChanged.bind(this));
this._windowClone._posChangedId = this.metaWindow.connect('position-changed',
this._computeBoundingBox.bind(this));
this._windowClone._destroyId = this._windowClone._destroyId =
this.realWindow.connect('destroy', () => { this.realWindow.connect('destroy', () => {
// First destroy the clone and then destroy everything // First destroy the clone and then destroy everything
@ -206,8 +208,7 @@ var WindowClone = new Lang.Class({
addAttachedDialog(win) { addAttachedDialog(win) {
this._doAddAttachedDialog(win, win.get_compositor_private()); this._doAddAttachedDialog(win, win.get_compositor_private());
this._computeBoundingBox(); this._onMetaWindowSizeChanged();
this.emit('size-changed');
}, },
hasAttachedDialogs() { hasAttachedDialogs() {
@ -216,15 +217,14 @@ var WindowClone = new Lang.Class({
_doAddAttachedDialog(metaWin, realWin) { _doAddAttachedDialog(metaWin, realWin) {
let clone = new Clutter.Clone({ source: realWin }); let clone = new Clutter.Clone({ source: realWin });
clone._updateId = metaWin.connect('size-changed', () => { clone._sizeChangedId = metaWin.connect('size-changed',
this._computeBoundingBox(); this._onMetaWindowSizeChanged.bind(this));
this.emit('size-changed'); clone._posChangedId = metaWin.connect('position-changed',
}); this._onMetaWindowSizeChanged.bind(this));
clone._destroyId = realWin.connect('destroy', () => { clone._destroyId = realWin.connect('destroy', () => {
clone.destroy(); clone.destroy();
this._computeBoundingBox(); this._onMetaWindowSizeChanged();
this.emit('size-changed');
}); });
this.actor.add_child(clone); this.actor.add_child(clone);
}, },
@ -321,12 +321,13 @@ var WindowClone = new Lang.Class({
else else
realWindow = child.source; realWindow = child.source;
realWindow.meta_window.disconnect(child._updateId); realWindow.meta_window.disconnect(child._sizeChangedId);
realWindow.meta_window.disconnect(child._posChangedId);
realWindow.disconnect(child._destroyId); realWindow.disconnect(child._destroyId);
}); });
}, },
_onRealWindowSizeChanged() { _onMetaWindowSizeChanged() {
this._computeBoundingBox(); this._computeBoundingBox();
this.emit('size-changed'); this.emit('size-changed');
}, },
@ -469,7 +470,6 @@ var WindowOverlay = new Lang.Class({
this._windowAddedId = 0; this._windowAddedId = 0;
button.hide(); button.hide();
title.hide();
this.title = title; this.title = title;
this.closeButton = button; this.closeButton = button;
@ -544,12 +544,10 @@ var WindowOverlay = new Lang.Class({
let titleX = cloneX + (cloneWidth - title.width) / 2; let titleX = cloneX + (cloneWidth - title.width) / 2;
let titleY = cloneY + cloneHeight - (title.height - this.borderSize) / 2; let titleY = cloneY + cloneHeight - (title.height - this.borderSize) / 2;
if (animate) { if (animate)
this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY), title.width); this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY));
} else { else
title.width = title.width;
title.set_position(Math.floor(titleX), Math.floor(titleY)); title.set_position(Math.floor(titleX), Math.floor(titleY));
}
let borderX = cloneX - this.borderSize; let borderX = cloneX - this.borderSize;
let borderY = cloneY - this.borderSize; let borderY = cloneY - this.borderSize;
@ -568,10 +566,12 @@ var WindowOverlay = new Lang.Class({
_animateOverlayActor(actor, x, y, width, height) { _animateOverlayActor(actor, x, y, width, height) {
let params = { x: x, let params = { x: x,
y: y, y: y,
width: width,
time: Overview.ANIMATION_TIME, time: Overview.ANIMATION_TIME,
transition: 'easeOutQuad' }; transition: 'easeOutQuad' };
if (width !== undefined)
params.width = width;
if (height !== undefined) if (height !== undefined)
params.height = height; params.height = height;
@ -1431,34 +1431,26 @@ var Workspace = new Lang.Class({
_doRemoveWindow(metaWin) { _doRemoveWindow(metaWin) {
let win = metaWin.get_compositor_private(); let win = metaWin.get_compositor_private();
// find the position of the window in our list let clone = this._removeWindowClone(metaWin);
let index = this._lookupIndex (metaWin);
if (index == -1) if (clone) {
return; // If metaWin.get_compositor_private() returned non-NULL, that
// means the window still exists (and is just being moved to
let clone = this._windows[index]; // another workspace or something), so set its overviewHint
// accordingly. (If it returned NULL, then the window is being
this._windows.splice(index, 1); // destroyed; we'd like to animate this, but it's too late at
this._windowOverlays.splice(index, 1); // this point.)
if (win) {
// If metaWin.get_compositor_private() returned non-NULL, that let [stageX, stageY] = clone.actor.get_transformed_position();
// means the window still exists (and is just being moved to let [stageWidth, stageHeight] = clone.actor.get_transformed_size();
// another workspace or something), so set its overviewHint win._overviewHint = {
// accordingly. (If it returned NULL, then the window is being x: stageX,
// destroyed; we'd like to animate this, but it's too late at y: stageY,
// this point.) scale: stageWidth / clone.actor.width
if (win) { };
let [stageX, stageY] = clone.actor.get_transformed_position(); }
let [stageWidth, stageHeight] = clone.actor.get_transformed_size(); clone.destroy();
win._overviewHint = {
x: stageX,
y: stageY,
scale: stageWidth / clone.actor.width
};
} }
clone.destroy();
// We need to reposition the windows; to avoid shuffling windows // We need to reposition the windows; to avoid shuffling windows
// around while the user is interacting with the workspace, we delay // around while the user is interacting with the workspace, we delay
@ -1514,7 +1506,7 @@ var Workspace = new Lang.Class({
if (metaWin.is_attached_dialog()) { if (metaWin.is_attached_dialog()) {
let parent = metaWin.get_transient_for(); let parent = metaWin.get_transient_for();
while (parent.is_attached_dialog()) while (parent.is_attached_dialog())
parent = metaWin.get_transient_for(); parent = parent.get_transient_for();
let idx = this._lookupIndex (parent); let idx = this._lookupIndex (parent);
if (idx < 0) { if (idx < 0) {
@ -1848,6 +1840,9 @@ var Workspace = new Lang.Class({
clone.connect('size-changed', () => { clone.connect('size-changed', () => {
this._recalculateWindowPositions(WindowPositionFlags.NONE); this._recalculateWindowPositions(WindowPositionFlags.NONE);
}); });
clone.actor.connect('destroy', () => {
this._removeWindowClone(clone.metaWindow);
});
this.actor.add_actor(clone.actor); this.actor.add_actor(clone.actor);
@ -1869,6 +1864,17 @@ var Workspace = new Lang.Class({
return [clone, overlay]; return [clone, overlay];
}, },
_removeWindowClone(metaWin) {
// find the position of the window in our list
let index = this._lookupIndex (metaWin);
if (index == -1)
return null;
this._windowOverlays.splice(index, 1);
return this._windows.splice(index, 1).pop();
},
_onShowOverlayClose(windowOverlay) { _onShowOverlayClose(windowOverlay) {
for (let i = 0; i < this._windowOverlays.length; i++) { for (let i = 0; i < this._windowOverlays.length; i++) {
let overlay = this._windowOverlays[i]; let overlay = this._windowOverlays[i];

View File

@ -31,7 +31,7 @@ var WORKSPACE_CUT_SIZE = 10;
var WORKSPACE_KEEP_ALIVE_TIME = 100; var WORKSPACE_KEEP_ALIVE_TIME = 100;
const OVERRIDE_SCHEMA = 'org.gnome.shell.overrides'; var OVERRIDE_SCHEMA = 'org.gnome.shell.overrides';
/* A layout manager that requests size only for primary_actor, but then allocates /* A layout manager that requests size only for primary_actor, but then allocates
all using a fixed layout */ all using a fixed layout */
@ -68,7 +68,7 @@ var WindowClone = new Lang.Class({
this.realWindow = realWindow; this.realWindow = realWindow;
this.metaWindow = realWindow.meta_window; this.metaWindow = realWindow.meta_window;
this.clone._updateId = this.metaWindow.connect('position-changed', this.clone._updateId = this.realWindow.connect('notify::position',
this._onPositionChanged.bind(this)); this._onPositionChanged.bind(this));
this.clone._destroyId = this.realWindow.connect('destroy', () => { this.clone._destroyId = this.realWindow.connect('destroy', () => {
// First destroy the clone and then destroy everything // First destroy the clone and then destroy everything
@ -153,7 +153,7 @@ var WindowClone = new Lang.Class({
let clone = new Clutter.Clone({ source: realDialog }); let clone = new Clutter.Clone({ source: realDialog });
this._updateDialogPosition(realDialog, clone); this._updateDialogPosition(realDialog, clone);
clone._updateId = metaDialog.connect('position-changed', dialog => { clone._updateId = realDialog.connect('notify::position', dialog => {
this._updateDialogPosition(dialog, clone); this._updateDialogPosition(dialog, clone);
}); });
clone._destroyId = realDialog.connect('destroy', () => { clone._destroyId = realDialog.connect('destroy', () => {
@ -171,7 +171,6 @@ var WindowClone = new Lang.Class({
}, },
_onPositionChanged() { _onPositionChanged() {
let rect = this.metaWindow.get_frame_rect();
this.actor.set_position(this.realWindow.x, this.realWindow.y); this.actor.set_position(this.realWindow.x, this.realWindow.y);
}, },
@ -179,7 +178,7 @@ var WindowClone = new Lang.Class({
this.actor.get_children().forEach(child => { this.actor.get_children().forEach(child => {
let realWindow = child.source; let realWindow = child.source;
realWindow.meta_window.disconnect(child._updateId); realWindow.disconnect(child._updateId);
realWindow.disconnect(child._destroyId); realWindow.disconnect(child._destroyId);
}); });
}, },
@ -241,7 +240,7 @@ var WindowClone = new Lang.Class({
Signals.addSignalMethods(WindowClone.prototype); Signals.addSignalMethods(WindowClone.prototype);
const ThumbnailState = { var ThumbnailState = {
NEW : 0, NEW : 0,
ANIMATING_IN : 1, ANIMATING_IN : 1,
NORMAL: 2, NORMAL: 2,
@ -275,8 +274,8 @@ var WorkspaceThumbnail = new Lang.Class({
this._createBackground(); this._createBackground();
let monitor = Main.layoutManager.primaryMonitor; let workArea = Main.layoutManager.getWorkAreaForMonitor(this.monitorIndex);
this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height); this.setPorthole(workArea.x, workArea.y, workArea.width, workArea.height);
let windows = global.get_window_actors().filter(actor => { let windows = global.get_window_actors().filter(actor => {
let win = actor.meta_window; let win = actor.meta_window;
@ -321,8 +320,6 @@ var WorkspaceThumbnail = new Lang.Class({
}, },
setPorthole(x, y, width, height) { setPorthole(x, y, width, height) {
this._portholeX = x;
this._portholeY = y;
this.actor.set_size(width, height); this.actor.set_size(width, height);
this._contents.set_position(-x, -y); this._contents.set_position(-x, -y);
}, },
@ -374,18 +371,9 @@ var WorkspaceThumbnail = new Lang.Class({
}, },
_doRemoveWindow(metaWin) { _doRemoveWindow(metaWin) {
let win = metaWin.get_compositor_private(); let clone = this._removeWindowClone(metaWin);
if (clone)
// find the position of the window in our list clone.destroy();
let index = this._lookupIndex (metaWin);
if (index == -1)
return;
let clone = this._windows[index];
this._windows.splice(index, 1);
clone.destroy();
}, },
_doAddWindow(metaWin) { _doAddWindow(metaWin) {
@ -428,7 +416,7 @@ var WorkspaceThumbnail = new Lang.Class({
} else if (metaWin.is_attached_dialog()) { } else if (metaWin.is_attached_dialog()) {
let parent = metaWin.get_transient_for(); let parent = metaWin.get_transient_for();
while (parent.is_attached_dialog()) while (parent.is_attached_dialog())
parent = metaWin.get_transient_for(); parent = parent.get_transient_for();
let idx = this._lookupIndex (parent); let idx = this._lookupIndex (parent);
if (idx < 0) { if (idx < 0) {
@ -537,6 +525,9 @@ var WorkspaceThumbnail = new Lang.Class({
clone.connect('drag-end', () => { clone.connect('drag-end', () => {
Main.overview.endWindowDrag(clone.metaWindow); Main.overview.endWindowDrag(clone.metaWindow);
}); });
clone.actor.connect('destroy', () => {
this._removeWindowClone(clone.metaWindow);
});
this._contents.add_actor(clone.actor); this._contents.add_actor(clone.actor);
if (this._windows.length == 0) if (this._windows.length == 0)
@ -549,6 +540,16 @@ var WorkspaceThumbnail = new Lang.Class({
return clone; return clone;
}, },
_removeWindowClone(metaWin) {
// find the position of the window in our list
let index = this._lookupIndex (metaWin);
if (index == -1)
return null;
return this._windows.splice(index, 1).pop();
},
activate(time) { activate(time) {
if (this.state > ThumbnailState.NORMAL) if (this.state > ThumbnailState.NORMAL)
return; return;
@ -1159,7 +1160,7 @@ var ThumbnailsBox = new Lang.Class({
// The "porthole" is the portion of the screen that we show in the // The "porthole" is the portion of the screen that we show in the
// workspaces // workspaces
_ensurePorthole() { _ensurePorthole() {
if (!Main.layoutManager.primaryMonitor) if (!Main.layoutManager.primaryMonitor || !Main.overview.visible)
return false; return false;
if (!this._porthole) if (!this._porthole)

View File

@ -470,6 +470,7 @@ var WorkspacesDisplay = new Lang.Class({
this._switchWorkspaceNotifyId = 0; this._switchWorkspaceNotifyId = 0;
this._notifyOpacityId = 0; this._notifyOpacityId = 0;
this._restackedNotifyId = 0;
this._scrollEventId = 0; this._scrollEventId = 0;
this._keyPressEventId = 0; this._keyPressEventId = 0;

View File

@ -1,5 +1,5 @@
project('gnome-shell', 'c', project('gnome-shell', 'c',
version: '3.28.1', version: '3.28.3',
meson_version: '>= 0.42.0', meson_version: '>= 0.42.0',
license: 'GPLv2+' license: 'GPLv2+'
) )

1500
po/af.po

File diff suppressed because it is too large Load Diff

View File

@ -1064,7 +1064,7 @@ msgstr "Načítá se…"
#: js/ui/dateMenu.js:321 #: js/ui/dateMenu.js:321
#, javascript-format #, javascript-format
msgid "Feels like %s." msgid "Feels like %s."
msgstr "Pocitově jako %s." msgstr "Pocitová teplota %s."
#: js/ui/dateMenu.js:324 #: js/ui/dateMenu.js:324
msgid "Go online for weather information" msgid "Go online for weather information"

757
po/gd.po

File diff suppressed because it is too large Load Diff

View File

@ -15,22 +15,22 @@
# Georges Basile Stavracas Neto <georges.stavracas@gmail.com>, 2014. # Georges Basile Stavracas Neto <georges.stavracas@gmail.com>, 2014.
# Felipe Braga <fbobraga@gmail.com>, 2015. # Felipe Braga <fbobraga@gmail.com>, 2015.
# Artur de Aquino Morais <artur.morais93@outlook.com>, 2016. # Artur de Aquino Morais <artur.morais93@outlook.com>, 2016.
# Rafael Fontenelle <rafaelff@gnome.org>, 2013-2017. # Rafael Fontenelle <rafaelff@gnome.org>, 2013-2018.
# Enrico Nicoletto <liverig@gmail.com>, 2013-2018. # Enrico Nicoletto <liverig@gmail.com>, 2013-2018.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gnome-shell\n" "Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2018-03-16 21:34+0000\n" "POT-Creation-Date: 2018-04-13 18:31+0000\n"
"PO-Revision-Date: 2018-02-09 21:52-0200\n" "PO-Revision-Date: 2018-05-02 15:45-0200\n"
"Last-Translator: Enrico Nicoletto <liverig@gmail.com>\n" "Last-Translator: Rafael Fontenelle <rafaelff@gnome.org>\n"
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n" "Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
"Language: pt_BR\n" "Language: pt_BR\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 2.0.6\n" "X-Generator: Virtaal 1.0.0-beta1\n"
"X-Project-Style: gnome\n" "X-Project-Style: gnome\n"
#: data/50-gnome-shell-system.xml:6 #: data/50-gnome-shell-system.xml:6
@ -356,7 +356,7 @@ msgid "There was an error loading the preferences dialog for %s:"
msgstr "Ocorreu um erro ao carregar o dialogo de preferências para %s:" msgstr "Ocorreu um erro ao carregar o dialogo de preferências para %s:"
#: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71 #: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71
#: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:148 #: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:153
#: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197 #: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197
#: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919 #: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919
msgid "Cancel" msgid "Cancel"
@ -642,7 +642,7 @@ msgstr "Negar acesso"
#: js/ui/accessDialog.js:64 js/ui/status/location.js:396 #: js/ui/accessDialog.js:64 js/ui/status/location.js:396
msgid "Grant Access" msgid "Grant Access"
msgstr "Garantir acesso" msgstr "Conceder acesso"
#: js/ui/appDisplay.js:793 #: js/ui/appDisplay.js:793
msgid "Frequently used applications will appear here" msgid "Frequently used applications will appear here"
@ -676,12 +676,12 @@ msgstr "Adicionar aos favoritos"
msgid "Show Details" msgid "Show Details"
msgstr "Mostrar detalhes" msgstr "Mostrar detalhes"
#: js/ui/appFavorites.js:138 #: js/ui/appFavorites.js:140
#, javascript-format #, javascript-format
msgid "%s has been added to your favorites." msgid "%s has been added to your favorites."
msgstr "%s foi adicionado aos seus favoritos." msgstr "%s foi adicionado aos seus favoritos."
#: js/ui/appFavorites.js:172 #: js/ui/appFavorites.js:174
#, javascript-format #, javascript-format
msgid "%s has been removed from your favorites." msgid "%s has been removed from your favorites."
msgstr "%s foi removido dos seus favoritos." msgstr "%s foi removido dos seus favoritos."
@ -876,7 +876,7 @@ msgstr "Unidade externa desconectada"
msgid "Open with %s" msgid "Open with %s"
msgstr "Abrir com %s" msgstr "Abrir com %s"
#: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:284 #: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:295
msgid "Password:" msgid "Password:"
msgstr "Senha:" msgstr "Senha:"
@ -964,15 +964,15 @@ msgstr "Uma senha é necessária para se conectar a “%s”."
msgid "Network Manager" msgid "Network Manager"
msgstr "Gerenciador de rede" msgstr "Gerenciador de rede"
#: js/ui/components/polkitAgent.js:43 #: js/ui/components/polkitAgent.js:48
msgid "Authentication Required" msgid "Authentication Required"
msgstr "Autenticação necessária" msgstr "Autenticação necessária"
#: js/ui/components/polkitAgent.js:71 #: js/ui/components/polkitAgent.js:76
msgid "Administrator" msgid "Administrator"
msgstr "Administrador" msgstr "Administrador"
#: js/ui/components/polkitAgent.js:151 #: js/ui/components/polkitAgent.js:156
msgid "Authenticate" msgid "Authenticate"
msgstr "Autenticação" msgstr "Autenticação"
@ -980,7 +980,7 @@ msgstr "Autenticação"
#. * requested authentication was not gained; this can happen #. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password), #. * because of an authentication error (like invalid password),
#. * for instance. #. * for instance.
#: js/ui/components/polkitAgent.js:270 js/ui/shellMountOperation.js:327 #: js/ui/components/polkitAgent.js:281 js/ui/shellMountOperation.js:327
msgid "Sorry, that didnt work. Please try again." msgid "Sorry, that didnt work. Please try again."
msgstr "Desculpe, isto não funcionou. Por favor, tente novamente." msgstr "Desculpe, isto não funcionou. Por favor, tente novamente."
@ -1028,7 +1028,7 @@ msgstr "Adicionar relógios mundiais…"
msgid "World Clocks" msgid "World Clocks"
msgstr "Relógios mundiais" msgstr "Relógios mundiais"
#: js/ui/dateMenu.js:225 #: js/ui/dateMenu.js:227
msgid "Weather" msgid "Weather"
msgstr "Meteorologia" msgstr "Meteorologia"
@ -1036,7 +1036,7 @@ msgstr "Meteorologia"
#. libgweather for the possible condition strings. If at all #. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of #. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions. #. the inserted conditions.
#: js/ui/dateMenu.js:289 #: js/ui/dateMenu.js:291
#, javascript-format #, javascript-format
msgid "%s all day." msgid "%s all day."
msgstr "%s por todo o dia." msgstr "%s por todo o dia."
@ -1045,7 +1045,7 @@ msgstr "%s por todo o dia."
#. libgweather for the possible condition strings. If at all #. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of #. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions. #. the inserted conditions.
#: js/ui/dateMenu.js:295 #: js/ui/dateMenu.js:297
#, javascript-format #, javascript-format
msgid "%s, then %s later." msgid "%s, then %s later."
msgstr "%s, depois %s mais tarde." msgstr "%s, depois %s mais tarde."
@ -1054,30 +1054,30 @@ msgstr "%s, depois %s mais tarde."
#. libgweather for the possible condition strings. If at all #. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of #. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions. #. the inserted conditions.
#: js/ui/dateMenu.js:301 #: js/ui/dateMenu.js:303
#, javascript-format #, javascript-format
msgid "%s, then %s, followed by %s later." msgid "%s, then %s, followed by %s later."
msgstr "%s, depois %s, seguido de %s mais tarde." msgstr "%s, depois %s, seguido de %s mais tarde."
#: js/ui/dateMenu.js:312 #: js/ui/dateMenu.js:314
msgid "Select a location…" msgid "Select a location…"
msgstr "Selecione uma localização…" msgstr "Selecione uma localização…"
#: js/ui/dateMenu.js:315 #: js/ui/dateMenu.js:317
msgid "Loading…" msgid "Loading…"
msgstr "Carregando…" msgstr "Carregando…"
#. Translators: %s is a temperature with unit, e.g. "23℃" #. Translators: %s is a temperature with unit, e.g. "23℃"
#: js/ui/dateMenu.js:321 #: js/ui/dateMenu.js:323
#, javascript-format #, javascript-format
msgid "Feels like %s." msgid "Feels like %s."
msgstr "Sensação térmica de %s." msgstr "Sensação térmica de %s."
#: js/ui/dateMenu.js:324 #: js/ui/dateMenu.js:326
msgid "Go online for weather information" msgid "Go online for weather information"
msgstr "Conecte-se à internet para obter as informações meteorológicas" msgstr "Conecte-se à internet para obter as informações meteorológicas"
#: js/ui/dateMenu.js:326 #: js/ui/dateMenu.js:328
msgid "Weather information is currently unavailable" msgid "Weather information is currently unavailable"
msgstr "No momento as informações meteorológicas não estão disponíveis" msgstr "No momento as informações meteorológicas não estão disponíveis"

View File

@ -18,8 +18,8 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gnome-shell\n" "Project-Id-Version: gnome-shell\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gnome-shell/issues\n"
"POT-Creation-Date: 2018-04-12 11:47+0000\n" "POT-Creation-Date: 2018-04-13 18:31+0000\n"
"PO-Revision-Date: 2018-04-12 16:48+0300\n" "PO-Revision-Date: 2018-04-19 23:31+0300\n"
"Last-Translator: Stas Solovey <whats_up@tut.by>\n" "Last-Translator: Stas Solovey <whats_up@tut.by>\n"
"Language-Team: Русский <gnome-cyr@gnome.org>\n" "Language-Team: Русский <gnome-cyr@gnome.org>\n"
"Language: ru\n" "Language: ru\n"
@ -344,7 +344,7 @@ msgid "There was an error loading the preferences dialog for %s:"
msgstr "Возникла ошибка загрузки диалогового окна параметров для %s:" msgstr "Возникла ошибка загрузки диалогового окна параметров для %s:"
#: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71 #: js/gdm/authPrompt.js:147 js/ui/audioDeviceSelection.js:71
#: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:149 #: js/ui/components/networkAgent.js:117 js/ui/components/polkitAgent.js:153
#: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197 #: js/ui/endSessionDialog.js:482 js/ui/extensionDownloader.js:197
#: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919 #: js/ui/shellMountOperation.js:343 js/ui/status/network.js:919
msgid "Cancel" msgid "Cancel"
@ -563,7 +563,6 @@ msgstr "Вчера, %H%M"
msgid "%A, %H%M" msgid "%A, %H%M"
msgstr "%A, %H%M" msgstr "%A, %H%M"
# fix даты "11 мар., 20:35"
#. Translators: this is the month name and day number #. Translators: this is the month name and day number
#. followed by a time string in 24h format. #. followed by a time string in 24h format.
#. i.e. "May 25, 14:30" #. i.e. "May 25, 14:30"
@ -572,7 +571,6 @@ msgstr "%A, %H%M"
msgid "%B %d, %H%M" msgid "%B %d, %H%M"
msgstr "%-d %B, %H%M" msgstr "%-d %B, %H%M"
# fix даты
#. Translators: this is the month name, day number, year #. Translators: this is the month name, day number, year
#. number followed by a time string in 24h format. #. number followed by a time string in 24h format.
#. i.e. "May 25 2012, 14:30" #. i.e. "May 25 2012, 14:30"
@ -581,7 +579,6 @@ msgstr "%-d %B, %H%M"
msgid "%B %d %Y, %H%M" msgid "%B %d %Y, %H%M"
msgstr "%-d %B %Y, %H%M" msgstr "%-d %B %Y, %H%M"
# по всей видимости разрабы коммент перепутали c "Translators: Time in 12h format"
#. Translators: Time in 12h format #. Translators: Time in 12h format
#: js/misc/util.js:257 #: js/misc/util.js:257
msgid "%l%M %p" msgid "%l%M %p"
@ -823,7 +820,6 @@ msgctxt "calendar heading"
msgid "%A, %B %d" msgid "%A, %B %d"
msgstr "%A, %-d %B" msgstr "%A, %-d %B"
# fix для даты в календаре и на экране блокировки
#: js/ui/calendar.js:868 #: js/ui/calendar.js:868
msgctxt "calendar heading" msgctxt "calendar heading"
msgid "%A, %B %d, %Y" msgid "%A, %B %d, %Y"
@ -876,7 +872,7 @@ msgstr "Внешний диск отключён"
msgid "Open with %s" msgid "Open with %s"
msgstr "Открыть с помощью %s" msgstr "Открыть с помощью %s"
#: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:285 #: js/ui/components/keyring.js:107 js/ui/components/polkitAgent.js:295
msgid "Password:" msgid "Password:"
msgstr "Пароль:" msgstr "Пароль:"
@ -963,15 +959,15 @@ msgstr "Для подключения к «%s» требуется пароль.
msgid "Network Manager" msgid "Network Manager"
msgstr "Диспетчер сети" msgstr "Диспетчер сети"
#: js/ui/components/polkitAgent.js:44 #: js/ui/components/polkitAgent.js:48
msgid "Authentication Required" msgid "Authentication Required"
msgstr "Требуется подтверждение подлинности" msgstr "Требуется подтверждение подлинности"
#: js/ui/components/polkitAgent.js:72 #: js/ui/components/polkitAgent.js:76
msgid "Administrator" msgid "Administrator"
msgstr "Администратор" msgstr "Администратор"
#: js/ui/components/polkitAgent.js:152 #: js/ui/components/polkitAgent.js:156
msgid "Authenticate" msgid "Authenticate"
msgstr "Подтвердить" msgstr "Подтвердить"
@ -979,7 +975,7 @@ msgstr "Подтвердить"
#. * requested authentication was not gained; this can happen #. * requested authentication was not gained; this can happen
#. * because of an authentication error (like invalid password), #. * because of an authentication error (like invalid password),
#. * for instance. #. * for instance.
#: js/ui/components/polkitAgent.js:271 js/ui/shellMountOperation.js:327 #: js/ui/components/polkitAgent.js:281 js/ui/shellMountOperation.js:327
msgid "Sorry, that didnt work. Please try again." msgid "Sorry, that didnt work. Please try again."
msgstr "Не удалось подтвердить подлинность. Попробуйте снова." msgstr "Не удалось подтвердить подлинность. Попробуйте снова."
@ -1004,7 +1000,6 @@ msgstr "Показать приложения"
msgid "Dash" msgid "Dash"
msgstr "Панель приложений" msgstr "Панель приложений"
# fix для даты в календаре и на экране блокировки
#. Translators: This is the date format to use when the calendar popup is #. Translators: This is the date format to use when the calendar popup is
#. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM"). #. * shown - it is shown just below the time in the shell (e.g. "Tue 9:29 AM").
#. #.
@ -1012,7 +1007,6 @@ msgstr "Панель приложений"
msgid "%B %e %Y" msgid "%B %e %Y"
msgstr "%-d %B %Y" msgstr "%-d %B %Y"
# fix для даты в календаре и на экране блокировки
#. Translators: This is the accessible name of the date button shown #. Translators: This is the accessible name of the date button shown
#. * below the time in the shell; it should combine the weekday and the #. * below the time in the shell; it should combine the weekday and the
#. * date, e.g. "Tuesday February 17 2015". #. * date, e.g. "Tuesday February 17 2015".
@ -1029,7 +1023,7 @@ msgstr "Добавить мировые часы…"
msgid "World Clocks" msgid "World Clocks"
msgstr "Мировые часы" msgstr "Мировые часы"
#: js/ui/dateMenu.js:225 #: js/ui/dateMenu.js:227
msgid "Weather" msgid "Weather"
msgstr "Погода" msgstr "Погода"
@ -1037,7 +1031,7 @@ msgstr "Погода"
#. libgweather for the possible condition strings. If at all #. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of #. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions. #. the inserted conditions.
#: js/ui/dateMenu.js:289 #: js/ui/dateMenu.js:291
#, javascript-format #, javascript-format
msgid "%s all day." msgid "%s all day."
msgstr "%s весь день." msgstr "%s весь день."
@ -1046,7 +1040,7 @@ msgstr "%s весь день."
#. libgweather for the possible condition strings. If at all #. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of #. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions. #. the inserted conditions.
#: js/ui/dateMenu.js:295 #: js/ui/dateMenu.js:297
#, javascript-format #, javascript-format
msgid "%s, then %s later." msgid "%s, then %s later."
msgstr "%s, затем позднее %s." msgstr "%s, затем позднее %s."
@ -1055,30 +1049,30 @@ msgstr "%s, затем позднее %s."
#. libgweather for the possible condition strings. If at all #. libgweather for the possible condition strings. If at all
#. possible, the sentence should match the grammatical case etc. of #. possible, the sentence should match the grammatical case etc. of
#. the inserted conditions. #. the inserted conditions.
#: js/ui/dateMenu.js:301 #: js/ui/dateMenu.js:303
#, javascript-format #, javascript-format
msgid "%s, then %s, followed by %s later." msgid "%s, then %s, followed by %s later."
msgstr "%s, затем %s, позже %s." msgstr "%s, затем %s, позже %s."
#: js/ui/dateMenu.js:312 #: js/ui/dateMenu.js:314
msgid "Select a location…" msgid "Select a location…"
msgstr "Выберите местоположение…" msgstr "Выберите местоположение…"
#: js/ui/dateMenu.js:315 #: js/ui/dateMenu.js:317
msgid "Loading…" msgid "Loading…"
msgstr "Загрузка…" msgstr "Загрузка…"
#. Translators: %s is a temperature with unit, e.g. "23℃" #. Translators: %s is a temperature with unit, e.g. "23℃"
#: js/ui/dateMenu.js:321 #: js/ui/dateMenu.js:323
#, javascript-format #, javascript-format
msgid "Feels like %s." msgid "Feels like %s."
msgstr "Ощущается как %s." msgstr "Ощущается как %s."
#: js/ui/dateMenu.js:324 #: js/ui/dateMenu.js:326
msgid "Go online for weather information" msgid "Go online for weather information"
msgstr "Подключите интернет для получения информации о погоде" msgstr "Подключите интернет для получения информации о погоде"
#: js/ui/dateMenu.js:326 #: js/ui/dateMenu.js:328
msgid "Weather information is currently unavailable" msgid "Weather information is currently unavailable"
msgstr "Информация о погоде сейчас недоступна" msgstr "Информация о погоде сейчас недоступна"

View File

@ -142,7 +142,7 @@ libst_gir = gnome.generate_gir(libst,
sources: st_gir_sources, sources: st_gir_sources,
nsversion: '1.0', nsversion: '1.0',
namespace: 'St', namespace: 'St',
includes: ['Clutter-' + mutter_api_version, 'Gtk-3.0'], includes: ['Clutter-' + mutter_api_version, 'Cally-' + mutter_api_version, 'Gtk-3.0'],
dependencies: [mutter_dep], dependencies: [mutter_dep],
include_directories: include_directories('..'), include_directories: include_directories('..'),
extra_args: ['-DST_COMPILATION', '--quiet'], extra_args: ['-DST_COMPILATION', '--quiet'],

View File

@ -177,15 +177,15 @@ st_bin_get_preferred_height (ClutterActor *self,
} }
static void static void
st_bin_dispose (GObject *gobject) st_bin_destroy (ClutterActor *actor)
{ {
StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (gobject)); StBinPrivate *priv = st_bin_get_instance_private (ST_BIN (actor));
if (priv->child) if (priv->child)
clutter_actor_destroy (priv->child); clutter_actor_destroy (priv->child);
g_assert (priv->child == NULL); g_assert (priv->child == NULL);
G_OBJECT_CLASS (st_bin_parent_class)->dispose (gobject); CLUTTER_ACTOR_CLASS (st_bin_parent_class)->destroy (actor);
} }
static void static void
@ -315,11 +315,11 @@ st_bin_class_init (StBinClass *klass)
gobject_class->set_property = st_bin_set_property; gobject_class->set_property = st_bin_set_property;
gobject_class->get_property = st_bin_get_property; gobject_class->get_property = st_bin_get_property;
gobject_class->dispose = st_bin_dispose;
actor_class->get_preferred_width = st_bin_get_preferred_width; actor_class->get_preferred_width = st_bin_get_preferred_width;
actor_class->get_preferred_height = st_bin_get_preferred_height; actor_class->get_preferred_height = st_bin_get_preferred_height;
actor_class->allocate = st_bin_allocate; actor_class->allocate = st_bin_allocate;
actor_class->destroy = st_bin_destroy;
widget_class->popup_menu = st_bin_popup_menu; widget_class->popup_menu = st_bin_popup_menu;
widget_class->navigate_focus = st_bin_navigate_focus; widget_class->navigate_focus = st_bin_navigate_focus;

View File

@ -90,7 +90,7 @@ adjustment_value_notify_cb (StAdjustment *adjustment,
GParamSpec *pspec, GParamSpec *pspec,
StBoxLayout *box) StBoxLayout *box)
{ {
clutter_actor_queue_redraw (CLUTTER_ACTOR (box)); clutter_actor_queue_relayout (CLUTTER_ACTOR (box));
} }
static void static void
@ -490,7 +490,7 @@ st_box_layout_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume) ClutterPaintVolume *volume)
{ {
StBoxLayout *self = ST_BOX_LAYOUT (actor); StBoxLayout *self = ST_BOX_LAYOUT (actor);
gdouble x, y; gdouble x, y, lower, upper;
StBoxLayoutPrivate *priv = self->priv; StBoxLayoutPrivate *priv = self->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor)); StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorBox allocation_box; ClutterActorBox allocation_box;
@ -505,13 +505,42 @@ st_box_layout_get_paint_volume (ClutterActor *actor,
* our paint volume on that. */ * our paint volume on that. */
if (priv->hadjustment || priv->vadjustment) if (priv->hadjustment || priv->vadjustment)
{ {
gdouble width, height;
clutter_actor_get_allocation_box (actor, &allocation_box); clutter_actor_get_allocation_box (actor, &allocation_box);
st_theme_node_get_content_box (theme_node, &allocation_box, &content_box); st_theme_node_get_content_box (theme_node, &allocation_box, &content_box);
origin.x = content_box.x1 - allocation_box.x1; origin.x = content_box.x1 - allocation_box.x1;
origin.y = content_box.y1 - allocation_box.y2; origin.y = content_box.y1 - allocation_box.y2;
origin.z = 0.f; origin.z = 0.f;
clutter_paint_volume_set_width (volume, content_box.x2 - content_box.x1);
clutter_paint_volume_set_height (volume, content_box.y2 - content_box.y1); if (priv->hadjustment)
{
g_object_get (priv->hadjustment,
"lower", &lower,
"upper", &upper,
NULL);
width = upper - lower;
}
else
{
width = content_box.x2 - content_box.x1;
}
if (priv->vadjustment)
{
g_object_get (priv->vadjustment,
"lower", &lower,
"upper", &upper,
NULL);
height = upper - lower;
}
else
{
height = content_box.y2 - content_box.y1;
}
clutter_paint_volume_set_width (volume, width);
clutter_paint_volume_set_height (volume, height);
} }
else if (!CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->get_paint_volume (actor, volume)) else if (!CLUTTER_ACTOR_CLASS (st_box_layout_parent_class)->get_paint_volume (actor, volume))
return FALSE; return FALSE;

View File

@ -248,14 +248,17 @@ st_button_touch_event (ClutterActor *actor,
if (event->type == CLUTTER_TOUCH_BEGIN && !priv->press_sequence) if (event->type == CLUTTER_TOUCH_BEGIN && !priv->press_sequence)
{ {
clutter_input_device_sequence_grab (device, sequence, actor); clutter_input_device_sequence_grab (device, sequence, actor);
st_button_press (button, device, 0, sequence); if (!clutter_event_is_pointer_emulated ((ClutterEvent*) event))
st_button_press (button, device, 0, sequence);
return CLUTTER_EVENT_STOP; return CLUTTER_EVENT_STOP;
} }
else if (event->type == CLUTTER_TOUCH_END && else if (event->type == CLUTTER_TOUCH_END &&
priv->device == device && priv->device == device &&
priv->press_sequence == sequence) priv->press_sequence == sequence)
{ {
st_button_release (button, device, mask, 0, sequence); if (!clutter_event_is_pointer_emulated ((ClutterEvent*) event))
st_button_release (button, device, mask, 0, sequence);
clutter_input_device_sequence_ungrab (device, sequence); clutter_input_device_sequence_ungrab (device, sequence);
return CLUTTER_EVENT_STOP; return CLUTTER_EVENT_STOP;
} }

View File

@ -906,6 +906,13 @@ st_entry_unmap (ClutterActor *actor)
CLUTTER_ACTOR_CLASS (st_entry_parent_class)->unmap (actor); CLUTTER_ACTOR_CLASS (st_entry_parent_class)->unmap (actor);
} }
static gboolean
st_entry_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
return clutter_paint_volume_set_from_allocation (volume, actor);
}
static void static void
st_entry_class_init (StEntryClass *klass) st_entry_class_init (StEntryClass *klass)
{ {
@ -923,6 +930,7 @@ st_entry_class_init (StEntryClass *klass)
actor_class->allocate = st_entry_allocate; actor_class->allocate = st_entry_allocate;
actor_class->paint = st_entry_paint; actor_class->paint = st_entry_paint;
actor_class->unmap = st_entry_unmap; actor_class->unmap = st_entry_unmap;
actor_class->get_paint_volume = st_entry_get_paint_volume;
actor_class->key_press_event = st_entry_key_press_event; actor_class->key_press_event = st_entry_key_press_event;
actor_class->key_focus_in = st_entry_key_focus_in; actor_class->key_focus_in = st_entry_key_focus_in;
@ -1287,10 +1295,10 @@ st_entry_get_input_hints (StEntry *entry)
return clutter_text_get_input_hints (CLUTTER_TEXT (priv->entry)); return clutter_text_get_input_hints (CLUTTER_TEXT (priv->entry));
} }
static gboolean static void
_st_entry_icon_press_cb (ClutterActor *actor, _st_entry_icon_clicked_cb (ClutterClickAction *action,
ClutterButtonEvent *event, ClutterActor *actor,
StEntry *entry) StEntry *entry)
{ {
StEntryPrivate *priv = ST_ENTRY_PRIV (entry); StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
@ -1298,8 +1306,6 @@ _st_entry_icon_press_cb (ClutterActor *actor,
g_signal_emit (entry, entry_signals[PRIMARY_ICON_CLICKED], 0); g_signal_emit (entry, entry_signals[PRIMARY_ICON_CLICKED], 0);
else else
g_signal_emit (entry, entry_signals[SECONDARY_ICON_CLICKED], 0); g_signal_emit (entry, entry_signals[SECONDARY_ICON_CLICKED], 0);
return FALSE;
} }
static void static void
@ -1309,21 +1315,24 @@ _st_entry_set_icon (StEntry *entry,
{ {
if (*icon) if (*icon)
{ {
g_signal_handlers_disconnect_by_func (*icon, clutter_actor_remove_action_by_name (*icon, "entry-icon-action");
_st_entry_icon_press_cb,
entry);
clutter_actor_remove_child (CLUTTER_ACTOR (entry), *icon); clutter_actor_remove_child (CLUTTER_ACTOR (entry), *icon);
*icon = NULL; *icon = NULL;
} }
if (new_icon) if (new_icon)
{ {
ClutterAction *action;
*icon = g_object_ref (new_icon); *icon = g_object_ref (new_icon);
clutter_actor_set_reactive (*icon, TRUE); clutter_actor_set_reactive (*icon, TRUE);
clutter_actor_add_child (CLUTTER_ACTOR (entry), *icon); clutter_actor_add_child (CLUTTER_ACTOR (entry), *icon);
g_signal_connect (*icon, "button-release-event",
G_CALLBACK (_st_entry_icon_press_cb), entry); action = clutter_click_action_new ();
clutter_actor_add_action_with_name (*icon, "entry-icon-action", action);
g_signal_connect (action, "clicked",
G_CALLBACK (_st_entry_icon_clicked_cb), entry);
} }
clutter_actor_queue_relayout (CLUTTER_ACTOR (entry)); clutter_actor_queue_relayout (CLUTTER_ACTOR (entry));

View File

@ -180,6 +180,7 @@ st_label_dispose (GObject *object)
{ {
StLabelPrivate *priv = ST_LABEL (object)->priv; StLabelPrivate *priv = ST_LABEL (object)->priv;
priv->label = NULL;
g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref); g_clear_pointer (&priv->text_shadow_pipeline, cogl_object_unref);
G_OBJECT_CLASS (st_label_parent_class)->dispose (object); G_OBJECT_CLASS (st_label_parent_class)->dispose (object);

View File

@ -304,6 +304,13 @@ st_scroll_view_pick (ClutterActor *actor,
clutter_actor_paint (priv->vscroll); clutter_actor_paint (priv->vscroll);
} }
static gboolean
st_scroll_view_get_paint_volume (ClutterActor *actor,
ClutterPaintVolume *volume)
{
return clutter_paint_volume_set_from_allocation (volume, actor);
}
static double static double
get_scrollbar_width (StScrollView *scroll, get_scrollbar_width (StScrollView *scroll,
gfloat for_height) gfloat for_height)
@ -793,6 +800,7 @@ st_scroll_view_class_init (StScrollViewClass *klass)
actor_class->paint = st_scroll_view_paint; actor_class->paint = st_scroll_view_paint;
actor_class->pick = st_scroll_view_pick; actor_class->pick = st_scroll_view_pick;
actor_class->get_paint_volume = st_scroll_view_get_paint_volume;
actor_class->get_preferred_width = st_scroll_view_get_preferred_width; actor_class->get_preferred_width = st_scroll_view_get_preferred_width;
actor_class->get_preferred_height = st_scroll_view_get_preferred_height; actor_class->get_preferred_height = st_scroll_view_get_preferred_height;
actor_class->allocate = st_scroll_view_allocate; actor_class->allocate = st_scroll_view_allocate;

View File

@ -37,6 +37,7 @@ struct _StTextureCachePrivate
/* Things that were loaded with a cache policy != NONE */ /* Things that were loaded with a cache policy != NONE */
GHashTable *keyed_cache; /* char * -> CoglTexture* */ GHashTable *keyed_cache; /* char * -> CoglTexture* */
GHashTable *keyed_surface_cache; /* char * -> cairo_surface_t* */
/* Presently this is used to de-duplicate requests for GIcons and async URIs. */ /* Presently this is used to de-duplicate requests for GIcons and async URIs. */
GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */ GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */
@ -145,6 +146,10 @@ st_texture_cache_init (StTextureCache *self)
self->priv->keyed_cache = g_hash_table_new_full (g_str_hash, g_str_equal, self->priv->keyed_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, cogl_object_unref); g_free, cogl_object_unref);
self->priv->keyed_surface_cache = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
(GDestroyNotify) cairo_surface_destroy);
self->priv->outstanding_requests = g_hash_table_new_full (g_str_hash, g_str_equal, self->priv->outstanding_requests = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, NULL); g_free, NULL);
self->priv->file_monitors = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, self->priv->file_monitors = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
@ -166,6 +171,7 @@ st_texture_cache_dispose (GObject *object)
} }
g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy); g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
g_clear_pointer (&self->priv->keyed_surface_cache, g_hash_table_destroy);
g_clear_pointer (&self->priv->outstanding_requests, g_hash_table_destroy); g_clear_pointer (&self->priv->outstanding_requests, g_hash_table_destroy);
g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy); g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy);
@ -520,6 +526,8 @@ finish_texture_load (AsyncTextureLoadData *data,
goto out; goto out;
texdata = pixbuf_to_cogl_texture (pixbuf); texdata = pixbuf_to_cogl_texture (pixbuf);
if (!texdata)
goto out;
if (data->policy != ST_TEXTURE_CACHE_POLICY_NONE) if (data->policy != ST_TEXTURE_CACHE_POLICY_NONE)
{ {
@ -772,13 +780,13 @@ st_texture_cache_load (StTextureCache *cache,
if (!texture) if (!texture)
{ {
texture = load (cache, key, data, error); texture = load (cache, key, data, error);
if (texture) if (texture && policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texture); g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), texture);
else
return NULL;
} }
cogl_object_ref (texture); if (texture && policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
cogl_object_ref (texture);
return texture; return texture;
} }
@ -976,7 +984,7 @@ file_changed_cb (GFileMonitor *monitor,
char *key; char *key;
guint file_hash; guint file_hash;
if (event_type != G_FILE_MONITOR_EVENT_CHANGED) if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
return; return;
file_hash = g_file_hash (file); file_hash = g_file_hash (file);
@ -986,7 +994,7 @@ file_changed_cb (GFileMonitor *monitor,
g_free (key); g_free (key);
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", file_hash); key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", file_hash);
g_hash_table_remove (cache->priv->keyed_cache, key); g_hash_table_remove (cache->priv->keyed_surface_cache, key);
g_free (key); g_free (key);
g_signal_emit (cache, signals[TEXTURE_FILE_CHANGED], 0, file); g_signal_emit (cache, signals[TEXTURE_FILE_CHANGED], 0, file);
@ -1273,6 +1281,9 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
texdata = pixbuf_to_cogl_texture (pixbuf); texdata = pixbuf_to_cogl_texture (pixbuf);
g_object_unref (pixbuf); g_object_unref (pixbuf);
if (!texdata)
goto out;
if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER) if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
{ {
cogl_object_ref (texdata); cogl_object_ref (texdata);
@ -1304,7 +1315,7 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file)); key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file));
surface = g_hash_table_lookup (cache->priv->keyed_cache, key); surface = g_hash_table_lookup (cache->priv->keyed_surface_cache, key);
if (surface == NULL) if (surface == NULL)
{ {
@ -1318,7 +1329,8 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER) if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
{ {
cairo_surface_reference (surface); cairo_surface_reference (surface);
g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), surface); g_hash_table_insert (cache->priv->keyed_surface_cache,
g_strdup (key), surface);
} }
} }
else else

View File

@ -229,9 +229,9 @@ unpremultiply (ClutterColor *color)
{ {
if (color->alpha != 0) if (color->alpha != 0)
{ {
color->red = (color->red * 255 + 127) / color->alpha; color->red = MIN((color->red * 255 + 127) / color->alpha, 255);
color->green = (color->green * 255 + 127) / color->alpha; color->green = MIN((color->green * 255 + 127) / color->alpha, 255);
color->blue = (color->blue * 255 + 127) / color->alpha; color->blue = MIN((color->blue * 255 + 127) / color->alpha, 255);
} }
} }
@ -402,7 +402,7 @@ st_theme_node_lookup_corner (StThemeNode *node,
return COGL_INVALID_HANDLE; return COGL_INVALID_HANDLE;
key = corner_to_string (&corner); key = corner_to_string (&corner);
texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_NONE, load_corner, &corner, NULL); texture = st_texture_cache_load (cache, key, ST_TEXTURE_CACHE_POLICY_FOREVER, load_corner, &corner, NULL);
if (texture) if (texture)
{ {
@ -1414,6 +1414,32 @@ st_theme_node_load_background_image (StThemeNode *node)
return node->background_texture != COGL_INVALID_HANDLE; return node->background_texture != COGL_INVALID_HANDLE;
} }
static gboolean
st_theme_node_invalidate_resources_for_file (StThemeNode *node,
GFile *file)
{
StBorderImage *border_image;
gboolean changed = FALSE;
GFile *theme_file;
theme_file = st_theme_node_get_background_image (node);
if ((theme_file != NULL) && g_file_equal (theme_file, file))
{
st_theme_node_invalidate_background_image (node);
changed = TRUE;
}
border_image = st_theme_node_get_border_image (node);
theme_file = border_image ? st_border_image_get_file (border_image) : NULL;
if ((theme_file != NULL) && g_file_equal (theme_file, file))
{
st_theme_node_invalidate_border_image (node);
changed = TRUE;
}
return changed;
}
static void st_theme_node_prerender_shadow (StThemeNodePaintState *state); static void st_theme_node_prerender_shadow (StThemeNodePaintState *state);
static void static void
@ -2751,3 +2777,17 @@ st_theme_node_paint_state_invalidate (StThemeNodePaintState *state)
state->alloc_width = 0; state->alloc_width = 0;
state->alloc_height = 0; state->alloc_height = 0;
} }
gboolean
st_theme_node_paint_state_invalidate_for_file (StThemeNodePaintState *state,
GFile *file)
{
if (state->node != NULL &&
st_theme_node_invalidate_resources_for_file (state->node, file))
{
st_theme_node_paint_state_invalidate (state);
return TRUE;
}
return FALSE;
}

View File

@ -287,6 +287,9 @@ void st_theme_node_paint_state_free (StThemeNodePaintState *state);
void st_theme_node_paint_state_copy (StThemeNodePaintState *state, void st_theme_node_paint_state_copy (StThemeNodePaintState *state,
StThemeNodePaintState *other); StThemeNodePaintState *other);
void st_theme_node_paint_state_invalidate (StThemeNodePaintState *state); void st_theme_node_paint_state_invalidate (StThemeNodePaintState *state);
gboolean st_theme_node_paint_state_invalidate_for_file (StThemeNodePaintState *state,
GFile *file);
void st_theme_node_paint_state_set_node (StThemeNodePaintState *state, void st_theme_node_paint_state_set_node (StThemeNodePaintState *state,
StThemeNode *node); StThemeNode *node);

View File

@ -289,44 +289,17 @@ st_widget_texture_cache_changed (StTextureCache *cache,
{ {
StWidget *actor = ST_WIDGET (user_data); StWidget *actor = ST_WIDGET (user_data);
StWidgetPrivate *priv = st_widget_get_instance_private (actor); StWidgetPrivate *priv = st_widget_get_instance_private (actor);
StThemeNode *node = priv->theme_node;
StBorderImage *border_image;
gboolean changed = FALSE; gboolean changed = FALSE;
GFile *theme_file; int i;
if (node == NULL) for (i = 0; i < G_N_ELEMENTS (priv->paint_states); i++)
return;
theme_file = st_theme_node_get_background_image (node);
if ((theme_file != NULL) && g_file_equal (theme_file, file))
{ {
st_theme_node_invalidate_background_image (node); StThemeNodePaintState *paint_state = &priv->paint_states[i];
changed = TRUE; changed |= st_theme_node_paint_state_invalidate_for_file (paint_state, file);
} }
border_image = st_theme_node_get_border_image (node); if (changed && clutter_actor_is_mapped (CLUTTER_ACTOR (actor)))
theme_file = border_image ? st_border_image_get_file (border_image) : NULL; clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
if ((theme_file != NULL) && g_file_equal (theme_file, file))
{
st_theme_node_invalidate_border_image (node);
changed = TRUE;
}
if (changed)
{
/* If we prerender the background / border, we need to update
* the paint state. We should probably implement a method to
* the theme node to determine this, but for now, just wipe
* the entire paint state.
*
* Use the existing state instead of a new one because it's
* assumed the rest of the state will stay the same.
*/
st_theme_node_paint_state_invalidate (current_paint_state (actor));
if (clutter_actor_is_mapped (CLUTTER_ACTOR (actor)))
clutter_actor_queue_redraw (CLUTTER_ACTOR (actor));
}
} }
static void static void