summaryrefslogtreecommitdiffstats
path: root/extensions/45/vertical-workspaces/lib/workspace.js
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/45/vertical-workspaces/lib/workspace.js')
-rw-r--r--extensions/45/vertical-workspaces/lib/workspace.js463
1 files changed, 0 insertions, 463 deletions
diff --git a/extensions/45/vertical-workspaces/lib/workspace.js b/extensions/45/vertical-workspaces/lib/workspace.js
deleted file mode 100644
index 1ff81f1..0000000
--- a/extensions/45/vertical-workspaces/lib/workspace.js
+++ /dev/null
@@ -1,463 +0,0 @@
-/**
- * V-Shell (Vertical Workspaces)
- * workspace.js
- *
- * @author GdH <G-dH@github.com>
- * @copyright 2022 - 2023
- * @license GPL-3.0
- *
- */
-
-'use strict';
-
-import St from 'gi://St';
-import Graphene from 'gi://Graphene';
-
-import * as Main from 'resource:///org/gnome/shell/ui/main.js';
-import * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js';
-import * as Params from 'resource:///org/gnome/shell/misc/params.js';
-import * as Util from 'resource:///org/gnome/shell/misc/util.js';
-
-let Me;
-let opt;
-
-let WINDOW_PREVIEW_MAXIMUM_SCALE = 0.95;
-
-export const WorkspaceModule = 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 = opt.get('workspaceModule');
- 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(' WorkspaceModule - Keeping untouched');
- }
-
- _activateModule() {
- if (!this._overrides)
- this._overrides = new Me.Util.Overrides();
-
- this._overrides.addOverride('WorkspaceBackground', Workspace.WorkspaceBackground.prototype, WorkspaceBackground);
-
- // fix overlay base for Vertical Workspaces
- this._overrides.addOverride('WorkspaceLayout', Workspace.WorkspaceLayout.prototype, WorkspaceLayout);
- console.debug(' WorkspaceModule - Activated');
- }
-
- _disableModule() {
- if (this._overrides)
- this._overrides.removeAll();
- this._overrides = null;
- console.debug(' WorkspaceModule - Disabled');
- }
-
- setWindowPreviewMaxScale(scale) {
- WINDOW_PREVIEW_MAXIMUM_SCALE = scale;
- }
-};
-
-// workaround for upstream bug (that is not that invisible in default shell)
-// smaller window cannot be scaled below 0.95 (WINDOW_PREVIEW_MAXIMUM_SCALE)
-// when its target scale for exposed windows view (workspace state 1) is bigger than the scale needed for ws state 0.
-// in workspace state 0 where windows are not spread and window scale should follow workspace scale,
-// this window follows proper top left corner position, but doesn't scale with the workspace
-// so it looks bad and the window can exceed border of the workspace
-// extremely annoying in OVERVIEW_MODE 1 with single smaller window on the workspace, also affects appGrid transition animation
-
-// disadvantage of following workaround - the WINDOW_PREVIEW_MAXIMUM_SCALE value is common for every workspace,
-// on multi-monitor system can be visible unwanted scaling of windows on workspace in WORKSPACE_MODE 0 (windows not spread)
-// when leaving overview while any other workspace is in the WORKSPACE_MODE 1.
-const WorkspaceLayout = {
- // injection to _init()
- after__init() {
- if (opt.OVERVIEW_MODE !== 1)
- WINDOW_PREVIEW_MAXIMUM_SCALE = 0.95;
- if (opt.OVERVIEW_MODE === 1) {
- this._stateAdjustment.connect('notify::value', () => {
- // scale 0.1 for window state 0 just needs to be smaller then possible scale of any window in spread view
- const scale = this._stateAdjustment.value ? 0.95 : 0.1;
- if (scale !== WINDOW_PREVIEW_MAXIMUM_SCALE) {
- WINDOW_PREVIEW_MAXIMUM_SCALE = scale;
- // when transition to ws state 1 (WINDOW_PICKER) begins, replace the constant with the original one
- // and force recalculation of the target layout, so the transition will be smooth
- this._needsLayout = true;
- }
- });
- }
- },
-
- // this fixes wrong size and position calculation of window clones while moving overview to the next (+1) workspace if vertical ws orientation is enabled in GS
- _adjustSpacingAndPadding(rowSpacing, colSpacing, containerBox) {
- if (this._sortedWindows.length === 0)
- return [rowSpacing, colSpacing, containerBox];
-
- // All of the overlays have the same chrome sizes,
- // so just pick the first one.
- const window = this._sortedWindows[0];
-
- const [topOversize, bottomOversize] = window.chromeHeights();
- const [leftOversize, rightOversize] = window.chromeWidths();
-
- const oversize = Math.max(topOversize, bottomOversize, leftOversize, rightOversize);
-
- if (rowSpacing !== null)
- rowSpacing += oversize;
- if (colSpacing !== null)
- colSpacing += oversize;
-
- if (containerBox) {
- const vertical = global.workspaceManager.layout_rows === -1;
-
- const monitor = Main.layoutManager.monitors[this._monitorIndex];
-
- const bottomPoint = new Graphene.Point3D();
- if (vertical)
- bottomPoint.x = containerBox.x2;
- else
- bottomPoint.y = containerBox.y2;
-
-
- const transformedBottomPoint =
- this._container.apply_transform_to_point(bottomPoint);
- const bottomFreeSpace = vertical
- ? (monitor.x + monitor.height) - transformedBottomPoint.x
- : (monitor.y + monitor.height) - transformedBottomPoint.y;
-
- const [, bottomOverlap] = window.overlapHeights();
-
- if ((bottomOverlap + oversize) > bottomFreeSpace && !vertical)
- containerBox.y2 -= (bottomOverlap + oversize) - bottomFreeSpace;
- }
-
- return [rowSpacing, colSpacing, containerBox];
- },
-
- _createBestLayout(area) {
- const [rowSpacing, columnSpacing] =
- this._adjustSpacingAndPadding(this._spacing, this._spacing, null);
-
- // We look for the largest scale that allows us to fit the
- // largest row/tallest column on the workspace.
- this._layoutStrategy = new UnalignedLayoutStrategy({
- monitor: Main.layoutManager.monitors[this._monitorIndex],
- rowSpacing,
- columnSpacing,
- });
-
- let lastLayout = null;
- let lastNumColumns = -1;
- let lastScale = 0;
- let lastSpace = 0;
-
- for (let numRows = 1; ; numRows++) {
- const numColumns = Math.ceil(this._sortedWindows.length / numRows);
-
- // If adding a new row does not change column count just stop
- // (for instance: 9 windows, with 3 rows -> 3 columns, 4 rows ->
- // 3 columns as well => just use 3 rows then)
- if (numColumns === lastNumColumns)
- break;
-
- const layout = this._layoutStrategy.computeLayout(this._sortedWindows, {
- numRows,
- });
-
- const [scale, space] = this._layoutStrategy.computeScaleAndSpace(layout, area);
-
- if (lastLayout && !this._isBetterScaleAndSpace(lastScale, lastSpace, scale, space))
- break;
-
- lastLayout = layout;
- lastNumColumns = numColumns;
- lastScale = scale;
- lastSpace = space;
- }
-
- return lastLayout;
- },
-};
-
-class UnalignedLayoutStrategy extends Workspace.LayoutStrategy {
- _newRow() {
- // Row properties:
- //
- // * x, y are the position of row, relative to area
- //
- // * width, height are the scaled versions of fullWidth, fullHeight
- //
- // * width also has the spacing in between windows. It's not in
- // fullWidth, as the spacing is constant, whereas fullWidth is
- // meant to be scaled
- //
- // * neither height/fullHeight have any sort of spacing or padding
- return {
- x: 0, y: 0,
- width: 0, height: 0,
- fullWidth: 0, fullHeight: 0,
- windows: [],
- };
- }
-
- // Computes and returns an individual scaling factor for @window,
- // to be applied in addition to the overall layout scale.
- _computeWindowScale(window) {
- // Since we align windows next to each other, the height of the
- // thumbnails is much more important to preserve than the width of
- // them, so two windows with equal height, but maybe differering
- // widths line up.
- let ratio = window.boundingBox.height / this._monitor.height;
-
- // The purpose of this manipulation here is to prevent windows
- // from getting too small. For something like a calculator window,
- // we need to bump up the size just a bit to make sure it looks
- // good. We'll use a multiplier of 1.5 for this.
-
- // Map from [0, 1] to [1.5, 1]
- return Util.lerp(1.5, 1, ratio);
- }
-
- _computeRowSizes(layout) {
- let { rows, scale } = layout;
- for (let i = 0; i < rows.length; i++) {
- let row = rows[i];
- row.width = row.fullWidth * scale + (row.windows.length - 1) * this._columnSpacing;
- row.height = row.fullHeight * scale;
- }
- }
-
- _keepSameRow(row, window, width, idealRowWidth) {
- if (row.fullWidth + width <= idealRowWidth)
- return true;
-
- let oldRatio = row.fullWidth / idealRowWidth;
- let newRatio = (row.fullWidth + width) / idealRowWidth;
-
- if (Math.abs(1 - newRatio) < Math.abs(1 - oldRatio))
- return true;
-
- return false;
- }
-
- _sortRow(row) {
- // Sort windows horizontally to minimize travel distance.
- // This affects in what order the windows end up in a row.
- row.windows.sort((a, b) => a.windowCenter.x - b.windowCenter.x);
- }
-
- computeLayout(windows, layoutParams) {
- layoutParams = Params.parse(layoutParams, {
- numRows: 0,
- });
-
- if (layoutParams.numRows === 0)
- throw new Error(`${this.constructor.name}: No numRows given in layout params`);
-
- const numRows = layoutParams.numRows;
-
- let rows = [];
- let totalWidth = 0;
- for (let i = 0; i < windows.length; i++) {
- let window = windows[i];
- let s = this._computeWindowScale(window);
- totalWidth += window.boundingBox.width * s;
- }
-
- let idealRowWidth = totalWidth / numRows;
-
- // Sort windows vertically to minimize travel distance.
- // This affects what rows the windows get placed in.
- let sortedWindows = windows.slice();
- sortedWindows.sort((a, b) => a.windowCenter.y - b.windowCenter.y);
-
- let windowIdx = 0;
- for (let i = 0; i < numRows; i++) {
- let row = this._newRow();
- rows.push(row);
-
- for (; windowIdx < sortedWindows.length; windowIdx++) {
- let window = sortedWindows[windowIdx];
- let s = this._computeWindowScale(window);
- let width = window.boundingBox.width * s;
- let height = window.boundingBox.height * s;
- row.fullHeight = Math.max(row.fullHeight, height);
-
- // either new width is < idealWidth or new width is nearer from idealWidth then oldWidth
- if (this._keepSameRow(row, window, width, idealRowWidth) || (i === numRows - 1)) {
- row.windows.push(window);
- row.fullWidth += width;
- } else {
- break;
- }
- }
- }
-
- let gridHeight = 0;
- let maxRow;
- for (let i = 0; i < numRows; i++) {
- let row = rows[i];
- this._sortRow(row);
-
- if (!maxRow || row.fullWidth > maxRow.fullWidth)
- maxRow = row;
- gridHeight += row.fullHeight;
- }
-
- return {
- numRows,
- rows,
- maxColumns: maxRow.windows.length,
- gridWidth: maxRow.fullWidth,
- gridHeight,
- };
- }
-
- computeScaleAndSpace(layout, area) {
- let hspacing = (layout.maxColumns - 1) * this._columnSpacing;
- let vspacing = (layout.numRows - 1) * this._rowSpacing;
-
- let spacedWidth = area.width - hspacing;
- let spacedHeight = area.height - vspacing;
-
- let horizontalScale = spacedWidth / layout.gridWidth;
- let verticalScale = spacedHeight / layout.gridHeight;
-
- // Thumbnails should be less than 70% of the original size
- let scale = Math.min(
- horizontalScale, verticalScale, WINDOW_PREVIEW_MAXIMUM_SCALE);
-
- let scaledLayoutWidth = layout.gridWidth * scale + hspacing;
- let scaledLayoutHeight = layout.gridHeight * scale + vspacing;
- let space = (scaledLayoutWidth * scaledLayoutHeight) / (area.width * area.height);
-
- layout.scale = scale;
-
- return [scale, space];
- }
-
- computeWindowSlots(layout, area) {
- this._computeRowSizes(layout);
-
- let { rows, scale } = layout;
-
- let slots = [];
-
- // Do this in three parts.
- let heightWithoutSpacing = 0;
- for (let i = 0; i < rows.length; i++) {
- let row = rows[i];
- heightWithoutSpacing += row.height;
- }
-
- let verticalSpacing = (rows.length - 1) * this._rowSpacing;
- let additionalVerticalScale = Math.min(1, (area.height - verticalSpacing) / heightWithoutSpacing);
-
- // keep track how much smaller the grid becomes due to scaling
- // so it can be centered again
- let compensation = 0;
- let y = 0;
-
- for (let i = 0; i < rows.length; i++) {
- let row = rows[i];
-
- // If this window layout row doesn't fit in the actual
- // geometry, then apply an additional scale to it.
- let horizontalSpacing = (row.windows.length - 1) * this._columnSpacing;
- let widthWithoutSpacing = row.width - horizontalSpacing;
- let additionalHorizontalScale = Math.min(1, (area.width - horizontalSpacing) / widthWithoutSpacing);
-
- if (additionalHorizontalScale < additionalVerticalScale) {
- row.additionalScale = additionalHorizontalScale;
- // Only consider the scaling in addition to the vertical scaling for centering.
- compensation += (additionalVerticalScale - additionalHorizontalScale) * row.height;
- } else {
- row.additionalScale = additionalVerticalScale;
- // No compensation when scaling vertically since centering based on a too large
- // height would undo what vertical scaling is trying to achieve.
- }
-
- row.x = area.x + (Math.max(area.width - (widthWithoutSpacing * row.additionalScale + horizontalSpacing), 0) / 2);
- row.y = area.y + (Math.max(area.height - (heightWithoutSpacing + verticalSpacing), 0) / 2) + y;
- y += row.height * row.additionalScale + this._rowSpacing;
- }
-
- compensation /= 2;
-
- for (let i = 0; i < rows.length; i++) {
- const row = rows[i];
- const rowY = row.y + compensation;
- const rowHeight = row.height * row.additionalScale;
-
- let x = row.x;
- for (let j = 0; j < row.windows.length; j++) {
- let window = row.windows[j];
-
- let s = scale * this._computeWindowScale(window) * row.additionalScale;
- let cellWidth = window.boundingBox.width * s;
- let cellHeight = window.boundingBox.height * s;
-
- s = Math.min(s, WINDOW_PREVIEW_MAXIMUM_SCALE);
- let cloneWidth = window.boundingBox.width * s;
- const cloneHeight = window.boundingBox.height * s;
-
- let cloneX = x + (cellWidth - cloneWidth) / 2;
- let cloneY;
-
- // If there's only one row, align windows vertically centered inside the row
- if (rows.length === 1)
- cloneY = rowY + (rowHeight - cloneHeight) / 2;
- // If there are multiple rows, align windows to the bottom edge of the row
- else
- cloneY = rowY + rowHeight - cellHeight;
-
- // Align with the pixel grid to prevent blurry windows at scale = 1
- cloneX = Math.floor(cloneX);
- cloneY = Math.floor(cloneY);
-
- slots.push([cloneX, cloneY, cloneWidth, cloneHeight, window]);
- x += cellWidth + this._columnSpacing;
- }
- }
- return slots;
- }
-}
-
-const WorkspaceBackground = {
- _updateBorderRadius(value = false) {
- // don't round already rounded corners during exposing windows
- if (value === false && opt.OVERVIEW_MODE === 1)
- return;
-
- const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
- const cornerRadius = scaleFactor * opt.WS_PREVIEW_BG_RADIUS;
-
- const backgroundContent = this._bgManager.backgroundActor.content;
- value = value !== false
- ? value
- : this._stateAdjustment.value;
-
- backgroundContent.rounded_clip_radius =
- Util.lerp(0, cornerRadius, value);
- },
-};