diff options
Diffstat (limited to '')
-rw-r--r-- | extensions/vertical-workspaces/lib/windowPreview.js (renamed from extensions/vertical-workspaces/windowPreview.js) | 220 |
1 files changed, 132 insertions, 88 deletions
diff --git a/extensions/vertical-workspaces/windowPreview.js b/extensions/vertical-workspaces/lib/windowPreview.js index 013f48c..5d2bd61 100644 --- a/extensions/vertical-workspaces/windowPreview.js +++ b/extensions/vertical-workspaces/lib/windowPreview.js @@ -1,7 +1,7 @@ /** - * Vertical Workspaces + * V-Shell (Vertical Workspaces) * windowPreview.js - * + * * @author GdH <G-dH@github.com> * @copyright 2022 - 2023 * @license GPL-3.0 @@ -10,7 +10,7 @@ 'use strict'; -const { Clutter, GLib, Graphene, Meta, Shell, St } = imports.gi; +const { Clutter, GLib, GObject, Graphene, Meta, Shell, St } = imports.gi; const Main = imports.ui.main; const WindowPreview = imports.ui.windowPreview; @@ -18,40 +18,54 @@ const WindowPreview = imports.ui.windowPreview; const ExtensionUtils = imports.misc.extensionUtils; const Me = ExtensionUtils.getCurrentExtension(); -const _Util = Me.imports.util; +const _Util = Me.imports.lib.util; +const shellVersion = _Util.shellVersion; + let _overrides; const WINDOW_SCALE_TIME = imports.ui.windowPreview.WINDOW_SCALE_TIME; const WINDOW_ACTIVE_SIZE_INC = imports.ui.windowPreview.WINDOW_ACTIVE_SIZE_INC; const WINDOW_OVERLAY_FADE_TIME = imports.ui.windowPreview.WINDOW_OVERLAY_FADE_TIME; -const SEARCH_WINDOWS_PREFIX = Me.imports.windowSearchProvider.prefix; +const SEARCH_WINDOWS_PREFIX = Me.imports.lib.windowSearchProvider.prefix; const ControlsState = imports.ui.overviewControls.ControlsState; -var opt = null; +let opt; +let _firstRun = true; function update(reset = false) { - if (_overrides) { + opt = Me.imports.lib.settings.opt; + const moduleEnabled = opt.get('windowPreviewModule', true); + reset = reset || !moduleEnabled; + + // don't even touch this module if disabled + if (_firstRun && reset) + return; + + _firstRun = false; + + if (_overrides) _overrides.removeAll(); - } + if (reset) { _overrides = null; opt = null; + WindowPreview.WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 750; return; } - opt = Me.imports.settings.opt; _overrides = new _Util.Overrides(); _overrides.addOverride('WindowPreview', WindowPreview.WindowPreview.prototype, WindowPreviewCommon); - // move titles into window previews - _overrides.addInjection('WindowPreview', WindowPreview.WindowPreview.prototype, WindowPreviewInjections); + // A shorter timeout allows user to quickly cancel the selection by leaving the preview with the mouse pointer + if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW) + WindowPreview.WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 150; } -//----- WindowPreview ------------------------------------------------------------------ -var WindowPreviewInjections = { - _init: function() { +const WindowPreviewCommon = { + // injection to _init() + after__init() { const ICON_OVERLAP = 0.7; if (opt.WIN_PREVIEW_ICON_SIZE < 64) { @@ -91,7 +105,7 @@ var WindowPreviewInjections = { const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); const iconOverlap = opt.WIN_PREVIEW_ICON_SIZE * ICON_OVERLAP; // we cannot get proper title height before it gets to the stage, so 35 is estimated height + spacing - this._title.get_constraints()[1].offset = scaleFactor * (- iconOverlap - 35); + this._title.get_constraints()[1].offset = scaleFactor * (-iconOverlap - 35); this.set_child_above_sibling(this._title, null); // if window is created while the overview is shown, icon and title should be visible immediately if (Main.overview._overview._controls._stateAdjustment.value < 1) { @@ -100,34 +114,23 @@ var WindowPreviewInjections = { this._title.opacity = 0; } - if (opt.ALWAYS_SHOW_WIN_TITLES) { + if (opt.ALWAYS_SHOW_WIN_TITLES) this._title.show(); - this._stateConId = this._workspace._background._stateAdjustment.connect('notify::value', (adj) => { - this._title.opacity = Math.floor(adj.value) * 255; - }); - - } if (opt.OVERVIEW_MODE === 1) { // spread windows on hover this._wsStateConId = this.connect('enter-event', () => { // don't spread windows if user don't use pointer device at this moment - if (global.get_pointer()[0] === opt.showingPointerX) + if (global.get_pointer()[0] === opt.showingPointerX || Main.overview._overview._controls._stateAdjustment.value < 1) return; const adjustment = this._workspace._background._stateAdjustment; - if (!adjustment.value && !Main.overview._animationInProgress) { - opt.WORKSPACE_MODE = 1; - if (adjustment.value === 0) { - adjustment.value = 0; - adjustment.ease(1, { - duration: 200, - mode: Clutter.AnimationMode.EASE_OUT_QUAD - }); - } - } + opt.WORKSPACE_MODE = 1; + _Util.exposeWindows(adjustment, false); + this.disconnect(this._wsStateConId); }); } + if (opt.OVERVIEW_MODE) { // show window icon and title on ws windows spread this._stateAdjustmentSigId = this._workspace.stateAdjustment.connect('notify::value', this._updateIconScale.bind(this)); @@ -135,37 +138,52 @@ var WindowPreviewInjections = { // replace click action with custom one const action = this.get_actions()[0]; - this.remove_action(action); - const clickAction = new Clutter.ClickAction(); - clickAction.connect('clicked', (action) => { - const button = action.get_button(); + const handlerId = GObject.signal_handler_find(action, { signalId: 'clicked' }); + if (handlerId) + action.disconnect(handlerId); + + action.connect('clicked', act => { + const button = act.get_button(); if (button === Clutter.BUTTON_PRIMARY) { this._activate(); + return Clutter.EVENT_STOP; } else if (button === Clutter.BUTTON_SECONDARY) { // this action cancels long-press event and the 'long-press-cancel' event is used by the Shell to actually initiate DnD // so the dnd initiation needs to be removed if (this._longPressLater) { - Meta.later_remove(this._longPressLater); - delete this._longPressLater; + if (shellVersion >= 44) { + const laters = global.compositor.get_laters(); + laters.remove(this._longPressLater); + } else { + Meta.later_remove(this._longPressLater); + delete this._longPressLater; + } } const tracker = Shell.WindowTracker.get_default(); const appName = tracker.get_window_app(this.metaWindow).get_name(); _Util.activateSearchProvider(`${SEARCH_WINDOWS_PREFIX} ${appName}`); return Clutter.EVENT_STOP; } + return Clutter.EVENT_PROPAGATE; }); - clickAction.connect('long-press', this._onLongPress.bind(this)); - this.add_action(clickAction); - - this.connect('destroy', () => this._workspace.stateAdjustment.disconnect(this._stateConId)); - } -} + if (opt.WINDOW_ICON_CLICK_SEARCH) { + const iconClickAction = new Clutter.ClickAction(); + iconClickAction.connect('clicked', act => { + if (act.get_button() === Clutter.BUTTON_PRIMARY) { + const tracker = Shell.WindowTracker.get_default(); + const appName = tracker.get_window_app(this.metaWindow).get_name(); + _Util.activateSearchProvider(`${SEARCH_WINDOWS_PREFIX} ${appName}`); + return Clutter.EVENT_STOP; + } + return Clutter.EVENT_PROPAGATE; + }); + this._icon.add_action(iconClickAction); + } + }, -// WindowPreview -var WindowPreviewCommon = { - _updateIconScale: function() { + _updateIconScale() { let { currentState, initialState, finalState } = this._overviewAdjustment.getStateTransitionParams(); @@ -173,46 +191,60 @@ var WindowPreviewCommon = { const primaryMonitor = this.metaWindow.get_monitor() === global.display.get_primary_monitor(); const visible = - (initialState > ControlsState.HIDDEN || finalState > ControlsState.HIDDEN) - && !(finalState === ControlsState.APP_GRID && primaryMonitor); + (initialState > ControlsState.HIDDEN || finalState > ControlsState.HIDDEN) && + !(finalState === ControlsState.APP_GRID && primaryMonitor); - let scale = visible - ? (currentState >= 1 ? 1 : currentState % 1) : 0; - if (!primaryMonitor && + let scale = 0; + if (visible) + scale = currentState >= 1 ? 1 : currentState % 1; + + if (!primaryMonitor && opt.WORKSPACE_MODE && ((initialState === ControlsState.WINDOW_PICKER && finalState === ControlsState.APP_GRID) || (initialState === ControlsState.APP_GRID && finalState === ControlsState.WINDOW_PICKER)) - ) { + ) scale = 1; - /*} else if (primaryMonitor && ((initialState === ControlsState.WINDOW_PICKER && finalState === ControlsState.APP_GRID) || + else if (!primaryMonitor && opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE) + scale = 0; + /* } else if (primaryMonitor && ((initialState === ControlsState.WINDOW_PICKER && finalState === ControlsState.APP_GRID) || initialState === ControlsState.APP_GRID && finalState === ControlsState.HIDDEN)) {*/ - } else if (primaryMonitor && currentState > ControlsState.WINDOW_PICKER) { + else if (primaryMonitor && currentState > ControlsState.WINDOW_PICKER) scale = 0; - } - // in static workspace mode show icon and title on ws windows spread + + // in static workspace mode show icon and title on windows expose if (opt.OVERVIEW_MODE) { - const windowsSpread = this._workspace.stateAdjustment.value; - if (currentState === 1) { - scale = windowsSpread; - } else if (finalState === 1 || (finalState === 0 && !windowsSpread)) { + if (currentState === 1) + scale = opt.WORKSPACE_MODE; + else if (finalState === 1 || (finalState === 0 && !opt.WORKSPACE_MODE)) return; - } } - this._icon.set({ - scale_x: scale, - scale_y: scale, - }); + if (scale === 1) { + this._icon.ease({ + duration: 50, + scale_x: scale, + scale_y: scale, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + this._title.ease({ + duration: 100, + opacity: 255, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } else if (this._icon.scale_x !== 0) { + this._icon.set({ + scale_x: 0, + scale_y: 0, + }); + this._title.opacity = 0; + } // if titles are in 'always show' mode, we need to add transition between visible/invisible state // but the transition is quite expensive, // showing the titles at the end of the transition is good enough and workspace preview transition is much smoother - this._title.set({ - opacity: Math.floor(scale) * 255, - }); }, - showOverlay: function(animate) { + showOverlay(animate) { if (!this._overlayEnabled) return; @@ -220,7 +252,8 @@ var WindowPreviewCommon = { return; this._overlayShown = true; - //this._restack(); + if (!opt.ALWAYS_ACTIVATE_SELECTED_WINDOW) + this._restack(); // If we're supposed to animate and an animation in our direction // is already happening, let that one continue @@ -234,9 +267,9 @@ var WindowPreviewCommon = { ? [this._closeButton] : []; - if (!opt.ALWAYS_SHOW_WIN_TITLES) { + if (!opt.ALWAYS_SHOW_WIN_TITLES) toShow.push(this._title); - } + toShow.forEach(a => { a.opacity = 0; @@ -264,11 +297,17 @@ var WindowPreviewCommon = { this.emit('show-chrome'); }, - hideOverlay: function(animate) { + hideOverlay(animate) { if (!this._overlayShown) return; this._overlayShown = false; - //this._restack(); + if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW && Main.overview._overview.controls._stateAdjustment.value < 1) { + this.get_parent()?.set_child_above_sibling(this, null); + this._activateSelected = true; + } + + if (!opt.ALWAYS_ACTIVATE_SELECTED_WINDOW) + this._restack(); // If we're supposed to animate and an animation in our direction // is already happening, let that one continue @@ -280,9 +319,9 @@ var WindowPreviewCommon = { const toHide = [this._closeButton]; - if (!opt.ALWAYS_SHOW_WIN_TITLES) { + if (!opt.ALWAYS_SHOW_WIN_TITLES) toHide.push(this._title); - } + toHide.forEach(a => { a.opacity = 255; a.ease({ @@ -304,18 +343,24 @@ var WindowPreviewCommon = { }, _onDestroy() { - // fix for upstream bug - hideOverlay is called after windowPreview is destroyed, from the leave event callback - // but it still throws: - // clutter_actor_get_preferred_width: assertion 'CLUTTER_IS_ACTOR (self)' failed - // clutter_actor_get_preferred_height: assertion 'CLUTTER_IS_ACTOR (self)' failed - this.hideOverlay(false); + // workaround for upstream bug - hideOverlay is called after windowPreview is destroyed, from the leave event callback + // hiding the preview now avoids firing the post-mortem leave event + this.hide(); + if (this._activateSelected) + this._activate(); this.metaWindow._delegate = null; this._delegate = null; if (this._longPressLater) { - Meta.later_remove(this._longPressLater); - delete this._longPressLater; + if (shellVersion >= 44) { + const laters = global.compositor.get_laters(); + laters.remove(this._longPressLater); + delete this._longPressLater; + } else { + Meta.later_remove(this._longPressLater); + delete this._longPressLater; + } } if (this._idleHideOverlayId > 0) { @@ -328,8 +373,7 @@ var WindowPreviewCommon = { this.inDrag = false; } - if (this._stateAdjustmentSigId) { + if (this._stateAdjustmentSigId) this._workspace.stateAdjustment.disconnect(this._stateAdjustmentSigId); - } - } -} + }, +}; |