Merge lp:~3v1n0/gnome-shell/bionic-patches-picks into lp:~ubuntu-desktop/gnome-shell/ubuntu

Proposed by Marco Trevisan (Treviño)
Status: Merged
Merged at revision: 143
Proposed branch: lp:~3v1n0/gnome-shell/bionic-patches-picks
Merge into: lp:~ubuntu-desktop/gnome-shell/ubuntu
Diff against target: 1534 lines (+1455/-1)
13 files modified
debian/changelog (+26/-0)
debian/patches/StIcon-only-compute-shadow-pipeline-when-the-texture-is-p.patch (+134/-0)
debian/patches/js-fix-invalid-access-errors.patch (+564/-0)
debian/patches/popupMenu-Fix-wrong-call-to-clutter_actor_add_child.patch (+28/-0)
debian/patches/series (+12/-1)
debian/patches/shell-ignore-invalid-window-monitor-index.patch (+98/-0)
debian/patches/st-texture-cache-Cancel-sliced-image-loading-on-target-ac.patch (+118/-0)
debian/patches/st-texture-cache-Don-t-add-NULL-textures-to-cache.patch (+92/-0)
debian/patches/volume-Add-back-sound-feedback-on-scroll.patch (+106/-0)
debian/patches/workspace-fix-repositioned-windows-in-activities.patch (+148/-0)
debian/patches/workspaceThumbnail-initialize-porthole-based-on-workArea.patch (+36/-0)
debian/patches/workspaceThumbnail-only-update-_porthole-if-the-overview-.patch (+29/-0)
debian/patches/workspaceThumbnail-rebuild-thumbnails-if-workareas-size-c.patch (+64/-0)
To merge this branch: bzr merge lp:~3v1n0/gnome-shell/bionic-patches-picks
Reviewer Review Type Date Requested Status
Jeremy Bícha Approve
Review via email: mp+343423@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jeremy Bícha (jbicha) wrote :

I am very concerned with the decision to add 11 more patches to bionic's gnome-shell. I am concerned that this could make updating to 3.28.2 difficult (or the 3.30 series) if too much code is changed before these patches are accepted in to GNOME.

You could at least help reduce this number by following up on the patches that have already been applied to upstream master to see if they can be pushed to the gnome-3-28 branch.

Please also try to be more persistent with getting upstream review of the remaining patches.

I encourage you to talk to Debian's smcv to see if he would be interested in taking some of these patches in to Debian.

One minor note. The patch rename wasn't done in this merge proposal. Maybe that was missed when exporting your work from git.

review: Approve
Revision history for this message
Marco Trevisan (Treviño) (3v1n0) wrote :

2018-04-17 13:15 GMT-05:00 Jeremy Bicha <email address hidden>:
> I am very concerned with the decision to add 11 more patches to bionic's gnome-shell. I am concerned that this
> could make updating to 3.28.2 difficult (or the 3.30 series) if too much code is changed before these patches
> are accepted in to GNOME.

Considering how the pace at gnome-shell development is currently, I
think this won't be really a problem.
Plus, I've linked the git repo I've used to generate all this, and
using patch-queue, you know that rebasing won't really be an issue.
In any, case I can take care of it. Although I hope some of these
patch will merge (where's it's not already the case).

> You could at least help reduce this number by following up on the patches that have already been applied to upstream master
> to see if they can be pushed to the gnome-3-28 branch.

There's not gnome-3-28 branch yet, thus everything that here has been
cherry-picked from master, will be in 3.28.X.

> Please also try to be more persistent with getting upstream review of the remaining patches.

Eh, true, but I also don't like to bother people :).

> I encourage you to talk to Debian's smcv to see if he would be interested in taking some of these patches in to Debian.

Yeah, I already planned to propose some of them to salsa too.

> One minor note. The patch rename wasn't done in this merge proposal. Maybe that was missed when exporting your work from git.

Oh, well spotted. Thanks.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2018-04-14 01:50:15 +0000
3+++ debian/changelog 2018-04-17 10:30:40 +0000
4@@ -1,10 +1,36 @@
5 gnome-shell (3.28.1-0ubuntu1) UNRELEASED; urgency=medium
6
7+ [ Jeremy Bicha ]
8 * New upstream release
9 * Drop obsolete patches:
10 - 27-nm-libexec-path.patch
11 - fix-wayland-vbox-crash.patch
12
13+ [ Marco Trevisan (Treviño) ]
14+ * ui-Theme-lookup-should-respect-XDG_DATA_DIRS.patch:
15+ - Renamed from ubuntu_theme_lookup_xdg.patch and cherry-picked from
16+ upstream
17+ * StIcon-only-compute-shadow-pipeline-when-the-texture-is-p.patch:
18+ - Don't try to compute shadows on not allocated icons (LP: #1723378)
19+ * js-fix-invalid-access-errors.patch:
20+ - Fix javascript errors (LP: #1747566)
21+ * popupMenu-Fix-wrong-call-to-clutter_actor_add_child.patch:
22+ - Cherry-pick from upstream
23+ * shell-ignore-invalid-window-monitor-index.patch:
24+ - Fix crash on accessing on invalid monitor windows (LP: #1724439)
25+ * volume-Add-back-sound-feedback-on-scroll.patch:
26+ - Fix regression causing missing feedback on volume slider scroll
27+ * workspace-fix-repositioned-windows-in-activities.patch:
28+ - Ensure windows thumbnails coordinates are correct (LP: #1653153)
29+ * workspaceThumbnail-initialize-porthole-based-on-workArea.patch:
30+ workspaceThumbnail-only-update-_porthole-if-the-overview-.patch:
31+ workspaceThumbnail-rebuild-thumbnails-if-workareas-size-c.patch:
32+ - Cherry-picks from upstream, avoid unneeded computations in activities
33+ * st-texture-cache-Cancel-sliced-image-loading-on-target-ac.patch:
34+ - Fix possible crash on cache loading
35+ * st-texture-cache-Don-t-add-NULL-textures-to-cache.patch:
36+ - Fix crash when deleting NULL textures from cash (LP: #1754445)
37+
38 -- Jeremy Bicha <jbicha@ubuntu.com> Fri, 13 Apr 2018 21:40:17 -0400
39
40 gnome-shell (3.28.0-0ubuntu5) bionic; urgency=medium
41
42=== added file 'debian/patches/StIcon-only-compute-shadow-pipeline-when-the-texture-is-p.patch'
43--- debian/patches/StIcon-only-compute-shadow-pipeline-when-the-texture-is-p.patch 1970-01-01 00:00:00 +0000
44+++ debian/patches/StIcon-only-compute-shadow-pipeline-when-the-texture-is-p.patch 2018-04-17 10:30:40 +0000
45@@ -0,0 +1,134 @@
46+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
47+Date: Wed, 18 Oct 2017 05:32:22 -0500
48+Subject: StIcon: only compute shadow pipeline when the texture is properly
49+ allocated
50+
51+Creating the shadow pipeline requires the actor to be allocated in order
52+to get its dimensions, however in the current state we just compute it
53+even if this is not the case.
54+This causes _st_create_shadow_pipeline_from_actor (when getting the allocation
55+box) to trigger an allocation cycle, which might lead to a convolution to
56+st_icon_finish_update causing breakage on data as soon as we return from it.
57+
58+Generating it at paint if not done before, it's a way for avoiding this.
59+
60+https://bugzilla.gnome.org/show_bug.cgi?id=788908
61+
62+Bug-GNOME: https://bugzilla.gnome.org/show_bug.cgi?id=788908
63+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gnome-shell/+bug/1723378
64+Forwarded: yes, https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/3
65+---
66+ src/st/st-icon.c | 48 +++++++++++++++++++++++++++++++++++++-----------
67+ 1 file changed, 37 insertions(+), 11 deletions(-)
68+
69+diff --git a/src/st/st-icon.c b/src/st/st-icon.c
70+index 192df60..332e5b2 100644
71+--- a/src/st/st-icon.c
72++++ b/src/st/st-icon.c
73+@@ -56,12 +56,15 @@ struct _StIconPrivate
74+
75+ CoglPipeline *shadow_pipeline;
76+ StShadow *shadow_spec;
77++ ClutterSize shadow_size;
78+ };
79+
80+ G_DEFINE_TYPE_WITH_PRIVATE (StIcon, st_icon, ST_TYPE_WIDGET)
81+
82+ static void st_icon_update (StIcon *icon);
83+ static gboolean st_icon_update_icon_size (StIcon *icon);
84++static void st_icon_update_shadow_pipeline (StIcon *icon);
85++static void st_icon_clean_shadow_pipeline (StIcon *icon);
86+
87+ #define DEFAULT_ICON_SIZE 48
88+
89+@@ -164,18 +167,31 @@ st_icon_paint (ClutterActor *actor)
90+
91+ if (priv->icon_texture)
92+ {
93+- if (priv->shadow_pipeline)
94+- {
95++ if (priv->shadow_spec)
96++ {
97+ ClutterActorBox allocation;
98+ float width, height;
99+
100+ clutter_actor_get_allocation_box (priv->icon_texture, &allocation);
101+ clutter_actor_box_get_size (&allocation, &width, &height);
102+
103+- _st_paint_shadow_with_opacity (priv->shadow_spec,
104+- priv->shadow_pipeline,
105+- &allocation,
106+- clutter_actor_get_paint_opacity (priv->icon_texture));
107++ if (priv->shadow_pipeline == NULL ||
108++ priv->shadow_size.width != width ||
109++ priv->shadow_size.height != height)
110++ {
111++ st_icon_update_shadow_pipeline (ST_ICON (actor));
112++
113++ if (priv->shadow_pipeline)
114++ clutter_size_init (&priv->shadow_size, width, height);
115++ }
116++
117++ if (priv->shadow_pipeline)
118++ {
119++ _st_paint_shadow_with_opacity (priv->shadow_spec,
120++ priv->shadow_pipeline,
121++ &allocation,
122++ clutter_actor_get_paint_opacity (priv->icon_texture));
123++ }
124+ }
125+
126+ clutter_actor_paint (priv->icon_texture);
127+@@ -189,7 +205,7 @@ st_icon_style_changed (StWidget *widget)
128+ StThemeNode *theme_node = st_widget_get_theme_node (widget);
129+ StIconPrivate *priv = self->priv;
130+
131+- g_clear_pointer (&priv->shadow_pipeline, cogl_object_unref);
132++ st_icon_clean_shadow_pipeline (self);
133+ g_clear_pointer (&priv->shadow_spec, st_shadow_unref);
134+
135+ priv->shadow_spec = st_theme_node_get_shadow (theme_node, "icon-shadow");
136+@@ -268,21 +284,31 @@ st_icon_init (StIcon *self)
137+ }
138+
139+ static void
140+-st_icon_update_shadow_pipeline (StIcon *icon)
141++st_icon_clean_shadow_pipeline (StIcon *icon)
142+ {
143+ StIconPrivate *priv = icon->priv;
144+
145+ g_clear_pointer (&priv->shadow_pipeline, cogl_object_unref);
146++ clutter_size_init (&priv->shadow_size, 0, 0);
147++}
148++
149++static void
150++st_icon_update_shadow_pipeline (StIcon *icon)
151++{
152++ StIconPrivate *priv = icon->priv;
153++
154++ st_icon_clean_shadow_pipeline (icon);
155+
156+ if (priv->shadow_spec)
157+- priv->shadow_pipeline = _st_create_shadow_pipeline_from_actor (priv->shadow_spec, priv->icon_texture);
158++ priv->shadow_pipeline = _st_create_shadow_pipeline_from_actor (priv->shadow_spec, priv->icon_texture);
159+ }
160+
161+ static void
162+ on_pixbuf_changed (ClutterTexture *texture,
163+ StIcon *icon)
164+ {
165+- st_icon_update_shadow_pipeline (icon);
166++ st_icon_clean_shadow_pipeline (icon);
167++ clutter_actor_queue_redraw (CLUTTER_ACTOR (icon));
168+ }
169+
170+ static void
171+@@ -307,7 +333,7 @@ st_icon_finish_update (StIcon *icon)
172+ /* Remove the temporary ref we added */
173+ g_object_unref (priv->icon_texture);
174+
175+- st_icon_update_shadow_pipeline (icon);
176++ st_icon_clean_shadow_pipeline (icon);
177+
178+ /* "pixbuf-change" is actually a misnomer for "texture-changed" */
179+ g_signal_connect_object (priv->icon_texture, "pixbuf-change",
180
181=== added file 'debian/patches/js-fix-invalid-access-errors.patch'
182--- debian/patches/js-fix-invalid-access-errors.patch 1970-01-01 00:00:00 +0000
183+++ debian/patches/js-fix-invalid-access-errors.patch 2018-04-17 10:30:40 +0000
184@@ -0,0 +1,564 @@
185+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
186+Date: Mon, 4 Dec 2017 19:41:50 -0600
187+Subject: js: fix invalid-access errors
188+
189+tweener: Save handlers on target and remove them on destroy
190+
191+Saving handlers we had using the wrapper as a property of the object and delete
192+them when resetting the object state.
193+Without doing this an handler could be called on a destroyed target when this
194+happens on the onComplete callback.
195+
196+https://bugzilla.gnome.org/show_bug.cgi?id=791233
197+
198+dnd: Nullify _dragActor after we've destroyed it, and avoid invalid access
199+
200+We need to avoid that we use the _dragActor instance after that it has
201+been destroyed or we'll get errors. We now set it to null when this
202+happens, protecting any access to that.
203+
204+Add a DragState enum-like object to keep track of the state
205+instead of using booleans.
206+
207+Remove duplicated handler on 'destroy' and just use a generic one.
208+
209+https://bugzilla.gnome.org/show_bug.cgi?id=791233
210+
211+workspaceThumbnail: Disconnect from window signals on destruction
212+
213+Avoid to try to destroy the window clone content more than once
214+when a window is destroyed, and do it in proper order.
215+
216+https://bugzilla.gnome.org/show_bug.cgi?id=791233
217+
218+workspaceThumbnail: Remove WindowClone's from _windows when destroyed
219+
220+A WindowClone might be destroyed earlier than its MetaWindow counterpart
221+as its WindowActor could be destroyed earlier, thus when happens it's safer
222+to remove the clone from the windows list, without waiting for the workspace
223+to request to do so.
224+
225+WindowClone now emits a 'destroy' signals earlier enough and this now
226+triggers a _doRemoveWindow on WorkspaceThumbnail which will lead
227+to the proper cleanup; keeping track of the signal connections, in
228+order to avoid callback loops (not really harmful in this case, but
229+good practice).
230+
231+https://bugzilla.gnome.org/show_bug.cgi?id=791233
232+
233+workspace: Disconnect from window signals on destruction
234+
235+Avoid to try to destroy the window clone content more than once
236+when a window is destroyed, and do it in proper order.
237+
238+https://bugzilla.gnome.org/show_bug.cgi?id=791233
239+
240+workspace: Remove WindowClone's from _windows when destroyed
241+
242+A WindowClone might be destroyed earlier than its MetaWindow counterpart
243+as its WindowActor could be destroyed earlier, thus when happens it's safer
244+to remove the clone from the windows list, without waiting for the workspace
245+to request to do so.
246+
247+WindowClone now emits a 'destroy' signals earlier enough and this now
248+triggers a _doRemoveWindow on WorkspaceThumbnail which will lead
249+to the proper cleanup; keeping track of the signal connections, in
250+order to avoid callback loops (not really harmful in this case, but
251+good practice).
252+
253+https://bugzilla.gnome.org/show_bug.cgi?id=791233
254+
255+Bug-GNOME: https://bugzilla.gnome.org/show_bug.cgi?id=791233
256+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/bionic/+source/gnome-shell/+bug/1747566
257+Forwarded: yes, https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/4
258+---
259+ js/ui/dnd.js | 65 +++++++++++++++++++++++++++------------------
260+ js/ui/tweener.js | 64 +++++++++++++++++++++++++++++++++++---------
261+ js/ui/workspace.js | 35 +++++++++++++++++-------
262+ js/ui/workspaceThumbnail.js | 33 +++++++++++++++++------
263+ 4 files changed, 140 insertions(+), 57 deletions(-)
264+
265+diff --git a/js/ui/dnd.js b/js/ui/dnd.js
266+index a38607c..431c60d 100644
267+--- a/js/ui/dnd.js
268++++ b/js/ui/dnd.js
269+@@ -27,6 +27,12 @@ var DragMotionResult = {
270+ CONTINUE: 3
271+ };
272+
273++var DragState = {
274++ INIT: 0,
275++ DRAGGING: 1,
276++ CANCELLED: 2,
277++};
278++
279+ var DRAG_CURSOR_MAP = {
280+ 0: Meta.Cursor.DND_UNSUPPORTED_TARGET,
281+ 1: Meta.Cursor.DND_COPY,
282+@@ -78,6 +84,8 @@ var _Draggable = new Lang.Class({
283+ dragActorOpacity: undefined });
284+
285+ this.actor = actor;
286++ this._dragState = DragState.INIT;
287++
288+ if (!params.manualMode) {
289+ this.actor.connect('button-press-event',
290+ this._onButtonPress.bind(this));
291+@@ -88,7 +96,7 @@ var _Draggable = new Lang.Class({
292+ this.actor.connect('destroy', () => {
293+ this._actorDestroyed = true;
294+
295+- if (this._dragInProgress && this._dragCancellable)
296++ if (this._dragState == DragState.DRAGGING && this._dragCancellable)
297+ this._cancelDrag(global.get_current_time());
298+ this.disconnectAll();
299+ });
300+@@ -100,7 +108,6 @@ var _Draggable = new Lang.Class({
301+ this._dragActorOpacity = params.dragActorOpacity;
302+
303+ this._buttonDown = false; // The mouse button has been pressed and has not yet been released.
304+- this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
305+ this._animationInProgress = false; // The drag is over and the item is in the process of animating to its original position (snapping back or reverting).
306+ this._dragCancellable = true;
307+
308+@@ -206,9 +213,10 @@ var _Draggable = new Lang.Class({
309+ (event.type() == Clutter.EventType.TOUCH_END &&
310+ global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
311+ this._buttonDown = false;
312+- if (this._dragInProgress) {
313++ if (this._dragState == DragState.DRAGGING) {
314+ return this._dragActorDropped(event);
315+- } else if (this._dragActor != null && !this._animationInProgress) {
316++ } else if ((this._dragActor != null || this._dragState == DragState.CANCELLED) &&
317++ !this._animationInProgress) {
318+ // Drag must have been cancelled with Esc.
319+ this._dragComplete();
320+ return Clutter.EVENT_STOP;
321+@@ -222,14 +230,14 @@ var _Draggable = new Lang.Class({
322+ } else if (event.type() == Clutter.EventType.MOTION ||
323+ (event.type() == Clutter.EventType.TOUCH_UPDATE &&
324+ global.display.is_pointer_emulating_sequence(event.get_event_sequence()))) {
325+- if (this._dragInProgress) {
326++ if (this._dragActor && this._dragState == DragState.DRAGGING) {
327+ return this._updateDragPosition(event);
328+- } else if (this._dragActor == null) {
329++ } else if (this._dragActor == null && this._dragState != DragState.CANCELLED) {
330+ return this._maybeStartDrag(event);
331+ }
332+ // We intercept KEY_PRESS event so that we can process Esc key press to cancel
333+ // dragging and ignore all other key presses.
334+- } else if (event.type() == Clutter.EventType.KEY_PRESS && this._dragInProgress) {
335++ } else if (event.type() == Clutter.EventType.KEY_PRESS && this._dragState == DragState.DRAGGING) {
336+ let symbol = event.get_key_symbol();
337+ if (symbol == Clutter.Escape) {
338+ this._cancelDrag(event.get_time());
339+@@ -265,7 +273,7 @@ var _Draggable = new Lang.Class({
340+ */
341+ startDrag(stageX, stageY, time, sequence) {
342+ currentDraggable = this;
343+- this._dragInProgress = true;
344++ this._dragState = DragState.DRAGGING;
345+
346+ // Special-case St.Button: the pointer grab messes with the internal
347+ // state, so force a reset to a reasonable state here
348+@@ -342,6 +350,13 @@ var _Draggable = new Lang.Class({
349+ Shell.util_set_hidden_from_pick(this._dragActor, true);
350+ }
351+
352++ this._dragActorDestroyId = this._dragActor.connect('destroy', () => {
353++ // Cancel ongoing animation (if any)
354++ this._finishAnimation();
355++
356++ this._dragActor = null;
357++ this._dragState = DragState.CANCELLED;
358++ });
359+ this._dragOrigOpacity = this._dragActor.opacity;
360+ if (this._dragActorOpacity != undefined)
361+ this._dragActor.opacity = this._dragActorOpacity;
362+@@ -500,7 +515,7 @@ var _Draggable = new Lang.Class({
363+ event.get_time())) {
364+ // If it accepted the drop without taking the actor,
365+ // handle it ourselves.
366+- if (this._dragActor.get_parent() == Main.uiGroup) {
367++ if (this._dragActor && this._dragActor.get_parent() == Main.uiGroup) {
368+ if (this._restoreOnSuccess) {
369+ this._restoreDragActor(event.get_time());
370+ return true;
371+@@ -508,7 +523,7 @@ var _Draggable = new Lang.Class({
372+ this._dragActor.destroy();
373+ }
374+
375+- this._dragInProgress = false;
376++ this._dragState = DragState.INIT;
377+ global.screen.set_cursor(Meta.Cursor.DEFAULT);
378+ this.emit('drag-end', event.get_time(), true);
379+ this._dragComplete();
380+@@ -557,20 +572,22 @@ var _Draggable = new Lang.Class({
381+
382+ _cancelDrag(eventTime) {
383+ this.emit('drag-cancelled', eventTime);
384+- this._dragInProgress = false;
385+- let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
386++ let wasCancelled = (this._dragState == DragState.CANCELLED);
387++ this._dragState = DragState.CANCELLED;
388+
389+- if (this._actorDestroyed) {
390++ if (this._actorDestroyed || wasCancelled) {
391+ global.screen.set_cursor(Meta.Cursor.DEFAULT);
392+ if (!this._buttonDown)
393+ this._dragComplete();
394+ this.emit('drag-end', eventTime, false);
395+- if (!this._dragOrigParent)
396++ if (!this._dragOrigParent && this._dragActor)
397+ this._dragActor.destroy();
398+
399+ return;
400+ }
401+
402++ let [snapBackX, snapBackY, snapBackScale] = this._getRestoreLocation();
403++
404+ this._animateDragEnd(eventTime,
405+ { x: snapBackX,
406+ y: snapBackY,
407+@@ -581,7 +598,7 @@ var _Draggable = new Lang.Class({
408+ },
409+
410+ _restoreDragActor(eventTime) {
411+- this._dragInProgress = false;
412++ this._dragState = DragState.INIT;
413+ let [restoreX, restoreY, restoreScale] = this._getRestoreLocation();
414+
415+ // fade the actor back in at its original location
416+@@ -596,12 +613,6 @@ var _Draggable = new Lang.Class({
417+ _animateDragEnd(eventTime, params) {
418+ this._animationInProgress = true;
419+
420+- // finish animation if the actor gets destroyed
421+- // during it
422+- this._dragActorDestroyId =
423+- this._dragActor.connect('destroy',
424+- this._finishAnimation.bind(this));
425+-
426+ params['opacity'] = this._dragOrigOpacity;
427+ params['transition'] = 'easeOutQuad';
428+ params['onComplete'] = this._onAnimationComplete;
429+@@ -624,9 +635,6 @@ var _Draggable = new Lang.Class({
430+ },
431+
432+ _onAnimationComplete(dragActor, eventTime) {
433+- dragActor.disconnect(this._dragActorDestroyId);
434+- this._dragActorDestroyId = 0;
435+-
436+ if (this._dragOrigParent) {
437+ Main.uiGroup.remove_child(this._dragActor);
438+ this._dragOrigParent.add_actor(this._dragActor);
439+@@ -641,7 +649,7 @@ var _Draggable = new Lang.Class({
440+ },
441+
442+ _dragComplete() {
443+- if (!this._actorDestroyed)
444++ if (!this._actorDestroyed && this._dragActor)
445+ Shell.util_set_hidden_from_pick(this._dragActor, false);
446+
447+ this._ungrabEvents();
448+@@ -652,7 +660,12 @@ var _Draggable = new Lang.Class({
449+ this._updateHoverId = 0;
450+ }
451+
452+- this._dragActor = undefined;
453++ if (this._dragActor) {
454++ this._dragActor.disconnect(this._dragActorDestroyId);
455++ this._dragActor = null;
456++ }
457++
458++ this._dragState = DragState.INIT;
459+ currentDraggable = null;
460+ }
461+ });
462+diff --git a/js/ui/tweener.js b/js/ui/tweener.js
463+index 1a85e2f..663b97b 100644
464+--- a/js/ui/tweener.js
465++++ b/js/ui/tweener.js
466+@@ -69,30 +69,68 @@ function _getTweenState(target) {
467+ return target.__ShellTweenerState;
468+ }
469+
470++function _ensureHandlers(target) {
471++ if (!target.__ShellTweenerHandlers)
472++ target.__ShellTweenerHandlers = {};
473++ return target.__ShellTweenerHandlers;
474++}
475++
476+ function _resetTweenState(target) {
477+ let state = target.__ShellTweenerState;
478+
479+ if (state) {
480+- if (state.destroyedId)
481++ if (state.destroyedId) {
482+ state.actor.disconnect(state.destroyedId);
483++ delete state.destroyedId;
484++ }
485+ }
486+
487++ _removeHandler(target, 'onComplete', _tweenCompleted);
488+ target.__ShellTweenerState = {};
489+ }
490+
491+ function _addHandler(target, params, name, handler) {
492+- if (params[name]) {
493+- let oldHandler = params[name];
494+- let oldScope = params[name + 'Scope'];
495+- let oldParams = params[name + 'Params'];
496+- let eventScope = oldScope ? oldScope : target;
497+-
498+- params[name] = () => {
499+- oldHandler.apply(eventScope, oldParams);
500+- handler(target);
501+- };
502+- } else
503+- params[name] = () => { handler(target); };
504++ let wrapperNeeded = false;
505++ let tweenerHandlers = _ensureHandlers(target);
506++
507++ if (!(name in tweenerHandlers))
508++ {
509++ tweenerHandlers[name] = [];
510++ wrapperNeeded = true;
511++ }
512++
513++ let handlers = tweenerHandlers[name];
514++ handlers.push(handler);
515++
516++ if (wrapperNeeded) {
517++ if (params[name]) {
518++ let oldHandler = params[name];
519++ let oldScope = params[name + 'Scope'];
520++ let oldParams = params[name + 'Params'];
521++ let eventScope = oldScope ? oldScope : target;
522++
523++ params[name] = () => {
524++ oldHandler.apply(eventScope, oldParams);
525++ handlers.forEach((h) => h(target));
526++ };
527++ } else {
528++ params[name] = () => { handlers.forEach((h) => h(target)); };
529++ }
530++ }
531++}
532++
533++function _removeHandler(target, name, handler) {
534++ let tweenerHandlers = _ensureHandlers(target);
535++
536++ if (name in tweenerHandlers) {
537++ let handlers = tweenerHandlers[name];
538++ let handlerIndex = handlers.indexOf(handler);
539++
540++ while (handlerIndex > -1) {
541++ handlers.splice(handlerIndex, 1);
542++ handlerIndex = handlers.indexOf(handler);
543++ }
544++ }
545+ }
546+
547+ function _actorDestroyed(target) {
548+diff --git a/js/ui/workspace.js b/js/ui/workspace.js
549+index 1e121b7..8836537 100644
550+--- a/js/ui/workspace.js
551++++ b/js/ui/workspace.js
552+@@ -139,14 +139,8 @@ var WindowClone = new Lang.Class({
553+
554+ this._windowClone._updateId = this.metaWindow.connect('size-changed',
555+ this._onRealWindowSizeChanged.bind(this));
556+- this._windowClone._destroyId =
557+- this.realWindow.connect('destroy', () => {
558+- // First destroy the clone and then destroy everything
559+- // This will ensure that we never see it in the
560+- // _disconnectSignals loop
561+- this._windowClone.destroy();
562+- this.destroy();
563+- });
564++ this._windowClone._destroyId = this.realWindow.connect('destroy',
565++ this.destroy.bind(this));
566+
567+ this._updateAttachedDialogs();
568+ this._computeBoundingBox();
569+@@ -310,6 +304,14 @@ var WindowClone = new Lang.Class({
570+ },
571+
572+ destroy() {
573++ this.emit('destroy');
574++
575++ // First destroy the clone and then destroy everything
576++ // This will ensure that we never see it in the _disconnectSignals loop
577++ this.metaWindow.disconnect(this._windowClone._updateId);
578++ this.realWindow.disconnect(this._windowClone._destroyId);
579++ this._windowClone.destroy();
580++
581+ this.actor.destroy();
582+ },
583+
584+@@ -1131,6 +1133,7 @@ var Workspace = new Lang.Class({
585+ // Create clones for windows that should be
586+ // visible in the Overview
587+ this._windows = [];
588++ this._windowsDestroyedIds = [];
589+ this._windowOverlays = [];
590+ for (let i = 0; i < windows.length; i++) {
591+ if (this._isOverviewWindow(windows[i])) {
592+@@ -1428,7 +1431,7 @@ var Workspace = new Lang.Class({
593+ return GLib.SOURCE_REMOVE;
594+ },
595+
596+- _doRemoveWindow(metaWin) {
597++ _doRemoveWindow(metaWin, {cloneDestroy}={cloneDestroy: true}) {
598+ let win = metaWin.get_compositor_private();
599+
600+ // find the position of the window in our list
601+@@ -1438,8 +1441,10 @@ var Workspace = new Lang.Class({
602+ return;
603+
604+ let clone = this._windows[index];
605++ clone.disconnect(this._windowsDestroyedIds[index]);
606+
607+ this._windows.splice(index, 1);
608++ this._windowsDestroyedIds.splice(index, 1);
609+ this._windowOverlays.splice(index, 1);
610+
611+ // If metaWin.get_compositor_private() returned non-NULL, that
612+@@ -1457,7 +1462,9 @@ var Workspace = new Lang.Class({
613+ scale: stageWidth / clone.actor.width
614+ };
615+ }
616+- clone.destroy();
617++
618++ if (cloneDestroy)
619++ clone.destroy();
620+
621+
622+ // We need to reposition the windows; to avoid shuffling windows
623+@@ -1800,7 +1807,11 @@ var Workspace = new Lang.Class({
624+ this._actualGeometryLater = 0;
625+ }
626+
627++ for (let index = 0; index < this._windows.length; ++index)
628++ this._windows[index].disconnect(this._windowsDestroyedIds[index]);
629++
630+ this._windows = [];
631++ this._windowsDestroyedIds = [];
632+ },
633+
634+ // Sets this.leavingOverview flag to false.
635+@@ -1848,6 +1859,9 @@ var Workspace = new Lang.Class({
636+ clone.connect('size-changed', () => {
637+ this._recalculateWindowPositions(WindowPositionFlags.NONE);
638+ });
639++ let cloneDestroyedId = clone.connect('destroy', () => {
640++ this._doRemoveWindow(clone.metaWindow, {cloneDestroy: false});
641++ });
642+
643+ this.actor.add_actor(clone.actor);
644+
645+@@ -1864,6 +1878,7 @@ var Workspace = new Lang.Class({
646+ clone.setStackAbove(this._windows[this._windows.length - 1].actor);
647+
648+ this._windows.push(clone);
649++ this._windowsDestroyedIds.push(cloneDestroyedId);
650+ this._windowOverlays.push(overlay);
651+
652+ return [clone, overlay];
653+diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js
654+index c1b4bdd..0c72e74 100644
655+--- a/js/ui/workspaceThumbnail.js
656++++ b/js/ui/workspaceThumbnail.js
657+@@ -70,12 +70,7 @@ var WindowClone = new Lang.Class({
658+
659+ this.clone._updateId = this.metaWindow.connect('position-changed',
660+ this._onPositionChanged.bind(this));
661+- this.clone._destroyId = this.realWindow.connect('destroy', () => {
662+- // First destroy the clone and then destroy everything
663+- // This will ensure that we never see it in the _disconnectSignals loop
664+- this.clone.destroy();
665+- this.destroy();
666+- });
667++ this.clone._destroyId = this.realWindow.connect('destroy', this.destroy.bind(this));
668+ this._onPositionChanged();
669+
670+ this.actor.connect('button-release-event',
671+@@ -142,6 +137,14 @@ var WindowClone = new Lang.Class({
672+ },
673+
674+ destroy() {
675++ this.emit('destroy');
676++
677++ // First destroy the clone and then destroy everything
678++ // This will ensure that we never see it in the _disconnectSignals loop
679++ this.metaWindow.disconnect(this.clone._updateId);
680++ this.realWindow.disconnect(this.clone._destroyId);
681++ this.clone.destroy();
682++
683+ this.actor.destroy();
684+ },
685+
686+@@ -285,6 +288,7 @@ var WorkspaceThumbnail = new Lang.Class({
687+
688+ // Create clones for windows that should be visible in the Overview
689+ this._windows = [];
690++ this._windowsDestroyedIds = [];
691+ this._allWindows = [];
692+ this._minimizedChangedIds = [];
693+ for (let i = 0; i < windows.length; i++) {
694+@@ -371,7 +375,7 @@ var WorkspaceThumbnail = new Lang.Class({
695+ return this._collapseFraction;
696+ },
697+
698+- _doRemoveWindow(metaWin) {
699++ _doRemoveWindow(metaWin, {cloneDestroy}={cloneDestroy: true}) {
700+ let win = metaWin.get_compositor_private();
701+
702+ // find the position of the window in our list
703+@@ -381,9 +385,13 @@ var WorkspaceThumbnail = new Lang.Class({
704+ return;
705+
706+ let clone = this._windows[index];
707++ clone.disconnect(this._windowsDestroyedIds[index]);
708++
709+ this._windows.splice(index, 1);
710++ this._windowsDestroyedIds.splice(index, 1);
711+
712+- clone.destroy();
713++ if (cloneDestroy)
714++ clone.destroy();
715+ },
716+
717+ _doAddWindow(metaWin) {
718+@@ -502,7 +510,11 @@ var WorkspaceThumbnail = new Lang.Class({
719+ this._bgManager = null;
720+ }
721+
722++ for (let index = 0; index < this._windows.length; ++index)
723++ this._windows[index].disconnect(this._windowsDestroyedIds[index]);
724++
725+ this._windows = [];
726++ this._windowsDestroyedIds = [];
727+ this.actor = null;
728+ },
729+
730+@@ -535,6 +547,10 @@ var WorkspaceThumbnail = new Lang.Class({
731+ clone.connect('drag-end', () => {
732+ Main.overview.endWindowDrag(clone.metaWindow);
733+ });
734++ let cloneDestroyedId = clone.connect('destroy', () => {
735++ this._doRemoveWindow(clone.metaWindow, {cloneDestroy: false});
736++ });
737++
738+ this._contents.add_actor(clone.actor);
739+
740+ if (this._windows.length == 0)
741+@@ -543,6 +559,7 @@ var WorkspaceThumbnail = new Lang.Class({
742+ clone.setStackAbove(this._windows[this._windows.length - 1].actor);
743+
744+ this._windows.push(clone);
745++ this._windowsDestroyedIds.push(cloneDestroyedId);
746+
747+ return clone;
748+ },
749
750=== added file 'debian/patches/popupMenu-Fix-wrong-call-to-clutter_actor_add_child.patch'
751--- debian/patches/popupMenu-Fix-wrong-call-to-clutter_actor_add_child.patch 1970-01-01 00:00:00 +0000
752+++ debian/patches/popupMenu-Fix-wrong-call-to-clutter_actor_add_child.patch 2018-04-17 10:30:40 +0000
753@@ -0,0 +1,28 @@
754+From: Mario Sanchez Prada <mario@endlessm.com>
755+Date: Mon, 16 Apr 2018 05:47:57 -0500
756+Subject: popupMenu: Fix wrong call to clutter_actor_add_child()
757+
758+Specify the horizontal alignment via the x_align property when creating
759+the StIcon, since this function expects one argument, not two.
760+
761+Origin: https://gitlab.gnome.org/GNOME/gnome-shell/commit/cdbc99e
762+---
763+ js/ui/popupMenu.js | 5 +++--
764+ 1 file changed, 3 insertions(+), 2 deletions(-)
765+
766+diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js
767+index 67b928c..83194d7 100644
768+--- a/js/ui/popupMenu.js
769++++ b/js/ui/popupMenu.js
770+@@ -394,8 +394,9 @@ var PopupImageMenuItem = new Lang.Class({
771+ _init(text, icon, params) {
772+ this.parent(params);
773+
774+- this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
775+- this.actor.add_child(this._icon, { align: St.Align.END });
776++ this._icon = new St.Icon({ style_class: 'popup-menu-icon',
777++ x_align: Clutter.ActorAlign.END });
778++ this.actor.add_child(this._icon);
779+ this.label = new St.Label({ text: text });
780+ this.actor.add_child(this.label);
781+ this.actor.label_actor = this.label;
782
783=== modified file 'debian/patches/series'
784--- debian/patches/series 2018-04-14 01:50:15 +0000
785+++ debian/patches/series 2018-04-17 10:30:40 +0000
786@@ -11,5 +11,16 @@
787 ubuntu_background_login.patch
788 ubuntu_gdm_alternatives.patch
789 ubuntu_block_mode_extension_update.patch
790-ubuntu_theme_lookup_xdg.patch
791+ui-Theme-lookup-should-respect-XDG_DATA_DIRS.patch
792 workaround_crasher_fractional_scaling.patch
793+shell-ignore-invalid-window-monitor-index.patch
794+workspaceThumbnail-only-update-_porthole-if-the-overview-.patch
795+workspaceThumbnail-rebuild-thumbnails-if-workareas-size-c.patch
796+workspaceThumbnail-initialize-porthole-based-on-workArea.patch
797+popupMenu-Fix-wrong-call-to-clutter_actor_add_child.patch
798+StIcon-only-compute-shadow-pipeline-when-the-texture-is-p.patch
799+volume-Add-back-sound-feedback-on-scroll.patch
800+js-fix-invalid-access-errors.patch
801+workspace-fix-repositioned-windows-in-activities.patch
802+st-texture-cache-Cancel-sliced-image-loading-on-target-ac.patch
803+st-texture-cache-Don-t-add-NULL-textures-to-cache.patch
804
805=== added file 'debian/patches/shell-ignore-invalid-window-monitor-index.patch'
806--- debian/patches/shell-ignore-invalid-window-monitor-index.patch 1970-01-01 00:00:00 +0000
807+++ debian/patches/shell-ignore-invalid-window-monitor-index.patch 2018-04-17 10:30:40 +0000
808@@ -0,0 +1,98 @@
809+From: Sam Spilsbury <sam@endlessm.com>
810+Date: Wed, 11 Oct 2017 05:42:04 -0500
811+Subject: shell: ignore invalid window monitor index
812+
813+windowMenu: Check if monitorIndex is valid before using it
814+
815+Calling meta_window_get_monitor on an unmanaged window may return
816+-1, so we need to check the return value.
817+
818+Fixes https://bugzilla.gnome.org/show_bug.cgi?id=788882
819+
820+keyboard: Handle case where keyboardMonitor is unset
821+
822+This may be the case where keyboardIndex is -1, which may be the
823+case where either the keyboard monitor hasn't been set yet, or
824+the keyboard is being unmanaged and meta_window_get_monitor
825+returns -1
826+
827+https://bugzilla.gnome.org/show_bug.cgi?id=788882
828+
829+layout: Remove focusMonitor, as it is unused
830+
831+It also uses focusIndex to determine which monitor to
832+return and may occassionally return undefined if focusIndex
833+was -1.
834+
835+https://bugzilla.gnome.org/show_bug.cgi?id=788882
836+
837+Bug-GNOME: https://bugzilla.gnome.org/show_bug.cgi?id=788882
838+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gnome-shell/+bug/1724439
839+Forwarded: yes
840+---
841+ js/ui/keyboard.js | 8 ++++++++
842+ js/ui/layout.js | 4 ----
843+ js/ui/windowMenu.js | 7 ++++---
844+ 3 files changed, 12 insertions(+), 7 deletions(-)
845+
846+diff --git a/js/ui/keyboard.js b/js/ui/keyboard.js
847+index e13c7b7..14f6e7b 100644
848+--- a/js/ui/keyboard.js
849++++ b/js/ui/keyboard.js
850+@@ -939,6 +939,12 @@ var Keyboard = new Lang.Class({
851+ if (this.actor == null)
852+ return;
853+ let monitor = Main.layoutManager.keyboardMonitor;
854++
855++ // monitor may be null here if the underlying keyboard monitor
856++ // index was still unset.
857++ if (!monitor)
858++ return;
859++
860+ let maxHeight = monitor.height / 3;
861+ this.actor.width = monitor.width;
862+ this.actor.height = maxHeight;
863+@@ -1001,6 +1007,8 @@ var Keyboard = new Lang.Class({
864+ if (!this._enabled)
865+ return;
866+
867++
868++
869+ this._clearShowIdle();
870+ this._keyboardRequested = true;
871+
872+diff --git a/js/ui/layout.js b/js/ui/layout.js
873+index 3d53bd4..cf0dad0 100644
874+--- a/js/ui/layout.js
875++++ b/js/ui/layout.js
876+@@ -564,10 +564,6 @@ var LayoutManager = new Lang.Class({
877+ return i;
878+ },
879+
880+- get focusMonitor() {
881+- return this.monitors[this.focusIndex];
882+- },
883+-
884+ set keyboardIndex(v) {
885+ this._keyboardIndex = v;
886+ this._updateKeyboardBox();
887+diff --git a/js/ui/windowMenu.js b/js/ui/windowMenu.js
888+index f0e564b..9bd7d19 100644
889+--- a/js/ui/windowMenu.js
890++++ b/js/ui/windowMenu.js
891+@@ -128,11 +128,12 @@ var WindowMenu = new Lang.Class({
892+
893+ let screen = global.screen;
894+ let nMonitors = screen.get_n_monitors();
895+- if (nMonitors > 1) {
896++ let monitorIndex = window.get_monitor();
897++ // meta_window_get_monitor can return -1, so handle that case
898++ // appropriately.
899++ if (nMonitors > 1 && monitorIndex >= 0) {
900+ this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
901+
902+- let monitorIndex = window.get_monitor();
903+-
904+ let dir = Meta.ScreenDirection.UP;
905+ let upMonitorIndex =
906+ screen.get_monitor_neighbor_index(monitorIndex, dir);
907
908=== added file 'debian/patches/st-texture-cache-Cancel-sliced-image-loading-on-target-ac.patch'
909--- debian/patches/st-texture-cache-Cancel-sliced-image-loading-on-target-ac.patch 1970-01-01 00:00:00 +0000
910+++ debian/patches/st-texture-cache-Cancel-sliced-image-loading-on-target-ac.patch 2018-04-17 10:30:40 +0000
911@@ -0,0 +1,118 @@
912+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
913+Date: Wed, 29 Nov 2017 19:48:02 -0600
914+Subject: st-texture-cache: Cancel sliced image loading on target actor
915+ destroy
916+
917+It might happen that the target clutter actor that we return on call
918+of st_texture_cache_load_sliced_image might be destroyed while the
919+loading task is still running. To protect from this, let's connect
920+to "destroy" signal and when this happens we use a cancellable to
921+stop the task.
922+
923+This allows to safely reuse the return value of this function to
924+cancel the execution and avoiding that load_callback is called
925+even for a request that is not anymore under our control.
926+
927+Forwarded: yes, https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/5
928+---
929+ src/st/st-texture-cache.c | 30 ++++++++++++++++++++++++++----
930+ 1 file changed, 26 insertions(+), 4 deletions(-)
931+
932+diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c
933+index e8a832d..13b019e 100644
934+--- a/src/st/st-texture-cache.c
935++++ b/src/st/st-texture-cache.c
936+@@ -1019,6 +1019,7 @@ typedef struct {
937+ gint grid_width, grid_height;
938+ gint scale_factor;
939+ ClutterActor *actor;
940++ GCancellable *cancellable;
941+ GFunc load_callback;
942+ gpointer load_callback_data;
943+ } AsyncImageData;
944+@@ -1029,10 +1030,21 @@ on_data_destroy (gpointer data)
945+ AsyncImageData *d = (AsyncImageData *)data;
946+ g_object_unref (d->gfile);
947+ g_object_unref (d->actor);
948++ g_object_unref (d->cancellable);
949+ g_free (d);
950+ }
951+
952+ static void
953++on_sliced_image_actor_destroyed (ClutterActor *actor,
954++ gpointer data)
955++{
956++ GTask *task = data;
957++ GCancellable *cancellable = g_task_get_cancellable (task);
958++
959++ g_cancellable_cancel (cancellable);
960++}
961++
962++static void
963+ on_sliced_image_loaded (GObject *source_object,
964+ GAsyncResult *res,
965+ gpointer user_data)
966+@@ -1042,7 +1054,7 @@ on_sliced_image_loaded (GObject *source_object,
967+ GTask *task = G_TASK (res);
968+ GList *list, *pixbufs;
969+
970+- if (g_task_had_error (task))
971++ if (g_task_had_error (task) || g_cancellable_is_cancelled (data->cancellable))
972+ return;
973+
974+ pixbufs = g_task_propagate_pointer (task, NULL);
975+@@ -1056,6 +1068,10 @@ on_sliced_image_loaded (GObject *source_object,
976+
977+ g_list_free_full (pixbufs, g_object_unref);
978+
979++ g_signal_handlers_disconnect_by_func (data->actor,
980++ on_sliced_image_actor_destroyed,
981++ task);
982++
983+ if (data->load_callback != NULL)
984+ data->load_callback (cache, data->load_callback_data);
985+ }
986+@@ -1093,7 +1109,7 @@ load_sliced_image (GTask *result,
987+ gchar *buffer = NULL;
988+ gsize length;
989+
990+- g_assert (!cancellable);
991++ g_assert (cancellable);
992+
993+ data = task_data;
994+ g_assert (data);
995+@@ -1101,7 +1117,7 @@ load_sliced_image (GTask *result,
996+ loader = gdk_pixbuf_loader_new ();
997+ g_signal_connect (loader, "size-prepared", G_CALLBACK (on_loader_size_prepared), data);
998+
999+- if (!g_file_load_contents (data->gfile, NULL, &buffer, &length, NULL, &error))
1000++ if (!g_file_load_contents (data->gfile, cancellable, &buffer, &length, NULL, &error))
1001+ {
1002+ g_warning ("Failed to open sliced image: %s", error->message);
1003+ goto out;
1004+@@ -1169,6 +1185,7 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
1005+ AsyncImageData *data;
1006+ GTask *result;
1007+ ClutterActor *actor = clutter_actor_new ();
1008++ GCancellable *cancellable = g_cancellable_new ();
1009+
1010+ data = g_new0 (AsyncImageData, 1);
1011+ data->grid_width = grid_width;
1012+@@ -1176,11 +1193,16 @@ st_texture_cache_load_sliced_image (StTextureCache *cache,
1013+ data->scale_factor = scale;
1014+ data->gfile = g_object_ref (file);
1015+ data->actor = actor;
1016++ data->cancellable = cancellable;
1017+ data->load_callback = load_callback;
1018+ data->load_callback_data = user_data;
1019+ g_object_ref (G_OBJECT (actor));
1020+
1021+- result = g_task_new (cache, NULL, on_sliced_image_loaded, data);
1022++ result = g_task_new (cache, cancellable, on_sliced_image_loaded, data);
1023++
1024++ g_signal_connect (actor, "destroy",
1025++ G_CALLBACK (on_sliced_image_actor_destroyed), result);
1026++
1027+ g_task_set_task_data (result, data, on_data_destroy);
1028+ g_task_run_in_thread (result, load_sliced_image);
1029+
1030
1031=== added file 'debian/patches/st-texture-cache-Don-t-add-NULL-textures-to-cache.patch'
1032--- debian/patches/st-texture-cache-Don-t-add-NULL-textures-to-cache.patch 1970-01-01 00:00:00 +0000
1033+++ debian/patches/st-texture-cache-Don-t-add-NULL-textures-to-cache.patch 2018-04-17 10:30:40 +0000
1034@@ -0,0 +1,92 @@
1035+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
1036+Date: Tue, 17 Apr 2018 04:43:34 -0500
1037+Subject: st-texture-cache: Don't add NULL textures to cache
1038+
1039+This might cause a crash when cleaning up the cache as the hash table has
1040+cogl_object_unref as DestroyNotify function but that assumes that
1041+the passed object is a valid CoglObject.
1042+
1043+st-texture-cache: Save cairo surfaces to a different map
1044+
1045+The default keyed_surface is meant to handle CoglTextures thus we can't
1046+add cairo surfaces to it, as the DestroyNotify function won't handle them.
1047+
1048+Then the quicker way is to just add another Hash table for handling
1049+such types of textures, with proper destroy function.
1050+
1051+Forwarded: yes, https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/79
1052+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/210
1053+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gnome-shell/+bug/1754445
1054+---
1055+ src/st/st-texture-cache.c | 16 ++++++++++++++--
1056+ 1 file changed, 14 insertions(+), 2 deletions(-)
1057+
1058+diff --git a/src/st/st-texture-cache.c b/src/st/st-texture-cache.c
1059+index 13b019e..168473b 100644
1060+--- a/src/st/st-texture-cache.c
1061++++ b/src/st/st-texture-cache.c
1062+@@ -37,6 +37,7 @@ struct _StTextureCachePrivate
1063+
1064+ /* Things that were loaded with a cache policy != NONE */
1065+ GHashTable *keyed_cache; /* char * -> CoglTexture* */
1066++ GHashTable *surfaces_keyed_cache; /* char * -> cairo_surface_t* */
1067+
1068+ /* Presently this is used to de-duplicate requests for GIcons and async URIs. */
1069+ GHashTable *outstanding_requests; /* char * -> AsyncTextureLoadData * */
1070+@@ -145,6 +146,10 @@ st_texture_cache_init (StTextureCache *self)
1071+
1072+ self->priv->keyed_cache = g_hash_table_new_full (g_str_hash, g_str_equal,
1073+ g_free, cogl_object_unref);
1074++ self->priv->surfaces_keyed_cache = g_hash_table_new_full (g_str_hash,
1075++ g_str_equal,
1076++ g_free,
1077++ (GDestroyNotify) cairo_surface_destroy);
1078+ self->priv->outstanding_requests = g_hash_table_new_full (g_str_hash, g_str_equal,
1079+ g_free, NULL);
1080+ self->priv->file_monitors = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal,
1081+@@ -166,6 +171,7 @@ st_texture_cache_dispose (GObject *object)
1082+ }
1083+
1084+ g_clear_pointer (&self->priv->keyed_cache, g_hash_table_destroy);
1085++ g_clear_pointer (&self->priv->surfaces_keyed_cache, g_hash_table_destroy);
1086+ g_clear_pointer (&self->priv->outstanding_requests, g_hash_table_destroy);
1087+ g_clear_pointer (&self->priv->file_monitors, g_hash_table_destroy);
1088+
1089+@@ -520,6 +526,8 @@ finish_texture_load (AsyncTextureLoadData *data,
1090+ goto out;
1091+
1092+ texdata = pixbuf_to_cogl_texture (pixbuf);
1093++ if (!texdata)
1094++ goto out;
1095+
1096+ if (data->policy != ST_TEXTURE_CACHE_POLICY_NONE)
1097+ {
1098+@@ -1295,6 +1303,9 @@ st_texture_cache_load_file_sync_to_cogl_texture (StTextureCache *cache,
1099+ texdata = pixbuf_to_cogl_texture (pixbuf);
1100+ g_object_unref (pixbuf);
1101+
1102++ if (!texdata)
1103++ goto out;
1104++
1105+ if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
1106+ {
1107+ cogl_object_ref (texdata);
1108+@@ -1326,7 +1337,7 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
1109+
1110+ key = g_strdup_printf (CACHE_PREFIX_FILE_FOR_CAIRO "%u", g_file_hash (file));
1111+
1112+- surface = g_hash_table_lookup (cache->priv->keyed_cache, key);
1113++ surface = g_hash_table_lookup (cache->priv->surfaces_keyed_cache, key);
1114+
1115+ if (surface == NULL)
1116+ {
1117+@@ -1340,7 +1351,8 @@ st_texture_cache_load_file_sync_to_cairo_surface (StTextureCache *cache,
1118+ if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
1119+ {
1120+ cairo_surface_reference (surface);
1121+- g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), surface);
1122++ g_hash_table_insert (cache->priv->surfaces_keyed_cache,
1123++ g_strdup (key), surface);
1124+ }
1125+ }
1126+ else
1127
1128=== added file 'debian/patches/volume-Add-back-sound-feedback-on-scroll.patch'
1129--- debian/patches/volume-Add-back-sound-feedback-on-scroll.patch 1970-01-01 00:00:00 +0000
1130+++ debian/patches/volume-Add-back-sound-feedback-on-scroll.patch 2018-04-17 10:30:40 +0000
1131@@ -0,0 +1,106 @@
1132+From: =?utf-8?q?Florian_M=C3=BCllner?= <fmuellner@gnome.org>
1133+Date: Fri, 23 Feb 2018 16:58:22 -0600
1134+Subject: volume: Add back sound feedback on scroll
1135+
1136+Commit 8d4855f1008 accidentally removed the volume change feedback
1137+for scroll events. Add it back to be consistent again with moving
1138+the slider via arrow keys, slider drags/clicks and gsd's media keys
1139+handling.
1140+
1141+https://gitlab.gnome.org/GNOME/gnome-shell/issues/53
1142+
1143+volume: Only emit sound feedback after volume changes
1144+
1145+gnome-settings-daemon doesn't play the volume change sound when
1146+the volume stayed the same (that is, it is already at its maximum
1147+or minimum). This looks like the right thing to do, so copy its
1148+behavior.
1149+
1150+https://gitlab.gnome.org/GNOME/gnome-shell/issues/53
1151+
1152+slider: Stop emulating drags in key handling
1153+
1154+Emitting ::drag-end after changing the slider value via arrow keys
1155+was a cheap way to make the sound feedback work for keyboard input.
1156+But now that the volume indicator plays the sound on ::value-changed
1157+as well, we can stop doing that - after all, key presses aren't drags.
1158+
1159+Besides that, this will make the limiting of feedback to actual volume
1160+changes from the previous commit work for key events as well.
1161+
1162+https://gitlab.gnome.org/GNOME/gnome-shell/issues/53
1163+
1164+Bug-GNOME: https://gitlab.gnome.org/GNOME/gnome-shell/issues/53
1165+Forwarded: yes, https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/51
1166+---
1167+ js/ui/slider.js | 2 --
1168+ js/ui/status/volume.js | 19 ++++++++++++++++++-
1169+ 2 files changed, 18 insertions(+), 3 deletions(-)
1170+
1171+diff --git a/js/ui/slider.js b/js/ui/slider.js
1172+index 9853929..30295b4 100644
1173+--- a/js/ui/slider.js
1174++++ b/js/ui/slider.js
1175+@@ -232,9 +232,7 @@ var Slider = new Lang.Class({
1176+ let delta = key == Clutter.KEY_Right ? 0.1 : -0.1;
1177+ this._value = Math.max(0, Math.min(this._value + delta, 1));
1178+ this.actor.queue_repaint();
1179+- this.emit('drag-begin');
1180+ this.emit('value-changed', this._value);
1181+- this.emit('drag-end');
1182+ return Clutter.EVENT_STOP;
1183+ }
1184+ return Clutter.EVENT_PROPAGATE;
1185+diff --git a/js/ui/status/volume.js b/js/ui/status/volume.js
1186+index 65c4c42..c0f9cf3 100644
1187+--- a/js/ui/status/volume.js
1188++++ b/js/ui/status/volume.js
1189+@@ -4,6 +4,7 @@ const Clutter = imports.gi.Clutter;
1190+ const Lang = imports.lang;
1191+ const Gio = imports.gi.Gio;
1192+ const Gvc = imports.gi.Gvc;
1193++const Mainloop = imports.mainloop;
1194+ const St = imports.gi.St;
1195+ const Signals = imports.signals;
1196+
1197+@@ -36,9 +37,16 @@ var StreamSlider = new Lang.Class({
1198+
1199+ this.item = new PopupMenu.PopupBaseMenuItem({ activate: false });
1200+
1201++ this._inDrag = false;
1202++ this._notifyVolumeChangeId = 0;
1203++
1204+ this._slider = new Slider.Slider(0);
1205++ this._slider.connect('drag-begin', () => { this._inDrag = true; });
1206+ this._slider.connect('value-changed', this._sliderChanged.bind(this));
1207+- this._slider.connect('drag-end', this._notifyVolumeChange.bind(this));
1208++ this._slider.connect('drag-end', () => {
1209++ this._inDrag = false;
1210++ this._notifyVolumeChange();
1211++ });
1212+
1213+ this._icon = new St.Icon({ style_class: 'popup-menu-icon' });
1214+ this.item.actor.add(this._icon);
1215+@@ -135,6 +143,7 @@ var StreamSlider = new Lang.Class({
1216+
1217+ let volume = value * this._get_control_max_volume();
1218+ let prevMuted = this._stream.is_muted;
1219++ let prevVolume = this._stream.volume;
1220+ if (volume < 1) {
1221+ this._stream.volume = 0;
1222+ if (!prevMuted)
1223+@@ -145,6 +154,14 @@ var StreamSlider = new Lang.Class({
1224+ this._stream.change_is_muted(false);
1225+ }
1226+ this._stream.push_volume();
1227++
1228++ let volumeChanged = this._stream.volume != prevVolume;
1229++ if (volumeChanged && !this._notifyVolumeChangeId && !this._inDrag)
1230++ this._notifyVolumeChangeId = Mainloop.timeout_add(30, () => {
1231++ this._notifyVolumeChange();
1232++ this._notifyVolumeChangeId = 0;
1233++ return GLib.SOURCE_REMOVE;
1234++ });
1235+ },
1236+
1237+ _notifyVolumeChange() {
1238
1239=== added file 'debian/patches/workspace-fix-repositioned-windows-in-activities.patch'
1240--- debian/patches/workspace-fix-repositioned-windows-in-activities.patch 1970-01-01 00:00:00 +0000
1241+++ debian/patches/workspace-fix-repositioned-windows-in-activities.patch 2018-04-17 10:30:40 +0000
1242@@ -0,0 +1,148 @@
1243+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
1244+Date: Fri, 19 Jan 2018 08:00:10 -0600
1245+Subject: workspace: fix repositioned windows in activities
1246+
1247+workspace: Recompute bounding box on window 'position-changed'
1248+
1249+We need to update the clone position if window size changed
1250+also, rename meta window 'size-changed' callback accordingly.
1251+
1252+https://bugzilla.gnome.org/show_bug.cgi?id=792681
1253+
1254+workspaceThumbnail: Sync clone position changes with actor
1255+
1256+We need to update the clone position if window actor (not the meta window)
1257+position changed.
1258+
1259+https://bugzilla.gnome.org/show_bug.cgi?id=792681
1260+
1261+Bug-GNOME: https://bugzilla.gnome.org/show_bug.cgi?id=776588
1262+Bug-Ubuntu: https://bugs.launchpad.net/gnome-shell/+bug/1653153
1263+Forwarded: yes, https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/8
1264+---
1265+ js/ui/workspace.js | 28 +++++++++++++++-------------
1266+ js/ui/workspaceThumbnail.js | 9 ++++-----
1267+ 2 files changed, 19 insertions(+), 18 deletions(-)
1268+
1269+diff --git a/js/ui/workspace.js b/js/ui/workspace.js
1270+index 8836537..f06b78e 100644
1271+--- a/js/ui/workspace.js
1272++++ b/js/ui/workspace.js
1273+@@ -137,8 +137,10 @@ var WindowClone = new Lang.Class({
1274+ this._dragSlot = [0, 0, 0, 0];
1275+ this._stackAbove = null;
1276+
1277+- this._windowClone._updateId = this.metaWindow.connect('size-changed',
1278+- this._onRealWindowSizeChanged.bind(this));
1279++ this._windowClone._sizeChangedId = this.metaWindow.connect('size-changed',
1280++ this._onMetaWindowSizeChanged.bind(this));
1281++ this._windowClone._posChangedId = this.metaWindow.connect('position-changed',
1282++ this._computeBoundingBox.bind(this));
1283+ this._windowClone._destroyId = this.realWindow.connect('destroy',
1284+ this.destroy.bind(this));
1285+
1286+@@ -200,8 +202,7 @@ var WindowClone = new Lang.Class({
1287+
1288+ addAttachedDialog(win) {
1289+ this._doAddAttachedDialog(win, win.get_compositor_private());
1290+- this._computeBoundingBox();
1291+- this.emit('size-changed');
1292++ this._onMetaWindowSizeChanged();
1293+ },
1294+
1295+ hasAttachedDialogs() {
1296+@@ -210,15 +211,14 @@ var WindowClone = new Lang.Class({
1297+
1298+ _doAddAttachedDialog(metaWin, realWin) {
1299+ let clone = new Clutter.Clone({ source: realWin });
1300+- clone._updateId = metaWin.connect('size-changed', () => {
1301+- this._computeBoundingBox();
1302+- this.emit('size-changed');
1303+- });
1304++ clone._sizeChangedId = metaWin.connect('size-changed',
1305++ this._onMetaWindowSizeChanged.bind(this));
1306++ clone._posChangedId = metaWin.connect('position-changed',
1307++ this._onMetaWindowSizeChanged.bind(this));
1308+ clone._destroyId = realWin.connect('destroy', () => {
1309+ clone.destroy();
1310+
1311+- this._computeBoundingBox();
1312+- this.emit('size-changed');
1313++ this._onMetaWindowSizeChanged.bind(this);
1314+ });
1315+ this.actor.add_child(clone);
1316+ },
1317+@@ -308,7 +308,8 @@ var WindowClone = new Lang.Class({
1318+
1319+ // First destroy the clone and then destroy everything
1320+ // This will ensure that we never see it in the _disconnectSignals loop
1321+- this.metaWindow.disconnect(this._windowClone._updateId);
1322++ this.metaWindow.disconnect(this._windowClone._sizeChangedId);
1323++ this.metaWindow.disconnect(this._windowClone._posChangedId);
1324+ this.realWindow.disconnect(this._windowClone._destroyId);
1325+ this._windowClone.destroy();
1326+
1327+@@ -323,12 +324,13 @@ var WindowClone = new Lang.Class({
1328+ else
1329+ realWindow = child.source;
1330+
1331+- realWindow.meta_window.disconnect(child._updateId);
1332++ realWindow.meta_window.disconnect(child._sizeChangedId);
1333++ realWindow.meta_window.disconnect(child._posChangedId);
1334+ realWindow.disconnect(child._destroyId);
1335+ });
1336+ },
1337+
1338+- _onRealWindowSizeChanged() {
1339++ _onMetaWindowSizeChanged() {
1340+ this._computeBoundingBox();
1341+ this.emit('size-changed');
1342+ },
1343+diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js
1344+index 0c72e74..4db8c19 100644
1345+--- a/js/ui/workspaceThumbnail.js
1346++++ b/js/ui/workspaceThumbnail.js
1347+@@ -68,7 +68,7 @@ var WindowClone = new Lang.Class({
1348+ this.realWindow = realWindow;
1349+ this.metaWindow = realWindow.meta_window;
1350+
1351+- this.clone._updateId = this.metaWindow.connect('position-changed',
1352++ this.clone._updateId = this.realWindow.connect('notify::position',
1353+ this._onPositionChanged.bind(this));
1354+ this.clone._destroyId = this.realWindow.connect('destroy', this.destroy.bind(this));
1355+ this._onPositionChanged();
1356+@@ -141,7 +141,7 @@ var WindowClone = new Lang.Class({
1357+
1358+ // First destroy the clone and then destroy everything
1359+ // This will ensure that we never see it in the _disconnectSignals loop
1360+- this.metaWindow.disconnect(this.clone._updateId);
1361++ this.realWindow.disconnect(this.clone._updateId);
1362+ this.realWindow.disconnect(this.clone._destroyId);
1363+ this.clone.destroy();
1364+
1365+@@ -156,7 +156,7 @@ var WindowClone = new Lang.Class({
1366+ let clone = new Clutter.Clone({ source: realDialog });
1367+ this._updateDialogPosition(realDialog, clone);
1368+
1369+- clone._updateId = metaDialog.connect('position-changed', dialog => {
1370++ clone._updateId = metaDialog.connect('notify::position', dialog => {
1371+ this._updateDialogPosition(dialog, clone);
1372+ });
1373+ clone._destroyId = realDialog.connect('destroy', () => {
1374+@@ -174,7 +174,6 @@ var WindowClone = new Lang.Class({
1375+ },
1376+
1377+ _onPositionChanged() {
1378+- let rect = this.metaWindow.get_frame_rect();
1379+ this.actor.set_position(this.realWindow.x, this.realWindow.y);
1380+ },
1381+
1382+@@ -182,7 +181,7 @@ var WindowClone = new Lang.Class({
1383+ this.actor.get_children().forEach(child => {
1384+ let realWindow = child.source;
1385+
1386+- realWindow.meta_window.disconnect(child._updateId);
1387++ realWindow.disconnect(child._updateId);
1388+ realWindow.disconnect(child._destroyId);
1389+ });
1390+ },
1391
1392=== added file 'debian/patches/workspaceThumbnail-initialize-porthole-based-on-workArea.patch'
1393--- debian/patches/workspaceThumbnail-initialize-porthole-based-on-workArea.patch 1970-01-01 00:00:00 +0000
1394+++ debian/patches/workspaceThumbnail-initialize-porthole-based-on-workArea.patch 2018-04-17 10:30:40 +0000
1395@@ -0,0 +1,36 @@
1396+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
1397+Date: Fri, 19 Jan 2018 10:37:20 -0600
1398+Subject: workspaceThumbnail: initialize porthole based on workArea
1399+
1400+https://bugzilla.gnome.org/show_bug.cgi?id=792687
1401+
1402+Bug-GNOME: https://bugzilla.gnome.org/show_bug.cgi?id=792687
1403+Origin: https://gitlab.gnome.org/GNOME/gnome-shell/commit/b99e304
1404+---
1405+ js/ui/workspaceThumbnail.js | 6 ++----
1406+ 1 file changed, 2 insertions(+), 4 deletions(-)
1407+
1408+diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js
1409+index 3dffd12..c1b4bdd 100644
1410+--- a/js/ui/workspaceThumbnail.js
1411++++ b/js/ui/workspaceThumbnail.js
1412+@@ -275,8 +275,8 @@ var WorkspaceThumbnail = new Lang.Class({
1413+
1414+ this._createBackground();
1415+
1416+- let monitor = Main.layoutManager.primaryMonitor;
1417+- this.setPorthole(monitor.x, monitor.y, monitor.width, monitor.height);
1418++ let workArea = Main.layoutManager.getWorkAreaForMonitor(this.monitorIndex);
1419++ this.setPorthole(workArea.x, workArea.y, workArea.width, workArea.height);
1420+
1421+ let windows = global.get_window_actors().filter(actor => {
1422+ let win = actor.meta_window;
1423+@@ -321,8 +321,6 @@ var WorkspaceThumbnail = new Lang.Class({
1424+ },
1425+
1426+ setPorthole(x, y, width, height) {
1427+- this._portholeX = x;
1428+- this._portholeY = y;
1429+ this.actor.set_size(width, height);
1430+ this._contents.set_position(-x, -y);
1431+ },
1432
1433=== added file 'debian/patches/workspaceThumbnail-only-update-_porthole-if-the-overview-.patch'
1434--- debian/patches/workspaceThumbnail-only-update-_porthole-if-the-overview-.patch 1970-01-01 00:00:00 +0000
1435+++ debian/patches/workspaceThumbnail-only-update-_porthole-if-the-overview-.patch 2018-04-17 10:30:40 +0000
1436@@ -0,0 +1,29 @@
1437+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
1438+Date: Fri, 19 Jan 2018 09:31:01 -0600
1439+Subject: workspaceThumbnail: only update _porthole if the overview is visible
1440+
1441+Otherwise it happens that porthole is computed again after that the
1442+overlay is hidden (triggered by a layout reallocation) and thus not
1443+regenerated again afterwards.
1444+
1445+https://bugzilla.gnome.org/show_bug.cgi?id=792687
1446+
1447+Bug-GNOME: https://bugzilla.gnome.org/show_bug.cgi?id=792687
1448+Origin: https://gitlab.gnome.org/GNOME/gnome-shell/commit/5fcf40b
1449+---
1450+ js/ui/workspaceThumbnail.js | 2 +-
1451+ 1 file changed, 1 insertion(+), 1 deletion(-)
1452+
1453+diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js
1454+index 7d5d2c0..5565a1e 100644
1455+--- a/js/ui/workspaceThumbnail.js
1456++++ b/js/ui/workspaceThumbnail.js
1457+@@ -1159,7 +1159,7 @@ var ThumbnailsBox = new Lang.Class({
1458+ // The "porthole" is the portion of the screen that we show in the
1459+ // workspaces
1460+ _ensurePorthole() {
1461+- if (!Main.layoutManager.primaryMonitor)
1462++ if (!Main.layoutManager.primaryMonitor || !Main.overview.visible)
1463+ return false;
1464+
1465+ if (!this._porthole)
1466
1467=== added file 'debian/patches/workspaceThumbnail-rebuild-thumbnails-if-workareas-size-c.patch'
1468--- debian/patches/workspaceThumbnail-rebuild-thumbnails-if-workareas-size-c.patch 1970-01-01 00:00:00 +0000
1469+++ debian/patches/workspaceThumbnail-rebuild-thumbnails-if-workareas-size-c.patch 2018-04-17 10:30:40 +0000
1470@@ -0,0 +1,64 @@
1471+From: =?utf-8?b?Ik1hcmNvIFRyZXZpc2FuIChUcmV2acOxbyki?= <mail@3v1n0.net>
1472+Date: Fri, 19 Jan 2018 09:39:13 -0600
1473+Subject: workspaceThumbnail: rebuild thumbnails if workareas size changed
1474+
1475+https://bugzilla.gnome.org/show_bug.cgi?id=792687
1476+
1477+Origin: https://gitlab.gnome.org/GNOME/gnome-shell/commit/c29bd46
1478+Bug-GNOME: https://bugzilla.gnome.org/show_bug.cgi?id=792687
1479+---
1480+ js/ui/workspaceThumbnail.js | 21 ++++++++++++++++-----
1481+ 1 file changed, 16 insertions(+), 5 deletions(-)
1482+
1483+diff --git a/js/ui/workspaceThumbnail.js b/js/ui/workspaceThumbnail.js
1484+index 5565a1e..3dffd12 100644
1485+--- a/js/ui/workspaceThumbnail.js
1486++++ b/js/ui/workspaceThumbnail.js
1487+@@ -675,11 +675,7 @@ var ThumbnailsBox = new Lang.Class({
1488+ this._settings.connect('changed::dynamic-workspaces',
1489+ this._updateSwitcherVisibility.bind(this));
1490+
1491+- Main.layoutManager.connect('monitors-changed', () => {
1492+- this._destroyThumbnails();
1493+- if (Main.overview.visible)
1494+- this._createThumbnails();
1495+- });
1496++ Main.layoutManager.connect('monitors-changed', this._rebuildThumbnails.bind(this));
1497+ },
1498+
1499+ _updateSwitcherVisibility() {
1500+@@ -872,6 +868,9 @@ var ThumbnailsBox = new Lang.Class({
1501+ Main.overview.connect('windows-restacked',
1502+ this._syncStacking.bind(this));
1503+
1504++ this._workareasChangedId =
1505++ global.screen.connect('workareas-changed', this._rebuildThumbnails.bind(this));
1506++
1507+ this._targetScale = 0;
1508+ this._scale = 0;
1509+ this._pendingScaleUpdate = false;
1510+@@ -901,12 +900,24 @@ var ThumbnailsBox = new Lang.Class({
1511+ this._syncStackingId = 0;
1512+ }
1513+
1514++ if (this._workareasChangedId > 0) {
1515++ global.screen.disconnect(this._workareasChangedId);
1516++ this._workareasChangedId = 0;
1517++ }
1518++
1519+ for (let w = 0; w < this._thumbnails.length; w++)
1520+ this._thumbnails[w].destroy();
1521+ this._thumbnails = [];
1522+ this._porthole = null;
1523+ },
1524+
1525++ _rebuildThumbnails() {
1526++ this._destroyThumbnails();
1527++
1528++ if (Main.overview.visible)
1529++ this._createThumbnails();
1530++ },
1531++
1532+ _workspacesChanged() {
1533+ let validThumbnails =
1534+ this._thumbnails.filter(t => t.state <= ThumbnailState.NORMAL);

Subscribers

People subscribed via source and target branches