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 --- .../vertical-workspaces/lib/workspaceThumbnail.js | 1236 -------------------- 1 file changed, 1236 deletions(-) delete mode 100644 extensions/45/vertical-workspaces/lib/workspaceThumbnail.js (limited to 'extensions/45/vertical-workspaces/lib/workspaceThumbnail.js') diff --git a/extensions/45/vertical-workspaces/lib/workspaceThumbnail.js b/extensions/45/vertical-workspaces/lib/workspaceThumbnail.js deleted file mode 100644 index 75e5250..0000000 --- a/extensions/45/vertical-workspaces/lib/workspaceThumbnail.js +++ /dev/null @@ -1,1236 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspaceThumbnail.js - * - * @author GdH - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import Clutter from 'gi://Clutter'; -import St from 'gi://St'; -import Meta from 'gi://Meta'; -import Shell from 'gi://Shell'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'; -import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'; -import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'; -import * as WorkspaceThumbnail from 'resource:///org/gnome/shell/ui/workspaceThumbnail.js'; -import * as Background from 'resource:///org/gnome/shell/ui/background.js'; - -let Me; -let opt; - -const ThumbnailState = { - NEW: 0, - EXPANDING: 1, - EXPANDED: 2, - ANIMATING_IN: 3, - NORMAL: 4, - REMOVING: 5, - ANIMATING_OUT: 6, - ANIMATED_OUT: 7, - COLLAPSING: 8, - DESTROYED: 9, -}; - -const ControlsState = OverviewControls.ControlsState; - -const WORKSPACE_CUT_SIZE = 10; -const WORKSPACE_KEEP_ALIVE_TIME = 100; - -export const WorkspaceThumbnailModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this.moduleEnabled = true; - const conflict = false; - - reset = reset || !this.moduleEnabled || conflict; - - // don't 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(' WorkspaceThumbnailModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - // don't limit max thumbnail scale for other clients than overview, specifically AATWS. - // this variable is not yet implemented in 45.beta.1 - - this._overrides.addOverride('WorkspaceThumbnail', WorkspaceThumbnail.WorkspaceThumbnail.prototype, WorkspaceThumbnailCommon); - this._overrides.addOverride('ThumbnailsBoxCommon', WorkspaceThumbnail.ThumbnailsBox.prototype, ThumbnailsBoxCommon); - - // replacing opt.ORIENTATION local constant with boxOrientation internal variable allows external customers such as the AATWS extension to control the box orientation. - Main.overview._overview.controls._thumbnailsBox._boxOrientation = opt.ORIENTATION; - - console.debug(' WorkspaceThumbnailModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - console.debug(' WorkspaceThumbnailModule - Disabled'); - } -}; - -const WorkspaceThumbnailCommon = { - // injection to _init() - after__init() { - // layout manager allows aligning widget children - this.layout_manager = new Clutter.BinLayout(); - // adding layout manager to tmb widget breaks wallpaper background aligning and rounded corners - // unless border is removed - if (opt.SHOW_WS_TMB_BG) - this.add_style_class_name('ws-tmb-labeled'); - else - this.add_style_class_name('ws-tmb-transparent'); - - // add workspace thumbnails labels if enabled - if (opt.SHOW_WST_LABELS) { // 0 - disable - const getLabel = function () { - const wsIndex = this.metaWorkspace.index(); - let label = `${wsIndex + 1}`; - if (opt.SHOW_WST_LABELS === 2) { // 2 - index + workspace name - const settings = Me.getSettings('org.gnome.desktop.wm.preferences'); - const wsLabels = settings.get_strv('workspace-names'); - if (wsLabels.length > wsIndex && wsLabels[wsIndex]) - label += `: ${wsLabels[wsIndex]}`; - } else if (opt.SHOW_WST_LABELS === 3) { // 3- index + app name - // global.display.get_tab_list offers workspace filtering using the second argument, but... - // ... it sometimes includes windows from other workspaces, like minimized VBox machines, after Shell restarts - const metaWin = global.display.get_tab_list(0, null).filter( - w => w.get_monitor() === this.monitorIndex && w.get_workspace().index() === wsIndex)[0]; - - if (metaWin) { - const tracker = Shell.WindowTracker.get_default(); - const app = tracker.get_window_app(metaWin); - label += `: ${app ? app.get_name() : ''}`; - } - } else if (opt.SHOW_WST_LABELS === 4) { - const metaWin = global.display.get_tab_list(0, null).filter( - w => w.get_monitor() === this.monitorIndex && w.get_workspace().index() === wsIndex)[0]; - - if (metaWin) - label += `: ${metaWin.title}`; - } - return label; - }.bind(this); - - const label = getLabel(); - - this._wsLabel = new St.Label({ - text: label, - style_class: 'ws-tmb-label', - x_align: Clutter.ActorAlign.FILL, - y_align: Clutter.ActorAlign.END, - x_expand: true, - y_expand: true, - }); - - this._wsLabel._maxOpacity = 255; - this._wsLabel.opacity = this._wsLabel._maxOpacity; - - this.add_child(this._wsLabel); - this.set_child_above_sibling(this._wsLabel, null); - - this._wsIndexConId = this.metaWorkspace.connect('notify::workspace-index', () => { - const newLabel = getLabel(); - this._wsLabel.text = newLabel; - // avoid possibility of accessing non existing ws - if (this._updateLabelTimeout) { - GLib.source_remove(this._updateLabelTimeout); - this._updateLabelTimeout = 0; - } - }); - this._nWindowsConId = this.metaWorkspace.connect('notify::n-windows', () => { - if (this._updateLabelTimeout) - return; - // wait for new data - this._updateLabelTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, () => { - const newLabel = getLabel(); - this._wsLabel.text = newLabel; - this._updateLabelTimeout = 0; - return GLib.SOURCE_REMOVE; - }); - }); - } - - if (opt.CLOSE_WS_BUTTON_MODE) { - const closeButton = new St.Icon({ - style_class: 'workspace-close-button', - icon_name: 'window-close-symbolic', - x_align: Clutter.ActorAlign.END, - y_align: Clutter.ActorAlign.START, - x_expand: true, - y_expand: true, - reactive: true, - opacity: 0, - }); - - closeButton.connect('button-release-event', () => { - if (opt.CLOSE_WS_BUTTON_MODE) { - this._closeWorkspace(); - return Clutter.EVENT_STOP; - } else { - return Clutter.EVENT_PROPAGATE; - } - }); - - closeButton.connect('button-press-event', () => { - return Clutter.EVENT_STOP; - }); - - closeButton.connect('enter-event', () => { - closeButton.opacity = 255; - if (!Meta.prefs_get_dynamic_workspaces() || (Meta.prefs_get_dynamic_workspaces() && global.workspace_manager.get_n_workspaces() - 1 !== this.metaWorkspace.index())) { - // color the button red if ready to react on clicks - if (opt.CLOSE_WS_BUTTON_MODE < 3 || (opt.CLOSE_WS_BUTTON_MODE === 3 && Me.Util.isCtrlPressed())) - closeButton.add_style_class_name('workspace-close-button-hover'); - } - }); - - closeButton.connect('leave-event', () => { - closeButton.remove_style_class_name('workspace-close-button-hover'); - }); - - this.add_child(closeButton); - this._closeButton = closeButton; - - this.reactive = true; - this._lastCloseClickTime = 0; - } - - if (opt.SHOW_WST_LABELS_ON_HOVER) - this._wsLabel.opacity = 0; - - this.connect('enter-event', () => { - if (opt.CLOSE_WS_BUTTON_MODE && (!Meta.prefs_get_dynamic_workspaces() || (Meta.prefs_get_dynamic_workspaces() && global.workspace_manager.get_n_workspaces() - 1 !== this.metaWorkspace.index()))) - this._closeButton.opacity = 200; - if (opt.SHOW_WST_LABELS_ON_HOVER) { - this._wsLabel.ease({ - duration: 100, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - opacity: this._wsLabel._maxOpacity, - }); - } - }); - - this.connect('leave-event', () => { - this._closeButton.opacity = 0; - if (opt.SHOW_WST_LABELS_ON_HOVER) { - this._wsLabel.ease({ - duration: 100, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - opacity: 0, - }); - } - }); - - if (opt.SHOW_WS_TMB_BG) { - this._bgManager = new Background.BackgroundManager({ - monitorIndex: this.monitorIndex, - container: this._viewport, - vignette: false, - controlPosition: false, - }); - - this._viewport.set_child_below_sibling(this._bgManager.backgroundActor, null); - - // full brightness of the thumbnail bg draws unnecessary attention - // there is a grey bg under the wallpaper - this._bgManager.backgroundActor.opacity = 220; - } - - this.connect('destroy', () => { - if (this._wsIndexConId) - this.metaWorkspace.disconnect(this._wsIndexConId); - - if (this._nWindowsConId) - this.metaWorkspace.disconnect(this._nWindowsConId); - - if (this._updateLabelTimeout) - GLib.source_remove(this._updateLabelTimeout); - - if (this._bgManager) - this._bgManager.destroy(); - }); - }, - - _closeWorkspace() { - // CLOSE_WS_BUTTON_MODE 1: single click, 2: double-click, 3: Ctrl - - if (opt.CLOSE_WS_BUTTON_MODE === 2) { - const doubleClickTime = Clutter.Settings.get_default().double_click_time; - const clickDelay = Date.now() - this._lastCloseClickTime; - if (clickDelay > doubleClickTime) { - this._lastCloseClickTime = Date.now(); - return; - } - } else if (opt.CLOSE_WS_BUTTON_MODE === 3 && !Me.Util.isCtrlPressed()) { - return; - } - - // close windows on this monitor - const windows = global.display.get_tab_list(0, null).filter( - w => w.get_monitor() === this.monitorIndex && w.get_workspace() === this.metaWorkspace - ); - - for (let i = 0; i < windows.length; i++) { - if (!windows[i].is_on_all_workspaces()) - windows[i].delete(global.get_current_time() + i); - } - }, - - activate(time) { - if (this.state > ThumbnailState.NORMAL) - return; - - // if Static Workspace overview mode active, a click on the already active workspace should activate the window picker mode - const wsIndex = this.metaWorkspace.index(); - const lastWsIndex = global.display.get_workspace_manager().get_n_workspaces() - 1; - const stateAdjustment = Main.overview._overview.controls._stateAdjustment; - - if (stateAdjustment.value === ControlsState.APP_GRID) { - if (this.metaWorkspace.active) { - Main.overview._overview.controls._shiftState(Meta.MotionDirection.DOWN); - // if searchActive, hide it immediately - Main.overview.searchEntry.set_text(''); - } else { - this.metaWorkspace.activate(time); - } - } else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && wsIndex < lastWsIndex) { - if (stateAdjustment.value > 1) - stateAdjustment.value = 1; - - - // spread windows - // in OVERVIEW MODE 2 windows are not spread and workspace is not scaled - // we need to repeat transition to the overview state 1 (window picker), but with spreading windows animation - if (this.metaWorkspace.active) { - Main.overview._overview.controls._searchController._setSearchActive(false); - opt.WORKSPACE_MODE = 1; - // setting value to 0 would reset WORKSPACE_MODE - stateAdjustment.value = 0.01; - stateAdjustment.ease(1, { - duration: 200, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } else { - // switch ws - this.metaWorkspace.activate(time); - } - // a click on the current workspace should go back to the main view - } else if (this.metaWorkspace.active) { - Main.overview.hide(); - } else { - this.metaWorkspace.activate(time); - } - }, - - // Draggable target interface used only by ThumbnailsBox - handleDragOverInternal(source, actor, time) { - if (source === Main.xdndHandler) { - this.metaWorkspace.activate(time); - return DND.DragMotionResult.CONTINUE; - } - - if (this.state > ThumbnailState.NORMAL) - return DND.DragMotionResult.CONTINUE; - - if (source.metaWindow && - !this._isMyWindow(source.metaWindow.get_compositor_private())) - return DND.DragMotionResult.MOVE_DROP; - if (source.app && source.app.can_open_new_window()) - return DND.DragMotionResult.COPY_DROP; - if (!source.app && source.shellWorkspaceLaunch) - return DND.DragMotionResult.COPY_DROP; - - if (source instanceof AppDisplay.FolderIcon) - return DND.DragMotionResult.COPY_DROP; - - - return DND.DragMotionResult.CONTINUE; - }, - - acceptDropInternal(source, actor, time) { - if (this.state > ThumbnailState.NORMAL) - return false; - - if (source.metaWindow) { - let win = source.metaWindow.get_compositor_private(); - if (this._isMyWindow(win)) - return false; - - let metaWindow = win.get_meta_window(); - Main.moveWindowToMonitorAndWorkspace(metaWindow, - this.monitorIndex, this.metaWorkspace.index()); - return true; - } else if (source.app && source.app.can_open_new_window()) { - if (source.animateLaunchAtPos) - source.animateLaunchAtPos(actor.x, actor.y); - - source.app.open_new_window(this.metaWorkspace.index()); - return true; - } else if (!source.app && source.shellWorkspaceLaunch) { - // While unused in our own drag sources, shellWorkspaceLaunch allows - // extensions to define custom actions for their drag sources. - source.shellWorkspaceLaunch({ - workspace: this.metaWorkspace.index(), - timestamp: time, - }); - return true; - } else if (source instanceof AppDisplay.FolderIcon) { - for (let app of source.view._apps) { - // const app = Shell.AppSystem.get_default().lookup_app(id); - app.open_new_window(this.metaWorkspace.index()); - } - } - - return false; - }, -}; - -const ThumbnailsBoxCommon = { - after__init(scrollAdjustment, monitorIndex, orientation = opt.ORIENTATION) { - this._boxOrientation = orientation; - }, - - _activateThumbnailAtPoint(stageX, stageY, time, activateCurrent = false) { - if (activateCurrent) { - const thumbnail = this._thumbnails.find(t => t.metaWorkspace.active); - if (thumbnail) - thumbnail.activate(time); - return; - } - const [r_, x, y] = this.transform_stage_point(stageX, stageY); - - let thumbnail; - - if (this._boxOrientation) - thumbnail = this._thumbnails.find(t => y >= t.y && y <= t.y + t.height); - else - thumbnail = this._thumbnails.find(t => x >= t.x && x <= t.x + t.width); - - if (thumbnail) - thumbnail.activate(time); - }, - - acceptDrop(source, actor, x, y, time) { - if (this._dropWorkspace !== -1) { - return this._thumbnails[this._dropWorkspace].acceptDropInternal(source, actor, time); - } else if (this._dropPlaceholderPos !== -1) { - if (!source.metaWindow && - (!source.app || !source.app.can_open_new_window()) && - (source.app || !source.shellWorkspaceLaunch) && - !(source instanceof AppDisplay.FolderIcon)) - return false; - - - let isWindow = !!source.metaWindow; - - let newWorkspaceIndex; - [newWorkspaceIndex, this._dropPlaceholderPos] = [this._dropPlaceholderPos, -1]; - this._spliceIndex = newWorkspaceIndex; - - Main.wm.insertWorkspace(newWorkspaceIndex); - - if (isWindow) { - // Move the window to our monitor first if necessary. - let thumbMonitor = this._thumbnails[newWorkspaceIndex].monitorIndex; - Main.moveWindowToMonitorAndWorkspace(source.metaWindow, - thumbMonitor, newWorkspaceIndex, true); - } else if (source.app && source.app.can_open_new_window()) { - if (source.animateLaunchAtPos) - source.animateLaunchAtPos(actor.x, actor.y); - - source.app.open_new_window(newWorkspaceIndex); - } else if (!source.app && source.shellWorkspaceLaunch) { - // While unused in our own drag sources, shellWorkspaceLaunch allows - // extensions to define custom actions for their drag sources. - source.shellWorkspaceLaunch({ - workspace: newWorkspaceIndex, - timestamp: time, - }); - } else if (source instanceof AppDisplay.FolderIcon) { - for (let app of source.view._apps) { - // const app = Shell.AppSystem.get_default().lookup_app(id); - app.open_new_window(newWorkspaceIndex); - } - } - - if (source.app || (!source.app && source.shellWorkspaceLaunch)) { - // This new workspace will be automatically removed if the application fails - // to open its first window within some time, as tracked by Shell.WindowTracker. - // Here, we only add a very brief timeout to avoid the _immediate_ removal of the - // workspace while we wait for the startup sequence to load. - let workspaceManager = global.workspace_manager; - Main.wm.keepWorkspaceAlive(workspaceManager.get_workspace_by_index(newWorkspaceIndex), - WORKSPACE_KEEP_ALIVE_TIME); - } - - // Start the animation on the workspace (which is actually - // an old one which just became empty) - let thumbnail = this._thumbnails[newWorkspaceIndex]; - this._setThumbnailState(thumbnail, ThumbnailState.NEW); - thumbnail.slide_position = 1; - thumbnail.collapse_fraction = 1; - - this._queueUpdateStates(); - - return true; - } else { - return false; - } - }, - - handleDragOver(source, actor, x, y, time) { - // switch axis for vertical orientation - if (this._boxOrientation) - x = y; - - if (!source.metaWindow && - (!source.app || !source.app.can_open_new_window()) && - (source.app || !source.shellWorkspaceLaunch) && - source !== Main.xdndHandler && !(source instanceof AppDisplay.FolderIcon)) - return DND.DragMotionResult.CONTINUE; - - const rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL; - let canCreateWorkspaces = Meta.prefs_get_dynamic_workspaces(); - let spacing = this.get_theme_node().get_length('spacing'); - - this._dropWorkspace = -1; - let placeholderPos = -1; - let length = this._thumbnails.length; - for (let i = 0; i < length; i++) { - const index = rtl ? length - i - 1 : i; - - if (canCreateWorkspaces && source !== Main.xdndHandler) { - const [targetStart, targetEnd] = - this._getPlaceholderTarget(index, spacing, rtl); - - if (x > targetStart && x <= targetEnd) { - placeholderPos = index; - break; - } - } - - if (this._withinWorkspace(x, index, rtl)) { - this._dropWorkspace = index; - break; - } - } - - if (this._dropPlaceholderPos !== placeholderPos) { - this._dropPlaceholderPos = placeholderPos; - this.queue_relayout(); - } - - if (this._dropWorkspace !== -1) - return this._thumbnails[this._dropWorkspace].handleDragOverInternal(source, actor, time); - else if (this._dropPlaceholderPos !== -1) - return source.metaWindow ? DND.DragMotionResult.MOVE_DROP : DND.DragMotionResult.COPY_DROP; - else - return DND.DragMotionResult.CONTINUE; - }, - - _updateStates() { - const controlsManager = Main.overview._overview.controls; - const { currentState } = controlsManager._stateAdjustment.getStateTransitionParams(); - this.SLIDE_ANIMATION_TIME = 200; - this.RESCALE_ANIMATION_TIME = 200; - // remove rescale animation during this scale transition, it is redundant and delayed - if ((currentState < 2 && currentState > 1) || controlsManager._searchController.searchActive) - this.RESCALE_ANIMATION_TIME = 0; - - this._updateStateId = 0; - - // If we are animating the indicator, wait - if (this._animatingIndicator) - return; - - // Likewise if we are in the process of hiding - if (!this._shouldShow && this.visible) - return; - - // Then slide out any thumbnails that have been destroyed - this._iterateStateThumbnails(ThumbnailState.REMOVING, thumbnail => { - this._setThumbnailState(thumbnail, ThumbnailState.ANIMATING_OUT); - - thumbnail.ease_property('slide-position', 1, { - duration: this.SLIDE_ANIMATION_TIME, - mode: Clutter.AnimationMode.LINEAR, - onComplete: () => { - this._setThumbnailState(thumbnail, ThumbnailState.ANIMATED_OUT); - this._queueUpdateStates(); - }, - }); - }); - - // As long as things are sliding out, don't proceed - if (this._stateCounts[ThumbnailState.ANIMATING_OUT] > 0) - return; - - // Once that's complete, we can start scaling to the new size, - // collapse any removed thumbnails and expand added ones - this._iterateStateThumbnails(ThumbnailState.ANIMATED_OUT, thumbnail => { - this._setThumbnailState(thumbnail, ThumbnailState.COLLAPSING); - thumbnail.ease_property('collapse-fraction', 1, { - duration: this.RESCALE_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._stateCounts[thumbnail.state]--; - thumbnail.state = ThumbnailState.DESTROYED; - - let index = this._thumbnails.indexOf(thumbnail); - this._thumbnails.splice(index, 1); - thumbnail.destroy(); - - this._queueUpdateStates(); - }, - }); - }); - - this._iterateStateThumbnails(ThumbnailState.NEW, thumbnail => { - this._setThumbnailState(thumbnail, ThumbnailState.EXPANDING); - thumbnail.ease_property('collapse-fraction', 0, { - duration: this.SLIDE_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._setThumbnailState(thumbnail, ThumbnailState.EXPANDED); - this._queueUpdateStates(); - }, - }); - }); - - if (this._pendingScaleUpdate) { - this.ease_property('scale', this._targetScale, { - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - duration: this.RESCALE_ANIMATION_TIME, - onComplete: () => this._queueUpdateStates(), - }); - this._queueUpdateStates(); - this._pendingScaleUpdate = false; - } - - // Wait until that's done - if (this._scale !== this._targetScale || - this._stateCounts[ThumbnailState.COLLAPSING] > 0 || - this._stateCounts[ThumbnailState.EXPANDING] > 0) - return; - - // And then slide in any new thumbnails - this._iterateStateThumbnails(ThumbnailState.EXPANDED, thumbnail => { - this._setThumbnailState(thumbnail, ThumbnailState.ANIMATING_IN); - thumbnail.ease_property('slide-position', 0, { - duration: this.SLIDE_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._setThumbnailState(thumbnail, ThumbnailState.NORMAL); - }, - }); - }); - }, - - _getPlaceholderTarget(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical._getPlaceholderTarget.bind(this)(...args); - else - return ThumbnailsBoxHorizontal._getPlaceholderTarget.bind(this)(...args); - }, - - _withinWorkspace(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical._withinWorkspace.bind(this)(...args); - else - return ThumbnailsBoxHorizontal._withinWorkspace.bind(this)(...args); - }, - - vfunc_get_preferred_width(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical.vfunc_get_preferred_width.bind(this)(...args); - else - return ThumbnailsBoxHorizontal.vfunc_get_preferred_width.bind(this)(...args); - }, - - vfunc_get_preferred_height(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical.vfunc_get_preferred_height.bind(this)(...args); - else - return ThumbnailsBoxHorizontal.vfunc_get_preferred_height.bind(this)(...args); - }, - - vfunc_allocate(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical.vfunc_allocate.bind(this)(...args); - else - return ThumbnailsBoxHorizontal.vfunc_allocate.bind(this)(...args); - }, - - _updateShouldShow(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical._updateShouldShow.bind(this)(...args); - else - return ThumbnailsBoxHorizontal._updateShouldShow.bind(this)(...args); - }, -}; - -const ThumbnailsBoxVertical = { - _getPlaceholderTarget(index, spacing, rtl) { - this._dropPlaceholder.add_style_class_name('placeholder-vertical'); - const workspace = this._thumbnails[index]; - - let targetY1; - let targetY2; - - if (rtl) { - const baseY = workspace.y + workspace.height; - targetY1 = baseY - WORKSPACE_CUT_SIZE; - targetY2 = baseY + spacing + WORKSPACE_CUT_SIZE; - } else { - targetY1 = workspace.y - spacing - WORKSPACE_CUT_SIZE; - targetY2 = workspace.y + WORKSPACE_CUT_SIZE; - } - - if (index === 0) { - if (rtl) - targetY2 -= spacing + WORKSPACE_CUT_SIZE; - else - targetY1 += spacing + WORKSPACE_CUT_SIZE; - } - - if (index === this._dropPlaceholderPos) { - const placeholderHeight = this._dropPlaceholder.get_height() + spacing; - if (rtl) - targetY2 += placeholderHeight; - else - targetY1 -= placeholderHeight; - } - - return [targetY1, targetY2]; - }, - - _withinWorkspace(y, index, rtl) { - const length = this._thumbnails.length; - const workspace = this._thumbnails[index]; - - let workspaceY1 = workspace.y + WORKSPACE_CUT_SIZE; - let workspaceY2 = workspace.y + workspace.height - WORKSPACE_CUT_SIZE; - - if (index === length - 1) { - if (rtl) - workspaceY1 -= WORKSPACE_CUT_SIZE; - else - workspaceY2 += WORKSPACE_CUT_SIZE; - } - - return y > workspaceY1 && y <= workspaceY2; - }, - - vfunc_get_preferred_width(forHeight) { - if (forHeight < 10) - return [this._porthole.width, this._porthole.width]; - - let themeNode = this.get_theme_node(); - - forHeight = themeNode.adjust_for_width(forHeight); - - let spacing = themeNode.get_length('spacing'); - let nWorkspaces = this._thumbnails.length; - let totalSpacing = (nWorkspaces - 1) * spacing; - - const avail = forHeight - totalSpacing; - - let scale = (avail / nWorkspaces) / this._porthole.height; - - const width = Math.round(this._porthole.width * scale); - return themeNode.adjust_preferred_height(width, width); - }, - - vfunc_get_preferred_height(forWidth) { - if (forWidth < 10) - return [0, this._porthole.height]; - let themeNode = this.get_theme_node(); - - let spacing = themeNode.get_length('spacing'); - let nWorkspaces = this._thumbnails.length; - - // remove also top/bottom box padding - let totalSpacing = (nWorkspaces - 3) * spacing; - - const ratio = this._porthole.width / this._porthole.height; - const tmbHeight = themeNode.adjust_for_width(forWidth) / ratio; - - const naturalheight = this._thumbnails.reduce((accumulator, thumbnail/* , index*/) => { - const progress = 1 - thumbnail.collapse_fraction; - const height = tmbHeight * progress; - return accumulator + height; - }, 0); - return themeNode.adjust_preferred_width(totalSpacing, Math.round(naturalheight)); - }, - - // removes extra space (extraWidth in the original function), we need the box as accurate as possible - // for precise app grid transition animation - vfunc_allocate(box) { - this.set_allocation(box); - - let rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL; - - if (this._thumbnails.length === 0) // not visible - return; - - let themeNode = this.get_theme_node(); - box = themeNode.get_content_box(box); - - const portholeWidth = this._porthole.width; - const portholeHeight = this._porthole.height; - const spacing = themeNode.get_length('spacing'); - - /* const nWorkspaces = this._thumbnails.length;*/ - - // Compute the scale we'll need once everything is updated, - // unless we are currently transitioning - if (this._expandFraction === 1) { - // remove size "breathing" during adding/removing workspaces - - /* const totalSpacing = (nWorkspaces - 1) * spacing; - const availableHeight = (box.get_height() - totalSpacing) / nWorkspaces; */ - - const hScale = box.get_width() / portholeWidth; - /* const vScale = availableHeight / portholeHeight;*/ - const vScale = box.get_height() / portholeHeight; - const newScale = Math.min(hScale, vScale); - - if (newScale !== this._targetScale) { - if (this._targetScale > 0) { - // We don't ease immediately because we need to observe the - // ordering in queueUpdateStates - if workspaces have been - // removed we need to slide them out as the first thing. - this._targetScale = newScale; - this._pendingScaleUpdate = true; - } else { - this._targetScale = this._scale = newScale; - } - - this._queueUpdateStates(); - } - } - - const ratio = portholeWidth / portholeHeight; - const thumbnailFullHeight = Math.round(portholeHeight * this._scale); - const thumbnailWidth = Math.round(thumbnailFullHeight * ratio); - const thumbnailHeight = thumbnailFullHeight * this._expandFraction; - const roundedVScale = thumbnailHeight / portholeHeight; - - let indicatorValue = this._scrollAdjustment.value; - let indicatorUpperWs = Math.ceil(indicatorValue); - let indicatorLowerWs = Math.floor(indicatorValue); - - let indicatorLowerY1 = 0; - let indicatorLowerY2 = 0; - let indicatorUpperY1 = 0; - let indicatorUpperY2 = 0; - - let indicatorThemeNode = this._indicator.get_theme_node(); - let indicatorTopFullBorder = indicatorThemeNode.get_padding(St.Side.TOP) + indicatorThemeNode.get_border_width(St.Side.TOP); - let indicatorBottomFullBorder = indicatorThemeNode.get_padding(St.Side.BOTTOM) + indicatorThemeNode.get_border_width(St.Side.BOTTOM); - let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) + indicatorThemeNode.get_border_width(St.Side.LEFT); - let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) + indicatorThemeNode.get_border_width(St.Side.RIGHT); - - let y = box.y1; - - if (this._dropPlaceholderPos === -1) { - this._dropPlaceholder.allocate_preferred_size( - ...this._dropPlaceholder.get_position()); - - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.hide(); - }); - } - - let childBox = new Clutter.ActorBox(); - - for (let i = 0; i < this._thumbnails.length; i++) { - const thumbnail = this._thumbnails[i]; - if (i > 0) - y += spacing - Math.round(thumbnail.collapse_fraction * spacing); - - const x1 = box.x1; - const x2 = x1 + thumbnailWidth; - - if (i === this._dropPlaceholderPos) { - let [, placeholderHeight] = this._dropPlaceholder.get_preferred_width(-1); - childBox.x1 = x1; - childBox.x2 = x2; - - if (rtl) { - childBox.y2 = box.y2 - Math.round(y); - childBox.y1 = box.y2 - Math.round(y + placeholderHeight); - } else { - childBox.y1 = Math.round(y); - childBox.y2 = Math.round(y + placeholderHeight); - } - - this._dropPlaceholder.allocate(childBox); - - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.show(); - }); - y += placeholderHeight + spacing; - } - - // We might end up with thumbnailWidth being something like 99.33 - // pixels. To make this work and not end up with a gap at the end, - // we need some thumbnails to be 99 pixels and some 100 pixels width; - // we compute an actual scale separately for each thumbnail. - const y1 = Math.round(y); - const y2 = Math.round(y + thumbnailHeight); - const roundedHScale = (y2 - y1) / portholeHeight; - - // Allocating a scaled actor is funny - x1/y1 correspond to the origin - // of the actor, but x2/y2 are increased by the *unscaled* size. - if (rtl) { - childBox.y2 = box.y2 - y1; - childBox.y1 = box.y2 - (y1 + thumbnailHeight); - } else { - childBox.y1 = y1; - childBox.y2 = y1 + thumbnailHeight; - } - childBox.x1 = x1; - childBox.x2 = x1 + thumbnailWidth; - - thumbnail.setScale(roundedHScale, roundedVScale); - thumbnail.allocate(childBox); - - if (i === indicatorUpperWs) { - indicatorUpperY1 = childBox.y1; - indicatorUpperY2 = childBox.y2; - } - if (i === indicatorLowerWs) { - indicatorLowerY1 = childBox.y1; - indicatorLowerY2 = childBox.y2; - } - - // We round the collapsing portion so that we don't get thumbnails resizing - // during an animation due to differences in rounded, but leave the uncollapsed - // portion unrounded so that non-animating we end up with the right total - y += thumbnailHeight - Math.round(thumbnailHeight * thumbnail.collapse_fraction); - } - - childBox.x1 = box.x1; - childBox.x2 = box.x1 + thumbnailWidth; - - const indicatorY1 = indicatorLowerY1 + - (indicatorUpperY1 - indicatorLowerY1) * (indicatorValue % 1); - const indicatorY2 = indicatorLowerY2 + - (indicatorUpperY2 - indicatorLowerY2) * (indicatorValue % 1); - - childBox.y1 = indicatorY1 - indicatorTopFullBorder; - childBox.y2 = indicatorY2 + indicatorBottomFullBorder; - childBox.x1 -= indicatorLeftFullBorder; - childBox.x2 += indicatorRightFullBorder; - this._indicator.allocate(childBox); - }, - - _updateShouldShow() { - const shouldShow = opt.SHOW_WS_TMB; - if (this._shouldShow === shouldShow) - return; - - this._shouldShow = shouldShow; - this.notify('should-show'); - }, -}; - -// ThumbnailsBox Horizontal - -const ThumbnailsBoxHorizontal = { - _getPlaceholderTarget(index, spacing, rtl) { - const workspace = this._thumbnails[index]; - - let targetX1; - let targetX2; - - if (rtl) { - const baseX = workspace.x + workspace.width; - targetX1 = baseX - WORKSPACE_CUT_SIZE; - targetX2 = baseX + spacing + WORKSPACE_CUT_SIZE; - } else { - targetX1 = workspace.x - spacing - WORKSPACE_CUT_SIZE; - targetX2 = workspace.x + WORKSPACE_CUT_SIZE; - } - - if (index === 0) { - if (rtl) - targetX2 -= spacing + WORKSPACE_CUT_SIZE; - else - targetX1 += spacing + WORKSPACE_CUT_SIZE; - } - - if (index === this._dropPlaceholderPos) { - const placeholderWidth = this._dropPlaceholder.get_width() + spacing; - if (rtl) - targetX2 += placeholderWidth; - else - targetX1 -= placeholderWidth; - } - - return [targetX1, targetX2]; - }, - - _withinWorkspace(x, index, rtl) { - const length = this._thumbnails.length; - const workspace = this._thumbnails[index]; - - let workspaceX1 = workspace.x + WORKSPACE_CUT_SIZE; - let workspaceX2 = workspace.x + workspace.width - WORKSPACE_CUT_SIZE; - - if (index === length - 1) { - if (rtl) - workspaceX1 -= WORKSPACE_CUT_SIZE; - else - workspaceX2 += WORKSPACE_CUT_SIZE; - } - - return x > workspaceX1 && x <= workspaceX2; - }, - - vfunc_get_preferred_height(forWidth) { - if (forWidth < 10) - return [this._porthole.height, this._porthole.height]; - - let themeNode = this.get_theme_node(); - - forWidth = themeNode.adjust_for_width(forWidth); - - let spacing = themeNode.get_length('spacing'); - let nWorkspaces = this._thumbnails.length; - let totalSpacing = (nWorkspaces - 1) * spacing; - - const avail = forWidth - totalSpacing; - - let scale = (avail / nWorkspaces) / this._porthole.width; - - const height = Math.round(this._porthole.height * scale); - - return themeNode.adjust_preferred_height(height, height); - }, - - vfunc_get_preferred_width(forHeight) { - if (forHeight < 10) - return [0, this._porthole.width]; - - let themeNode = this.get_theme_node(); - - let spacing = themeNode.get_length('spacing'); - let nWorkspaces = this._thumbnails.length; - // remove also left/right box padding from the total spacing - let totalSpacing = (nWorkspaces - 3) * spacing; - - const ratio = this._porthole.height / this._porthole.width; - - const tmbWidth = themeNode.adjust_for_height(forHeight) / ratio; - - const naturalWidth = this._thumbnails.reduce((accumulator, thumbnail) => { - const progress = 1 - thumbnail.collapse_fraction; - const width = tmbWidth * progress; - return accumulator + width; - }, 0); - - return themeNode.adjust_preferred_width(totalSpacing, naturalWidth); - }, - - vfunc_allocate(box) { - this.set_allocation(box); - - let rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL; - - if (this._thumbnails.length === 0) // not visible - return; - - let themeNode = this.get_theme_node(); - box = themeNode.get_content_box(box); - - const portholeWidth = this._porthole.width; - const portholeHeight = this._porthole.height; - const spacing = themeNode.get_length('spacing'); - - /* const nWorkspaces = this._thumbnails.length; */ - - // Compute the scale we'll need once everything is updated, - // unless we are currently transitioning - if (this._expandFraction === 1) { - // remove size "breathing" during adding/removing workspaces - - /* const totalSpacing = (nWorkspaces - 1) * spacing; - const availableWidth = (box.get_width() - totalSpacing) / nWorkspaces; - - const hScale = availableWidth / portholeWidth; */ - const hScale = box.get_width() / portholeWidth; - const vScale = box.get_height() / portholeHeight; - const newScale = Math.min(hScale, vScale); - - if (newScale !== this._targetScale) { - if (this._targetScale > 0) { - // We don't ease immediately because we need to observe the - // ordering in queueUpdateStates - if workspaces have been - // removed we need to slide them out as the first thing. - this._targetScale = newScale; - this._pendingScaleUpdate = true; - } else { - this._targetScale = this._scale = newScale; - } - - this._queueUpdateStates(); - } - } - - const ratio = portholeWidth / portholeHeight; - const thumbnailFullHeight = Math.round(portholeHeight * this._scale); - const thumbnailWidth = Math.round(thumbnailFullHeight * ratio); - const thumbnailHeight = thumbnailFullHeight * this._expandFraction; - const roundedVScale = thumbnailHeight / portholeHeight; - - let indicatorValue = this._scrollAdjustment.value; - let indicatorUpperWs = Math.ceil(indicatorValue); - let indicatorLowerWs = Math.floor(indicatorValue); - - let indicatorLowerX1 = 0; - let indicatorLowerX2 = 0; - let indicatorUpperX1 = 0; - let indicatorUpperX2 = 0; - - let indicatorThemeNode = this._indicator.get_theme_node(); - let indicatorTopFullBorder = indicatorThemeNode.get_padding(St.Side.TOP) + indicatorThemeNode.get_border_width(St.Side.TOP); - let indicatorBottomFullBorder = indicatorThemeNode.get_padding(St.Side.BOTTOM) + indicatorThemeNode.get_border_width(St.Side.BOTTOM); - let indicatorLeftFullBorder = indicatorThemeNode.get_padding(St.Side.LEFT) + indicatorThemeNode.get_border_width(St.Side.LEFT); - let indicatorRightFullBorder = indicatorThemeNode.get_padding(St.Side.RIGHT) + indicatorThemeNode.get_border_width(St.Side.RIGHT); - - let x = box.x1; - - if (this._dropPlaceholderPos === -1) { - this._dropPlaceholder.allocate_preferred_size( - ...this._dropPlaceholder.get_position()); - - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.hide(); - }); - } - - let childBox = new Clutter.ActorBox(); - - for (let i = 0; i < this._thumbnails.length; i++) { - const thumbnail = this._thumbnails[i]; - if (i > 0) - x += spacing - Math.round(thumbnail.collapse_fraction * spacing); - - const y1 = box.y1; - const y2 = y1 + thumbnailHeight; - - if (i === this._dropPlaceholderPos) { - const [, placeholderWidth] = this._dropPlaceholder.get_preferred_width(-1); - childBox.y1 = y1; - childBox.y2 = y2; - - if (rtl) { - childBox.x2 = box.x2 - Math.round(x); - childBox.x1 = box.x2 - Math.round(x + placeholderWidth); - } else { - childBox.x1 = Math.round(x); - childBox.x2 = Math.round(x + placeholderWidth); - } - - this._dropPlaceholder.allocate(childBox); - - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.show(); - }); - x += placeholderWidth + spacing; - } - - // We might end up with thumbnailWidth being something like 99.33 - // pixels. To make this work and not end up with a gap at the end, - // we need some thumbnails to be 99 pixels and some 100 pixels width; - // we compute an actual scale separately for each thumbnail. - const x1 = Math.round(x); - const x2 = Math.round(x + thumbnailWidth); - const roundedHScale = (x2 - x1) / portholeWidth; - - // Allocating a scaled actor is funny - x1/y1 correspond to the origin - // of the actor, but x2/y2 are increased by the *unscaled* size. - if (rtl) { - childBox.x2 = box.x2 - x1; - childBox.x1 = box.x2 - (x1 + thumbnailWidth); - } else { - childBox.x1 = x1; - childBox.x2 = x1 + thumbnailWidth; - } - childBox.y1 = y1; - childBox.y2 = y1 + thumbnailHeight; - - thumbnail.setScale(roundedHScale, roundedVScale); - thumbnail.allocate(childBox); - - if (i === indicatorUpperWs) { - indicatorUpperX1 = childBox.x1; - indicatorUpperX2 = childBox.x2; - } - if (i === indicatorLowerWs) { - indicatorLowerX1 = childBox.x1; - indicatorLowerX2 = childBox.x2; - } - - // We round the collapsing portion so that we don't get thumbnails resizing - // during an animation due to differences in rounded, but leave the uncollapsed - // portion unrounded so that non-animating we end up with the right total - x += thumbnailWidth - Math.round(thumbnailWidth * thumbnail.collapse_fraction); - } - - childBox.y1 = box.y1; - childBox.y2 = box.y1 + thumbnailHeight; - - const indicatorX1 = indicatorLowerX1 + - (indicatorUpperX1 - indicatorLowerX1) * (indicatorValue % 1); - const indicatorX2 = indicatorLowerX2 + - (indicatorUpperX2 - indicatorLowerX2) * (indicatorValue % 1); - - childBox.x1 = indicatorX1 - indicatorLeftFullBorder; - childBox.x2 = indicatorX2 + indicatorRightFullBorder; - childBox.y1 -= indicatorTopFullBorder; - childBox.y2 += indicatorBottomFullBorder; - this._indicator.allocate(childBox); - }, - - _updateShouldShow: ThumbnailsBoxVertical._updateShouldShow, -}; -- cgit v1.2.3