diff --git a/@imports/ui/main.d.ts b/@imports/ui/main.d.ts index 3bc9492e..aa91a3d8 100644 --- a/@imports/ui/main.d.ts +++ b/@imports/ui/main.d.ts @@ -11,4 +11,14 @@ export const sessionMode = { declare const layoutManager: { _startingUp: boolean, connect (_: 'startup-complete', cb: () => void) -} & GObject.Object \ No newline at end of file +} & GObject.Object + +declare const overview: { + _overview: { + controls: { + _workspacesDisplay: { + _leavingOverview: boolean + } + } + } +} \ No newline at end of file diff --git a/src/extension.ts b/src/extension.ts index cde32cae..31af985b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -8,9 +8,9 @@ import { MonitorManager } from '@gi/Meta' import { WindowPreview } from '@imports/ui/windowPreview' import { WorkspaceGroup } from '@imports/ui/workspaceAnimation' import { WindowManager } from '@imports/ui/windowManager' -import { WorkspacesView } from '@imports/ui/workspacesView' import BackgroundMenu from '@imports/ui/backgroundMenu' import { sessionMode, layoutManager } from '@imports/ui/main' +import { overview } from '@imports/ui/main' // local modules import { constants } from '@me/utils/constants' @@ -27,21 +27,21 @@ import { WM } from '@gi/Shell' import { RoundedCornersCfg } from '@me/utils/types' import { Window, WindowActor } from '@gi/Meta' import { global } from '@global' +import { registerClass } from '@gi/GObject' // --------------------------------------------------------------- [end imports] + export class Extension { // The methods of gnome-shell to monkey patch - private _orig_add_window !: (_: Window) => void - private _orig_create_windows !: () => void - private _orig_size_changed !: (wm: WM, actor: WindowActor) => void - private _orig_scroll_to_active !: () => void - private _add_background_menu !: typeof BackgroundMenu.addBackgroundMenu + private _orig_add_window !: (_: Window) => void + private _orig_create_windows !: () => void + private _orig_size_changed !: (wm: WM, actor: WindowActor) => void + private _add_background_menu !: typeof BackgroundMenu.addBackgroundMenu private _services: Services | null = null private _rounded_corners_manager: RoundedCornersManager | null = null private _fs_timeout_id = 0 - private _shadow_timeout_id = 0 constructor () { // Show loaded message in debug mode @@ -54,7 +54,6 @@ export class Extension { this._orig_add_window = WindowPreview.prototype._addWindow this._orig_create_windows = WorkspaceGroup.prototype._createWindows this._orig_size_changed = WindowManager.prototype._sizeChangeWindowDone - this._orig_scroll_to_active = WorkspacesView.prototype._scrollToActive this._add_background_menu = BackgroundMenu.addBackgroundMenu this._services = new Services () @@ -121,11 +120,16 @@ export class Extension { const self = this + // WindowPreview is a widgets that show content of window in overview. + // this widget also contain a St.Label (show title of window), icon and + // close button for window. + // // When there is new window added into overview, this function will be // called. We need add our shadow actor and blur actor of rounded // corners window into overview. // WindowPreview.prototype._addWindow = function (window) { + // call original method from gnome-shell self._orig_add_window.apply (this, [window]) // Make sure patched method only be called in _init() of @@ -161,34 +165,22 @@ export class Extension { _log (`Add shadow for ${window.title} in overview`) + // WindowPreview.window_container used to show content of window const window_container = this.window_container let first_child: Clutter.Actor | null = window_container.first_child - // Set linear filter to window preview in overview - first_child.add_effect (new LinearFilterEffect ()) + // Set linear filter to let it looks better + first_child?.add_effect (new LinearFilterEffect ()) - const shadow_clone = new Clutter.Clone ({ - source: shadow, - pivot_point: new Point ({ x: 0.5, y: 0.5 }), - name: constants.OVERVIEW_SHADOW_ACTOR, - }) + // Add a clone of shadow to overview + const shadow_clone = new OverviewShadowActor (shadow, this) for (const prop of ['scale-x', 'scale-y']) { - window_container.bind_property (prop, shadow_clone, prop, 2) + window_container.bind_property (prop, shadow_clone, prop, 1) } - this.insert_child_below (shadow_clone, window_container) - UI.UpdateShadowOfWindowPreview (this) - - const c = connections.get () - c.connect (this, 'notify::width', () => - UI.UpdateShadowOfWindowPreview (this) - ) - c.connect (this, 'drag-end', () => - UI.UpdateShadowOfWindowPreview (this) - ) - // Disconnect all signals when Window preview in overview is destroy + const c = connections.get () c.connect (this, 'destroy', () => { first_child?.clear_effects () first_child = null @@ -196,28 +188,6 @@ export class Extension { }) } - // When we change workspace in overview, this method will be called. - // Need to recompute the Clutter.BindConstraint for shadow actor - // in overview. - // - // Relative to #39 - WorkspacesView.prototype._scrollToActive = function () { - self._orig_scroll_to_active.apply (this, []) - - if (self._shadow_timeout_id != 0) { - GLib.Source.remove (self._shadow_timeout_id) - self._shadow_timeout_id = 0 - } - self._shadow_timeout_id = GLib.timeout_add (0, 100, () => { - for (const ws of this._workspaces) { - for (const win of ws._windows) { - UI.UpdateShadowOfWindowPreview (win) - } - } - return false - }) - } - // Just Like the monkey patch when enter overview, need to add shadow // actor and blur actor into WorkspaceGroup to see them when switching // workspace @@ -306,7 +276,6 @@ export class Extension { WindowPreview.prototype._addWindow = this._orig_add_window WorkspaceGroup.prototype._createWindows = this._orig_create_windows WindowManager.prototype._sizeChangeWindowDone = this._orig_size_changed - WorkspacesView.prototype._scrollToActive = this._orig_scroll_to_active BackgroundMenu.addBackgroundMenu = this._add_background_menu // Remove main loop sources @@ -314,10 +283,6 @@ export class Extension { GLib.Source.remove (this._fs_timeout_id) this._fs_timeout_id = 0 } - if (this._shadow_timeout_id != 0) { - GLib.Source.remove (this._shadow_timeout_id) - this._shadow_timeout_id = 0 - } // Remove the item to open preferences page in background menu UI.RestoreBackgroundMenu () @@ -348,3 +313,70 @@ export class Extension { export function init () { return new Extension () } + +/** + * Copy shadow of rounded corners window and show it in overview. + * This actor will be created when window preview has created for overview + */ +const OverviewShadowActor = registerClass ( + {}, + class extends Clutter.Clone { + _window_preview !: WindowPreview + + /** + * Create shadow actor for WindowPreview in overview + * @param source the shadow actor create for rounded corners shadow + * @param window_preview the window preview has shown in overview + */ + _init (source: Clutter.Actor, window_preview: WindowPreview): void { + super._init ({ + source, // the source shadow actor shown in desktop + name: constants.OVERVIEW_SHADOW_ACTOR, + pivot_point: new Point ({ x: 0.5, y: 0.5 }), + }) + + this._window_preview = window_preview + } + + /** + * Recompute the position and size of shadow in overview + * This virtual function will be called when we: + * - entering/closing overview + * - dragging window + * - position and size of window preview in overview changed + * @param box The bound box of shadow actor + */ + vfunc_allocate (box: Clutter.ActorBox): void { + const leaving_overview = + overview._overview.controls._workspacesDisplay._leavingOverview + + // The window container that shown in overview + const window_container_box = leaving_overview + ? this._window_preview.window_container.get_allocation_box () + : this._window_preview.get_allocation_box () + + // Meta.Window contain the all information about a window + const meta_win = this._window_preview._windowActor.meta_window + + // As we known, preview shown in overview has been scaled + // in overview + const container_scaled = + window_container_box.get_width () / + meta_win.get_frame_rect ().width + const paddings = + constants.SHADOW_PADDING * + container_scaled * + UI.WindowScaleFactor (meta_win) + + // Setup bounds box of shadow actor + box.set_origin (-paddings, -paddings) + box.set_size ( + window_container_box.get_width () + 2 * paddings, + window_container_box.get_height () + 2 * paddings + ) + + // Make bounds box effect actor + super.vfunc_allocate (box) + } + } +) diff --git a/src/utils/ui.ts b/src/utils/ui.ts index dda45720..2daa284a 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -1,6 +1,5 @@ // imports.gi import * as Meta from '@gi/Meta' -import * as Clutter from '@gi/Clutter' import { Settings } from '@gi/Gio' // gnome modules @@ -15,7 +14,6 @@ import { constants } from '@me/utils/constants' import { global } from '@global' import * as types from '@me/utils/types' import { Actor } from '@gi/Clutter' -import { WindowPreview } from '@imports/ui/windowPreview' // --------------------------------------------------------------- [end imports] @@ -179,32 +177,3 @@ export function ShouldHasRoundedCorners ( return should_has_rounded_corners } - -/** Compute size & position of shadow actor for window in overview */ -export function UpdateShadowOfWindowPreview (win_preview: WindowPreview) { - const win = win_preview._windowActor.meta_window - const shadow_clone = win_preview.get_child_at_index (0) - - if (shadow_clone?.get_name () != constants.OVERVIEW_SHADOW_ACTOR) { - return - } - - shadow_clone.get_constraints ().forEach ((c) => { - shadow_clone.remove_constraint (c) - }) - - const paddings = - constants.SHADOW_PADDING * - (win_preview.window_container.width / win.get_frame_rect ().width) * - WindowScaleFactor (win) - - for (let i = 0; i < 4; i++) { - shadow_clone.add_constraint ( - new Clutter.BindConstraint ({ - coordinate: i, - source: win_preview.window_container, - offset: i < 2 ? -paddings : paddings * 2, - }) - ) - } -}