From a7253052777df3bcf4b2abe9367de244cbc35da1 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 14 Apr 2024 08:15:40 +0200 Subject: Adding upstream version 20240414. Signed-off-by: Daniel Baumann --- .../46/vertical-workspaces/lib/windowManager.js | 380 +++++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 extensions/46/vertical-workspaces/lib/windowManager.js (limited to 'extensions/46/vertical-workspaces/lib/windowManager.js') diff --git a/extensions/46/vertical-workspaces/lib/windowManager.js b/extensions/46/vertical-workspaces/lib/windowManager.js new file mode 100644 index 0000000..a6f9b09 --- /dev/null +++ b/extensions/46/vertical-workspaces/lib/windowManager.js @@ -0,0 +1,380 @@ +/** + * V-Shell (Vertical Workspaces) + * windowManager.js + * + * @author GdH + * @copyright 2022 - 2024 + * @license GPL-3.0 + * + */ + +'use strict'; + +import Clutter from 'gi://Clutter'; +import Meta from 'gi://Meta'; +import GObject from 'gi://GObject'; + +import * as Main from 'resource:///org/gnome/shell/ui/main.js'; +import * as WindowManager from 'resource:///org/gnome/shell/ui/windowManager.js'; +import * as WorkspaceAnimation from 'resource:///org/gnome/shell/ui/workspaceAnimation.js'; + +const MINIMIZE_WINDOW_ANIMATION_TIME = 400; // windowManager.MINIMIZE_WINDOW_ANIMATION_TIME +const MINIMIZE_WINDOW_ANIMATION_MODE = Clutter.AnimationMode.EASE_OUT_EXPO; // WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE + +let Me; +let opt; + +export const WindowManagerModule = class { + constructor(me) { + Me = me; + opt = Me.opt; + + this._firstActivation = true; + this.moduleEnabled = false; + this._overrides = null; + + this._originalMinimizeSigId = 0; + this._minimizeSigId = 0; + this._originalUnminimizeSigId = 0; + this._unminimizeSigId = 0; + } + + cleanGlobals() { + Me = null; + opt = null; + } + + update(reset) { + this.moduleEnabled = opt.get('windowManagerModule'); + const conflict = false; + + reset = reset || !this.moduleEnabled || conflict; + + // don't even touch the original code if module disabled + if (reset && !this._firstActivation) { + this._disableModule(); + } else if (!reset) { + this._firstActivation = false; + this._activateModule(); + } + if (reset && this._firstActivation) + console.debug(' WindowManagerModule - Keeping untouched'); + } + + _activateModule() { + if (!this._overrides) + this._overrides = new Me.Util.Overrides(); + + this._overrides.addOverride('WindowManager', WindowManager.WindowManager.prototype, WindowManagerCommon); + if (opt.WS_SWITCHER_CURRENT_MONITOR) + this._overrides.addOverride('WorkspaceAnimationController', WorkspaceAnimation.WorkspaceAnimationController.prototype, WorkspaceAnimationController); + + if (!this._minimizeSigId) { + this._originalMinimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'minimize' }); + if (this._originalMinimizeSigId) { + Main.wm._shellwm.block_signal_handler(this._originalMinimizeSigId); + this._minimizeSigId = Main.wm._shellwm.connect('minimize', WindowManagerCommon._minimizeWindow.bind(Main.wm)); + } + + this._originalUnminimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'unminimize' }); + if (this._originalUnminimizeSigId) { + Main.wm._shellwm.block_signal_handler(this._originalUnminimizeSigId); + this._unminimizeSigId = Main.wm._shellwm.connect('unminimize', WindowManagerCommon._unminimizeWindow.bind(Main.wm)); + } + } + console.debug(' WindowManagerModule - Activated'); + } + + _disableModule() { + if (this._overrides) + this._overrides.removeAll(); + this._overrides = null; + + if (this._minimizeSigId) { + Main.wm._shellwm.disconnect(this._minimizeSigId); + this._minimizeSigId = 0; + } + if (this._originalMinimizeSigId) { + Main.wm._shellwm.unblock_signal_handler(this._originalMinimizeSigId); + this._originalMinimizeSigId = 0; + } + + if (this._unminimizeSigId) { + Main.wm._shellwm.disconnect(this._unminimizeSigId); + this._unminimizeSigId = 0; + } + if (this._originalUnminimizeSigId) { + Main.wm._shellwm.unblock_signal_handler(this._originalUnminimizeSigId); + this._originalUnminimizeSigId = 0; + } + + console.debug(' WindowManagerModule - Disabled'); + } +}; + +const WindowManagerCommon = { + actionMoveWorkspace(workspace) { + if (!Main.sessionMode.hasWorkspaces) + return; + + if (opt.WS_SWITCHER_CURRENT_MONITOR) + this._switchWorkspaceCurrentMonitor(workspace); + else if (!workspace.active) + workspace.activate(global.get_current_time()); + }, + + actionMoveWindow(window, workspace) { + if (!Main.sessionMode.hasWorkspaces) + return; + + if (!workspace.active) { + // This won't have any effect for "always sticky" windows + // (like desktop windows or docks) + + this._workspaceAnimation.movingWindow = window; + window.change_workspace(workspace); + + global.display.clear_mouse_mode(); + + if (opt.SWITCH_ONLY_CURRENT_MONITOR_WS) { + this._switchWorkspaceCurrentMonitor(workspace, window.get_monitor()); + window.activate(global.get_current_time()); + } else { + workspace.activate_with_focus(window, global.get_current_time()); + } + } + }, + + _switchWorkspaceCurrentMonitor(workspace, monitor) { + // const focusedWindow = global.display.get_focus_window(); + // const currentMonitor = focusedWindow ? focusedWindow.get_monitor() : global.display.get_current_monitor(); + // using focused window to determine the current monitor can lead to inconsistent behavior and switching monitors between switches + // depending on which window takes focus on each workspace + // mouse pointer is more stable and predictable source + const currentMonitor = monitor ? monitor : global.display.get_current_monitor(); + const primaryMonitor = currentMonitor === Main.layoutManager.primaryIndex; + const nMonitors = Main.layoutManager.monitors.length; + const lastIndexCorrection = Meta.prefs_get_dynamic_workspaces() ? 2 : 1; + const lastIndex = global.workspaceManager.get_n_workspaces() - lastIndexCorrection; + const targetWsIndex = workspace.index(); + const activeWs = global.workspaceManager.get_active_workspace(); + const activeWsIndex = activeWs.index(); + const diff = activeWsIndex - targetWsIndex; + + let direction = diff > 0 ? Meta.MotionDirection.UP : Meta.MotionDirection.DOWN; + if (diff === 0) { + // no actual ws to switch, but secondary monitors are always in wraparound mode so we need to get direction + direction = activeWsIndex >= lastIndex ? Meta.MotionDirection.DOWN : Meta.MotionDirection.UP; + } + if (Math.abs(diff) > 1) { + // workspace is probably in wraparound mode and just wrapped so so we need to translate direction + direction = diff > 0 ? Meta.MotionDirection.DOWN : Meta.MotionDirection.UP; + } + + if (!primaryMonitor) { + this._rotateWorkspaces(direction, currentMonitor); + return; + } + + // avoid ws rotations if the last empty dynamic workspace is involved, but allow to rotate from the last to the first, if wraparound is enabled + if (workspace !== activeWs && !((targetWsIndex > lastIndex && direction === Meta.MotionDirection.DOWN) || (activeWsIndex > lastIndex && targetWsIndex >= lastIndex))) { + for (let i = 0; i < nMonitors; i++) { + if (i !== currentMonitor) { + const oppositeDirection = direction === Meta.MotionDirection.UP ? Meta.MotionDirection.DOWN : Meta.MotionDirection.UP; + this._rotateWorkspaces(oppositeDirection, i); + } + } + } + workspace.activate(global.get_current_time()); + }, + + _rotateWorkspaces(direction = 0, monitorIndex = -1, step = 1) { + step = direction === Meta.MotionDirection.UP ? Number(step) : -step; + const monitor = monitorIndex > -1 ? monitorIndex : global.display.get_current_monitor(); + // don't move windows to the last empty workspace if dynamic workspaces are enabled + const lastIndexCorrection = Meta.prefs_get_dynamic_workspaces() ? 2 : 1; + const lastIndex = global.workspaceManager.get_n_workspaces() - lastIndexCorrection; + let windows = Me.Util.getWindows(null); + for (let win of windows.reverse()) { + // avoid moving modal windows as they move with their parents (and vice versa) immediately, before we move the parent window. + if (win.get_monitor() === monitor && !win.is_always_on_all_workspaces() && !win.is_attached_dialog() && !win.get_transient_for()) { + let wWs = win.get_workspace().index(); + wWs += step; + if (wWs < 0) + wWs = lastIndex; + if (wWs > lastIndex) + wWs = 0; + const ws = global.workspaceManager.get_workspace_by_index(wWs); + win.change_workspace(ws); + } + } + }, + + // fix for mainstream bug - fullscreen windows should minimize using opacity transition + // but its being applied directly on window actor and that doesn't work + // anyway, animation is better, even if the Activities button is not visible... + // and also add support for bottom position of the panel + _minimizeWindow(shellwm, actor) { + const types = [ + Meta.WindowType.NORMAL, + Meta.WindowType.MODAL_DIALOG, + Meta.WindowType.DIALOG, + ]; + if (!this._shouldAnimateActor(actor, types)) { + shellwm.completed_minimize(actor); + return; + } + + actor.set_scale(1.0, 1.0); + + this._minimizing.add(actor); + + /* if (actor.meta_window.is_monitor_sized()) { + actor.get_first_child().ease({ + opacity: 0, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, + onStopped: () => this._minimizeWindowDone(shellwm, actor), + }); + } else { */ + let xDest, yDest, xScale, yScale; + let [success, geom] = actor.meta_window.get_icon_geometry(); + if (success) { + xDest = geom.x; + yDest = geom.y; + xScale = geom.width / actor.width; + yScale = geom.height / actor.height; + } else { + let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()]; + if (!monitor) { + this._minimizeWindowDone(); + return; + } + xDest = monitor.x; + yDest = opt.PANEL_POSITION_TOP ? monitor.y : monitor.y + monitor.height; + if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL) + xDest += monitor.width; + xScale = 0; + yScale = 0; + } + + actor.ease({ + scale_x: xScale, + scale_y: yScale, + x: xDest, + y: yDest, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, + onStopped: () => this._minimizeWindowDone(shellwm, actor), + }); + // } + }, + + _minimizeWindowDone(shellwm, actor) { + if (this._minimizing.delete(actor)) { + actor.remove_all_transitions(); + actor.set_scale(1.0, 1.0); + actor.get_first_child().set_opacity(255); + actor.set_pivot_point(0, 0); + + shellwm.completed_minimize(actor); + } + }, + + _unminimizeWindow(shellwm, actor) { + const types = [ + Meta.WindowType.NORMAL, + Meta.WindowType.MODAL_DIALOG, + Meta.WindowType.DIALOG, + ]; + if (!this._shouldAnimateActor(actor, types)) { + shellwm.completed_unminimize(actor); + return; + } + + this._unminimizing.add(actor); + + /* if (false/* actor.meta_window.is_monitor_sized()) { + actor.opacity = 0; + actor.set_scale(1.0, 1.0); + actor.ease({ + opacity: 255, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, + onStopped: () => this._unminimizeWindowDone(shellwm, actor), + }); + } else { */ + let [success, geom] = actor.meta_window.get_icon_geometry(); + if (success) { + actor.set_position(geom.x, geom.y); + actor.set_scale(geom.width / actor.width, + geom.height / actor.height); + } else { + let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()]; + if (!monitor) { + actor.show(); + this._unminimizeWindowDone(); + return; + } + actor.set_position(monitor.x, opt.PANEL_POSITION_TOP ? monitor.y : monitor.y + monitor.height); + if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL) + actor.x += monitor.width; + actor.set_scale(0, 0); + } + + let rect = actor.meta_window.get_buffer_rect(); + let [xDest, yDest] = [rect.x, rect.y]; + + actor.show(); + actor.ease({ + scale_x: 1, + scale_y: 1, + x: xDest, + y: yDest, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, + onStopped: () => this._unminimizeWindowDone(shellwm, actor), + }); + // } + }, +}; + +const WorkspaceAnimationController = { + _prepareWorkspaceSwitch(workspaceIndices) { + if (this._switchData) + return; + + const workspaceManager = global.workspace_manager; + const nWorkspaces = workspaceManager.get_n_workspaces(); + + const switchData = {}; + + this._switchData = switchData; + switchData.monitors = []; + + switchData.gestureActivated = false; + switchData.inProgress = false; + + if (!workspaceIndices) + workspaceIndices = [...Array(nWorkspaces).keys()]; + + let monitors = opt.WS_SWITCHER_CURRENT_MONITOR + ? [Main.layoutManager.currentMonitor] : Main.layoutManager.monitors; + monitors = Meta.prefs_get_workspaces_only_on_primary() + ? [Main.layoutManager.primaryMonitor] : monitors; + + for (const monitor of monitors) { + if (Meta.prefs_get_workspaces_only_on_primary() && + monitor.index !== Main.layoutManager.primaryIndex) + continue; + + const group = new WorkspaceAnimation.MonitorGroup(monitor, workspaceIndices, this.movingWindow); + + Main.uiGroup.insert_child_above(group, global.window_group); + + switchData.monitors.push(group); + } + + Meta.disable_unredirect_for_display(global.display); + }, +}; -- cgit v1.2.3