Skip to content

Commit c56008f

Browse files
committed
Overview: allocate shadow actor when position & size of window changed
1 parent 7324572 commit c56008f

File tree

3 files changed

+97
-86
lines changed

3 files changed

+97
-86
lines changed

@imports/ui/main.d.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,14 @@ export const sessionMode = {
1111
declare const layoutManager: {
1212
_startingUp: boolean,
1313
connect (_: 'startup-complete', cb: () => void)
14-
} & GObject.Object
14+
} & GObject.Object
15+
16+
declare const overview: {
17+
_overview: {
18+
controls: {
19+
_workspacesDisplay: {
20+
_leavingOverview: boolean
21+
}
22+
}
23+
}
24+
}

src/extension.ts

Lines changed: 86 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import { MonitorManager } from '@gi/Meta'
88
import { WindowPreview } from '@imports/ui/windowPreview'
99
import { WorkspaceGroup } from '@imports/ui/workspaceAnimation'
1010
import { WindowManager } from '@imports/ui/windowManager'
11-
import { WorkspacesView } from '@imports/ui/workspacesView'
1211
import BackgroundMenu from '@imports/ui/backgroundMenu'
1312
import { sessionMode, layoutManager } from '@imports/ui/main'
13+
import { overview } from '@imports/ui/main'
1414

1515
// local modules
1616
import { constants } from '@me/utils/constants'
@@ -27,21 +27,21 @@ import { WM } from '@gi/Shell'
2727
import { RoundedCornersCfg } from '@me/utils/types'
2828
import { Window, WindowActor } from '@gi/Meta'
2929
import { global } from '@global'
30+
import { registerClass } from '@gi/GObject'
3031

3132
// --------------------------------------------------------------- [end imports]
33+
3234
export class Extension {
3335
// The methods of gnome-shell to monkey patch
34-
private _orig_add_window !: (_: Window) => void
35-
private _orig_create_windows !: () => void
36-
private _orig_size_changed !: (wm: WM, actor: WindowActor) => void
37-
private _orig_scroll_to_active !: () => void
38-
private _add_background_menu !: typeof BackgroundMenu.addBackgroundMenu
36+
private _orig_add_window !: (_: Window) => void
37+
private _orig_create_windows !: () => void
38+
private _orig_size_changed !: (wm: WM, actor: WindowActor) => void
39+
private _add_background_menu !: typeof BackgroundMenu.addBackgroundMenu
3940

4041
private _services: Services | null = null
4142
private _rounded_corners_manager: RoundedCornersManager | null = null
4243

4344
private _fs_timeout_id = 0
44-
private _shadow_timeout_id = 0
4545

4646
constructor () {
4747
// Show loaded message in debug mode
@@ -54,7 +54,6 @@ export class Extension {
5454
this._orig_add_window = WindowPreview.prototype._addWindow
5555
this._orig_create_windows = WorkspaceGroup.prototype._createWindows
5656
this._orig_size_changed = WindowManager.prototype._sizeChangeWindowDone
57-
this._orig_scroll_to_active = WorkspacesView.prototype._scrollToActive
5857
this._add_background_menu = BackgroundMenu.addBackgroundMenu
5958

6059
this._services = new Services ()
@@ -121,11 +120,16 @@ export class Extension {
121120

122121
const self = this
123122

123+
// WindowPreview is a widgets that show content of window in overview.
124+
// this widget also contain a St.Label (show title of window), icon and
125+
// close button for window.
126+
//
124127
// When there is new window added into overview, this function will be
125128
// called. We need add our shadow actor and blur actor of rounded
126129
// corners window into overview.
127130
//
128131
WindowPreview.prototype._addWindow = function (window) {
132+
// call original method from gnome-shell
129133
self._orig_add_window.apply (this, [window])
130134

131135
// Make sure patched method only be called in _init() of
@@ -161,63 +165,29 @@ export class Extension {
161165

162166
_log (`Add shadow for ${window.title} in overview`)
163167

168+
// WindowPreview.window_container used to show content of window
164169
const window_container = this.window_container
165170
let first_child: Clutter.Actor | null = window_container.first_child
166171

167-
// Set linear filter to window preview in overview
168-
first_child.add_effect (new LinearFilterEffect ())
172+
// Set linear filter to let it looks better
173+
first_child?.add_effect (new LinearFilterEffect ())
169174

170-
const shadow_clone = new Clutter.Clone ({
171-
source: shadow,
172-
pivot_point: new Point ({ x: 0.5, y: 0.5 }),
173-
name: constants.OVERVIEW_SHADOW_ACTOR,
174-
})
175+
// Add a clone of shadow to overview
176+
const shadow_clone = new OverviewShadowActor (shadow, this)
175177
for (const prop of ['scale-x', 'scale-y']) {
176-
window_container.bind_property (prop, shadow_clone, prop, 2)
178+
window_container.bind_property (prop, shadow_clone, prop, 1)
177179
}
178-
179180
this.insert_child_below (shadow_clone, window_container)
180181

181-
UI.UpdateShadowOfWindowPreview (this)
182-
183-
const c = connections.get ()
184-
c.connect (this, 'notify::width', () =>
185-
UI.UpdateShadowOfWindowPreview (this)
186-
)
187-
c.connect (this, 'drag-end', () =>
188-
UI.UpdateShadowOfWindowPreview (this)
189-
)
190-
191182
// Disconnect all signals when Window preview in overview is destroy
183+
const c = connections.get ()
192184
c.connect (this, 'destroy', () => {
193185
first_child?.clear_effects ()
194186
first_child = null
195187
c.disconnect_all (this)
196188
})
197189
}
198190

199-
// When we change workspace in overview, this method will be called.
200-
// Need to recompute the Clutter.BindConstraint for shadow actor
201-
// in overview.
202-
//
203-
// Relative to #39
204-
WorkspacesView.prototype._scrollToActive = function () {
205-
self._orig_scroll_to_active.apply (this, [])
206-
207-
if (self._shadow_timeout_id != 0) {
208-
GLib.Source.remove (self._shadow_timeout_id)
209-
self._shadow_timeout_id = 0
210-
}
211-
self._shadow_timeout_id = GLib.timeout_add (0, 100, () => {
212-
for (const ws of this._workspaces) {
213-
for (const win of ws._windows) {
214-
UI.UpdateShadowOfWindowPreview (win)
215-
}
216-
}
217-
return false
218-
})
219-
}
220-
221191
// Just Like the monkey patch when enter overview, need to add shadow
222192
// actor and blur actor into WorkspaceGroup to see them when switching
223193
// workspace
@@ -306,18 +276,13 @@ export class Extension {
306276
WindowPreview.prototype._addWindow = this._orig_add_window
307277
WorkspaceGroup.prototype._createWindows = this._orig_create_windows
308278
WindowManager.prototype._sizeChangeWindowDone = this._orig_size_changed
309-
WorkspacesView.prototype._scrollToActive = this._orig_scroll_to_active
310279
BackgroundMenu.addBackgroundMenu = this._add_background_menu
311280

312281
// Remove main loop sources
313282
if (this._fs_timeout_id != 0) {
314283
GLib.Source.remove (this._fs_timeout_id)
315284
this._fs_timeout_id = 0
316285
}
317-
if (this._shadow_timeout_id != 0) {
318-
GLib.Source.remove (this._shadow_timeout_id)
319-
this._shadow_timeout_id = 0
320-
}
321286

322287
// Remove the item to open preferences page in background menu
323288
UI.RestoreBackgroundMenu ()
@@ -348,3 +313,70 @@ export class Extension {
348313
export function init () {
349314
return new Extension ()
350315
}
316+
317+
/**
318+
* Copy shadow of rounded corners window and show it in overview.
319+
* This actor will be created when window preview has created for overview
320+
*/
321+
const OverviewShadowActor = registerClass (
322+
{},
323+
class extends Clutter.Clone {
324+
_window_preview !: WindowPreview
325+
326+
/**
327+
* Create shadow actor for WindowPreview in overview
328+
* @param source the shadow actor create for rounded corners shadow
329+
* @param window_preview the window preview has shown in overview
330+
*/
331+
_init (source: Clutter.Actor, window_preview: WindowPreview): void {
332+
super._init ({
333+
source, // the source shadow actor shown in desktop
334+
name: constants.OVERVIEW_SHADOW_ACTOR,
335+
pivot_point: new Point ({ x: 0.5, y: 0.5 }),
336+
})
337+
338+
this._window_preview = window_preview
339+
}
340+
341+
/**
342+
* Recompute the position and size of shadow in overview
343+
* This virtual function will be called when we:
344+
* - entering/closing overview
345+
* - dragging window
346+
* - position and size of window preview in overview changed
347+
* @param box The bound box of shadow actor
348+
*/
349+
vfunc_allocate (box: Clutter.ActorBox): void {
350+
const leaving_overview =
351+
overview._overview.controls._workspacesDisplay._leavingOverview
352+
353+
// The window container that shown in overview
354+
const window_container_box = leaving_overview
355+
? this._window_preview.window_container.get_allocation_box ()
356+
: this._window_preview.get_allocation_box ()
357+
358+
// Meta.Window contain the all information about a window
359+
const meta_win = this._window_preview._windowActor.meta_window
360+
361+
// As we known, preview shown in overview has been scaled
362+
// in overview
363+
const container_scaled =
364+
window_container_box.get_width () /
365+
meta_win.get_frame_rect ().width
366+
const paddings =
367+
constants.SHADOW_PADDING *
368+
container_scaled *
369+
UI.WindowScaleFactor (meta_win)
370+
371+
// Setup bounds box of shadow actor
372+
box.set_origin (-paddings, -paddings)
373+
box.set_size (
374+
window_container_box.get_width () + 2 * paddings,
375+
window_container_box.get_height () + 2 * paddings
376+
)
377+
378+
// Make bounds box effect actor
379+
super.vfunc_allocate (box)
380+
}
381+
}
382+
)

src/utils/ui.ts

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// imports.gi
22
import * as Meta from '@gi/Meta'
3-
import * as Clutter from '@gi/Clutter'
43
import { Settings } from '@gi/Gio'
54

65
// gnome modules
@@ -15,7 +14,6 @@ import { constants } from '@me/utils/constants'
1514
import { global } from '@global'
1615
import * as types from '@me/utils/types'
1716
import { Actor } from '@gi/Clutter'
18-
import { WindowPreview } from '@imports/ui/windowPreview'
1917

2018
// --------------------------------------------------------------- [end imports]
2119

@@ -179,32 +177,3 @@ export function ShouldHasRoundedCorners (
179177

180178
return should_has_rounded_corners
181179
}
182-
183-
/** Compute size & position of shadow actor for window in overview */
184-
export function UpdateShadowOfWindowPreview (win_preview: WindowPreview) {
185-
const win = win_preview._windowActor.meta_window
186-
const shadow_clone = win_preview.get_child_at_index (0)
187-
188-
if (shadow_clone?.get_name () != constants.OVERVIEW_SHADOW_ACTOR) {
189-
return
190-
}
191-
192-
shadow_clone.get_constraints ().forEach ((c) => {
193-
shadow_clone.remove_constraint (c)
194-
})
195-
196-
const paddings =
197-
constants.SHADOW_PADDING *
198-
(win_preview.window_container.width / win.get_frame_rect ().width) *
199-
WindowScaleFactor (win)
200-
201-
for (let i = 0; i < 4; i++) {
202-
shadow_clone.add_constraint (
203-
new Clutter.BindConstraint ({
204-
coordinate: i,
205-
source: win_preview.window_container,
206-
offset: i < 2 ? -paddings : paddings * 2,
207-
})
208-
)
209-
}
210-
}

0 commit comments

Comments
 (0)