diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-09-16 17:26:54 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-09-16 17:31:57 +0000 |
commit | 0a7a4c5b38489621bf99415cdfba0e2538da3a49 (patch) | |
tree | b19fdd525465f01902a183f91492e284a665246c /extensions/46/vertical-workspaces/lib | |
parent | Releasing debian version 20240414-2. (diff) | |
download | gnome-shell-extensions-extra-0a7a4c5b38489621bf99415cdfba0e2538da3a49.tar.xz gnome-shell-extensions-extra-0a7a4c5b38489621bf99415cdfba0e2538da3a49.zip |
Merging upstream version 20240916 (Closes: #1079257).
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'extensions/46/vertical-workspaces/lib')
26 files changed, 0 insertions, 13061 deletions
diff --git a/extensions/46/vertical-workspaces/lib/appDisplay.js b/extensions/46/vertical-workspaces/lib/appDisplay.js deleted file mode 100644 index c33cf0d..0000000 --- a/extensions/46/vertical-workspaces/lib/appDisplay.js +++ /dev/null @@ -1,1694 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * appDisplay.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; -import Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; -import GObject from 'gi://GObject'; -import Graphene from 'gi://Graphene'; -import Meta from 'gi://Meta'; -import Pango from 'gi://Pango'; -import Shell from 'gi://Shell'; -import St from 'gi://St'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'; -import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'; - -let Me; -let opt; -// gettext -let _; - -let _timeouts; - -const APP_ICON_TITLE_EXPAND_TIME = 200; -const APP_ICON_TITLE_COLLAPSE_TIME = 100; - -const shellVersion46 = !Clutter.Container; // Container has been removed in 46 - -function _getCategories(info) { - let categoriesStr = info.get_categories(); - if (!categoriesStr) - return []; - return categoriesStr.split(';'); -} - -function _listsIntersect(a, b) { - for (let itemA of a) { - if (b.includes(itemA)) - return true; - } - return false; -} - -export const AppDisplayModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - _ = Me.gettext; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - - this._appGridLayoutSettings = null; - this._appDisplayScrollConId = 0; - this._appSystemStateConId = 0; - this._appGridLayoutConId = 0; - this._origAppViewItemAcceptDrop = null; - this._updateFolderIcons = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - _ = null; - } - - update(reset) { - this._removeTimeouts(); - this.moduleEnabled = opt.get('appDisplayModule'); - const conflict = false; - - reset = reset || !this.moduleEnabled || conflict; - - // don't touch the original code if module disabled - if (reset && !this._firstActivation) { - this._disableModule(); - this.moduleEnabled = false; - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - if (reset && this._firstActivation) { - this.moduleEnabled = false; - console.debug(' AppDisplayModule - Keeping untouched'); - } - } - - _activateModule() { - Me.Modules.iconGridModule.update(); - - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - _timeouts = {}; - - // Common - // this._overrides.addOverride('BaseAppViewCommon', AppDisplay.BaseAppView.prototype, BaseAppViewCommon); - // instead of overriding inaccessible BaseAppView class, we override its children - AppDisplay and FolderView - this._overrides.addOverride('BaseAppViewCommonApp', AppDisplay.AppDisplay.prototype, BaseAppViewCommon); - this._overrides.addOverride('BaseAppViewCommonFolder', AppDisplay.FolderView.prototype, BaseAppViewCommon); - this._overrides.addOverride('FolderView', AppDisplay.FolderView.prototype, FolderView); - this._overrides.addOverride('AppDisplay', AppDisplay.AppDisplay.prototype, AppDisplayCommon); - this._overrides.addOverride('AppViewItem', AppDisplay.AppViewItem.prototype, AppViewItemCommon); - this._overrides.addOverride('FolderIcon', AppDisplay.FolderIcon.prototype, FolderIcon); - if (opt.APP_GRID_ACTIVE_PREVIEW) - this._overrides.addOverride('ActiveFolderIcon', AppDisplay.FolderIcon, ActiveFolderIcon); - this._overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIcon); - - if (opt.ORIENTATION === Clutter.Orientation.VERTICAL) { - // this._overrides.addOverride('BaseAppViewVertical', AppDisplay.BaseAppView.prototype, BaseAppViewVertical); - this._overrides.addOverride('BaseAppViewVerticalApp', AppDisplay.AppDisplay.prototype, BaseAppViewVertical); - this._overrides.addOverride('BaseAppViewVerticalFolder', AppDisplay.FolderView.prototype, BaseAppViewVertical); - this._overrides.addOverride('AppDisplayVertical', AppDisplay.AppDisplay.prototype, AppDisplayVertical); - } - - // Custom App Grid - this._overrides.addOverride('AppFolderDialog', AppDisplay.AppFolderDialog.prototype, AppFolderDialog); - - // BaseAppViewGridLayout is not exported, we can only access current instance - this._overrides.addOverride('BaseAppViewGridLayout', Main.overview._overview.controls._appDisplay._appGridLayout, BaseAppViewGridLayout); - // this._overrides.addOverride('FolderGrid', AppDisplay.FolderGrid.prototype, FolderGrid); - - this._setAppDisplayOrientation(opt.ORIENTATION === Clutter.Orientation.VERTICAL); - this._updateDND(); - - const appDisplay = Main.overview._overview.controls._appDisplay; - - if (!this._originalWorkId) - this._originalWorkId = appDisplay._redisplayWorkId; - if (!this._newWorkId) { - appDisplay._redisplayWorkId = Main.initializeDeferredWork(appDisplay, () => { - appDisplay._redisplay(); - if (appDisplay._overviewHiddenId === 0) - appDisplay._overviewHiddenId = Main.overview.connect('hidden', () => appDisplay.goToPage(0)); - }); - this._newWorkId = appDisplay._redisplayWorkId; - } else { - appDisplay._redisplayWorkId = this._newWorkId; - } - - - if (!Main.sessionMode.isGreeter) - this._updateAppDisplayProperties(); - - console.debug(' AppDisplayModule - Activated'); - } - - _disableModule() { - Me.Modules.iconGridModule.update(true); - - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - const reset = true; - this._setAppDisplayOrientation(false); - this._updateAppDisplayProperties(reset); - this._updateDND(reset); - this._restoreOverviewGroup(); - this._removeStatusMessage(); - - // register a new appDisplay workId so the original code will be called from the callback - const appDisplay = Main.overview._overview.controls._appDisplay; - appDisplay._redisplayWorkId = this._originalWorkId; - - console.debug(' AppDisplayModule - Disabled'); - } - - _removeTimeouts() { - if (_timeouts) { - Object.values(_timeouts).forEach(t => { - if (t) - GLib.source_remove(t); - }); - _timeouts = null; - } - } - - _setAppDisplayOrientation(vertical = false) { - const CLUTTER_ORIENTATION = vertical ? Clutter.Orientation.VERTICAL : Clutter.Orientation.HORIZONTAL; - // app display to vertical has issues - page indicator not working - // global appDisplay orientation switch is not built-in - let appDisplay = Main.overview._overview._controls._appDisplay; - // following line itself only changes in which axis will operate overshoot detection which switches appDisplay pages while dragging app icon to vertical - appDisplay._orientation = CLUTTER_ORIENTATION; - appDisplay._grid.layoutManager._orientation = CLUTTER_ORIENTATION; - appDisplay._swipeTracker.orientation = CLUTTER_ORIENTATION; - appDisplay._swipeTracker._reset(); - if (vertical) { - appDisplay._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); - - // move and change orientation of page indicators - const pageIndicators = appDisplay._pageIndicators; - pageIndicators.vertical = true; - appDisplay._box.vertical = false; - pageIndicators.x_expand = false; - pageIndicators.y_align = Clutter.ActorAlign.CENTER; - pageIndicators.x_align = Clutter.ActorAlign.START; - - // moving these bars needs more patching of the appDisplay's code - // for now we just change bars style to be more like vertically oriented arrows indicating direction to prev/next page - appDisplay._nextPageIndicator.add_style_class_name('nextPageIndicator'); - appDisplay._prevPageIndicator.add_style_class_name('prevPageIndicator'); - - // setting their x_scale to 0 removes the arrows and avoid allocation issues compared to .hide() them - appDisplay._nextPageArrow.scale_x = 0; - appDisplay._prevPageArrow.scale_x = 0; - } else { - appDisplay._scrollView.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.NEVER); - if (this._appDisplayScrollConId) { - appDisplay._adjustment.disconnect(this._appDisplayScrollConId); - this._appDisplayScrollConId = 0; - } - - // restore original page indicators - const pageIndicators = appDisplay._pageIndicators; - pageIndicators.vertical = false; - appDisplay._box.vertical = true; - pageIndicators.x_expand = true; - pageIndicators.y_align = Clutter.ActorAlign.END; - pageIndicators.x_align = Clutter.ActorAlign.CENTER; - - // put back touch friendly navigation buttons - const scrollContainer = appDisplay._scrollView.get_parent(); - if (appDisplay._hintContainer && !appDisplay._hintContainer.get_parent()) { - scrollContainer.add_child(appDisplay._hintContainer); - // the hit container covers the entire app grid and added at the top of the stack blocks DND drops - // so it needs to be pushed below - scrollContainer.set_child_below_sibling(appDisplay._hintContainer, null); - } - - appDisplay._nextPageArrow.scale_x = 1; - appDisplay._prevPageArrow.scale_x = 1; - - appDisplay._nextPageIndicator.remove_style_class_name('nextPageIndicator'); - appDisplay._prevPageIndicator.remove_style_class_name('prevPageIndicator'); - } - - // value for page indicator is calculated from scroll adjustment, horizontal needs to be replaced by vertical - appDisplay._adjustment = vertical - ? appDisplay._scrollView.get_vscroll_bar().adjustment - : appDisplay._scrollView.get_hscroll_bar().adjustment; - - // no need to connect already connected signal (wasn't removed the original one before) - if (!vertical) { - // reset used appDisplay properties - Main.overview._overview._controls._appDisplay.scale_y = 1; - Main.overview._overview._controls._appDisplay.scale_x = 1; - Main.overview._overview._controls._appDisplay.opacity = 255; - return; - } - - // update appGrid dot pages indicators - this._appDisplayScrollConId = appDisplay._adjustment.connect('notify::value', adj => { - const value = adj.value / adj.page_size; - appDisplay._pageIndicators.setCurrentPosition(value); - }); - } - - // Set App Grid columns, rows, icon size, incomplete pages - _updateAppDisplayProperties(reset = false) { - opt._appGridNeedsRedisplay = false; - // columns, rows, icon size - const appDisplay = Main.overview._overview._controls._appDisplay; - appDisplay.visible = true; - if (reset) { - appDisplay._grid.layoutManager.fixedIconSize = -1; - appDisplay._grid.layoutManager.allow_incomplete_pages = true; - appDisplay._grid._currentMode = -1; - appDisplay._grid.setGridModes(); - if (this._appGridLayoutSettings) { - this._appGridLayoutSettings.disconnect(this._appGridLayoutConId); - this._appGridLayoutConId = 0; - this._appGridLayoutSettings = null; - } - appDisplay._redisplay(); - - appDisplay._grid.set_style(''); - this._updateAppGrid(reset); - } else { - // update grid on layout reset - if (!this._appGridLayoutSettings) { - this._appGridLayoutSettings = Me.getSettings('org.gnome.shell'); - this._appGridLayoutConId = this._appGridLayoutSettings.connect('changed::app-picker-layout', this._updateLayout); - } - - appDisplay._grid.layoutManager.allow_incomplete_pages = opt.APP_GRID_ALLOW_INCOMPLETE_PAGES; - // appDisplay._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`); - // APP_GRID_SPACING constant is used for grid dimensions calculation - // but sometimes the actual grid spacing properties affect/change the calculated size, therefore we set it lower to avoid this problem - // main app grid always use available space and the spacing is optimized for the grid dimensions - appDisplay._grid.set_style('column-spacing: 5px; row-spacing: 5px;'); - - // force redisplay - appDisplay._grid._currentMode = -1; - appDisplay._grid.setGridModes(); - appDisplay._grid.layoutManager.fixedIconSize = opt.APP_GRID_ICON_SIZE; - // avoid resetting appDisplay before startup animation - // x11 shell restart skips startup animation - if (!Main.layoutManager._startingUp) { - this._updateAppGrid(); - } else if (Main.layoutManager._startingUp && (Meta.is_restart() || Me.Util.dashIsDashToDock())) { - _timeouts.three = GLib.idle_add(GLib.PRIORITY_LOW, () => { - this._updateAppGrid(); - _timeouts.three = 0; - return GLib.SOURCE_REMOVE; - }); - } - } - } - - _updateDND(reset) { - if (!reset) { - if (!this._appSystemStateConId && opt.APP_GRID_INCLUDE_DASH >= 3) { - this._appSystemStateConId = Shell.AppSystem.get_default().connect( - 'app-state-changed', - () => { - this._updateFolderIcons = true; - Main.overview._overview.controls._appDisplay._redisplay(); - } - ); - } - } else if (this._appSystemStateConId) { - Shell.AppSystem.get_default().disconnect(this._appSystemStateConId); - this._appSystemStateConId = 0; - } - } - - _restoreOverviewGroup() { - Main.overview.dash.showAppsButton.checked = false; - Main.layoutManager.overviewGroup.opacity = 255; - Main.layoutManager.overviewGroup.scale_x = 1; - Main.layoutManager.overviewGroup.scale_y = 1; - Main.layoutManager.overviewGroup.hide(); - Main.overview._overview._controls._appDisplay.translation_x = 0; - Main.overview._overview._controls._appDisplay.translation_y = 0; - Main.overview._overview._controls._appDisplay.visible = true; - Main.overview._overview._controls._appDisplay.opacity = 255; - } - - // update all invalid positions that may be result of grid/icon size change - _updateIconPositions() { - const appDisplay = Main.overview._overview._controls._appDisplay; - const layout = JSON.stringify(global.settings.get_value('app-picker-layout').recursiveUnpack()); - // if app grid layout is empty, sort source alphabetically to avoid misplacing - if (layout === JSON.stringify([]) && appDisplay._sortOrderedItemsAlphabetically) - appDisplay._sortOrderedItemsAlphabetically(); - const icons = [...appDisplay._orderedItems]; - for (let i = 0; i < icons.length; i++) - appDisplay._moveItem(icons[i], -1, -1); - } - - _removeIcons() { - const appDisplay = Main.overview._overview._controls._appDisplay; - const icons = [...appDisplay._orderedItems]; - for (let i = 0; i < icons.length; i++) { - const icon = icons[i]; - if (icon._dialog) - Main.layoutManager.overviewGroup.remove_child(icon._dialog); - appDisplay._removeItem(icon); - icon.destroy(); - } - appDisplay._folderIcons = []; - } - - _removeStatusMessage() { - if (Me._vShellStatusMessage) { - if (Me._vShellMessageTimeoutId) { - GLib.source_remove(Me._vShellMessageTimeoutId); - Me._vShellMessageTimeoutId = 0; - } - Me._vShellStatusMessage.destroy(); - Me._vShellStatusMessage = null; - } - } - - _updateLayout(settings, key) { - const currentValue = JSON.stringify(settings.get_value(key).deep_unpack()); - const emptyValue = JSON.stringify([]); - const customLayout = currentValue !== emptyValue; - if (!customLayout) { - this._updateAppGrid(); - } - } - - _updateAppGrid(reset = false, callback) { - const appDisplay = Main.overview._overview._controls._appDisplay; - // reset the grid only if called directly without args or if all folders where removed by using reset button in Settings window - // otherwise this function is called every time a user moves icon to another position as a settings callback - - // force update icon size using adaptToSize(), the page size cannot be the same as the current one - appDisplay._grid.layoutManager._pageWidth += 1; - appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight); - - // don't delay the first screen lock whe extensions are rebased - // removing icons takes time and with other - if (!Main.sessionMode.isLocked) - this._removeIcons(); - - appDisplay._redisplay(); - - // don't realize appDisplay on disable, or at startup if disabled - // always realize appDisplay otherwise to avoid errors while opening folders (that I was unable to trace) - if (reset || (!opt.APP_GRID_PERFORMANCE && callback)) { - this._removeStatusMessage(); - if (callback) - callback(); - return; - } - - // workaround - silently realize appDisplay - // appDisplay and its content must be "visible" (opacity > 0) on the screen (within monitor geometry) - // to realize its objects - // this action takes some time and affects animations during the first use - // if we do it invisibly before user needs it, it can improve the user's experience - - this._exposeAppGrid(); - - // let the main loop process our changes before continuing - _timeouts.one = GLib.idle_add(GLib.PRIORITY_LOW, () => { - this._updateIconPositions(); - if (appDisplay._sortOrderedItemsAlphabetically) { - appDisplay._sortOrderedItemsAlphabetically(); - appDisplay._grid.layoutManager._pageWidth += 1; - appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight); - appDisplay._setLinearPositions(appDisplay._orderedItems); - } - - appDisplay._redisplay(); - // realize also all app folders (by opening them) so the first popup is as smooth as the second one - // let the main loop process our changes before continuing - _timeouts.two = GLib.idle_add(GLib.PRIORITY_LOW, () => { - this._restoreAppGrid(); - Me._resetInProgress = false; - this._removeStatusMessage(); - - if (callback) - callback(); - - _timeouts.two = 0; - return GLib.SOURCE_REMOVE; - }); - _timeouts.one = 0; - return GLib.SOURCE_REMOVE; - }); - } - - _exposeAppGrid() { - const overviewGroup = Main.layoutManager.overviewGroup; - if (!overviewGroup.visible) { - // scale down the overviewGroup so it don't cover uiGroup - overviewGroup.scale_y = 0.001; - // make it invisible to the eye, but visible for the renderer - overviewGroup.opacity = 1; - // if overview is hidden, show it - overviewGroup.visible = true; - } - - const appDisplay = Main.overview._overview._controls._appDisplay; - appDisplay.opacity = 1; - - // find usable value, sometimes it's one, sometime the other... - let [x, y] = appDisplay.get_position(); - let { x1, y1 } = appDisplay.allocation; - x = x === Infinity ? 0 : x; - y = y === Infinity ? 0 : y; - x1 = x1 === Infinity ? 0 : x1; - y1 = y1 === Infinity ? 0 : y1; - appDisplay.translation_x = -(x ? x : x1); - appDisplay.translation_y = -(y ? y : y1); - this._exposeAppFolders(); - } - - _exposeAppFolders() { - const appDisplay = Main.overview._overview._controls._appDisplay; - appDisplay._folderIcons.forEach(d => { - d._ensureFolderDialog(); - d._dialog._updateFolderSize(); - d._dialog.scale_y = 0.0001; - d._dialog.show(); - }); - } - - _restoreAppGrid() { - const appDisplay = Main.overview._overview._controls._appDisplay; - appDisplay.translation_x = 0; - appDisplay.translation_y = 0; - // appDisplay.opacity = 0; - this._hideAppFolders(); - - const overviewGroup = Main.layoutManager.overviewGroup; - if (!Main.overview._shown) - overviewGroup.hide(); - overviewGroup.scale_y = 1; - overviewGroup.opacity = 255; - - this._removeStatusMessage(); - } - - _hideAppFolders() { - const appDisplay = Main.overview._overview._controls._appDisplay; - appDisplay._folderIcons.forEach(d => { - if (d._dialog) { - d._dialog._updateFolderSize(); - d._dialog.hide(); - d._dialog.scale_y = 1; - } - }); - } - - _getWindowApp(metaWin) { - const tracker = Shell.WindowTracker.get_default(); - return tracker.get_window_app(metaWin); - } - - _getAppLastUsedWindow(app) { - let recentWin; - global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => { - const winApp = this._getWindowApp(metaWin); - if (!recentWin && winApp === app) - recentWin = metaWin; - }); - return recentWin; - } - - _getAppRecentWorkspace(app) { - const recentWin = this._getAppLastUsedWindow(app); - if (recentWin) - return recentWin.get_workspace(); - - return null; - } -}; - -const AppDisplayVertical = { - // correction of the appGrid size when page indicators were moved from the bottom to the right - adaptToSize(width, height) { - const [, indicatorWidth] = this._pageIndicators.get_preferred_width(-1); - width -= indicatorWidth; - - this._grid.findBestModeForSize(width, height); - - const adaptToSize = AppDisplay.BaseAppView.prototype.adaptToSize.bind(this); - adaptToSize(width, height); - }, -}; - -function _getViewFromIcon(icon) { - for (let parent = icon.get_parent(); parent; parent = parent.get_parent()) { - if (parent instanceof AppDisplay.AppDisplay || parent instanceof AppDisplay.FolderView) { - return parent; - } - } - return null; -} - -const AppDisplayCommon = { - _ensureDefaultFolders() { - // disable creation of default folders if user deleted them - }, - - // apps load adapted for custom sorting and including dash items - _loadApps() { - let appIcons = []; - const runningApps = Shell.AppSystem.get_default().get_running().map(a => a.id); - - this._appInfoList = Shell.AppSystem.get_default().get_installed().filter(appInfo => { - try { - appInfo.get_id(); // catch invalid file encodings - } catch (e) { - return false; - } - - const appIsRunning = runningApps.includes(appInfo.get_id()); - const appIsFavorite = this._appFavorites.isFavorite(appInfo.get_id()); - const excludeApp = (opt.APP_GRID_EXCLUDE_RUNNING && appIsRunning) || (opt.APP_GRID_EXCLUDE_FAVORITES && appIsFavorite); - - return this._parentalControlsManager.shouldShowApp(appInfo) && !excludeApp; - }); - - let apps = this._appInfoList.map(app => app.get_id()); - - let appSys = Shell.AppSystem.get_default(); - - const appsInsideFolders = new Set(); - this._folderIcons = []; - if (!opt.APP_GRID_USAGE) { - let folders = this._folderSettings.get_strv('folder-children'); - folders.forEach(id => { - let path = `${this._folderSettings.path}folders/${id}/`; - let icon = this._items.get(id); - if (!icon) { - icon = new AppDisplay.FolderIcon(id, path, this); - icon.connect('apps-changed', () => { - this._redisplay(); - this._savePages(); - }); - icon.connect('notify::pressed', () => { - if (icon.pressed) - this.updateDragFocus(icon); - }); - } else if (this._updateFolderIcons && opt.APP_GRID_EXCLUDE_RUNNING) { - // if any app changed its running state, update folder icon - icon.icon.update(); - } - - // remove empty folder icons - if (!icon.visible) { - icon.destroy(); - return; - } - - appIcons.push(icon); - this._folderIcons.push(icon); - - icon.getAppIds().forEach(appId => appsInsideFolders.add(appId)); - }); - } - - // reset request to update active icon - this._updateFolderIcons = false; - - // Allow dragging of the icon only if the Dash would accept a drop to - // change favorite-apps. There are no other possible drop targets from - // the app picker, so there's no other need for a drag to start, - // at least on single-monitor setups. - // This also disables drag-to-launch on multi-monitor setups, - // but we hope that is not used much. - const isDraggable = - global.settings.is_writable('favorite-apps') || - global.settings.is_writable('app-picker-layout'); - - apps.forEach(appId => { - if (!opt.APP_GRID_USAGE && appsInsideFolders.has(appId)) - return; - - let icon = this._items.get(appId); - if (!icon) { - let app = appSys.lookup_app(appId); - icon = new AppDisplay.AppIcon(app, { isDraggable }); - icon.connect('notify::pressed', () => { - if (icon.pressed) - this.updateDragFocus(icon); - }); - } - - appIcons.push(icon); - }); - - // At last, if there's a placeholder available, add it - if (this._placeholder) - appIcons.push(this._placeholder); - - return appIcons; - }, - - // support active preview icons - _onDragBegin(overview, source) { - if (source._sourceItem) - source = source._sourceItem; - - this._dragMonitor = { - dragMotion: this._onDragMotion.bind(this), - }; - DND.addDragMonitor(this._dragMonitor); - - this._appGridLayout.showPageIndicators(); - this._dragFocus = null; - this._swipeTracker.enabled = false; - - // When dragging from a folder dialog, the dragged app icon doesn't - // exist in AppDisplay. We work around that by adding a placeholder - // icon that is either destroyed on cancel, or becomes the effective - // new icon when dropped. - if (/* AppDisplay.*/_getViewFromIcon(source) instanceof AppDisplay.FolderView || - (opt.APP_GRID_EXCLUDE_FAVORITES && this._appFavorites.isFavorite(source.id))) - this._ensurePlaceholder(source); - }, - - _ensurePlaceholder(source) { - if (this._placeholder) - return; - - if (source._sourceItem) - source = source._sourceItem; - - const appSys = Shell.AppSystem.get_default(); - const app = appSys.lookup_app(source.id); - - const isDraggable = - global.settings.is_writable('favorite-apps') || - global.settings.is_writable('app-picker-layout'); - - this._placeholder = new AppDisplay.AppIcon(app, { isDraggable }); - this._placeholder.connect('notify::pressed', () => { - if (this._placeholder?.pressed) - this.updateDragFocus(this._placeholder); - }); - this._placeholder.scaleAndFade(); - this._redisplay(); - }, - - // accept source from active folder preview - acceptDrop(source) { - if (opt.APP_GRID_USAGE) - return false; - if (source._sourceItem) - source = source._sourceItem; - - if (!this._acceptDropCommon(source)) - return false; - - let view = /* AppDisplay.*/_getViewFromIcon(source); - if (view instanceof AppDisplay.FolderView) - view.removeApp(source.app); - - if (this._currentDialog) - this._currentDialog.popdown(); - - if (opt.APP_GRID_EXCLUDE_FAVORITES && this._appFavorites.isFavorite(source.id)) - this._appFavorites.removeFavorite(source.id); - - return true; - }, -}; - -const BaseAppViewVertical = { - after__init() { - this._grid.layoutManager._orientation = Clutter.Orientation.VERTICAL; - this._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL); - this._orientation = Clutter.Orientation.VERTICAL; - this._swipeTracker.orientation = Clutter.Orientation.VERTICAL; - this._swipeTracker._reset(); - this._pageIndicators.vertical = true; - this._box.vertical = false; - this._pageIndicators.x_expand = false; - this._pageIndicators.y_align = Clutter.ActorAlign.CENTER; - this._pageIndicators.x_align = Clutter.ActorAlign.START; - this._pageIndicators.set_style('margin-right: 10px;'); - // moving these bars needs more patching of the this's code - // for now we just change bars style to be more like vertically oriented arrows indicating direction to prev/next page - this._nextPageIndicator.add_style_class_name('nextPageIndicator'); - this._prevPageIndicator.add_style_class_name('prevPageIndicator'); - - // setting their x_scale to 0 removes the arrows and avoid allocation issues compared to .hide() them - this._nextPageArrow.scale_x = 0; - this._prevPageArrow.scale_x = 0; - - this._adjustment = this._scrollView.get_vscroll_bar().adjustment; - - this._adjustment.connect('notify::value', adj => { - const value = adj.value / adj.page_size; - this._pageIndicators.setCurrentPosition(value); - }); - }, -}; - -const BaseAppViewCommon = { - _sortOrderedItemsAlphabetically(icons = null) { - if (!icons) - icons = this._orderedItems; - icons.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())); - }, - - _setLinearPositions(icons) { - const { itemsPerPage } = this._grid; - icons.forEach((icon, i) => { - const page = Math.floor(i / itemsPerPage); - const position = i % itemsPerPage; - try { - this._moveItem(icon, page, position); - } catch (e) { - console.warn(`Warning:${e}`); - } - }); - }, - - // adds sorting options and option to add favorites and running apps - _redisplay() { - if (this._folderIcons) { - this._folderIcons.forEach(icon => { - icon.view._redisplay(); - }); - } - let oldApps = this._orderedItems.slice(); - let oldAppIds = oldApps.map(icon => icon.id); - - let newApps = this._loadApps().sort(this._compareItems.bind(this)); - let newAppIds = newApps.map(icon => icon.id); - - let addedApps = newApps.filter(icon => !oldAppIds.includes(icon.id)); - let removedApps = oldApps.filter(icon => !newAppIds.includes(icon.id)); - - // Remove old app icons - removedApps.forEach(icon => { - this._removeItem(icon); - icon.destroy(); - }); - - // Add new app icons, or move existing ones - newApps.forEach(icon => { - const [page, position] = this._getItemPosition(icon); - if (addedApps.includes(icon)) { - this._addItem(icon, page, position); - } else if (page !== -1 && position !== -1) { - this._moveItem(icon, page, position); - } else { - // App is part of a folder - } - }); - - // different options for root app grid and app folders - const thisIsFolder = this instanceof AppDisplay.FolderView; - const thisIsAppDisplay = !thisIsFolder; - if ((opt.APP_GRID_ORDER && thisIsAppDisplay) || - (opt.APP_FOLDER_ORDER && thisIsFolder)) { - // const { itemsPerPage } = this._grid; - let appIcons = this._orderedItems; - // sort all alphabetically - this._sortOrderedItemsAlphabetically(appIcons); - // appIcons.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())); - // then sort used apps by usage - if ((opt.APP_GRID_USAGE && thisIsAppDisplay) || - (opt.APP_FOLDER_USAGE && thisIsFolder)) - appIcons.sort((a, b) => Shell.AppUsage.get_default().compare(a.app.id, b.app.id)); - - // sort favorites first - if (opt.APP_GRID_DASH_FIRST) { - const fav = Object.keys(this._appFavorites._favorites); - appIcons.sort((a, b) => { - let aFav = fav.indexOf(a.id); - if (aFav < 0) - aFav = 999; - let bFav = fav.indexOf(b.id); - if (bFav < 0) - bFav = 999; - return bFav < aFav; - }); - } - - // sort running first - if (opt.APP_GRID_DASH_FIRST && thisIsAppDisplay) - appIcons.sort((a, b) => a.app.get_state() !== Shell.AppState.RUNNING && b.app.get_state() === Shell.AppState.RUNNING); - - if (opt.APP_GRID_FOLDERS_FIRST) - appIcons.sort((a, b) => b._folder && !a._folder); - else if (opt.APP_GRID_FOLDERS_LAST) - appIcons.sort((a, b) => a._folder && !b._folder); - - this._setLinearPositions(appIcons); - - this._orderedItems = appIcons; - } - - this.emit('view-loaded'); - if (!opt.APP_GRID_ALLOW_INCOMPLETE_PAGES) { - for (let i = 0; i < this._grid.nPages; i++) - this._grid.layoutManager._fillItemVacancies(i); - } - }, - - _canAccept(source) { - return source instanceof AppDisplay.AppViewItem; - }, - - // this method is replacing BaseAppVew.acceptDrop which can't be overridden directly - _acceptDropCommon(source) { - const dropTarget = this._dropTarget; - delete this._dropTarget; - - if (!this._canAccept(source)) - return false; - - if (dropTarget === this._prevPageIndicator || - dropTarget === this._nextPageIndicator) { - let increment; - - increment = dropTarget === this._prevPageIndicator ? -1 : 1; - - const { currentPage, nPages } = this._grid; - const page = Math.min(currentPage + increment, nPages); - const position = page < nPages ? -1 : 0; - - this._moveItem(source, page, position); - this.goToPage(page); - } else if (this._delayedMoveData) { - // Dropped before the icon was moved - const { page, position } = this._delayedMoveData; - - try { - this._moveItem(source, page, position); - } catch (e) { - console.warn(`Warning:${e}`); - } - this._removeDelayedMove(); - } - - return true; - }, - - // support active preview icons - _onDragMotion(dragEvent) { - if (!(dragEvent.source instanceof AppDisplay.AppViewItem)) - return DND.DragMotionResult.CONTINUE; - - if (dragEvent.source._sourceItem) - dragEvent.source = dragEvent.source._sourceItem; - - const appIcon = dragEvent.source; - - if (appIcon instanceof AppDisplay.AppViewItem) { - if (!this._dragMaybeSwitchPageImmediately(dragEvent)) { - // Two ways of switching pages during DND: - // 1) When "bumping" the cursor against the monitor edge, we switch - // page immediately. - // 2) When hovering over the next-page indicator for a certain time, - // we also switch page. - - const { targetActor } = dragEvent; - - if (targetActor === this._prevPageIndicator || - targetActor === this._nextPageIndicator) - this._maybeSetupDragPageSwitchInitialTimeout(dragEvent); - else - this._resetDragPageSwitch(); - } - } - - const thisIsFolder = this instanceof AppDisplay.FolderView; - const thisIsAppDisplay = !thisIsFolder; - if ((!opt.APP_GRID_ORDER && thisIsAppDisplay) || (!opt.APP_FOLDER_ORDER && thisIsFolder)) - this._maybeMoveItem(dragEvent); - - return DND.DragMotionResult.CONTINUE; - }, -}; - -const BaseAppViewGridLayout = { - _getIndicatorsWidth(box) { - const [width, height] = box.get_size(); - const arrows = [ - this._nextPageArrow, - this._previousPageArrow, - ]; - - const minArrowsWidth = arrows.reduce( - (previousWidth, accessory) => { - const [min] = accessory.get_preferred_width(height); - return Math.max(previousWidth, min); - }, 0); - - const idealIndicatorWidth = (width * 0.1/* PAGE_PREVIEW_RATIO*/) / 2; - - return Math.max(idealIndicatorWidth, minArrowsWidth); - }, -}; - -const FolderIcon = { - after__init() { - /* // If folder preview icons are clickable, - // disable opening the folder with primary mouse button and enable the secondary one - const buttonMask = opt.APP_GRID_ACTIVE_PREVIEW - ? St.ButtonMask.TWO | St.ButtonMask.THREE - : St.ButtonMask.ONE | St.ButtonMask.TWO; - this.button_mask = buttonMask;*/ - this.button_mask = St.ButtonMask.ONE | St.ButtonMask.TWO; - if (shellVersion46) - this.add_style_class_name('app-folder-46'); - else - this.add_style_class_name('app-folder-45'); - }, - - open() { - this._ensureFolderDialog(); - this._dialog._updateFolderSize(); - // always open folder with the first page - this.view._scrollView.get_vscroll_bar().adjustment.value = 0; - this._dialog.popup(); - }, -}; - -const ActiveFolderIcon = { - handleDragOver() { - return DND.DragMotionResult.CONTINUE; - }, - - acceptDrop() { - return false; - }, - - _onDragEnd() { - this._dragging = false; - this.undoScaleAndFade(); - Main.overview.endItemDrag(this._sourceItem.icon); - }, -}; - -const FolderView = { - _createGrid() { - let grid = new FolderGrid(); - return grid; - }, - - createFolderIcon(size) { - const layout = new Clutter.GridLayout({ - row_homogeneous: true, - column_homogeneous: true, - }); - - let icon = new St.Widget({ - layout_manager: layout, - x_align: Clutter.ActorAlign.CENTER, - style: `width: ${size}px; height: ${size}px;`, - }); - - const numItems = this._orderedItems.length; - // decide what number of icons switch to 3x3 grid - // APP_GRID_FOLDER_ICON_GRID: 3 -> more than 4 - // : 4 -> more than 8 - const threshold = opt.APP_GRID_FOLDER_ICON_GRID % 3 ? 8 : 4; - const gridSize = opt.APP_GRID_FOLDER_ICON_GRID > 2 && numItems > threshold ? 3 : 2; - const FOLDER_SUBICON_FRACTION = gridSize === 2 ? 0.4 : 0.27; - - let subSize = Math.floor(FOLDER_SUBICON_FRACTION * size); - let rtl = icon.get_text_direction() === Clutter.TextDirection.RTL; - for (let i = 0; i < gridSize * gridSize; i++) { - const style = `width: ${subSize}px; height: ${subSize}px;`; - let bin = new St.Bin({ style, reactive: true }); - bin.pivot_point = new Graphene.Point({ x: 0.5, y: 0.5 }); - if (i < numItems) { - if (!opt.APP_GRID_ACTIVE_PREVIEW) { - bin.child = this._orderedItems[i].app.create_icon_texture(subSize); - } else { - const app = this._orderedItems[i].app; - const child = new AppDisplay.AppIcon(app, { - setSizeManually: true, - showLabel: false, - }); - - child._sourceItem = this._orderedItems[i]; - child._sourceFolder = this; - child.icon.style_class = ''; - child.set_style_class_name(''); - child.icon.set_style('margin: 0; padding: 0;'); - child._dot.set_style('margin-bottom: 1px;'); - child.icon.setIconSize(subSize); - - bin.child = child; - - bin.connect('enter-event', () => { - bin.ease({ - duration: 100, - translation_y: -3, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - }); - bin.connect('leave-event', () => { - bin.ease({ - duration: 100, - translation_y: 0, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - }); - } - } - - layout.attach(bin, rtl ? (i + 1) % gridSize : i % gridSize, Math.floor(i / gridSize), 1, 1); - } - - // if folder content changed, update folder size, but not if it's empty - /* if (this._dialog && this._dialog._designCapacity !== this._orderedItems.length && this._orderedItems.length) - this._dialog._updateFolderSize();*/ - - return icon; - }, - - _loadApps() { - this._apps = []; - const excludedApps = this._folder.get_strv('excluded-apps'); - const appSys = Shell.AppSystem.get_default(); - const addAppId = appId => { - if (excludedApps.includes(appId)) - return; - - if (opt.APP_GRID_EXCLUDE_FAVORITES && this._appFavorites.isFavorite(appId)) - return; - - const app = appSys.lookup_app(appId); - if (!app) - return; - - if (opt.APP_GRID_EXCLUDE_RUNNING) { - const runningApps = Shell.AppSystem.get_default().get_running().map(a => a.id); - if (runningApps.includes(appId)) - return; - } - - if (!this._parentalControlsManager.shouldShowApp(app.get_app_info())) - return; - - if (this._apps.indexOf(app) !== -1) - return; - - this._apps.push(app); - }; - - const folderApps = this._folder.get_strv('apps'); - folderApps.forEach(addAppId); - - const folderCategories = this._folder.get_strv('categories'); - const appInfos = this._parentView.getAppInfos(); - appInfos.forEach(appInfo => { - let appCategories = /* AppDisplay.*/_getCategories(appInfo); - if (!_listsIntersect(folderCategories, appCategories)) - return; - - addAppId(appInfo.get_id()); - }); - - let items = []; - this._apps.forEach(app => { - let icon = this._items.get(app.get_id()); - if (!icon) - icon = new AppDisplay.AppIcon(app); - - items.push(icon); - }); - - if (opt.APP_FOLDER_ORDER) - Main.overview._overview.controls._appDisplay._sortOrderedItemsAlphabetically(items); - - if (opt.APP_FOLDER_USAGE) - items.sort((a, b) => Shell.AppUsage.get_default().compare(a.app.id, b.app.id)); - - this._appIds = this._apps.map(app => app.get_id()); - return items; - }, - - // 42 only - don't apply appGrid scale on folders - adaptToSize(width, height) { - if (!opt.ORIENTATION) { - const [, indicatorHeight] = this._pageIndicators.get_preferred_height(-1); - height -= indicatorHeight; - } - BaseAppViewCommon.adaptToSize.bind(this)(width, height, true); - }, - - acceptDrop(source) { - /* if (!BaseAppViewCommon.acceptDrop.bind(this)(source)) - return false;*/ - if (opt.APP_FOLDER_ORDER) - return false; - if (source._sourceItem) - source = source._sourceItem; - - if (!this._acceptDropCommon(source)) - return false; - - const folderApps = this._orderedItems.map(item => item.id); - this._folder.set_strv('apps', folderApps); - - return true; - }, -}; - -const FolderGrid = GObject.registerClass( -class FolderGrid extends AppDisplay.AppGrid { - _init() { - super._init({ - allow_incomplete_pages: false, - columns_per_page: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 20, - rows_per_page: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 20, - page_halign: Clutter.ActorAlign.CENTER, - page_valign: Clutter.ActorAlign.CENTER, - }); - this.layout_manager._isFolder = true; - const spacing = opt.APP_GRID_SPACING; - this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`); - this.layoutManager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE; - - this.setGridModes([ - { - columns: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 3, - rows: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 3, - }, - ]); - } - - adaptToSize(width, height) { - this.layout_manager.adaptToSize(width, height); - } -}); - - -const FOLDER_DIALOG_ANIMATION_TIME = 200; // AppDisplay.FOLDER_DIALOG_ANIMATION_TIME -const AppFolderDialog = { - // injection to _init() - after__init() { - this._viewBox.add_style_class_name('app-folder-dialog-vshell'); - // GS 46 changed the aligning to CENTER which restricts max folder dialog size - this._viewBox.set({ - x_align: Clutter.ActorAlign.FILL, - y_align: Clutter.ActorAlign.FILL, - }); - - // delegate this dialog to the FolderIcon._view - // so its _createFolderIcon function can update the dialog if folder content changed - this._view._dialog = this; - - // right click into the folder popup should close it - this.child.reactive = true; - const clickAction = new Clutter.ClickAction(); - clickAction.connect('clicked', act => { - if (act.get_button() === Clutter.BUTTON_PRIMARY) - return Clutter.EVENT_STOP; - const [x, y] = clickAction.get_coords(); - const actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y); - // if it's not entry for editing folder title - if (actor !== this._entry) - this.popdown(); - return Clutter.EVENT_STOP; - }); - - this.child.add_action(clickAction); - }, - - after__addFolderNameEntry() { - // edit-folder-button class has been replaced with icon-button class which is not transparent in 46 - this._editButton.add_style_class_name('edit-folder-button'); - if (shellVersion46) - this._editButton.add_style_class_name('edit-folder-button-46'); - - // Edit button - this._removeButton = new St.Button({ - style_class: 'icon-button edit-folder-button', - button_mask: St.ButtonMask.ONE, - toggle_mode: false, - reactive: true, - can_focus: true, - x_align: Clutter.ActorAlign.END, - y_align: Clutter.ActorAlign.CENTER, - child: new St.Icon({ - icon_name: 'user-trash-symbolic', - icon_size: 16, - }), - }); - - this._removeButton.connect('clicked', () => { - if (Date.now() - this._removeButton._lastClick < Clutter.Settings.get_default().double_click_time) { - this._grabHelper.ungrab({ actor: this }); - // without hiding the dialog, Shell crashes (at least on X11) - this.hide(); - this._view._deletingFolder = true; - - // Resetting all keys deletes the relocatable schema - let keys = this._folder.settings_schema.list_keys(); - for (const key of keys) - this._folder.reset(key); - - let settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' }); - let folders = settings.get_strv('folder-children'); - folders.splice(folders.indexOf(this._view._id), 1); - - // remove all abandoned folders (usually my own garbage and unwanted default folders...) - /* const appFolders = this._appDisplay._folderIcons.map(icon => icon._id); - folders.forEach(folder => { - if (!appFolders.includes(folder)) { - folders.splice(folders.indexOf(folder._id), 1); - } - });*/ - settings.set_strv('folder-children', folders); - - this._view._deletingFolder = false; - return; - } - this._removeButton._lastClick = Date.now(); - }); - - this._entryBox.add_child(this._removeButton); - - // Adjust empty actor to center the title - this._entryBox.get_first_child().width = 82; - }, - - popup() { - if (this._isOpen) - return; - - this._isOpen = this._grabHelper.grab({ - actor: this, - onUngrab: () => this.popdown(), - }); - - if (!this._isOpen) - return; - - this.get_parent().set_child_above_sibling(this, null); - - this._needsZoomAndFade = true; - - // the first folder dialog realization needs size correction - // so set the folder size, let it realize and then update the folder content - if (!this.realized) { - this._updateFolderSize(); - GLib.idle_add( - GLib.PRIORITY_DEFAULT, - () => { - this._updateFolderSize(); - } - ); - } - - this.show(); - this.emit('open-state-changed', true); - }, - - _updateFolderSize() { - const view = this._view; - const [firstItem] = view._grid.layoutManager._container; - if (!firstItem) - return; - // adapt folder size according to the settings and number of icons - const appDisplay = this._source._parentView; - if (!appDisplay.width || appDisplay.allocation.x2 === Infinity || appDisplay.allocation.x2 === -Infinity) { - return; - } - - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - const itemPadding = 55; // default icon item padding on Fedora 44 - // const dialogMargin = 30; - const nItems = view._orderedItems.length; - let columns = opt.APP_GRID_FOLDER_COLUMNS; - let rows = opt.APP_GRID_FOLDER_ROWS; - const fullAdaptiveGrid = !columns && !rows; - let spacing = opt.APP_GRID_SPACING; - const minItemSize = 48 + itemPadding; - - if (fullAdaptiveGrid) { - columns = Math.ceil(Math.sqrt(nItems)); - rows = columns; - if (columns * (columns - 1) >= nItems) { - rows = columns - 1; - } else if ((columns + 1) * (columns - 1) >= nItems) { - rows = columns - 1; - columns += 1; - } - } else if (!columns && rows) { - columns = Math.ceil(nItems / rows); - } else if (columns && !rows) { - rows = Math.ceil(nItems / columns); - } - - const iconSize = opt.APP_GRID_FOLDER_ICON_SIZE < 0 ? opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT : opt.APP_GRID_FOLDER_ICON_SIZE; - view._grid.layoutManager.fixedIconSize = iconSize; - view._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`); - view._grid.layoutManager._pageWidth += 1; - view._grid.layoutManager.adaptToSize(view._grid.layoutManager._pageWidth - 1, view._grid.layoutManager._pageHeight); - - let itemSize = iconSize + 55; // icon padding - // first run sets the grid before we can read the real icon size - // so we estimate the size from default properties - // and correct it in the second run - if (this.realized) { - firstItem.icon.setIconSize(iconSize); - const [firstItemWidth] = firstItem.get_preferred_size(); - const realSize = firstItemWidth / scaleFactor; - // if the preferred item size is smaller than icon plus some padding, ignore it - // (icons that are not yet realized are returning sizes like 45 or 53) - if (realSize > (iconSize + 24)) - itemSize = realSize; - } - - let width = columns * (itemSize + spacing) + /* padding for nav arrows*/64; - width = Math.round(width + (opt.ORIENTATION ? 100 : 160/* space for navigation arrows*/)); - let height = rows * (itemSize + spacing) + /* header*/75 + /* padding*/ 2 * 30 + /* padding + ?page indicator*/(!opt.ORIENTATION || !opt.APP_GRID_FOLDER_COLUMNS ? 100 : 70); - - // allocation is more reliable than appDisplay width/height properties - const appDisplayWidth = appDisplay.allocation.x2 - appDisplay.allocation.x1; - const appDisplayHeight = appDisplay.allocation.y2 - appDisplay.allocation.y1 + (opt.SHOW_SEARCH_ENTRY ? Main.overview._overview.controls._searchEntryBin.height : 0); - - // folder must fit the appDisplay area - // reduce columns/rows if needed and count with the scaled values - if (!opt.APP_GRID_FOLDER_ROWS) { - while ((height * scaleFactor) > appDisplayHeight) { - height -= itemSize + spacing; - rows -= 1; - } - } - - if (!opt.APP_GRID_FOLDER_COLUMNS) { - while ((width * scaleFactor) > appDisplayWidth) { - width -= itemSize + spacing; - columns -= 1; - } - } - // try to compensate for the previous reduction if there is a space - if (!opt.APP_GRID_FOLDER_COLUMNS) { - while ((nItems > columns * rows) && ((width * scaleFactor + itemSize + spacing) <= appDisplayWidth)) { - width += itemSize + spacing; - columns += 1; - } - // remove columns that cannot be displayed - if ((columns * minItemSize + (columns - 1) * spacing) > appDisplayWidth) - columns = Math.floor(appDisplayWidth / (minItemSize + spacing)); - } - if (!opt.APP_GRID_FOLDER_ROWS) { - while ((nItems > columns * rows) && ((height * scaleFactor + itemSize + spacing) <= appDisplayHeight)) { - height += itemSize + spacing; - rows += 1; - } - // remove rows that cannot be displayed - if ((rows * minItemSize + (rows - 1) * spacing) > appDisplayHeight) - rows = Math.floor(appDisplayWidth / (minItemSize + spacing)); - } - - width = Math.clamp(width, 640, appDisplayWidth); - height = Math.min(height, appDisplayHeight); - - const layoutManager = view._grid.layoutManager; - layoutManager.rows_per_page = rows; - layoutManager.columns_per_page = columns; - - // this line is required by GS 43 - // view._grid.setGridModes([{ columns, rows }]); - - this.child.set_style(` - width: ${width}px; - height: ${height}px; - padding: 30px; - `); - - view._redisplay(); - // store original item count - this._designCapacity = nItems; - }, - - _zoomAndFadeIn() { - let [sourceX, sourceY] = - this._source.get_transformed_position(); - let [dialogX, dialogY] = - this.child.get_transformed_position(); - - const sourceCenterX = sourceX + this._source.width / 2; - const sourceCenterY = sourceY + this._source.height / 2; - - // this. covers the whole screen - let dialogTargetX = dialogX; - let dialogTargetY = dialogY; - - const appDisplay = this._source._parentView; - - const [appDisplayX, appDisplayY] = this._source._parentView.get_transformed_position(); - if (!opt.APP_GRID_FOLDER_CENTER) { - dialogTargetX = sourceCenterX - this.child.width / 2; - dialogTargetY = sourceCenterY - this.child.height / 2; - - // keep the dialog in appDisplay area if possible - dialogTargetX = Math.clamp( - dialogTargetX, - appDisplayX, - appDisplayX + appDisplay.width - this.child.width - ); - - dialogTargetY = Math.clamp( - dialogTargetY, - appDisplayY, - appDisplayY + appDisplay.height - this.child.height - ); - } else { - const searchEntryHeight = opt.SHOW_SEARCH_ENTRY ? Main.overview._overview.controls._searchEntryBin.height : 0; - dialogTargetX = appDisplayX + appDisplay.width / 2 - this.child.width / 2; - dialogTargetY = appDisplayY - searchEntryHeight + ((appDisplay.height + searchEntryHeight) / 2 - this.child.height / 2) / 2; - } - - const dialogOffsetX = Math.round(dialogTargetX - dialogX); - const dialogOffsetY = Math.round(dialogTargetY - dialogY); - - this.child.set({ - translation_x: sourceX - dialogX, - translation_y: sourceY - dialogY, - scale_x: this._source.width / this.child.width, - scale_y: this._source.height / this.child.height, - opacity: 0, - }); - - this.child.ease({ - translation_x: dialogOffsetX, - translation_y: dialogOffsetY, - scale_x: 1, - scale_y: 1, - opacity: 255, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - appDisplay.ease({ - opacity: 0, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - if (opt.SHOW_SEARCH_ENTRY) { - Main.overview.searchEntry.ease({ - opacity: 0, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - this._needsZoomAndFade = false; - - if (this._sourceMappedId === 0) { - this._sourceMappedId = this._source.connect( - 'notify::mapped', this._zoomAndFadeOut.bind(this)); - } - }, - - _zoomAndFadeOut() { - if (!this._isOpen) - return; - - if (!this._source.mapped) { - this.hide(); - return; - } - - // if the dialog was shown silently, skip animation - if (this.scale_y < 1) { - this._needsZoomAndFade = false; - this.hide(); - this._popdownCallbacks.forEach(func => func()); - this._popdownCallbacks = []; - return; - } - - let [sourceX, sourceY] = - this._source.get_transformed_position(); - let [dialogX, dialogY] = - this.child.get_transformed_position(); - - this.child.ease({ - translation_x: sourceX - dialogX + this.child.translation_x, - translation_y: sourceY - dialogY + this.child.translation_y, - scale_x: this._source.width / this.child.width, - scale_y: this._source.height / this.child.height, - opacity: 0, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this.child.set({ - translation_x: 0, - translation_y: 0, - scale_x: 1, - scale_y: 1, - opacity: 255, - }); - this.hide(); - - this._popdownCallbacks.forEach(func => func()); - this._popdownCallbacks = []; - }, - }); - - const appDisplay = this._source._parentView; - appDisplay.ease({ - opacity: 255, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - if (opt.SHOW_SEARCH_ENTRY) { - Main.overview.searchEntry.ease({ - opacity: 255, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - this._needsZoomAndFade = false; - }, - - _setLighterBackground(lighter) { - if (this._isOpen) - Main.overview._overview._controls._appDisplay.opacity = lighter ? 20 : 0; - /* const backgroundColor = lighter - ? this.DIALOG_SHADE_HIGHLIGHT - : this.DIALOG_SHADE_NORMAL; - - this.ease({ - backgroundColor, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); */ - }, -}; - -const AppIcon = { - after__init() { - // update the app label behavior - this._updateMultiline(); - }, - - // avoid accepting by placeholder when dragging active preview - // and also by icon if alphabet or usage sorting are used - _canAccept(source) { - if (source._sourceItem) - source = source._sourceItem; - let view = /* AppDisplay.*/_getViewFromIcon(source); - - return source !== this && - (source instanceof this.constructor) && - (view instanceof AppDisplay.AppDisplay && - !opt.APP_GRID_USAGE); - }, -}; - -const AppViewItemCommon = { - _updateMultiline() { - const { label } = this.icon; - if (label) - label.opacity = 255; - if (!this._expandTitleOnHover || !this.icon.label) - return; - - const { clutterText } = label; - - const isHighlighted = this.has_key_focus() || this.hover || this._forcedHighlight; - - if (opt.APP_GRID_NAMES_MODE === 2 && this._expandTitleOnHover) { // !_expandTitleOnHover indicates search result icon - label.opacity = isHighlighted || !this.app ? 255 : 0; - } - if (isHighlighted) - this.get_parent()?.set_child_above_sibling(this, null); - - if (!opt.APP_GRID_NAMES_MODE) { - const layout = clutterText.get_layout(); - if (!layout.is_wrapped() && !layout.is_ellipsized()) - return; - } - - label.remove_transition('allocation'); - - const id = label.connect('notify::allocation', () => { - label.restore_easing_state(); - label.disconnect(id); - }); - - const expand = opt.APP_GRID_NAMES_MODE === 1 || this._forcedHighlight || this.hover || this.has_key_focus(); - - label.save_easing_state(); - label.set_easing_duration(expand - ? APP_ICON_TITLE_EXPAND_TIME - : APP_ICON_TITLE_COLLAPSE_TIME); - clutterText.set({ - line_wrap: expand, - line_wrap_mode: expand ? Pango.WrapMode.WORD_CHAR : Pango.WrapMode.NONE, - ellipsize: expand ? Pango.EllipsizeMode.NONE : Pango.EllipsizeMode.END, - }); - }, - - // support active preview icons - acceptDrop(source, _actor, x) { - if (opt.APP_GRID_USAGE) - return DND.DragMotionResult.NO_DROP; - - this._setHoveringByDnd(false); - - if (!this._canAccept(source)) - return false; - - if (this._withinLeeways(x)) - return false; - - // added - remove app from the source folder after dnd to other folder - if (source._sourceItem) { - const app = source._sourceItem.app; - source._sourceFolder.removeApp(app); - } - - return true; - }, - -}; diff --git a/extensions/46/vertical-workspaces/lib/appFavorites.js b/extensions/46/vertical-workspaces/lib/appFavorites.js deleted file mode 100644 index 977e65a..0000000 --- a/extensions/46/vertical-workspaces/lib/appFavorites.js +++ /dev/null @@ -1,79 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * appFavorites.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import * as AppFavorites from 'resource:///org/gnome/shell/ui/appFavorites.js'; - -let Me; -let opt; - -export const AppFavoritesModule = 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('appFavoritesModule'); - - // if notifications are enabled no override is needed - reset = reset || !this.moduleEnabled || opt.SHOW_FAV_NOTIFICATION; - - // don't touch original code if module disabled - if (reset && !this._firstActivation) { - this._disableModule(); - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - if (reset && this._firstActivation) { - this.moduleEnabled = false; - console.debug(' AppFavoritesModule - Keeping untouched'); - } - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - // use actual instance instead of prototype - this._overrides.addOverride('AppFavorites', AppFavorites.getAppFavorites(), AppFavoritesCommon); - - console.debug(' AppFavoritesModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - console.debug(' AppFavoritesModule - Deactivated'); - } -}; - -const AppFavoritesCommon = { - addFavoriteAtPos(appId, pos) { - this._addFavorite(appId, pos); - }, - - removeFavorite(appId) { - this._removeFavorite(appId); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/dash.js b/extensions/46/vertical-workspaces/lib/dash.js deleted file mode 100644 index 719c3de..0000000 --- a/extensions/46/vertical-workspaces/lib/dash.js +++ /dev/null @@ -1,1310 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * dash.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022-2024 - * @license GPL-3.0 - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; -import GLib from 'gi://GLib'; -import Meta from 'gi://Meta'; -import Shell from 'gi://Shell'; -import St from 'gi://St'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Dash from 'resource:///org/gnome/shell/ui/dash.js'; -import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'; -import * as AppFavorites from 'resource:///org/gnome/shell/ui/appFavorites.js'; -import * as AppMenu from 'resource:///org/gnome/shell/ui/appMenu.js'; -import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js'; -import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'; -import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; - -let Me; -let opt; -// gettext -let _; - -let _moduleEnabled; -let _timeouts; - -// added values to achieve a better ability to scale down according to available space -export const BaseIconSizes = [16, 24, 32, 40, 44, 48, 56, 64, 72, 80, 96, 112, 128]; - -const DASH_ITEM_LABEL_SHOW_TIME = 150; - -const shellVersion46 = !Clutter.Container; // Container has been removed in 46 - -export const DashModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - _ = Me.gettext; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - this._horizontalWorkId = null; - this._verticalWorkId = null; - this._showAppsIconBtnPressId = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - _ = null; - } - - update(reset) { - this._removeTimeouts(); - - this.moduleEnabled = opt.get('dashModule'); - const conflict = !!(Me.Util.getEnabledExtensions('dash-to-dock').length || - Me.Util.getEnabledExtensions('ubuntu-dock').length || - Me.Util.getEnabledExtensions('dash-to-panel').length); - - if (conflict && !reset) - console.warn(`[${Me.metadata.name}] Warning: "Dash" module disabled due to potential conflict with another extension`); - - reset = reset || !this.moduleEnabled || conflict; - this._conflict = 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(' DashModule - Keeping untouched'); - } - - updateStyle(dash) { - if (opt.DASH_BG_LIGHT) - dash._background.add_style_class_name('dash-background-light'); - else - dash._background.remove_style_class_name('dash-background-light'); - - dash._background.opacity = opt.DASH_BG_OPACITY; - let radius = opt.DASH_BG_RADIUS; - if (radius) { - let style; - switch (opt.DASH_POSITION) { - case 1: - style = opt.DASH_BG_GS3_STYLE ? `border-radius: ${radius}px 0 0 ${radius}px;` : `border-radius: ${radius}px;`; - break; - case 3: - style = opt.DASH_BG_GS3_STYLE ? `border-radius: 0 ${radius}px ${radius}px 0;` : `border-radius: ${radius}px;`; - break; - default: - style = `border-radius: ${radius}px;`; - } - dash._background.set_style(style); - } else { - dash._background.set_style(''); - } - } - - _activateModule() { - _moduleEnabled = true; - _timeouts = {}; - const dash = Main.overview._overview._controls.layoutManager._dash; - - if (!this._originalWorkId) - this._originalWorkId = dash._workId; - - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._resetStyle(dash); - this.updateStyle(dash); - - this._overrides.addOverride('DashItemContainer', Dash.DashItemContainer.prototype, DashItemContainerCommon); - this._overrides.addOverride('DashCommon', Dash.Dash.prototype, DashCommon); - this._overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIconCommon); - this._overrides.addOverride('DashIcon', Dash.DashIcon.prototype, DashIconCommon); - this._overrides.addOverride('AppMenu', AppMenu.AppMenu.prototype, AppMenuCommon); - - if (shellVersion46) - dash.add_style_class_name('dash-46'); - - if (opt.DASH_VERTICAL) { - // this._overrides.addOverride('Dash', Dash.Dash.prototype, DashVerticalOverride); - dash.add_style_class_name(shellVersion46 - ? 'vertical-46' - : 'vertical' - ); - this._setOrientation(Clutter.Orientation.VERTICAL); - } else { - this._setOrientation(Clutter.Orientation.HORIZONTAL); - } - - if (opt.DASH_VERTICAL && opt.DASH_BG_GS3_STYLE) { - if (opt.DASH_LEFT) { - dash.add_style_class_name(shellVersion46 - ? 'vertical-46-gs3-left' - : 'vertical-gs3-left'); - } else if (opt.DASH_RIGHT) { - dash.add_style_class_name(shellVersion46 - ? 'vertical-46-gs3-right' - : 'vertical-gs3-right'); - } - } else { - dash.remove_style_class_name('vertical-gs3-left'); - dash.remove_style_class_name('vertical-gs3-right'); - dash.remove_style_class_name('vertical-46-gs3-left'); - dash.remove_style_class_name('vertical-46-gs3-right'); - } - - if (!this._customWorkId) - this._customWorkId = Main.initializeDeferredWork(dash._box, dash._redisplay.bind(dash)); - dash._workId = this._customWorkId; - - this._moveDashAppGridIcon(); - this._connectShowAppsIcon(); - - dash.visible = opt.DASH_VISIBLE; - // dash._background.add_style_class_name('dash-background-reduced'); - dash._queueRedisplay(); - - if (opt.DASH_ISOLATE_WS && !this._wmSwitchWsConId) { - this._wmSwitchWsConId = global.windowManager.connect('switch-workspace', () => dash._queueRedisplay()); - this._newWindowConId = global.display.connect_after('window-created', () => dash._queueRedisplay()); - } - - console.debug(' DashModule - Activated'); - } - - _disableModule() { - const dash = Main.overview._overview._controls.layoutManager._dash; - - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - dash._workId = this._originalWorkId; - - if (this._wmSwitchWsConId) { - global.windowManager.disconnect(this._wmSwitchWsConId); - this._wmSwitchWsConId = 0; - } - if (this._newWindowConId) { - global.windowManager.disconnect(this._newWindowConId); - this._newWindowConId = 0; - } - - const reset = true; - this._setOrientation(Clutter.Orientation.HORIZONTAL); - this._moveDashAppGridIcon(reset); - this._connectShowAppsIcon(reset); - - this._resetStyle(dash); - dash.visible = !this._conflict; - dash._background.opacity = 255; - - _moduleEnabled = false; - console.debug(' DashModule - Disabled'); - } - - _resetStyle(dash) { - dash.remove_style_class_name('vertical'); - dash.remove_style_class_name('vertical-46'); - dash.remove_style_class_name('vertical-gs3-left'); - dash.remove_style_class_name('vertical-gs3-right'); - dash.remove_style_class_name('vertical-46-gs3-left'); - dash.remove_style_class_name('vertical-46-gs3-right'); - dash.remove_style_class_name('vertical-left'); - dash.remove_style_class_name('vertical-right'); - dash._background.remove_style_class_name('dash-background-light'); - dash._background.remove_style_class_name('dash-background-reduced'); - dash._background.set_style(''); - } - - _removeTimeouts() { - if (_timeouts) { - Object.values(_timeouts).forEach(t => { - if (t) - GLib.source_remove(t); - }); - _timeouts = null; - } - } - - _setOrientation(orientation, dash) { - dash = dash ?? Main.overview._overview._controls.layoutManager._dash; - - dash._box.layout_manager.orientation = orientation; - dash._dashContainer.layout_manager.orientation = orientation; - dash._dashContainer.y_expand = !orientation; - dash._dashContainer.x_expand = !!orientation; - dash.x_align = orientation ? Clutter.ActorAlign.START : Clutter.ActorAlign.CENTER; - dash.y_align = orientation ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.FILL; - - let sizerBox = dash._background.get_children()[0]; - sizerBox.clear_constraints(); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: dash._showAppsIcon.icon, - coordinate: orientation ? Clutter.BindCoordinate.WIDTH : Clutter.BindCoordinate.HEIGHT, - })); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: dash._dashContainer, - coordinate: orientation ? Clutter.BindCoordinate.HEIGHT : Clutter.BindCoordinate.WIDTH, - })); - dash._box.remove_all_children(); - dash._separator = null; - dash._queueRedisplay(); - dash._adjustIconSize(); - } - - _moveDashAppGridIcon(reset = false) { - // move dash app grid icon to the front - const dash = Main.overview._overview._controls.layoutManager._dash; - - const appIconPosition = opt.get('showAppsIconPosition'); - dash._showAppsIcon.remove_style_class_name('show-apps-icon-vertical-hide'); - dash._showAppsIcon.remove_style_class_name('show-apps-icon-horizontal-hide'); - dash._showAppsIcon.opacity = 255; - if (!reset && appIconPosition === 0) // 0 - start - dash._dashContainer.set_child_at_index(dash._showAppsIcon, 0); - if (reset || appIconPosition === 1) { // 1 - end - const index = dash._dashContainer.get_children().length - 1; - dash._dashContainer.set_child_at_index(dash._showAppsIcon, index); - } - if (!reset && appIconPosition === 2) { // 2 - hide - const style = opt.DASH_VERTICAL ? 'show-apps-icon-vertical-hide' : 'show-apps-icon-horizontal-hide'; - dash._showAppsIcon.add_style_class_name(style); - // for some reason even if the icon height in vertical mode should be set to 0 by the style, it stays visible in full size returning height 1px - dash._showAppsIcon.opacity = 0; - } - } - - _connectShowAppsIcon(reset = false, dash) { - dash = dash ?? Main.overview._overview._controls.layoutManager._dash; - if (!reset) { - if (this._showAppsIconBtnPressId || Me.Util.dashIsDashToDock()) { - // button is already connected || dash is Dash to Dock - return; - } - dash._showAppsIcon.reactive = true; - this._showAppsIconBtnPressId = dash._showAppsIcon.connect('button-press-event', (actor, event) => { - const button = event.get_button(); - if (button === Clutter.BUTTON_MIDDLE) - Me.Util.openPreferences(); - else if (button === Clutter.BUTTON_SECONDARY) - Me.Util.activateSearchProvider(Me.WSP_PREFIX); - else - return Clutter.EVENT_PROPAGATE; - return Clutter.EVENT_STOP; - }); - } else if (this._showAppsIconBtnPressId) { - dash._showAppsIcon.disconnect(this._showAppsIconBtnPressId); - this._showAppsIconBtnPressId = 0; - dash._showAppsIcon.reactive = false; - } - } -}; - -function getAppFromSource(source) { - if (source instanceof AppDisplay.AppIcon) - return source.app; - else - return null; -} - -const DashItemContainerCommon = { - // move labels according dash position - showLabel() { - if (!this._labelText) - return; - - const windows = this.child.app?.get_windows(); - const recentWindowTitle = windows && windows.length ? windows[0].get_title() : ''; - const windowCount = this.child.app?.get_windows().length; - let labelSuffix = ''; - if (windowCount > 1) - labelSuffix = ` (${windowCount})`; - if (recentWindowTitle && recentWindowTitle !== this._labelText) - labelSuffix += `\n ${recentWindowTitle}`; - - this.label.set_text(this._labelText + labelSuffix); - - this.label.opacity = 0; - this.label.show(); - - let [stageX, stageY] = this.get_transformed_position(); - - const itemWidth = this.allocation.get_width(); - const itemHeight = this.allocation.get_height(); - - const labelWidth = this.label.get_width(); - const labelHeight = this.label.get_height(); - let xOffset = Math.floor((itemWidth - labelWidth) / 2); - let x = Math.clamp(stageX + xOffset, 0, global.stage.width - labelWidth); - const primaryMonitor = global.display.get_monitor_geometry(global.display.get_primary_monitor()); - x = Math.clamp(x, primaryMonitor.x, primaryMonitor.x + primaryMonitor.width - labelWidth); - - let node = this.label.get_theme_node(); - let y; - - if (opt.DASH_TOP) { - const yOffset = itemHeight + (shellVersion46 ? 0 : -3); - y = stageY + yOffset; - } else if (opt.DASH_BOTTOM) { - const yOffset = node.get_length('-y-offset'); - y = stageY - this.label.height - yOffset; - } else if (opt.DASH_RIGHT) { - const yOffset = Math.floor((itemHeight - labelHeight) / 2); - xOffset = shellVersion46 ? 8 : 4; - - x = stageX - xOffset - this.label.width; - y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight); - } else if (opt.DASH_LEFT) { - const yOffset = Math.floor((itemHeight - labelHeight) / 2); - xOffset = shellVersion46 ? 8 : 4; - - x = stageX + this.width + xOffset; - y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight); - } - - this.label.set_position(x, y); - this.label.ease({ - opacity: 255, - duration: DASH_ITEM_LABEL_SHOW_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - this.label.set_position(x, y); - this.label.ease({ - opacity: 255, - duration: DASH_ITEM_LABEL_SHOW_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - }, -}; - -const DashCommon = { - _redisplay() { - // After disabling V-Shell queueRedisplay() may call this function - // In that case redirect the call to the current _redisplay() - if (!_moduleEnabled) { - this._redisplay(); - return; - } - - let favorites = AppFavorites.getAppFavorites().getFavoriteMap(); - - let running = this._appSystem.get_running(); - - if (opt.DASH_ISOLATE_WS) { - const currentWs = global.workspace_manager.get_active_workspace(); - running = running.filter(app => { - return app.get_windows().filter(w => w.get_workspace() === currentWs).length; - }); - this._box.get_children().forEach(a => a.child?._updateRunningStyle()); - } - - let children = this._box.get_children().filter(actor => { - return actor.child && - actor.child._delegate && - actor.child._delegate.app; - }); - // Apps currently in the dash - let oldApps = children.map(actor => actor.child._delegate.app); - // Apps supposed to be in the dash - let newApps = []; - - for (let id in favorites) - newApps.push(favorites[id]); - - for (let i = 0; i < running.length; i++) { - let app = running[i]; - if (app.get_id() in favorites) - continue; - newApps.push(app); - } - - // Figure out the actual changes to the list of items; we iterate - // over both the list of items currently in the dash and the list - // of items expected there, and collect additions and removals. - // Moves are both an addition and a removal, where the order of - // the operations depends on whether we encounter the position - // where the item has been added first or the one from where it - // was removed. - // There is an assumption that only one item is moved at a given - // time; when moving several items at once, everything will still - // end up at the right position, but there might be additional - // additions/removals (e.g. it might remove all the launchers - // and add them back in the new order even if a smaller set of - // additions and removals is possible). - // If above assumptions turns out to be a problem, we might need - // to use a more sophisticated algorithm, e.g. Longest Common - // Subsequence as used by diff. - let addedItems = []; - let removedActors = []; - - let newIndex = 0; - let oldIndex = 0; - while (newIndex < newApps.length || oldIndex < oldApps.length) { - let oldApp = oldApps.length > oldIndex ? oldApps[oldIndex] : null; - let newApp = newApps.length > newIndex ? newApps[newIndex] : null; - - // No change at oldIndex/newIndex - if (oldApp === newApp) { - oldIndex++; - newIndex++; - continue; - } - - // App removed at oldIndex - if (oldApp && !newApps.includes(oldApp)) { - removedActors.push(children[oldIndex]); - oldIndex++; - continue; - } - - // App added at newIndex - if (newApp && !oldApps.includes(newApp)) { - addedItems.push({ - app: newApp, - item: this._createAppItem(newApp), - pos: newIndex, - }); - newIndex++; - continue; - } - - // App moved - let nextApp = newApps.length > newIndex + 1 - ? newApps[newIndex + 1] : null; - let insertHere = nextApp && nextApp === oldApp; - let alreadyRemoved = removedActors.reduce((result, actor) => { - let removedApp = actor.child._delegate.app; - return result || removedApp === newApp; - }, false); - - if (insertHere || alreadyRemoved) { - let newItem = this._createAppItem(newApp); - addedItems.push({ - app: newApp, - item: newItem, - pos: newIndex + removedActors.length, - }); - newIndex++; - } else { - removedActors.push(children[oldIndex]); - oldIndex++; - } - } - - for (let i = 0; i < addedItems.length; i++) { - this._box.insert_child_at_index( - addedItems[i].item, - addedItems[i].pos); - } - - for (let i = 0; i < removedActors.length; i++) { - let item = removedActors[i]; - - // Don't animate item removal when the overview is transitioning - // or hidden - if (Main.overview.visible && !Main.overview.animationInProgress) - item.animateOutAndDestroy(); - else - item.destroy(); - } - - this._adjustIconSize(); - - // Skip animations on first run when adding the initial set - // of items, to avoid all items zooming in at once - - let animate = this._shownInitially && Main.overview.visible && - !Main.overview.animationInProgress; - - if (!this._shownInitially) - this._shownInitially = true; - - for (let i = 0; i < addedItems.length; i++) - addedItems[i].item.show(animate); - - // Update separator - const nFavorites = Object.keys(favorites).length; - const nIcons = children.length + addedItems.length - removedActors.length; - if (nFavorites > 0 && nFavorites < nIcons) { - // destroy the horizontal separator if it exists. - // this is incredibly janky, but I can't think of a better way atm. - if (this._separator && this._separator.height !== 1) { - this._separator.destroy(); - this._separator = null; - } - - if (!this._separator) { - this._separator = new St.Widget({ - style_class: 'dash-separator', - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.CENTER, - width: opt.DASH_VERTICAL ? this.iconSize : 1, - height: opt.DASH_VERTICAL ? 1 : this.iconSize, - }); - this._box.add_child(this._separator); - } - - // FIXME: separator placement is broken (also in original dash) - let pos = nFavorites + this._animatingPlaceholdersCount; - if (this._dragPlaceholder) - pos++; - this._box.set_child_at_index(this._separator, pos); - } else if (this._separator) { - this._separator.destroy(); - this._separator = null; - } - // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 - // Without it, StBoxLayout may use a stale size cache - this._box.queue_relayout(); - }, - - _createAppItem(app) { - let appIcon = new Dash.DashIcon(app); - - let indicator = appIcon._dot; - if (opt.DASH_VERTICAL) { - indicator.x_align = opt.DASH_LEFT ? Clutter.ActorAlign.START : Clutter.ActorAlign.END; - indicator.y_align = Clutter.ActorAlign.CENTER; - } else { - indicator.x_align = Clutter.ActorAlign.CENTER; - indicator.y_align = Clutter.ActorAlign.END; - } - - appIcon.connect('menu-state-changed', - (o, opened) => { - this._itemMenuStateChanged(item, opened); - }); - - let item = new Dash.DashItemContainer(); - item.setChild(appIcon); - - // Override default AppIcon label_actor, now the - // accessible_name is set at DashItemContainer.setLabelText - appIcon.label_actor = null; - item.setLabelText(app.get_name()); - - appIcon.icon.setIconSize(this.iconSize); - this._hookUpLabel(item, appIcon); - - return item; - }, - - // use custom BaseIconSizes and add support for custom icons - _adjustIconSize() { - // if a user launches multiple apps at once, this function may be called again before the previous call has finished - // as a result, new icons will not reach their full size, or will be missing, if adding a new icon and changing the dash size due to lack of space at the same time - if (this._adjustingInProgress) - return; - - // For the icon size, we only consider children which are "proper" - // icons (i.e. ignoring drag placeholders) and which are not - // animating out (which means they will be destroyed at the end of - // the animation) - let iconChildren = this._box.get_children().filter(actor => { - return actor.child && - actor.child._delegate && - actor.child._delegate.icon && - !actor.animatingOut; - }); - - // add new custom icons to the list - if (this._showAppsIcon.visible) - iconChildren.push(this._showAppsIcon); - - - // showWindowsIcon and extensionsIcon can be provided by the WSP and ESP extensions - if (this._showWindowsIcon) - iconChildren.push(this._showWindowsIcon); - - if (this._extensionsIcon) - iconChildren.push(this._extensionsIcon); - - - if (!iconChildren.length) - return; - - if (this._maxWidth === -1 || this._maxHeight === -1) - return; - - const dashHorizontal = !opt.DASH_VERTICAL; - - const themeNode = this.get_theme_node(); - const maxAllocation = new Clutter.ActorBox({ - x1: 0, - y1: 0, - x2: dashHorizontal ? this._maxWidth : 42, // not whatever - y2: dashHorizontal ? 42 : this._maxHeight, - }); - - let maxContent = themeNode.get_content_box(maxAllocation); - - let spacing = themeNode.get_length('spacing'); - - let firstButton = iconChildren[0].child; - let firstIcon = firstButton._delegate.icon; - - if (!firstIcon.icon) - return; - - // Enforce valid spacings during the size request - firstIcon.icon.ensure_style(); - const [, , iconWidth, iconHeight] = firstIcon.icon.get_preferred_size(); - const [, , buttonWidth, buttonHeight] = firstButton.get_preferred_size(); - let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor; - - let availWidth, availHeight, maxIconSize; - if (dashHorizontal) { - availWidth = maxContent.x2 - maxContent.x1; - // Subtract icon padding and box spacing from the available width - availWidth -= iconChildren.length * (buttonWidth - iconWidth) + - (iconChildren.length - 1) * spacing + - 2 * this._background.get_theme_node().get_horizontal_padding(); - - availHeight = this._maxHeight; - availHeight -= this.margin_top + this.margin_bottom; - availHeight -= this._background.get_theme_node().get_vertical_padding(); - availHeight -= themeNode.get_vertical_padding(); - availHeight -= buttonHeight - iconHeight; - - maxIconSize = Math.min(availWidth / iconChildren.length, availHeight, opt.MAX_ICON_SIZE * scaleFactor); - } else { - availWidth = this._maxWidth; - availWidth -= this._background.get_theme_node().get_horizontal_padding(); - availWidth -= themeNode.get_horizontal_padding(); - availWidth -= buttonWidth - iconWidth; - - availHeight = maxContent.y2 - maxContent.y1; - availHeight -= iconChildren.length * (buttonHeight - iconHeight) + - (iconChildren.length - 1) * spacing + - 2 * this._background.get_theme_node().get_vertical_padding(); - - maxIconSize = Math.min(availWidth, availHeight / iconChildren.length, opt.MAX_ICON_SIZE * scaleFactor); - } - - let iconSizes = BaseIconSizes.map(s => s * scaleFactor); - - let newIconSize = BaseIconSizes[0]; - for (let i = 0; i < iconSizes.length; i++) { - if (iconSizes[i] <= maxIconSize) - newIconSize = BaseIconSizes[i]; - } - - if (newIconSize === this.iconSize) - return; - - // set the in-progress state here after all the possible cancels - this._adjustingInProgress = true; - - let oldIconSize = this.iconSize; - this.iconSize = newIconSize; - this.emit('icon-size-changed'); - - let scale = oldIconSize / newIconSize; - for (let i = 0; i < iconChildren.length; i++) { - let icon = iconChildren[i].child._delegate.icon; - - // Set the new size immediately, to keep the icons' sizes - // in sync with this.iconSize - icon.setIconSize(this.iconSize); - - // Don't animate the icon size change when the overview - // is transitioning, not visible or when initially filling - // the dash - if (!Main.overview.visible || Main.overview.animationInProgress || - !this._shownInitially) - continue; - - let [targetWidth, targetHeight] = icon.icon.get_size(); - - // Scale the icon's texture to the previous size and - // tween to the new size - icon.icon.set_size(icon.icon.width * scale, - icon.icon.height * scale); - - icon.icon.ease({ - width: targetWidth, - height: targetHeight, - duration: Dash.DASH_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - if (this._separator) { - this._separator.ease({ - width: dashHorizontal ? 1 : this.iconSize, - height: dashHorizontal ? this.iconSize : 1, - duration: Dash.DASH_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - this._adjustingInProgress = false; - }, - - handleDragOver(source, actor, x, y, _time) { - let app = getAppFromSource(source); - - // Don't allow favoriting of transient apps - if (app === null || app.is_window_backed()) - return DND.DragMotionResult.NO_DROP; - if (!global.settings.is_writable('favorite-apps')) - return DND.DragMotionResult.NO_DROP; - let favorites = AppFavorites.getAppFavorites().getFavorites(); - let numFavorites = favorites.length; - - let favPos = favorites.indexOf(app); - - let children = this._box.get_children(); - let numChildren = children.length; - let boxSize = opt.DASH_VERTICAL ? this._box.height : this._box.width; - - // Keep the placeholder out of the index calculation; assuming that - // the remove target has the same size as "normal" items, we don't - // need to do the same adjustment there. - if (this._dragPlaceholder) { - boxSize -= opt.DASH_VERTICAL ? this._dragPlaceholder.height : this._dragPlaceholder.width; - numChildren--; - } - - // Same with the separator - if (this._separator) { - boxSize -= opt.DASH_VERTICAL ? this._separator.height : this._separator.width; - numChildren--; - } - - let pos; - if (this._emptyDropTarget) - pos = 0; // always insert at the start when dash is empty - else if (this.text_direction === Clutter.TextDirection.RTL) - pos = numChildren - Math.floor((opt.DASH_VERTICAL ? y : x) * numChildren / boxSize); - else - pos = Math.floor((opt.DASH_VERTICAL ? y : x) * numChildren / boxSize); - - // Put the placeholder after the last favorite if we are not - // in the favorites zone - if (pos > numFavorites) - pos = numFavorites; - - if (pos !== this._dragPlaceholderPos && this._animatingPlaceholdersCount === 0) { - this._dragPlaceholderPos = pos; - - // Don't allow positioning before or after self - if (favPos !== -1 && (pos === favPos || pos === favPos + 1)) { - this._clearDragPlaceholder(); - return DND.DragMotionResult.CONTINUE; - } - - // If the placeholder already exists, we just move - // it, but if we are adding it, expand its size in - // an animation - let fadeIn; - if (this._dragPlaceholder) { - this._dragPlaceholder.destroy(); - fadeIn = false; - } else { - fadeIn = true; - } - - // this._dragPlaceholder = new Dash.DragPlaceholderItem(); // not exported in 45 - this._dragPlaceholder = new Dash.DashItemContainer(); - this._dragPlaceholder.setChild(new St.Bin({ style_class: 'placeholder' })); - this._dragPlaceholder.child.set_width(this.iconSize / (opt.DASH_VERTICAL ? 2 : 1)); - this._dragPlaceholder.child.set_height(this.iconSize / (opt.DASH_VERTICAL ? 1 : 2)); - this._box.insert_child_at_index( - this._dragPlaceholder, - this._dragPlaceholderPos); - this._dragPlaceholder.show(fadeIn); - } - - if (!this._dragPlaceholder) - return DND.DragMotionResult.NO_DROP; - - let srcIsFavorite = favPos !== -1; - - if (srcIsFavorite) - return DND.DragMotionResult.MOVE_DROP; - - return DND.DragMotionResult.COPY_DROP; - }, -}; - -const DashIconCommon = { - after__init() { - if (opt.DASH_ICON_SCROLL && !Me.Util.dashNotDefault()) { - this._scrollConId = this.connect('scroll-event', DashExtensions.onScrollEvent.bind(this)); - this._leaveConId = this.connect('leave-event', DashExtensions.onLeaveEvent.bind(this)); - } - - if (this._updateRunningDotStyle) - this._updateRunningDotStyle(); - }, - - /* popupMenu() { - const side = opt.DASH_VERTICAL ? St.Side.LEFT : St.Side.BOTTOM; - AppIconCommon.popupMenu.bind(this)(side); - },*/ - - _updateRunningStyle() { - const currentWs = global.workspace_manager.get_active_workspace(); - const show = opt.DASH_ISOLATE_WS - ? this.app.get_windows().filter(w => w.get_workspace() === currentWs).length - : this.app.state !== Shell.AppState.STOPPED; - - if (show) - this._dot.show(); - else - this._dot.hide(); - }, - - /* after__init() { - if (this._updateRunningDotStyle) - this._updateRunningDotStyle(); - },*/ - - _updateRunningDotStyle() { - if (opt.RUNNING_DOT_STYLE) - this._dot.add_style_class_name('app-well-app-running-dot-custom'); - else - this._dot.remove_style_class_name('app-well-app-running-dot-custom'); - - if (!this.label && shellVersion46) { - if (opt.DASH_VERTICAL) { - this._dot.translation_y = 0; - this._dot.translation_x = 0; // opt.DASH_LEFT ? -4 : 4; - } else { - this._dot.translation_y = 8; - this._dot.translation_x = 0; - } - } - }, - - activate(button) { - const event = Clutter.get_current_event(); - const state = event ? event.get_state() : 0; - const isMiddleButton = button && button === Clutter.BUTTON_MIDDLE; - const isCtrlPressed = Me.Util.isCtrlPressed(state); - const isShiftPressed = Me.Util.isShiftPressed(state); - - const currentWS = global.workspace_manager.get_active_workspace(); - const appRecentWorkspace = this._getAppRecentWorkspace(this.app); - // this feature shouldn't affect search results, dash icons don't have labels, so we use them as a condition - const showWidowsBeforeActivation = opt.DASH_CLICK_ACTION === 1 && !this.icon.label; - - let targetWindowOnCurrentWs = false; - if (opt.DASH_FOLLOW_RECENT_WIN) { - targetWindowOnCurrentWs = appRecentWorkspace === currentWS; - } else { - this.app.get_windows().forEach( - w => { - targetWindowOnCurrentWs = targetWindowOnCurrentWs || (w.get_workspace() === currentWS); - } - ); - } - - const openNewWindow = this.app.can_open_new_window() && - this.app.state === Shell.AppState.RUNNING && - (((isCtrlPressed || isMiddleButton) && !opt.DASH_CLICK_OPEN_NEW_WIN) || - (opt.DASH_CLICK_OPEN_NEW_WIN && !this._selectedMetaWin && !isMiddleButton) || - ((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !targetWindowOnCurrentWs)); - - if ((this.app.state === Shell.AppState.STOPPED || openNewWindow) && !isShiftPressed) - this.animateLaunch(); - - if (openNewWindow) { - this.app.open_new_window(-1); - // if DASH_CLICK_ACTION == "SHOW_WINS_BEFORE", the app has more than one window and has no window on the current workspace, - // don't activate the app immediately, only move the overview to the workspace with the app's recent window - } else if (showWidowsBeforeActivation && !isShiftPressed && this.app.get_n_windows() > 1 && !targetWindowOnCurrentWs/* && !(opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE)*/) { - - Main.wm.actionMoveWorkspace(appRecentWorkspace); - Main.overview.dash.showAppsButton.checked = false; - return; - } else if (this._selectedMetaWin) { - this._selectedMetaWin.activate(global.get_current_time()); - } else if (showWidowsBeforeActivation && opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && !isShiftPressed && this.app.get_n_windows() > 1) { - // expose windows - Main.overview._overview._controls._thumbnailsBox._activateThumbnailAtPoint(0, 0, global.get_current_time(), true); - return; - } else if (((opt.DASH_SHIFT_CLICK_MV && isShiftPressed) || ((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !openNewWindow)) && this.app.get_windows().length) { - this._moveAppToCurrentWorkspace(); - if (opt.DASH_ISOLATE_WS) { - this.app.activate(); - // hide the overview after the window is re-created - GLib.idle_add(GLib.PRIORITY_LOW, () => Main.overview.hide()); - } - return; - } else if (isShiftPressed) { - return; - } else { - this.app.activate(); - } - - Main.overview.hide(); - }, - - _moveAppToCurrentWorkspace() { - this.app.get_windows().forEach(w => w.change_workspace(global.workspace_manager.get_active_workspace())); - }, - - popupMenu(side = St.Side.LEFT) { - side = opt.DASH_VERTICAL ? St.Side.LEFT : St.Side.BOTTOM; - // AppIconCommon.popupMenu.bind(this)(side); - - this.setForcedHighlight(true); - this._removeMenuTimeout(); - this.fake_release(); - - if (!this._getWindowsOnCurrentWs) { - this._getWindowsOnCurrentWs = function () { - const winList = []; - this.app.get_windows().forEach(w => { - if (w.get_workspace() === global.workspace_manager.get_active_workspace()) - winList.push(w); - }); - return winList; - }; - - this._windowsOnOtherWs = function () { - return (this.app.get_windows().length - this._getWindowsOnCurrentWs().length) > 0; - }; - } - - if (!this._menu) { - this._menu = new AppMenu.AppMenu(this, side, { - favoritesSection: true, - showSingleWindows: true, - }); - - this._menu.setApp(this.app); - this._openSigId = this._menu.connect('open-state-changed', (menu, isPoppedUp) => { - if (!isPoppedUp) - this._onMenuPoppedDown(); - }); - // Main.overview.connectObject('hiding', - this._hidingSigId = Main.overview.connect('hiding', - () => this._menu.close(), this); - - Main.uiGroup.add_child(this._menu.actor); - this._menuManager.addMenu(this._menu); - } - - // once the menu is created, it stays unchanged and we need to modify our items based on current situation - if (this._addedMenuItems && this._addedMenuItems.length) - this._addedMenuItems.forEach(i => i.destroy()); - - - const popupItems = []; - - const separator = new PopupMenu.PopupSeparatorMenuItem(); - this._menu.addMenuItem(separator); - - if (this.app.get_n_windows()) { - // if (/* opt.APP_MENU_FORCE_QUIT*/true) {} - popupItems.push([_('Force Quit'), () => { - this.app.get_windows()[0].kill(); - }]); - - // if (opt.APP_MENU_CLOSE_WS) {} - const nWin = this._getWindowsOnCurrentWs().length; - if (nWin) { - popupItems.push([_(`Close ${nWin} Windows on Current Workspace`), () => { - const windows = this._getWindowsOnCurrentWs(); - let time = global.get_current_time(); - for (let win of windows) { - // increase time by 1 ms for each window to avoid errors from GS - win.delete(time++); - } - }]); - } - - - popupItems.push([_('Move App to Current Workspace ( Shift + Click )'), this._moveAppToCurrentWorkspace]); - // WTMB (Windows Thumbnails) extension required - if (global.windowThumbnails) { - popupItems.push([_('Create Window Thumbnail/PiP'), () => { - global.windowThumbnails?.createThumbnail(this.app.get_windows()[0]); - }]); - } - } - - this._addedMenuItems = []; - this._addedMenuItems.push(separator); - popupItems.forEach(i => { - let item = new PopupMenu.PopupMenuItem(i[0]); - this._menu.addMenuItem(item); - item.connect('activate', i[1].bind(this)); - if (i[1] === this._moveAppToCurrentWorkspace && !this._windowsOnOtherWs()) - item.setSensitive(false); - this._addedMenuItems.push(item); - }); - - this.emit('menu-state-changed', true); - - this._menu.open(BoxPointer.PopupAnimation.FULL); - this._menuManager.ignoreRelease(); - this.emit('sync-tooltip'); - - return false; - }, - - _getWindowApp(metaWin) { - const tracker = Shell.WindowTracker.get_default(); - return tracker.get_window_app(metaWin); - }, - - _getAppLastUsedWindow(app) { - let recentWin; - global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => { - const winApp = this._getWindowApp(metaWin); - if (!recentWin && winApp === app) - recentWin = metaWin; - }); - return recentWin; - }, - - _getAppRecentWorkspace(app) { - const recentWin = this._getAppLastUsedWindow(app); - if (recentWin) - return recentWin.get_workspace(); - - return null; - }, -}; - -const DashExtensions = { - onScrollEvent(source, event) { - if ((this.app && !opt.DASH_ICON_SCROLL) || (this._isSearchWindowsIcon && !opt.SEARCH_WINDOWS_ICON_SCROLL)) { - if (this._scrollConId) { - this.disconnect(this._scrollConId); - this._scrollConId = 0; - } - if (this._leaveConId) { - this.disconnect(this._leaveConId); - this._leaveConId = 0; - } - return Clutter.EVENT_PROPAGATE; - } - - if (Main.overview._overview.controls._stateAdjustment.value > 1) - return Clutter.EVENT_PROPAGATE; - - let direction = Me.Util.getScrollDirection(event); - if (direction === Clutter.ScrollDirection.UP) - direction = 1; - else if (direction === Clutter.ScrollDirection.DOWN) - direction = -1; - else - return Clutter.EVENT_STOP; - - // avoid uncontrollable switching if smooth scroll wheel or trackpad is used - if (this._lastScroll && Date.now() - this._lastScroll < 160) - return Clutter.EVENT_STOP; - - this._lastScroll = Date.now(); - - DashExtensions.switchWindow.bind(this)(direction); - return Clutter.EVENT_STOP; - }, - - onLeaveEvent() { - if (!this._selectedMetaWin || this.has_pointer || this.toggleButton?.has_pointer) - return; - - this._selectedPreview._activateSelected = false; - this._selectedMetaWin = null; - this._scrolledWindows = null; - DashExtensions.showWindowPreview.bind(this)(null); - }, - - - switchWindow(direction) { - if (!this._scrolledWindows) { - this._initialSelection = true; - // source is app icon - if (this.app) { - this._scrolledWindows = this.app.get_windows(); - if (opt.DASH_ISOLATE_WS) { - const currentWs = global.workspaceManager.get_active_workspace(); - this._scrolledWindows = this._scrolledWindows.filter(w => w.get_workspace() === currentWs); - } - - const wsList = []; - this._scrolledWindows.forEach(w => { - const ws = w.get_workspace(); - if (!wsList.includes(ws)) - wsList.push(ws); - }); - - // sort windows by workspaces in MRU order - this._scrolledWindows.sort((a, b) => wsList.indexOf(a.get_workspace()) > wsList.indexOf(b.get_workspace())); - // source is Search Windows icon - } else if (this._isSearchWindowsIcon) { - if (opt.SEARCH_WINDOWS_ICON_SCROLL === 1) // all windows - this._scrolledWindows = Me.Util.getWindows(null); - else - this._scrolledWindows = Me.Util.getWindows(global.workspace_manager.get_active_workspace()); - } - } - - let windows = this._scrolledWindows; - - if (!windows.length) - return; - - // if window selection is in the process, the previewed window must be the current one - let currentWin = this._selectedMetaWin ? this._selectedMetaWin : windows[0]; - - const currentIdx = windows.indexOf(currentWin); - let targetIdx = currentIdx; - // const focusWindow = Me.Util.getWindows(null)[0]; // incompatible 45 - const focusWindow = Me.Util.getWindows(null)[0]; - const appFocused = this._scrolledWindows[0] === focusWindow && this._scrolledWindows[0].get_workspace() === global.workspace_manager.get_active_workspace(); - // only if the app has focus, immediately switch to the previous window - // otherwise just set the current window above others - if (!this._initialSelection || appFocused) - targetIdx += direction; - else - this._initialSelection = false; - - if (targetIdx > windows.length - 1) - targetIdx = 0; - else if (targetIdx < 0) - targetIdx = windows.length - 1; - - const metaWin = windows[targetIdx]; - DashExtensions.showWindowPreview.bind(this)(metaWin); - this._selectedMetaWin = metaWin; - }, - - showWindowPreview(metaWin) { - const views = Main.overview._overview.controls._workspacesDisplay._workspacesViews; - const viewsIter = [views[0]]; - // secondary monitors use different structure - views.forEach(v => { - if (v._workspacesView) - viewsIter.push(v._workspacesView); - }); - - viewsIter.forEach(view => { - // if workspaces are on primary monitor only - if (!view || !view._workspaces) - return; - - view._workspaces.forEach(ws => { - ws._windows.forEach(windowPreview => { - // metaWin === null resets opacity - let opacity = metaWin ? 50 : 255; - windowPreview._activateSelected = false; - - // minimized windows are invisible if windows are not exposed (WORKSPACE_MODE === 0) - if (!windowPreview.opacity) - windowPreview.opacity = 255; - - // app windows set to lower opacity, so they can be recognized - if (this._scrolledWindows && this._scrolledWindows.includes(windowPreview.metaWindow)) { - if (opt.DASH_ICON_SCROLL === 2) - opacity = 254; - } - if (windowPreview.metaWindow === metaWin) { - if (metaWin && metaWin.get_workspace() !== global.workspace_manager.get_active_workspace()) { - Main.wm.actionMoveWorkspace(metaWin.get_workspace()); - if (_timeouts.wsSwitcherAnimation) - GLib.source_remove(_timeouts.wsSwitcherAnimation); - // setting window preview above siblings before workspace switcher animation has no effect - // we need to set the window above after the ws preview become visible on the screen - // the default switcher animation time is 250, 200 ms delay should be enough - _timeouts.wsSwitcherAnimation = GLib.timeout_add(0, 200 * St.Settings.get().slow_down_factor, () => { - windowPreview.get_parent().set_child_above_sibling(windowPreview, null); - _timeouts.wsSwitcherAnimation = 0; - return GLib.SOURCE_REMOVE; - }); - } else { - windowPreview.get_parent().set_child_above_sibling(windowPreview, null); - } - - opacity = 255; - this._selectedPreview = windowPreview; - windowPreview._activateSelected = true; - } - - // if windows are exposed, highlight selected using opacity - if ((opt.OVERVIEW_MODE && opt.WORKSPACE_MODE) || !opt.OVERVIEW_MODE) { - if (metaWin && opacity === 255) - windowPreview.showOverlay(true); - else - windowPreview.hideOverlay(true); - windowPreview.ease({ - duration: 200, - opacity, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - }); - }); - }); - }, -}; - -const AppIconCommon = { - after__init() { - if (this._updateRunningDotStyle) - this._updateRunningDotStyle(); - }, - - _updateRunningDotStyle() { - if (opt.RUNNING_DOT_STYLE) - this._dot.add_style_class_name('app-well-app-running-dot-custom'); - else - this._dot.remove_style_class_name('app-well-app-running-dot-custom'); - }, -}; - -const AppMenuCommon = { - _updateWindowsSection() { - if (global.compositor) { - if (this._updateWindowsLaterId) { - const laters = global.compositor.get_laters(); - laters.remove(this._updateWindowsLaterId); - } - } else if (this._updateWindowsLaterId) { - Meta.later_remove(this._updateWindowsLaterId); - } - - this._updateWindowsLaterId = 0; - - this._windowSection.removeAll(); - this._openWindowsHeader.hide(); - - if (!this._app) - return; - - const minWindows = this._showSingleWindows ? 1 : 2; - const currentWs = global.workspaceManager.get_active_workspace(); - const isolateWs = opt.DASH_ISOLATE_WS && !Main.overview.dash.showAppsButton.checked; - const windows = this._app.get_windows().filter(w => !w.skip_taskbar && (isolateWs ? w.get_workspace() === currentWs : true)); - if (windows.length < minWindows) - return; - - this._openWindowsHeader.show(); - - windows.forEach(window => { - const title = window.title || this._app.get_name(); - const item = this._windowSection.addAction(title, event => { - Main.activateWindow(window, event.get_time()); - }); - window.connectObject('notify::title', () => { - item.label.text = window.title || this._app.get_name(); - }, item); - }); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/iconGrid.js b/extensions/46/vertical-workspaces/lib/iconGrid.js deleted file mode 100644 index 87f6adb..0000000 --- a/extensions/46/vertical-workspaces/lib/iconGrid.js +++ /dev/null @@ -1,346 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * iconGrid.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import St from 'gi://St'; - -import * as IconGrid from 'resource:///org/gnome/shell/ui/iconGrid.js'; - -let Me; -let opt; - -// added sizes for better scaling -const IconSize = { - LARGEST: 256, - 224: 224, - 208: 208, - 192: 192, - 176: 176, - 160: 160, - 144: 144, - 128: 128, - 112: 112, - LARGE: 96, - 80: 80, - 64: 64, - TINY: 48, -}; - -const PAGE_WIDTH_CORRECTION = 100; - -export const IconGridModule = 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('appDisplayModule'); - // if notifications are enabled no override is needed - reset = reset || !this.moduleEnabled; - - // don't touch original code if module disabled - if (reset && !this._firstActivation) { - this._disableModule(); - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._overrides.addOverride('IconGrid', IconGrid.IconGrid.prototype, IconGridCommon); - this._overrides.addOverride('IconGridLayout', IconGrid.IconGridLayout.prototype, IconGridLayoutCommon); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - } -}; - -const IconGridCommon = { - getItemsAtPage(page) { - if (page < 0 || page >= this.nPages) - return []; - // throw new Error(`Page ${page} does not exist at IconGrid`); - - const layoutManager = this.layout_manager; - return layoutManager.getItemsAtPage(page); - }, - - _findBestModeForSize(width, height) { - // this function is for main grid only, folder grid calculation is in appDisplay.AppFolderDialog class - if (this._currentMode > -1 || this.layoutManager._isFolder) - return; - const { pagePadding } = this.layout_manager; - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - const iconPadding = 51 * scaleFactor; - // provided width is usually about 100px wider in horizontal orientation with prev/next page indicators - const pageIndicatorCompensation = opt.ORIENTATION ? 0 : PAGE_WIDTH_CORRECTION; - - width -= pagePadding.left + pagePadding.right + pageIndicatorCompensation; - width *= opt.APP_GRID_PAGE_WIDTH_SCALE; - height -= pagePadding.top + pagePadding.bottom; - - // store grid max dimensions for icon size algorithm - this.layoutManager._gridWidth = width; - this.layoutManager._gridHeight = height; - - width -= 80; // compensation for default padding - height -= 80; - - const spacing = opt.APP_GRID_SPACING; - // set the icon size as fixed to avoid changes in size later - const iconSize = opt.APP_GRID_ICON_SIZE > 0 ? opt.APP_GRID_ICON_SIZE : opt.APP_GRID_ICON_SIZE_DEFAULT; - // this.layout_manager.fixedIconSize = iconSize; - const itemSize = iconSize * scaleFactor + iconPadding; - // if this._gridModes.length === 1, custom grid should be used - // if (iconSize > 0 && this._gridModes.length > 1) { - let columns = opt.APP_GRID_COLUMNS; - let rows = opt.APP_GRID_ROWS; - // 0 means adaptive size - let unusedSpaceH = -1; - let unusedSpaceV = -1; - if (!columns) { - // calculate #columns + 1 without spacing - columns = Math.floor(width / itemSize) + 1; - // check if columns with spacing fits the available width - // and reduce the number until it fits - while (unusedSpaceH < 0) { - columns -= 1; - unusedSpaceH = width - columns * itemSize - (columns - 1) * spacing; - } - } - if (!rows) { - rows = Math.floor(height / itemSize) + 1; - while (unusedSpaceV < 0) { - rows -= 1; - unusedSpaceV = height - rows * itemSize - ((rows - 1) * spacing); - } - } - - this._gridModes = [{ columns, rows }]; - // } - - this._setGridMode(0); - }, -}; - -const IconGridLayoutCommon = { - _findBestIconSize() { - if (this.fixedIconSize !== -1) - return this.fixedIconSize; - - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - const nColumns = this.columnsPerPage; - const nRows = this.rowsPerPage; - - // if grid is not defined return default icon size - if (nColumns < 1 && nRows < 1) { - let iconSize; - if (this._isFolder) - iconSize = opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT; - else - iconSize = opt.APP_GRID_ICON_SIZE_DEFAULT; - - return iconSize; - } - - const columnSpacingPerPage = /* opt.APP_GRID_SPACING*/ 1 * (nColumns - 1); - const rowSpacingPerPage = /* opt.APP_GRID_SPACING*/ 1 * (nRows - 1); - const iconPadding = 55 * scaleFactor; - - const paddingH = this._isFolder ? this.pagePadding.left + this.pagePadding.right : 0; - const paddingV = this._isFolder ? this.pagePadding.top + this.pagePadding.bottom : 0; - - const width = this._gridWidth ? this._gridWidth : this._pageWidth; - const height = this._gridHeight ? this._gridHeight : this._pageHeight; - if (!width || !height) - return opt.APP_GRID_ICON_SIZE_DEFAULT; - - const [firstItem] = this._container; - - /* if (opt.APP_GRID_ADAPTIVE && !this._isFolder) - return opt.APP_GRID_ICON_SIZE_DEFAULT;*/ - - let iconSizes = Object.values(IconSize).sort((a, b) => b - a); - // limit max icon size for folders and fully adaptive folder grids, the whole range is for the main grid with active folders - if (this._isFolder && opt.APP_GRID_FOLDER_ADAPTIVE && opt.APP_GRID_FOLDER_ICON_SIZE < 0) - iconSizes = iconSizes.slice(iconSizes.indexOf(opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT), -1); - else if (this._isFolder) - iconSizes = iconSizes.slice(iconSizes.indexOf(IconSize.LARGE), -1); - else if (opt.APP_GRID_ADAPTIVE && opt.APP_GRID_ICON_SIZE < 0) - iconSizes = iconSizes.slice(iconSizes.indexOf(opt.APP_GRID_ICON_SIZE_DEFAULT), -1); - - let sizeInvalid = false; - for (const size of iconSizes) { - let usedWidth, usedHeight; - - if (firstItem) { - firstItem.icon.setIconSize(size); - const [firstItemWidth] = firstItem.get_preferred_size(); - - const itemSize = firstItemWidth; - if (itemSize < size) - sizeInvalid = true; - - usedWidth = itemSize * nColumns; - usedHeight = itemSize * nRows; - } - - if (!firstItem || sizeInvalid) { - usedWidth = (size + iconPadding) * nColumns; - usedHeight = (size + iconPadding) * nRows; - } - const emptyHSpace = - width - usedWidth - columnSpacingPerPage - paddingH; - // this.pagePadding.left - this.pagePadding.right; - const emptyVSpace = - height - usedHeight - rowSpacingPerPage - paddingV; - // this.pagePadding.top - this.pagePadding.bottom; - - if (emptyHSpace >= 0 && emptyVSpace >= 0) { - return size; - } - } - - return IconSize.TINY; - }, - - removeItem(item) { - if (!this._items.has(item)) { - console.error(`iconGrid: Item ${item} is not part of the IconGridLayout`); - return; - // throw new Error(`Item ${item} is not part of the IconGridLayout`); - } - - if (!this._container) - return; - - this._shouldEaseItems = true; - - this._container.remove_child(item); - this._removeItemData(item); - }, - - addItem(item, page = -1, index = -1) { - if (this._items.has(item)) { - console.error(`iconGrid: Item ${item} already added to IconGridLayout`); - return; - // throw new Error(`Item ${item} already added to IconGridLayout`); - } - - if (page > this._pages.length) { - console.error(`iconGrid: Cannot add ${item} to page ${page}`); - page = -1; - index = -1; - // throw new Error(`Cannot add ${item} to page ${page}`); - } - - if (!this._container) - return; - - if (page !== -1 && index === -1) - page = this._findBestPageToAppend(page); - - this._shouldEaseItems = true; - this._container.add_child(item); - this._addItemToPage(item, page, index); - }, - - moveItem(item, newPage, newPosition) { - if (!this._items.has(item)) { - console.error(`iconGrid: Item ${item} is not part of the IconGridLayout`); - return; - // throw new Error(`Item ${item} is not part of the IconGridLayout`); - } - - this._shouldEaseItems = true; - - this._removeItemData(item); - - if (newPage !== -1 && newPosition === -1) - newPage = this._findBestPageToAppend(newPage); - this._addItemToPage(item, newPage, newPosition); - }, - - _addItemToPage(item, pageIndex, index) { - // Ensure we have at least one page - if (this._pages.length === 0) - this._appendPage(); - - // Append a new page if necessary - if (pageIndex === this._pages.length) - this._appendPage(); - - if (pageIndex >= this._pages.length) { - pageIndex = -1; - index = -1; - } - - if (pageIndex === -1) - pageIndex = this._pages.length - 1; - - if (index === -1) - index = this._pages[pageIndex].children.length; - - this._items.set(item, { - actor: item, - pageIndex, - destroyId: item.connect('destroy', () => this._removeItemData(item)), - visibleId: item.connect('notify::visible', () => { - const itemData = this._items.get(item); - - this._updateVisibleChildrenForPage(itemData.pageIndex); - - if (item.visible) - this._relocateSurplusItems(itemData.pageIndex); - else if (!this.allowIncompletePages) - this._fillItemVacancies(itemData.pageIndex); - }), - queueRelayoutId: item.connect('queue-relayout', () => { - this._childrenMaxSize = -1; - }), - }); - - item.icon.setIconSize(this._iconSize); - this._pages[pageIndex].children.splice(index, 0, item); - this._updateVisibleChildrenForPage(pageIndex); - this._relocateSurplusItems(pageIndex); - }, - - _findBestPageToAppend(startPage) { - const itemsPerPage = this.columnsPerPage * this.rowsPerPage; - - for (let i = startPage; i < this._pages.length; i++) { - const visibleItems = this._pages[i].visibleChildren; - - if (visibleItems.length < itemsPerPage) - return i; - } - - return this._pages.length; - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/layout.js b/extensions/46/vertical-workspaces/lib/layout.js deleted file mode 100644 index 807f9e0..0000000 --- a/extensions/46/vertical-workspaces/lib/layout.js +++ /dev/null @@ -1,473 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * layout.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import Meta from 'gi://Meta'; -import Gio from 'gi://Gio'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'; - -let Me; -let opt; -let _timeouts; - -export const LayoutModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - _timeouts = {}; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - this._originalUpdateHotCorners = null; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this._removeTimeouts(); - - this.moduleEnabled = opt.get('layoutModule'); - const conflict = Me.Util.getEnabledExtensions('custom-hot-corners').length || - Me.Util.getEnabledExtensions('dash-to-panel').length; - - if (conflict && !reset) - console.warn(`[${Me.metadata.name}] Warning: "Layout" module disabled due to potential conflict with another extension`); - - 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(' LayoutModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - _timeouts = {}; - - this._overrides.addOverride('LayoutManager', Main.layoutManager, LayoutManagerCommon); - this._overrides.addOverride('HotCorner', Layout.HotCorner.prototype, HotCornerCommon); - - Main.layoutManager._updatePanelBarrier(); - Main.layoutManager._updateHotCorners(); - - if (!this._hotCornersEnabledConId) { - this._interfaceSettings = new Gio.Settings({ - schema_id: 'org.gnome.desktop.interface', - }); - this._hotCornersEnabledConId = this._interfaceSettings.connect('changed::enable-hot-corners', - () => Main.layoutManager._updateHotCorners()); - } - - console.debug(' LayoutModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - Main.layoutManager._updateHotCorners(); - - if (this._hotCornersEnabledConId) { - this._interfaceSettings.disconnect(this._hotCornersEnabledConId); - this._hotCornersEnabledConId = 0; - this._interfaceSettings = null; - } - - console.debug(' LayoutModule - Disabled'); - } - - _removeTimeouts() { - if (_timeouts) { - Object.values(_timeouts).forEach(t => { - if (t) - GLib.source_remove(t); - }); - _timeouts = null; - } - } -}; - -const LayoutManagerCommon = { - _updatePanelBarrier() { - if (this._rightPanelBarrier) { - this._rightPanelBarrier.destroy(); - this._rightPanelBarrier = null; - } - - if (this._leftPanelBarrier) { - this._leftPanelBarrier.destroy(); - this._leftPanelBarrier = null; - } - - if (!this.primaryMonitor || !opt || Me.Util.getEnabledExtensions('hidetopbar')) - return; - - if (this.panelBox.height) { - const backend = !!Meta.Barrier.prototype.backend; - let params = {}; - if (backend) - params['backend'] = global.backend; - else - params['display'] = global.display; - - let primary = this.primaryMonitor; - if ([0, 1, 3].includes(opt.HOT_CORNER_POSITION)) { - params = Object.assign({}, params, { - x1: primary.x + primary.width, y1: this.panelBox.allocation.y1, - x2: primary.x + primary.width, y2: this.panelBox.allocation.y2, - directions: Meta.BarrierDirection.NEGATIVE_X, - }); - this._rightPanelBarrier = new Meta.Barrier(params); - } - - if ([2, 4].includes(opt.HOT_CORNER_POSITION)) { - params = Object.assign({}, params, { - x1: primary.x, y1: this.panelBox.allocation.y1, - x2: primary.x, y2: this.panelBox.allocation.y2, - directions: Meta.BarrierDirection.POSITIVE_X, - }); - this._leftPanelBarrier = new Meta.Barrier(params); - } - } - }, - - _updateHotCorners() { - // avoid errors if called from foreign override - if (!opt) - return; - - // destroy old hot corners - this.hotCorners.forEach(corner => corner?.destroy()); - this.hotCorners = []; - - if (!this._interfaceSettings.get_boolean('enable-hot-corners')) { - this.emit('hot-corners-changed'); - return; - } - - let size = this.panelBox.height ? this.panelBox.height : 27; - - // position 0 - default, 1-TL, 2-TR, 3-BL, 4-BR - const position = opt.HOT_CORNER_POSITION; - - // build new hot corners - for (let i = 0; i < this.monitors.length; i++) { - let monitor = this.monitors[i]; - let cornerX, cornerY; - - if (position === 0) { - cornerX = this._rtl ? monitor.x + monitor.width : monitor.x; - cornerY = monitor.y; - } else if (position === 1) { - cornerX = monitor.x; - cornerY = monitor.y; - } else if (position === 2) { - cornerX = monitor.x + monitor.width; - cornerY = monitor.y; - } else if (position === 3) { - cornerX = monitor.x; - cornerY = monitor.y + monitor.height; - } else { - cornerX = monitor.x + monitor.width; - cornerY = monitor.y + monitor.height; - } - - let haveCorner = true; - - if (i !== this.primaryIndex) { - // Check if we have a top left (right for RTL) corner. - // I.e. if there is no monitor directly above or to the left(right) - let besideX = this._rtl ? monitor.x + 1 : cornerX - 1; - let besideY = cornerY; - let aboveX = cornerX; - let aboveY = cornerY - 1; - - for (let j = 0; j < this.monitors.length; j++) { - if (i === j) - continue; - let otherMonitor = this.monitors[j]; - if (besideX >= otherMonitor.x && - besideX < otherMonitor.x + otherMonitor.width && - besideY >= otherMonitor.y && - besideY < otherMonitor.y + otherMonitor.height) { - haveCorner = false; - break; - } - if (aboveX >= otherMonitor.x && - aboveX < otherMonitor.x + otherMonitor.width && - aboveY >= otherMonitor.y && - aboveY < otherMonitor.y + otherMonitor.height) { - haveCorner = false; - break; - } - } - } - - if (haveCorner) { - let corner = new Layout.HotCorner(this, monitor, cornerX, cornerY); - corner.setBarrierSize(size, false); - this.hotCorners.push(corner); - } else { - this.hotCorners.push(null); - } - } - - this.emit('hot-corners-changed'); - }, -}; - -const HotCornerCommon = { - after__init() { - let angle = 0; - switch (opt.HOT_CORNER_POSITION) { - case 2: - angle = 90; - break; - case 3: - angle = 270; - break; - case 4: - angle = 180; - break; - } - - this._ripples._ripple1.rotation_angle_z = angle; - this._ripples._ripple2.rotation_angle_z = angle; - this._ripples._ripple3.rotation_angle_z = angle; - }, - - setBarrierSize(size, notMyCall = true) { - // ignore calls from the original _updateHotCorners() callback to avoid building barriers outside screen - if (notMyCall && size > 0) - return; - - if (this._verticalBarrier) { - this._pressureBarrier.removeBarrier(this._verticalBarrier); - this._verticalBarrier.destroy(); - this._verticalBarrier = null; - } - - if (this._horizontalBarrier) { - this._pressureBarrier.removeBarrier(this._horizontalBarrier); - this._horizontalBarrier.destroy(); - this._horizontalBarrier = null; - } - - if (size > 0) { - const primaryMonitor = global.display.get_primary_monitor(); - const monitor = this._monitor; - const extendV = opt && opt.HOT_CORNER_ACTION && opt.HOT_CORNER_EDGE && opt.DASH_VERTICAL && monitor.index === primaryMonitor; - const extendH = opt && opt.HOT_CORNER_ACTION && opt.HOT_CORNER_EDGE && !opt.DASH_VERTICAL && monitor.index === primaryMonitor; - - const backend = !!Meta.Barrier.prototype.backend; - let params = {}; - if (backend) - params['backend'] = global.backend; - else - params['display'] = global.display; - - if (opt.HOT_CORNER_POSITION <= 1) { - params = Object.assign({}, params, { - x1: this._x, x2: this._x, - y1: this._y, y2: this._y + (extendV ? monitor.height : size), - directions: Meta.BarrierDirection.POSITIVE_X, - }); - this._verticalBarrier = new Meta.Barrier(params); - params = Object.assign({}, params, { - x1: this._x, x2: this._x + (extendH ? monitor.width : size), - y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.POSITIVE_Y, - }); - this._horizontalBarrier = new Meta.Barrier(params); - } else if (opt.HOT_CORNER_POSITION === 2) { - params = Object.assign({}, params, { - x1: this._x, x2: this._x, - y1: this._y, y2: this._y + (extendV ? monitor.height : size), - directions: Meta.BarrierDirection.NEGATIVE_X, - }); - this._verticalBarrier = new Meta.Barrier(params); - params = Object.assign({}, params, { - x1: this._x - size, x2: this._x, - y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.POSITIVE_Y, - }); - this._horizontalBarrier = new Meta.Barrier(params); - } else if (opt.HOT_CORNER_POSITION === 3) { - params = Object.assign({}, params, { - x1: this._x, x2: this._x, - y1: this._y, y2: this._y - size, - directions: Meta.BarrierDirection.POSITIVE_X, - }); - this._verticalBarrier = new Meta.Barrier(params); - params = Object.assign({}, params, { - x1: this._x, x2: this._x + (extendH ? monitor.width : size), - y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.NEGATIVE_Y, - }); - this._horizontalBarrier = new Meta.Barrier(params); - } else if (opt.HOT_CORNER_POSITION === 4) { - params = Object.assign({}, params, { - x1: this._x, x2: this._x, - y1: this._y, y2: this._y - size, - directions: Meta.BarrierDirection.NEGATIVE_X, - }); - this._verticalBarrier = new Meta.Barrier(params); - params = Object.assign({}, params, { - x1: this._x, x2: this._x - size, - y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.NEGATIVE_Y, - }); - this._horizontalBarrier = new Meta.Barrier(params); - } - - this._pressureBarrier.addBarrier(this._verticalBarrier); - this._pressureBarrier.addBarrier(this._horizontalBarrier); - } - }, - - _toggleOverview() { - if (!opt.HOT_CORNER_ACTION || (!opt.HOT_CORNER_FULLSCREEN && this._monitor.inFullscreen && !Main.overview.visible)) - return; - - if (Main.overview.shouldToggleByCornerOrButton()) { - if (Main.overview._shown) { - this._toggleWindowPicker(true); - } else if ((opt.HOT_CORNER_ACTION === 2 && !Me.Util.isCtrlPressed()) || ([3, 4, 5, 6].includes(opt.HOT_CORNER_ACTION) && Me.Util.isCtrlPressed())) { - // Default overview - opt.OVERVIEW_MODE = 0; - opt.OVERVIEW_MODE2 = false; - opt.WORKSPACE_MODE = 1; - this._toggleWindowPicker(true, true); - } else if (opt.HOT_CORNER_ACTION === 1) { - Main.overview.resetOverviewMode(); - this._toggleWindowPicker(true, true); - } else if ((opt.HOT_CORNER_ACTION === 3 && !Me.Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 2 && Me.Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 6 && Me.Util.isCtrlPressed())) { - // Applications - this._toggleApplications(true); - } else if (opt.HOT_CORNER_ACTION === 4 && !Me.Util.isCtrlPressed()) { - // Overview - static ws preview - opt.OVERVIEW_MODE = 1; - opt.OVERVIEW_MODE2 = false; - opt.WORKSPACE_MODE = 0; - this._toggleWindowPicker(true, true); - } else if (opt.HOT_CORNER_ACTION === 5 && !Me.Util.isCtrlPressed()) { - // Overview - static ws - opt.OVERVIEW_MODE = 2; - opt.OVERVIEW_MODE2 = true; - opt.WORKSPACE_MODE = 0; - this._toggleWindowPicker(true, true); - } else if (opt.HOT_CORNER_ACTION === 6 && !Me.Util.isCtrlPressed()) { - // Window search provider - opt.OVERVIEW_MODE = 2; - opt.OVERVIEW_MODE2 = true; - opt.WORKSPACE_MODE = 0; - this._toggleWindowSearchProvider(); - } - if (opt.HOT_CORNER_RIPPLES && Main.overview.animationInProgress) - this._ripples.playAnimation(this._x, this._y); - } - }, - - _toggleWindowPicker(leaveOverview = false, customOverviewMode = false) { - if (Main.overview._shown && (leaveOverview || !Main.overview.dash.showAppsButton.checked)) { - Main.overview.hide(); - } else if (Main.overview.dash.showAppsButton.checked) { - Main.overview.dash.showAppsButton.checked = false; - } else { - const focusWindow = global.display.get_focus_window(); - // at least GS 42 is unable to show overview in X11 session if VirtualBox Machine window grabbed keyboard - if (!Meta.is_wayland_compositor() && focusWindow && focusWindow.wm_class.includes('VirtualBox Machine')) { - // following should help when windowed VBox Machine has focus. - global.stage.set_key_focus(Main.panel); - // key focus doesn't take the effect immediately, we must wait for it - // still looking for better solution! - _timeouts.releaseKeyboardTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - // delay cannot be too short - 200, - () => { - Main.overview.show(1, customOverviewMode); - - _timeouts.releaseKeyboardTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); - } else { - Main.overview.show(1, customOverviewMode); - } - } - }, - - _toggleApplications(leaveOverview = false) { - if ((leaveOverview && Main.overview._shown) || Main.overview.dash.showAppsButton.checked) { - Main.overview.hide(); - } else { - const focusWindow = global.display.get_focus_window(); - // at least GS 42 is unable to show overview in X11 session if VirtualBox Machine window grabbed keyboard - if (!Meta.is_wayland_compositor() && focusWindow && focusWindow.wm_class.includes('VirtualBox Machine')) { - // following should help when windowed VBox Machine has focus. - global.stage.set_key_focus(Main.panel); - // key focus doesn't take the effect immediately, we must wait for it - // still looking for better solution! - _timeouts.releaseKeyboardTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - // delay cannot be too short - 200, - () => { - Main.overview.show(2); - - _timeouts.releaseKeyboardTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); - } else if (Main.overview._shown) { - Main.overview.dash.showAppsButton.checked = true; - } else { - Main.overview.show(2); // 2 for App Grid - } - } - }, - - _toggleWindowSearchProvider() { - if (!Main.overview.searchController._searchActive) { - opt.OVERVIEW_MODE = 2; - opt.OVERVIEW_MODE2 = true; - opt.WORKSPACE_MODE = 0; - this._toggleWindowPicker(false, true); - const prefix = Me.WSP_PREFIX; - const position = prefix.length; - const searchEntry = Main.overview.searchEntry; - searchEntry.set_text(prefix); - // searchEntry.grab_key_focus(); - searchEntry.get_first_child().set_cursor_position(position); - searchEntry.get_first_child().set_selection(position, position); - } else { - // Main.overview.searchEntry.text = ''; - Main.overview.hide(); - } - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/messageTray.js b/extensions/46/vertical-workspaces/lib/messageTray.js deleted file mode 100644 index 28d6b1d..0000000 --- a/extensions/46/vertical-workspaces/lib/messageTray.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * messageTray.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; - -let Me; -let opt; - -export const MessageTrayModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this.moduleEnabled = opt.get('messageTrayModule'); - 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(' MessageTrayModule - Keeping untouched'); - } - - _activateModule() { - this._setNotificationPosition(opt.NOTIFICATION_POSITION); - - console.debug(' MessageTrayModule - Activated'); - } - - _disableModule() { - this._setNotificationPosition(1); - - console.debug(' MessageTrayModule - Disabled'); - } - - _setNotificationPosition(position) { - switch (position) { - case 0: - Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.START; - Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START; - break; - case 1: - Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.CENTER; - Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START; - break; - case 2: - Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.END; - Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.START; - break; - case 3: - Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.START; - Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END; - break; - case 4: - Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.CENTER; - Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END; - break; - case 5: - Main.messageTray._bannerBin.x_align = Clutter.ActorAlign.END; - Main.messageTray._bannerBin.y_align = Clutter.ActorAlign.END; - break; - } - } -}; diff --git a/extensions/46/vertical-workspaces/lib/optionsFactory.js b/extensions/46/vertical-workspaces/lib/optionsFactory.js deleted file mode 100644 index 05e14b0..0000000 --- a/extensions/46/vertical-workspaces/lib/optionsFactory.js +++ /dev/null @@ -1,496 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * optionsFactory.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - */ - -'use strict'; - -import Adw from 'gi://Adw'; -import Gio from 'gi://Gio'; -import GObject from 'gi://GObject'; -import Gtk from 'gi://Gtk'; - -let Me; - -// gettext -let _; - -export function init(me) { - Me = me; - _ = Me.gettext; -} - -export const ItemFactory = class ItemFactory { - constructor() { - this._settings = Me.Opt._gsettings; - } - - getRowWidget(text, caption, widget, variable, options = [], dependsOn) { - let item = []; - let label; - if (widget) { - label = new Gtk.Box({ - orientation: Gtk.Orientation.VERTICAL, - spacing: 4, - halign: Gtk.Align.START, - valign: Gtk.Align.CENTER, - }); - const option = new Gtk.Label({ - halign: Gtk.Align.START, - }); - option.set_text(text); - label.append(option); - - if (caption) { - const captionLabel = new Gtk.Label({ - halign: Gtk.Align.START, - wrap: true, - /* width_chars: 80, */ - xalign: 0, - }); - const context = captionLabel.get_style_context(); - context.add_class('dim-label'); - context.add_class('caption'); - captionLabel.set_text(caption); - label.append(captionLabel); - } - label._title = text; - } else { - label = text; - } - item.push(label); - item.push(widget); - - let key; - - if (variable && Me.Opt.options[variable]) { - const opt = Me.Opt.options[variable]; - key = opt[1]; - } - - if (widget) { - if (widget._isSwitch) - this._connectSwitch(widget, key, variable); - else if (widget._isSpinButton || widget._isScale) - this._connectSpinButton(widget, key, variable); - else if (widget._isComboBox) - this._connectComboBox(widget, key, variable, options); - else if (widget._isDropDown) - this._connectDropDown(widget, key, variable, options); - - if (dependsOn) { - const dKey = Me.Opt.options[dependsOn][1]; - this._settings.bind(dKey, widget, 'sensitive', Gio.SettingsBindFlags.GET); - } - } - - return item; - } - - _connectSwitch(widget, key /* , variable */) { - this._settings.bind(key, widget, 'active', Gio.SettingsBindFlags.DEFAULT); - } - - _connectSpinButton(widget, key /* , variable */) { - this._settings.bind(key, widget.adjustment, 'value', Gio.SettingsBindFlags.DEFAULT); - } - - _connectComboBox(widget, key, variable, options) { - let model = widget.get_model(); - widget._comboMap = {}; - const currentValue = Me.Opt.get(variable); - for (const [label, value] of options) { - let iter; - model.set(iter = model.append(), [0, 1], [label, value]); - if (value === currentValue) - widget.set_active_iter(iter); - - widget._comboMap[value] = iter; - } - Me.Opt.connect(`changed::${key}`, () => { - widget.set_active_iter(widget._comboMap[Me.Opt.get(variable, true)]); - }); - widget.connect('changed', () => { - const [success, iter] = widget.get_active_iter(); - - if (!success) - return; - - Me.Opt.set(variable, model.get_value(iter, 1)); - }); - } - - _connectDropDown(widget, key, variable, options) { - const model = widget.get_model(); - const currentValue = Me.Opt.get(variable); - for (let i = 0; i < options.length; i++) { - const text = options[i][0]; - const id = options[i][1]; - model.append(new DropDownItem({ text, id })); - if (id === currentValue) - widget.set_selected(i); - } - - const factory = new Gtk.SignalListItemFactory(); - factory.connect('setup', (fact, listItem) => { - const label = new Gtk.Label({ xalign: 0 }); - listItem.set_child(label); - }); - factory.connect('bind', (fact, listItem) => { - const label = listItem.get_child(); - const item = listItem.get_item(); - label.set_text(item.text); - }); - - widget.connect('notify::selected-item', dropDown => { - const item = dropDown.get_selected_item(); - Me.Opt.set(variable, item.id); - }); - - Me.Opt.connect(`changed::${key}`, () => { - const newId = Me.Opt.get(variable, true); - for (let i = 0; i < options.length; i++) { - const id = options[i][1]; - if (id === newId) - widget.set_selected(i); - } - }); - - widget.set_factory(factory); - } - - newSwitch() { - let sw = new Gtk.Switch({ - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - }); - sw._isSwitch = true; - return sw; - } - - newSpinButton(adjustment) { - let spinButton = new Gtk.SpinButton({ - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - vexpand: false, - xalign: 0.5, - }); - spinButton.set_adjustment(adjustment); - spinButton._isSpinButton = true; - return spinButton; - } - - newComboBox() { - const model = new Gtk.ListStore(); - model.set_column_types([GObject.TYPE_STRING, GObject.TYPE_INT]); - const comboBox = new Gtk.ComboBox({ - model, - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - }); - const renderer = new Gtk.CellRendererText(); - comboBox.pack_start(renderer, true); - comboBox.add_attribute(renderer, 'text', 0); - comboBox._isComboBox = true; - return comboBox; - } - - newDropDown() { - const dropDown = new Gtk.DropDown({ - model: new Gio.ListStore({ - item_type: DropDownItem, - }), - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - }); - dropDown._isDropDown = true; - return dropDown; - } - - newScale(adjustment) { - const scale = new Gtk.Scale({ - orientation: Gtk.Orientation.HORIZONTAL, - draw_value: true, - has_origin: false, - value_pos: Gtk.PositionType.LEFT, - digits: 0, - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - vexpand: false, - }); - scale.set_size_request(300, -1); - scale.set_adjustment(adjustment); - scale._isScale = true; - return scale; - } - - newLabel(text = '') { - const label = new Gtk.Label({ - label: text, - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - }); - label._activatable = false; - return label; - } - - newLinkButton(uri) { - const linkBtn = new Gtk.LinkButton({ - uri, - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - icon_name: 'emblem-symbolic-link', - }); - return linkBtn; - } - - newButton() { - const btn = new Gtk.Button({ - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - }); - - btn._activatable = true; - return btn; - } - - newPresetButton(opt, profileIndex) { - const load = opt.loadProfile.bind(opt); - const save = opt.storeProfile.bind(opt); - const reset = opt.resetProfile.bind(opt); - - const box = new Gtk.Box({ - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - spacing: 8, - }); - box.is_profile_box = true; - - const entry = new Gtk.Entry({ - width_chars: 40, - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - xalign: 0, - }); - entry.set_text(opt.get(`profileName${profileIndex}`)); - entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'edit-clear-symbolic'); - entry.set_icon_activatable(Gtk.EntryIconPosition.SECONDARY, true); - - const resetProfile = this.newButton(); - resetProfile.set({ - tooltip_text: _('Reset profile to defaults'), - icon_name: 'document-revert-symbolic', - hexpand: false, - css_classes: ['destructive-action'], - }); - - function setName() { - const ProfileNames = [ - _('GNOME 3'), - _('GNOME 40+ - Bottom Hot Edge'), - _('Hot Corner Centric - Top Left Hot Corner'), - _('Dock Overview - Bottom Hot Edge'), - ]; - - let name = opt.get(`profileName${profileIndex}`, true); - if (!name) - name = ProfileNames[profileIndex - 1]; - entry.set_text(name); - } - - setName(); - - entry.connect('icon-press', e => e.set_text('')); - entry.connect('changed', e => opt.set(`profileName${profileIndex}`, e.get_text())); - - resetProfile.connect('clicked', () => { - reset(profileIndex); - setName(); - }); - resetProfile._activatable = false; - - const loadProfile = this.newButton(); - loadProfile.set({ - tooltip_text: _('Load profile'), - icon_name: 'view-refresh-symbolic', - hexpand: false, - }); - loadProfile.connect('clicked', () => load(profileIndex)); - loadProfile._activatable = false; - - const saveProfile = this.newButton(); - saveProfile.set({ - tooltip_text: _('Save current settings into this profile'), - icon_name: 'document-save-symbolic', - hexpand: false, - }); - saveProfile.connect('clicked', () => save(profileIndex)); - saveProfile._activatable = false; - - box.append(resetProfile); - box.append(entry); - box.append(saveProfile); - box.append(loadProfile); - return box; - } - - newResetButton(callback) { - const btn = this.newButton(); - btn.set({ - css_classes: ['destructive-action'], - icon_name: 'edit-delete-symbolic', - }); - - btn.connect('clicked', callback); - btn._activatable = false; - return btn; - } - - newOptionsResetButton() { - const btn = new Gtk.Button({ - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - css_classes: ['destructive-action'], - icon_name: 'document-revert-symbolic', - }); - - btn.connect('clicked', () => { - const settings = this._settings; - settings.list_keys().forEach( - key => settings.reset(key) - ); - }); - btn._activatable = false; - return btn; - } -}; - -export const AdwPrefs = class { - constructor(gOptions) { - Me.Opt = gOptions; - } - - getFilledWindow(window, pages) { - for (let page of pages) { - const title = page.title; - const iconName = page.iconName; - const optionList = page.optionList; - - window.add( - this._getAdwPage(optionList, { - title, - icon_name: iconName, - }) - ); - } - - window.set_search_enabled(true); - - return window; - } - - _getAdwPage(optionList, pageProperties = {}) { - // pageProperties.width_request = 740; - const page = new Adw.PreferencesPage(pageProperties); - let group; - for (let item of optionList) { - // label can be plain text for Section Title - // or GtkBox for Option - const option = item[0]; - const widget = item[1]; - if (!widget) { - if (group) - page.add(group); - - group = new Adw.PreferencesGroup({ - title: option, - hexpand: true, - width_request: 700, - }); - continue; - } - - const row = new Adw.ActionRow({ - title: option._title, - }); - - const grid = new Gtk.Grid({ - column_homogeneous: false, - column_spacing: 20, - margin_start: 8, - margin_end: 8, - margin_top: 8, - margin_bottom: 8, - hexpand: true, - }); - /* for (let i of item) { - box.append(i);*/ - grid.attach(option, 0, 0, 1, 1); - if (widget) - grid.attach(widget, 1, 0, 1, 1); - - row.set_child(grid); - if (widget._activatable === false) - row.activatable = false; - else - row.activatable_widget = widget; - - group.add(row); - } - page.add(group); - return page; - } -}; - -const DropDownItem = GObject.registerClass({ - // Registered name should be unique - GTypeName: `DropDownItem${Math.floor(Math.random() * 1000)}`, - Properties: { - 'text': GObject.ParamSpec.string( - 'text', - 'Text', - 'DropDown item text', - GObject.ParamFlags.READWRITE, - '' - ), - 'id': GObject.ParamSpec.int( - 'id', - 'Id', - 'Item id stored in settings', - GObject.ParamFlags.READWRITE, - // min, max, default - -2147483648, 2147483647, 0 - ), - }, -}, class DropDownItem extends GObject.Object { - get text() { - return this._text; - } - - set text(text) { - this._text = text; - } - - get id() { - return this._id; - } - - set id(id) { - this._id = id; - } -}); diff --git a/extensions/46/vertical-workspaces/lib/osdWindow.js b/extensions/46/vertical-workspaces/lib/osdWindow.js deleted file mode 100644 index a06a331..0000000 --- a/extensions/46/vertical-workspaces/lib/osdWindow.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * osdWindow.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as OsdWindow from 'resource:///org/gnome/shell/ui/osdWindow.js'; - -let Me; -let opt; - -let OsdPositions; - -export const OsdWindowModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - - OsdPositions = { - 1: { - x_align: Clutter.ActorAlign.START, - y_align: Clutter.ActorAlign.START, - }, - 2: { - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.START, - }, - 3: { - x_align: Clutter.ActorAlign.END, - y_align: Clutter.ActorAlign.START, - }, - 4: { - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.CENTER, - }, - 5: { - x_align: Clutter.ActorAlign.START, - y_align: Clutter.ActorAlign.END, - }, - 6: { - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.END, - }, - 7: { - x_align: Clutter.ActorAlign.END, - y_align: Clutter.ActorAlign.END, - }, - }; - } - - cleanGlobals() { - Me = null; - opt = null; - OsdPositions = null; - } - - update(reset) { - this.moduleEnabled = opt.get('osdWindowModule'); - 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(' OsdWindowModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._overrides.addOverride('osdWindow', OsdWindow.OsdWindow.prototype, OsdWindowCommon); - console.debug(' OsdWindowModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - this._updateExistingOsdWindows(6); - - console.debug(' WorkspaceSwitcherPopupModule - Disabled'); - } - - _updateExistingOsdWindows(position) { - position = position ? position : opt.OSD_POSITION; - Main.osdWindowManager._osdWindows.forEach(osd => { - osd.set(OsdPositions[position]); - }); - } -}; - -const OsdWindowCommon = { - after_show() { - if (!opt.OSD_POSITION) - this.opacity = 0; - this.set(OsdPositions[opt.OSD_POSITION]); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/overlayKey.js b/extensions/46/vertical-workspaces/lib/overlayKey.js deleted file mode 100644 index 5ffd973..0000000 --- a/extensions/46/vertical-workspaces/lib/overlayKey.js +++ /dev/null @@ -1,170 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * overlayKey.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import St from 'gi://St'; -import Meta from 'gi://Meta'; -import GObject from 'gi://GObject'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Overview from 'resource:///org/gnome/shell/ui/overview.js'; - -let Me; -let opt; - -export const OverlayKeyModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - this._originalOverlayKeyHandlerId = 0; - this._overlayKeyHandlerId = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this.moduleEnabled = opt.get('overlayKeyModule'); - const conflict = false; - // Avoid modifying the overlay key if its configuration is consistent with the GNOME default - const defaultConfig = opt.OVERVIEW_MODE === 0 && opt.OVERLAY_KEY_PRIMARY === 2 && opt.OVERLAY_KEY_SECONDARY === 1; - - reset = reset || !this.moduleEnabled || conflict || defaultConfig; - - if (reset && !this._firstActivation) { - this._disableModule(); - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - if (reset && this._firstActivation) - console.debug(' OverlayKeyModule - Keeping untouched'); - } - - _activateModule() { - if (!this._originalOverlayKeyHandlerId) { - this._originalOverlayKeyHandlerId = GObject.signal_handler_find(global.display, { signalId: 'overlay-key' }); - if (this._originalOverlayKeyHandlerId !== null) { - global.display.block_signal_handler(this._originalOverlayKeyHandlerId); - this._connectOverlayKey(); - } - } - console.debug(' OverlayKeyModule - Activated'); - } - - _disableModule() { - this._restoreOverlayKeyHandler(); - - console.debug(' OverlayKeyModule - Disabled'); - } - - _restoreOverlayKeyHandler() { - // Disconnect modified overlay key handler - if (this._overlayKeyHandlerId) { - global.display.disconnect(this._overlayKeyHandlerId); - this._overlayKeyHandlerId = 0; - } - - // Unblock original overlay key handler - if (this._originalOverlayKeyHandlerId) { - global.display.unblock_signal_handler(this._originalOverlayKeyHandlerId); - this._originalOverlayKeyHandlerId = 0; - } - } - - _connectOverlayKey() { - if (this._overlayKeyHandlerId) - return; - - this._overlayKeyHandlerId = global.display.connect('overlay-key', this._onOverlayKeyPressed.bind(Main.overview._overview.controls)); - } - - _onOverlayKeyPressed() { - if (this._a11ySettings.get_boolean('stickykeys-enable')) - return; - - const { initialState, finalState, transitioning } = - this._stateAdjustment.getStateTransitionParams(); - - const time = GLib.get_monotonic_time() / 1000; - const timeDiff = time - this._lastOverlayKeyTime; - this._lastOverlayKeyTime = time; - - const shouldShift = St.Settings.get().enable_animations - ? transitioning && finalState > initialState - : Main.overview.visible && timeDiff < Overview.ANIMATION_TIME; - - const mode = opt.OVERLAY_KEY_SECONDARY; - if (shouldShift) { - Me.Util.activateSearchProvider(''); - if (mode === 1) { - this._shiftState(Meta.MotionDirection.UP); - } else if (mode === 2) { - Me.Util.activateSearchProvider(Me.WSP_PREFIX); - } else if (mode === 3) { - // Changing the overview mode automatically changes the overview transition - opt.OVERVIEW_MODE = 0; - opt.OVERVIEW_MODE2 = false; - opt.WORKSPACE_MODE = 1; - } - } else { - if (Main.overview._shown) { - Main.overview.hide(); - return; - } - switch (opt.OVERLAY_KEY_PRIMARY) { - case 0: // Disabled - return; - case 1: // Follow global overview mode - Main.overview.resetOverviewMode(); - break; - case 2: // Default overview - opt.OVERVIEW_MODE = 0; - opt.OVERVIEW_MODE2 = false; - opt.WORKSPACE_MODE = 1; - break; - case 3: // App grid - if (Main.overview._shown) - Main.overview.hide(); - else - Main.overview.show(2); - return; - case 4: // Static WS preview - opt.OVERVIEW_MODE = 1; - opt.OVERVIEW_MODE2 = false; - if (!Main.overview._shown) - opt.WORKSPACE_MODE = 0; - break; - case 5: // Static WS - opt.OVERVIEW_MODE = 2; - opt.OVERVIEW_MODE2 = true; - opt.WORKSPACE_MODE = 0; - break; - case 6: // Window Search - opt.OVERVIEW_MODE = 2; - opt.OVERVIEW_MODE2 = true; - if (!Main.overview._shown) - opt.WORKSPACE_MODE = 0; - break; - } - const customOverviewMode = !Main.overview._shown; - Main.overview.toggle(customOverviewMode); - if (opt.OVERLAY_KEY_PRIMARY === 6) - Me.Util.activateSearchProvider(Me.WSP_PREFIX); - } - } -}; diff --git a/extensions/46/vertical-workspaces/lib/overview.js b/extensions/46/vertical-workspaces/lib/overview.js deleted file mode 100644 index 30cc5db..0000000 --- a/extensions/46/vertical-workspaces/lib/overview.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * overview.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Overview from 'resource:///org/gnome/shell/ui/overview.js'; -import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'; - -let Me; -let opt; - -export const OverviewModule = 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(' OverviewModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._overrides.addOverride('Overview', Overview.Overview.prototype, OverviewCommon); - console.debug(' OverviewModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - console.debug(' OverviewModule - Disabled'); - } -}; - -const OverviewCommon = { - show(state = OverviewControls.ControlsState.WINDOW_PICKER, customOverviewMode) { - if (!customOverviewMode) - this.resetOverviewMode(); - - if (state === OverviewControls.ControlsState.HIDDEN) - throw new Error('Invalid state, use hide() to hide'); - - if (this.isDummy) - return; - if (this._shown) - return; - this._shown = true; - - if (!this._syncGrab()) - return; - - Main.layoutManager.showOverview(); - this._animateVisible(state); - }, - - toggle(customOverviewMode) { - if (this.isDummy) - return; - - if (this._visible) - this.hide(); - else - this.show(OverviewControls.ControlsState.WINDOW_PICKER, customOverviewMode); - }, - - resetOverviewMode() { - // reset Overview Mode do default - opt.OVERVIEW_MODE = opt.get('overviewMode'); - opt.OVERVIEW_MODE2 = opt.OVERVIEW_MODE === 2; - opt.WORKSPACE_MODE = opt.OVERVIEW_MODE > 0 ? 0 : 1; - }, - - _showDone() { - this._animationInProgress = false; - this._coverPane.hide(); - - if (this._shownState !== 'SHOWN') - this._changeShownState('SHOWN'); - - // Handle any calls to hide* while we were showing - if (!this._shown) - this._animateNotVisible(); - - // if user activates overview during startup animation, transition needs to be shifted to the state 2 here - const controls = this._overview._controls; - if (controls._searchController._searchActive && controls._stateAdjustment.value === 1) { - if (opt.SEARCH_VIEW_ANIMATION) - controls._onSearchChanged(); - else if (!opt.OVERVIEW_MODE2) - controls._stateAdjustment.value = 2; - } - - this._syncGrab(); - }, - - // Workaround - should probably be fixed elsewhere in the upstream code - // If a new window is opened from the overview - // and is realized before the overview animation is complete, - // the new window will not get focus - after__hideDone() { - if (!opt.FIX_NEW_WINDOW_FOCUS) - return; - - const workspace = global.workspace_manager.get_active_workspace(); - const recentDesktopWin = global.display.get_tab_list(1, workspace)[0]; - let recentNormalWin = null; - const tabList = global.display.get_tab_list(0, workspace); - - for (let i = 0; i < tabList.length; i++) { - if (tabList[i].minimized === false) { - recentNormalWin = tabList[i]; - break; - } - } - - let recentWin = recentNormalWin; - if (recentNormalWin && recentDesktopWin) { - recentWin = recentNormalWin.get_user_time() > recentDesktopWin.get_user_time() - ? recentNormalWin - : recentDesktopWin; - } - - const focusedWin = global.display.focus_window; - - if (recentWin && focusedWin !== recentWin) - recentWin.activate(global.get_current_time()); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/overviewControls.js b/extensions/46/vertical-workspaces/lib/overviewControls.js deleted file mode 100644 index 41db47f..0000000 --- a/extensions/46/vertical-workspaces/lib/overviewControls.js +++ /dev/null @@ -1,1795 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * overviewControls.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @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 GObject from 'gi://GObject'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Overview from 'resource:///org/gnome/shell/ui/overview.js'; -import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'; -import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'; -import * as WorkspacesView from 'resource:///org/gnome/shell/ui/workspacesView.js'; -import * as Background from 'resource:///org/gnome/shell/ui/background.js'; -import * as Util from 'resource:///org/gnome/shell/misc/util.js'; - -let Me; -let opt; -// gettext -let _; - -const ControlsState = OverviewControls.ControlsState; -const FitMode = WorkspacesView.FitMode; - -const ANIMATION_TIME = Overview.ANIMATION_TIME; -const DASH_MAX_SIZE_RATIO = 0.25; - -let _originalSearchControllerSigId; -let _searchControllerSigId; -let _timeouts; - -export const OverviewControlsModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - _ = Me.gettext; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - } - - cleanGlobals() { - Me = null; - opt = null; - _ = null; - } - - update(reset) { - this._removeTimeouts(); - 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(' OverviewControlsModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - _timeouts = {}; - - this._replaceOnSearchChanged(); - - this._overrides.addOverride('ControlsManager', OverviewControls.ControlsManager.prototype, ControlsManagerCommon); - - if (opt.ORIENTATION === Clutter.Orientation.VERTICAL) - this._overrides.addOverride('ControlsManagerLayout', Main.overview._overview.controls.layoutManager, ControlsManagerLayoutVertical); - else - this._overrides.addOverride('ControlsManagerLayout', Main.overview._overview.controls.layoutManager, ControlsManagerLayoutHorizontal); - - this._overrides.addOverride('LayoutManager', Layout.LayoutManager.prototype, LayoutManager); - - console.debug(' OverviewControlsModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - const reset = true; - this._replaceOnSearchChanged(reset); - Main.overview._overview._controls._appDisplay.opacity = 255; - - console.debug(' OverviewControlsModule - Disabled'); - } - - _removeTimeouts() { - if (_timeouts) { - Object.values(_timeouts).forEach(t => { - if (t) - GLib.source_remove(t); - }); - _timeouts = null; - } - } - - _replaceOnSearchChanged(reset) { - const searchController = Main.overview.searchController; - if (reset) { - if (_searchControllerSigId) { - searchController.disconnect(_searchControllerSigId); - _searchControllerSigId = 0; - } - if (_originalSearchControllerSigId) { - searchController.unblock_signal_handler(_originalSearchControllerSigId); - _originalSearchControllerSigId = 0; - } - Main.overview.searchController._searchResults.translation_x = 0; - Main.overview.searchController._searchResults.translation_y = 0; - Main.overview.searchEntry.visible = true; - Main.overview.searchEntry.opacity = 255; - } else { - // reconnect signal to use custom function (callbacks cannot be overridden in class prototype, they are already in memory as a copy for the given callback) - if (!_originalSearchControllerSigId) - _originalSearchControllerSigId = GObject.signal_handler_find(searchController, { signalId: 'notify', detail: 'search-active' }); - if (_originalSearchControllerSigId) - searchController.block_signal_handler(_originalSearchControllerSigId); - - if (!_searchControllerSigId) - _searchControllerSigId = searchController.connect('notify::search-active', ControlsManagerCommon._onSearchChanged.bind(Main.overview._overview.controls)); - } - } -}; - -const ControlsManagerCommon = { - // this function is used as a callback by a signal handler, needs to be reconnected after modification as the original callback uses a copy of the original function - /* _update: function() { - ... - }*/ - - // this function has duplicate in WorkspaceView so we use one function for both to avoid issues with syncing them - _getFitModeForState(state) { - return _getFitModeForState(state); - }, - - _updateThumbnailsBox() { - const { currentState } = this._stateAdjustment.getStateTransitionParams(); - const { shouldShow } = this._thumbnailsBox; - const thumbnailsBoxVisible = shouldShow && - ((currentState < ControlsState.APP_GRID && opt.SHOW_WS_TMB) || - (currentState > ControlsState.WINDOW_PICKER && opt.SHOW_WS_TMB_APPGRID) || - (currentState > ControlsState.WINDOW_PICKER && this._searchController.searchActive && opt.SHOW_WS_TMB) - ); - this._thumbnailsBox.visible = thumbnailsBoxVisible; - - // this call should be directly in _update(), but it's used as a callback function and it would require to reconnect the signal - this._updateOverview(); - }, - - // this function is pure addition to the original code and handles wsDisp transition to APP_GRID view - _updateOverview() { - this._workspacesDisplay.translation_x = 0; - this._workspacesDisplay.translation_y = 0; - this._workspacesDisplay.scale_x = 1; - this._workspacesDisplay.scale_y = 1; - const { initialState, finalState, progress, currentState } = this._stateAdjustment.getStateTransitionParams(); - - const paramsForState = s => { - let opacity; - switch (s) { - case ControlsState.HIDDEN: - case ControlsState.WINDOW_PICKER: - opacity = 255; - break; - case ControlsState.APP_GRID: - opacity = 0; - break; - default: - opacity = 255; - break; - } - return { opacity }; - }; - - let initialParams = paramsForState(initialState); - let finalParams = paramsForState(finalState); - - let opacity = Math.round(Util.lerp(initialParams.opacity, finalParams.opacity, progress)); - - let workspacesDisplayVisible = opacity !== 0; - - // improve transition from search results to desktop - if (finalState === 0 && this._searchController._searchResults.visible) - this._searchController.hide(); - - // reset Static Workspace window picker mode - if (currentState === 0 && opt.OVERVIEW_MODE && opt.WORKSPACE_MODE) - opt.WORKSPACE_MODE = 0; - - if (!opt.WS_ANIMATION || !opt.SHOW_WS_TMB) { - this._workspacesDisplay.opacity = opacity; - } else if (!opt.SHOW_WS_TMB_BG) { - // fade out ws wallpaper during transition to ws switcher if ws switcher background disabled - const ws = this._workspacesDisplay._workspacesViews[global.display.get_primary_monitor()]?._workspaces[this._workspaceAdjustment.value]; - if (ws) - ws._background.opacity = opacity; - } - - // if ws preview background is disabled, animate tmb box and dash - const tmbBox = this._thumbnailsBox; - const dash = this.dash; - const searchEntryBin = this._searchEntryBin; - // this dash transition collides with startup animation and freezes GS for good, needs to be delayed (first Main.overview 'hiding' event enables it) - const skipDash = Me.Util.dashNotDefault(); - - // OVERVIEW_MODE 2 should animate dash and wsTmbBox only if WORKSPACE_MODE === 0 (windows not spread) - const animateOverviewMode2 = opt.OVERVIEW_MODE2 && !(finalState === 1 && opt.WORKSPACE_MODE); - if (!Main.layoutManager._startingUp && ((!opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2) || animateOverviewMode2)) { - if (!tmbBox._translationOriginal || Math.abs(tmbBox._translationOriginal[0]) > 500) { // swipe gesture can call this calculation before tmbBox is finalized, giving nonsense width - const [dashTranslationX, dashTranslationY, tmbTranslationX, tmbTranslationY, searchTranslationY] = this._getOverviewTranslations(dash, tmbBox, searchEntryBin); - tmbBox._translationOriginal = [tmbTranslationX, tmbTranslationY]; - dash._translationOriginal = [dashTranslationX, dashTranslationY]; - searchEntryBin._translationOriginal = searchTranslationY; - } - if (finalState === 0 || initialState === 0) { - const prg = Math.abs((finalState === 0 ? 0 : 1) - progress); - tmbBox.translation_x = Math.round(prg * tmbBox._translationOriginal[0]); - tmbBox.translation_y = Math.round(prg * tmbBox._translationOriginal[1]); - if (!skipDash) { - dash.translation_x = Math.round(prg * dash._translationOriginal[0]); - dash.translation_y = Math.round(prg * dash._translationOriginal[1]); - } - searchEntryBin.translation_y = Math.round(prg * searchEntryBin._translationOriginal); - } - if (progress === 1) { - tmbBox._translationOriginal = 0; - if (!skipDash) - dash._translationOriginal = 0; - - searchEntryBin._translationOriginal = 0; - } - } else if (!Main.layoutManager._startingUp && (tmbBox.translation_x || tmbBox.translation_y)) { - tmbBox.translation_x = 0; - tmbBox.translation_y = 0; - if (!skipDash) { - dash.translation_x = 0; - dash.translation_y = 0; - } - searchEntryBin.translation_y = 0; - } - - if (!Main.layoutManager._startingUp) { - if (initialState === ControlsState.HIDDEN && finalState === ControlsState.APP_GRID) - this._appDisplay.opacity = Math.round(progress * 255); - else - this._appDisplay.opacity = 255 - opacity; - } - - if (currentState === ControlsState.APP_GRID) { - // in app grid hide workspaces so they're not blocking app grid or ws thumbnails - this._workspacesDisplay.scale_x = 0; - } else { - this._workspacesDisplay.scale_x = 1; - } - this._workspacesDisplay.setPrimaryWorkspaceVisible(workspacesDisplayVisible); - - if (!this.dash._isAbove && progress > 0 && opt.OVERVIEW_MODE2) { - // set searchEntry above appDisplay - this.set_child_above_sibling(this._searchEntryBin, null); - // move dash above wsTmb for case that dash and wsTmb animate from the same side - if (!Me.Util.dashNotDefault()) - this.set_child_above_sibling(dash, null); - this.set_child_below_sibling(this._thumbnailsBox, null); - this.set_child_below_sibling(this._workspacesDisplay, null); - this.set_child_below_sibling(this._appDisplay, null); - } else if (!this.dash._isAbove && progress === 1 && finalState > ControlsState.HIDDEN) { - // set dash above workspace in the overview - this.set_child_above_sibling(this._thumbnailsBox, null); - this.set_child_above_sibling(this._searchEntryBin, null); - if (!Me.Util.dashNotDefault()) - this.set_child_above_sibling(this.dash, null); - - this.dash._isAbove = true; - } else if (this.dash._isAbove && progress < 1) { - // keep dash below for ws transition between the overview and hidden state - this.set_child_above_sibling(this._workspacesDisplay, null); - this.dash._isAbove = false; - } - }, - - // fix for upstream bug - appGrid.visible after transition from APP_GRID to HIDDEN - _updateAppDisplayVisibility(stateTransitionParams = null) { - if (!stateTransitionParams) - stateTransitionParams = this._stateAdjustment.getStateTransitionParams(); - - const { currentState } = stateTransitionParams; - if (this.dash.showAppsButton.checked) - this._searchTransition = false; - - // if !APP_GRID_ANIMATION, appGrid needs to be hidden in WINDOW_PICKER mode (1) - // but needs to be visible for transition from HIDDEN (0) to APP_GRID (2) - this._appDisplay.visible = - currentState > ControlsState.HIDDEN && - !this._searchController.searchActive && - !(currentState === ControlsState.WINDOW_PICKER && !opt.APP_GRID_ANIMATION) && - !this._searchTransition; - }, - - _onSearchChanged() { - // something is somewhere setting the opacity to 0 if V-Shell is rebased while in overview / search - this._searchController.opacity = 255; - - const { finalState, currentState } = this._stateAdjustment.getStateTransitionParams(); - - const { searchActive } = this._searchController; - const SIDE_CONTROLS_ANIMATION_TIME = 250; // OverviewControls.SIDE_CONTROLS_ANIMATION_TIME = Overview.ANIMATION_TIME = 250 - - const entry = this._searchEntry; - if (opt.SHOW_SEARCH_ENTRY) { - entry.visible = true; - entry.opacity = 255; - } else if (!(searchActive && entry.visible)) { - entry.visible = true; - entry.opacity = searchActive ? 0 : 255; - // show search entry only if the user starts typing, and hide it when leaving the search mode - entry.ease({ - opacity: searchActive ? 255 : 0, - duration: SIDE_CONTROLS_ANIMATION_TIME / 2, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - entry.visible = searchActive; - }, - }); - } - - // if user start typing or activated search provider during overview animation, this switcher will be called again after animation ends - if (opt.SEARCH_VIEW_ANIMATION && Main.overview._animationInProgress && finalState !== ControlsState.HIDDEN) - return; - - if (!searchActive) { - this._workspacesDisplay.reactive = true; - this._workspacesDisplay.setPrimaryWorkspaceVisible(true); - } else { - if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) - this._searchController._searchResults._statusText.add_style_class_name('search-statustext-om2'); - else - this._searchController._searchResults._statusText.remove_style_class_name('search-statustext-om2'); - this._searchController.show(); - entry.visible = true; - entry.opacity = 255; - } - - if (opt.SHOW_BG_IN_OVERVIEW && this._bgManagers) - this._updateBackground(this._bgManagers[0]); - this._searchTransition = true; - - this._searchController._searchResults.translation_x = 0; - this._searchController._searchResults.translation_y = 0; - this._searchController.visible = true; - - if (opt.SEARCH_VIEW_ANIMATION && ![4, 8].includes(opt.WS_TMB_POSITION)) { - this._updateAppDisplayVisibility(); - this._searchController._searchResults._statusBin.opacity = 1; - - let translationX = 0; - let translationY = 0; - const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor()); - - switch (opt.SEARCH_VIEW_ANIMATION) { - case 1: - // make it longer to cover the delay before results appears - translationX = geometry.width; - translationY = 0; - break; - case 2: - translationX = -geometry.width; - translationY = 0; - break; - case 3: - translationX = 0; - translationY = geometry.height; - break; - case 5: - translationX = 0; - translationY = -geometry.height; - break; - } - - if (searchActive) { - this._searchController._searchResults.translation_x = translationX; - this._searchController._searchResults.translation_y = translationY; - } else { - this._searchController._searchResults.translation_x = 0; - this._searchController._searchResults.translation_y = 0; - } - - this._searchController._searchResults.ease({ - delay: 150, // wait for results - opacity: searchActive ? 255 : 0, - translation_x: searchActive ? 0 : translationX, - translation_y: searchActive ? 0 : translationY, - duration: SIDE_CONTROLS_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._searchController.visible = searchActive; - this._searchTransition = false; - this._searchController._searchResults._statusBin.opacity = 255; - }, - }); - - this._workspacesDisplay.opacity = 255; - } else { - this._appDisplay.ease({ - opacity: searchActive || currentState < 2 ? 0 : 255, - duration: SIDE_CONTROLS_ANIMATION_TIME / 2, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._updateAppDisplayVisibility(); - }, - }); - - this._workspacesDisplay.setPrimaryWorkspaceVisible(true); - - this._searchController._searchResults.ease({ - opacity: searchActive ? 255 : 0, - duration: searchActive ? SIDE_CONTROLS_ANIMATION_TIME / 2 : 0, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => (this._searchController.visible = searchActive), - }); - } - - // reuse already tuned overview transition, just replace APP_GRID with the search view - if (!(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) && !Main.overview._animationInProgress && finalState !== ControlsState.HIDDEN && !this.dash.showAppsButton.checked) { - this._searchController._searchResults._content.remove_style_class_name('search-section-content-bg-om2'); - this._searchController._searchResults._content.add_style_class_name('search-section-content-bg'); - this._searchEntry.remove_style_class_name('search-entry-om2'); - const duration = opt.SEARCH_VIEW_ANIMATION ? 140 : 0; - this._stateAdjustment.ease(searchActive ? ControlsState.APP_GRID : ControlsState.WINDOW_PICKER, { - // shorter animation time when entering search view can avoid stuttering in transition - // collecting search results take some time and the problematic part is the realization of the object on the screen - // if the ws animation ends before this event, the whole transition is smoother - // removing the ws transition (duration: 0) seems like the best solution here - duration: searchActive ? duration : SIDE_CONTROLS_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._workspacesDisplay.setPrimaryWorkspaceVisible(!searchActive); - // Set the delay before processing a new search entry to 150 on deactivation, so search providers can't make make the workspace animation stuttering - // set it back to 0 after in-animation, so the search can be snappy - opt.SEARCH_DELAY = searchActive || !opt.SEARCH_VIEW_ANIMATION ? 0 : 150; - }, - }); - } else if (opt.OVERVIEW_MODE2 && !(opt.WORKSPACE_MODE || this.dash.showAppsButton.checked)) { - // add background to search results and make searchEntry border thicker for better visibility - this._searchController._searchResults._content.remove_style_class_name('search-section-content-bg'); - this._searchController._searchResults._content.add_style_class_name('search-section-content-bg-om2'); - Main.overview.searchEntry.add_style_class_name('search-entry-om2'); - } else { - this._searchController._searchResults._content.add_style_class_name('search-section-content-bg'); - this._searchController._searchResults._content.remove_style_class_name('search-section-content-bg-om2'); - this._searchEntry.remove_style_class_name('search-entry-om2'); - } - }, - - async runStartupAnimation(callback) { - this._ignoreShowAppsButtonToggle = true; - - this.prepareToEnterOverview(); - - this._stateAdjustment.value = ControlsState.HIDDEN; - this._stateAdjustment.ease(ControlsState.WINDOW_PICKER, { - duration: ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - this.dash.showAppsButton.checked = false; - this._ignoreShowAppsButtonToggle = false; - - // Set the opacity here to avoid a 1-frame flicker - this.opacity = 1; - this._appDisplay.opacity = 1; - - // We can't run the animation before the first allocation happens - await this.layout_manager.ensureAllocation(); - - this._setBackground(); - Main.panel.opacity = 255; - - const STARTUP_ANIMATION_TIME = 500; - // Opacity - this.ease({ - opacity: opt.STARTUP_STATE === 1 ? 0 : 255, - duration: STARTUP_ANIMATION_TIME, - mode: Clutter.AnimationMode.LINEAR, - onComplete: () => { - // part of the workaround for stuttering first app grid animation - this._appDisplay.visible = true; - }, - }); - - const dash = this.dash; - const tmbBox = this._thumbnailsBox; - - // Set the opacity here to avoid a 1-frame flicker - dash.opacity = 0; - for (const view of this._workspacesDisplay._workspacesViews) { - if (view._monitorIndex !== global.display.get_primary_monitor()) - view._thumbnails.opacity = 0; - } - - const searchEntryBin = this._searchEntryBin; - const [dashTranslationX, dashTranslationY, tmbTranslationX, tmbTranslationY, searchTranslationY] = - this._getOverviewTranslations(dash, tmbBox, searchEntryBin); - - const onComplete = function () { - // running init callback again causes issues (multiple connections) - if (!Main.overview._startupInitComplete) - callback(); - - const appDisplayModule = Me.Modules.appDisplayModule; - if (!appDisplayModule.moduleEnabled) - this._finishStartupSequence(); - else - this._realizeAppDisplayAndFinishSequence(); - - Main.overview._startupInitComplete = true; - }.bind(this); - - if (dash.visible && !Me.Util.dashNotDefault()) { - dash.translation_x = dashTranslationX; - dash.translation_y = dashTranslationY; - dash.opacity = 255; - dash.ease({ - translation_x: 0, - translation_y: 0, - delay: STARTUP_ANIMATION_TIME / 2, - duration: STARTUP_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete, - }); - } else { - // set dash opacity to make it visible if user enable it later - dash.opacity = 255; - // if dash is hidden, substitute the ease timeout with GLib.timeout - _timeouts.startupAnim2 = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - // delay + animation time - STARTUP_ANIMATION_TIME * 2 * St.Settings.get().slow_down_factor, - () => { - onComplete(); - Main.overview._startupInitComplete = true; - _timeouts.startupAnim2 = 0; - return GLib.SOURCE_REMOVE; - } - ); - } - - if (searchEntryBin.visible) { - searchEntryBin.translation_y = searchTranslationY; - searchEntryBin.ease({ - translation_y: 0, - delay: STARTUP_ANIMATION_TIME / 2, - duration: STARTUP_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - if (tmbBox.visible) { - tmbBox.translation_x = tmbTranslationX; - tmbBox.translation_y = tmbTranslationY; - tmbBox.ease({ - translation_x: 0, - translation_y: 0, - delay: STARTUP_ANIMATION_TIME / 2, - duration: STARTUP_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - // upstream bug - following animation will be cancelled, don't know where - // needs further investigation - const workspacesViews = this._workspacesDisplay._workspacesViews; - if (workspacesViews.length > 1) { - for (const view of workspacesViews) { - if (view._monitorIndex !== global.display.get_primary_monitor() && view._thumbnails.visible) { - const secTmbBox = view._thumbnails; - - if (opt.SEC_WS_TMB_LEFT) - secTmbBox.translation_x = -(secTmbBox.width + 12); // compensate for padding - else if (opt.SEC_WS_TMB_RIGHT) - secTmbBox.translation_x = secTmbBox.width + 12; - else if (opt.SEC_WS_TMB_TOP) - secTmbBox.translation_y = -(secTmbBox.height + 12); - else if (opt.SEC_WS_TMB_BOTTOM) - secTmbBox.translation_y = secTmbBox.height + 12; - - secTmbBox.opacity = 255; - - secTmbBox.ease({ - translation_y: 0, - delay: STARTUP_ANIMATION_TIME / 2, - duration: STARTUP_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - } - } - }, - - _realizeAppDisplayAndFinishSequence() { - const appDisplayModule = Me.Modules.appDisplayModule; - // realize app grid for smoother first animation - appDisplayModule._updateAppGrid(false, this._finishStartupSequence.bind(this)); - }, - - _finishStartupSequence() { - if (!this._bgManagers) - this._setBackground(); - - /* if (Me.Util.dashIsDashToDock()) - return;*/ - - _timeouts.finishStartup = GLib.idle_add( - GLib.PRIORITY_LOW, () => { - this._appDisplay.opacity = 255; - if (opt.STARTUP_STATE === 1) { - Main.overview.hide(); - } else if (opt.STARTUP_STATE === 2) { - Main.overview.show(2); // just because of DtD, because we skipped startup animation - this.dash.showAppsButton.checked = true; - } else if (!opt.STARTUP_STATE && Me.Util.dashNotDefault()) { - Main.overview.show(); - } - - _timeouts.finishStartup = 0; - return GLib.SOURCE_REMOVE; - } - ); - }, - - setInitialTranslations() { - const dash = this.dash; - const tmbBox = this._thumbnailsBox; - const searchEntryBin = this._searchEntryBin; - const [dashTranslationX, dashTranslationY, tmbTranslationX, tmbTranslationY, searchTranslationY] = - this._getOverviewTranslations(dash, tmbBox, searchEntryBin); - if (!Me.Util.dashNotDefault()) { - dash.translation_x = dashTranslationX; - dash.translation_y = dashTranslationY; - } - tmbBox.translation_x = tmbTranslationX; - tmbBox.translation_y = tmbTranslationY; - searchEntryBin.translation_y = searchTranslationY; - }, - - _getOverviewTranslations(dash, tmbBox, searchEntryBin) { - // const tmbBox = Main.overview._overview._controls._thumbnailsBox; - const animationsDisabled = !St.Settings.get().enable_animations || ((opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2) && !Main.layoutManager._startingUp); - if (animationsDisabled) - return [0, 0, 0, 0, 0]; - - let searchTranslationY = 0; - if (searchEntryBin.visible) { - const offset = (dash.visible && (!opt.DASH_VERTICAL ? dash.height + 12 : 0)) + - (opt.WS_TMB_TOP ? tmbBox.height + 12 : 0); - searchTranslationY = -searchEntryBin.height - offset - 30; - } - - let tmbTranslationX = 0; - let tmbTranslationY = 0; - let offset; - if (tmbBox.visible) { - const tmbWidth = tmbBox.width === Infinity ? 0 : tmbBox.width; - const tmbHeight = tmbBox.height === Infinity ? 0 : tmbBox.height; - switch (opt.WS_TMB_POSITION) { - case 3: // left - offset = 10 + (dash?.visible && opt.DASH_LEFT ? dash.width : 0); - tmbTranslationX = -tmbWidth - offset; - tmbTranslationY = 0; - break; - case 1: // right - offset = 10 + (dash?.visible && opt.DASH_RIGHT ? dash.width : 0); - tmbTranslationX = tmbWidth + offset; - tmbTranslationY = 0; - break; - case 0: // top - offset = 10 + (dash?.visible && opt.DASH_TOP ? dash.height : 0) + Main.panel.height; - tmbTranslationX = 0; - tmbTranslationY = -tmbHeight - offset; - break; - case 2: // bottom - offset = 10 + (dash?.visible && opt.DASH_BOTTOM ? dash.height : 0) + Main.panel.height; // just for case the panel is at bottom - tmbTranslationX = 0; - tmbTranslationY = tmbHeight + offset; - break; - } - } - - let dashTranslationX = 0; - let dashTranslationY = 0; - let position = opt.DASH_POSITION; - // if DtD replaced the original Dash, read its position - if (Me.Util.dashIsDashToDock()) - position = dash._position; - - if (dash?.visible) { - const dashWidth = dash.width === Infinity ? 0 : dash.width; - const dashHeight = dash.height === Infinity ? 0 : dash.height; - switch (position) { - case 0: // top - dashTranslationX = 0; - dashTranslationY = -dashHeight - dash.margin_bottom - Main.panel.height; - break; - case 1: // right - dashTranslationX = dashWidth; - dashTranslationY = 0; - break; - case 2: // bottom - dashTranslationX = 0; - dashTranslationY = dashHeight + dash.margin_bottom + Main.panel.height; - break; - case 3: // left - dashTranslationX = -dashWidth; - dashTranslationY = 0; - break; - } - } - - return [dashTranslationX, dashTranslationY, tmbTranslationX, tmbTranslationY, searchTranslationY]; - }, - - animateToOverview(state, callback) { - this._ignoreShowAppsButtonToggle = true; - this._searchTransition = false; - - this._stateAdjustment.value = ControlsState.HIDDEN; - - // building window thumbnails takes some time and with many windows on the workspace - // the time can be close to or longer than ANIMATION_TIME - // in which case the the animation is greatly delayed, stuttering, or even skipped - // for user it is more acceptable to watch delayed smooth animation, - // even if it takes little more time, than jumping frames - let delay = 0; - if (opt.DELAY_OVERVIEW_ANIMATION) - delay = global.display.get_tab_list(0, global.workspace_manager.get_active_workspace()).length * 3; - - this._stateAdjustment.ease(state, { - delay, - duration: 250, // Overview.ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onStopped: () => { - if (callback) - callback(); - }, - }); - - this.dash.showAppsButton.checked = - state === ControlsState.APP_GRID; - - this._ignoreShowAppsButtonToggle = false; - }, - - _setBackground(reset = false) { - if (this._bgManagers) { - this._bgManagers.forEach(bg => { - Main.overview._overview._controls._stateAdjustment.disconnect(bg._fadeSignal); - bg.destroy(); - }); - } - - // if (!SHOW_BG_IN_OVERVIEW && !SHOW_WS_PREVIEW_BG) the background is used for static transition from wallpaper to empty bg in the overview - if (reset || (!opt.SHOW_BG_IN_OVERVIEW && opt.SHOW_WS_PREVIEW_BG)) { - delete this._bgManagers; - return; - } - - this._bgManagers = []; - for (const monitor of Main.layoutManager.monitors) { - const bgManager = new Background.BackgroundManager({ - monitorIndex: monitor.index, - container: Main.layoutManager.overviewGroup, - vignette: true, - }); - - bgManager.backgroundActor.content.vignette_sharpness = 0; - bgManager.backgroundActor.content.brightness = 1; - - - bgManager._fadeSignal = Main.overview._overview._controls._stateAdjustment.connect('notify::value', v => { - this._updateBackground(bgManager, v.value, v); - }); - - if (monitor.index === global.display.get_primary_monitor()) { - bgManager._primary = true; - this._bgManagers.unshift(bgManager); // primary monitor first - } else { - bgManager._primary = false; - this._bgManagers.push(bgManager); - } - } - }, - - _updateBackground(bgManager, stateValue = 2, stateAdjustment = null) { - // Blur My Shell extension destroys all background actors in the overview and doesn't care about consequences - if (this._bgManagers[0] && !Main.layoutManager.overviewGroup.get_children().includes(this._bgManagers[0].backgroundActor)) { - Main.notifyError(`[${Me.metadata.name}]`, _('Overview background crashed!\nIf you are using Blur My Shell, disable overview blur in its settings and re-enable V-Shell Overview Background to avoid visual glitches.')); - // remove and disconnect our destroyed backgrounds to avoid more errors - this._setBackground(true); - return; - } - - const finalState = stateAdjustment?.getStateTransitionParams().finalState; - if (!opt.SHOW_BG_IN_OVERVIEW && !opt.SHOW_WS_PREVIEW_BG) { - // if no bg shown in the overview, fade out the wallpaper - if (!(opt.OVERVIEW_MODE2 && opt.WORKSPACE_MODE && finalState === 1)) - bgManager.backgroundActor.opacity = Util.lerp(255, 0, Math.min(stateValue, 1)); - } else { - let VIGNETTE, BRIGHTNESS, bgValue; - if (opt.OVERVIEW_MODE2 && stateValue <= 1 && !opt.WORKSPACE_MODE) { - VIGNETTE = 0; - BRIGHTNESS = 1; - bgValue = stateValue; - } else { - VIGNETTE = 0.2; - BRIGHTNESS = opt.OVERVIEW_BG_BRIGHTNESS; - if (opt.OVERVIEW_MODE2 && stateValue > 1 && !opt.WORKSPACE_MODE) - bgValue = stateValue - 1; - else - bgValue = stateValue; - } - - let blurEffect = bgManager.backgroundActor.get_effect('blur'); - if (!blurEffect) { - blurEffect = new Shell.BlurEffect({ - brightness: 1, - mode: Shell.BlurMode.ACTOR, - }); - bgManager.backgroundActor.add_effect_with_name('blur', blurEffect); - } - - // In GNOME 46 the "sigma" property has been renamed to "radius" - const radius = blurEffect.sigma !== undefined ? 'sigma' : 'radius'; - blurEffect[radius] = 0; - - const searchActive = this._searchController.searchActive; - if (searchActive) - BRIGHTNESS = opt.SEARCH_BG_BRIGHTNESS; - - bgManager.backgroundActor.content.vignette_sharpness = VIGNETTE; - bgManager.backgroundActor.content.brightness = BRIGHTNESS; - - let vignetteInit, brightnessInit;// , sigmaInit; - if (opt.SHOW_BG_IN_OVERVIEW && opt.SHOW_WS_PREVIEW_BG) { - vignetteInit = VIGNETTE; - brightnessInit = BRIGHTNESS; - // sigmaInit = opt.OVERVIEW_BG_BLUR_SIGMA; - } else { - vignetteInit = 0; - brightnessInit = 1; - // sigmaInit = 0; - } - - if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) { - bgManager.backgroundActor.content.vignette_sharpness = Util.lerp(vignetteInit, VIGNETTE, bgValue); - bgManager.backgroundActor.content.brightness = Util.lerp(brightnessInit, BRIGHTNESS, bgValue); - } else { - bgManager.backgroundActor.content.vignette_sharpness = Util.lerp(vignetteInit, VIGNETTE, Math.min(stateValue, 1)); - bgManager.backgroundActor.content.brightness = Util.lerp(brightnessInit, BRIGHTNESS, Math.min(stateValue, 1)); - } - - if (opt.OVERVIEW_BG_BLUR_SIGMA || opt.APP_GRID_BG_BLUR_SIGMA) { - // reduce number of steps of blur transition to improve performance - const step = opt.SMOOTH_BLUR_TRANSITIONS ? 0.05 : 0.2; - const progress = stateValue - (stateValue % step); - if (opt.SHOW_WS_PREVIEW_BG && stateValue < 1 && !searchActive) { // no need to animate transition, unless appGrid state is involved, static bg is covered by the ws preview bg - if (blurEffect[radius] !== opt.OVERVIEW_BG_BLUR_SIGMA) - blurEffect[radius] = opt.OVERVIEW_BG_BLUR_SIGMA; - } else if (stateValue < 1 && !searchActive && !(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)) { - const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress)); - if (sigma !== blurEffect[radius]) - blurEffect[radius] = sigma; - } else if (stateValue < 1 && !searchActive && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && blurEffect[radius])) { - const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress)); - if (sigma !== blurEffect[radius]) - blurEffect[radius] = sigma; - } else if (stateValue > 1 && !searchActive && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && finalState === 1)) { - const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress % 1)); - if (sigma !== blurEffect[radius]) - blurEffect[radius] = sigma; - } else if ((stateValue > 1 && bgManager._primary) || searchActive) { - const sigma = Math.round(Util.lerp(opt.OVERVIEW_BG_BLUR_SIGMA, opt.APP_GRID_BG_BLUR_SIGMA, progress % 1)); - if (sigma !== blurEffect[radius]) - blurEffect[radius] = sigma; - } else if (stateValue === 1 && !(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)) { - blurEffect[radius] = opt.OVERVIEW_BG_BLUR_SIGMA; - } else if (stateValue === 0 || (stateValue === 1 && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE))) { - blurEffect[radius] = 0; - } - } - } - }, - - _updatePositionFromDashToDock() { - // update variables that cannot be processed within settings - const dash = Main.overview.dash; - opt.DASH_POSITION = dash._position; - opt.DASH_TOP = opt.DASH_POSITION === 0; - opt.DASH_RIGHT = opt.DASH_POSITION === 1; - opt.DASH_BOTTOM = opt.DASH_POSITION === 2; - opt.DASH_LEFT = opt.DASH_POSITION === 3; - opt.DASH_VERTICAL = opt.DASH_LEFT || opt.DASH_RIGHT; - }, -}; - -const ControlsManagerLayoutVertical = { - _computeWorkspacesBoxForState(state, box, workAreaBox, dashWidth, dashHeight, thumbnailsWidth, thumbnailsHeight, searchHeight, startY) { - // in case the function is called from the DtD - if (startY === undefined) - workAreaBox = box; - - const workspaceBox = box.copy(); - let [width, height] = workspaceBox.get_size(); - const spacing = 12; - - const dash = Main.overview.dash; - // including Dash to Dock and clones properties for compatibility - - if (Me.Util.dashIsDashToDock()) { - // ensure or position variables are updated - ControlsManagerCommon._updatePositionFromDashToDock(); - // Dash to Dock also always affects workAreaBox - Main.layoutManager._trackedActors.forEach(actor => { - if (actor.affectsStruts && actor.actor.width === dash.width) { - if (dash._isHorizontal) { - // disabled inteli-hide don't needs compensation - // startY needs to be corrected in allocate() - if (dash.get_parent()?.get_parent()?.get_parent()?._intellihideIsEnabled) - height += dash.height; - } else { - width += dash.width; - } - } - }); - } - - let wWidth; - let wHeight; - let wsBoxY; - - switch (state) { - case ControlsState.HIDDEN: - // if PANEL_OVERVIEW_ONLY, the affectStruts property is set to false to avoid stuttering - // therefore we added panel height to startY for the overview allocation, - // but here we need to remove the correction because the panel will be in the hidden state - if (opt.START_Y_OFFSET) { - let [x, y] = workAreaBox.get_origin(); - y -= opt.START_Y_OFFSET; - workspaceBox.set_origin(x, y); - } else { - workspaceBox.set_origin(...workAreaBox.get_origin()); - } - workspaceBox.set_size(...workAreaBox.get_size()); - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - if (opt.WS_ANIMATION && opt.SHOW_WS_TMB && state === ControlsState.APP_GRID) { - workspaceBox.set_origin(...this._workspacesThumbnails.get_position()); - workspaceBox.set_size(thumbnailsWidth, thumbnailsHeight); - } else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) { - if (opt.START_Y_OFFSET) { - let [x, y] = workAreaBox.get_origin(); - y -= opt.START_Y_OFFSET; - workspaceBox.set_origin(x, y); - } else { - workspaceBox.set_origin(...workAreaBox.get_origin()); - } - workspaceBox.set_size(...workAreaBox.get_size()); - } else { - // if PANEL_OVERVIEW_ONLY, panel doesn't affect workArea height (affectStruts === false), it is necessary to compensate - height = opt.PANEL_POSITION_TOP ? height : height - Main.panel.height; - searchHeight = opt.SHOW_SEARCH_ENTRY ? searchHeight : 0; - wWidth = width - - (opt.DASH_VERTICAL ? dashWidth : 0) - - thumbnailsWidth - - 4 * spacing; - wHeight = height - - (opt.DASH_VERTICAL ? 0 : dashHeight) - - searchHeight - - 4 * spacing; - - const ratio = width / height; - let wRatio = wWidth / wHeight; - let scale = ratio / wRatio; - - if (scale > 1) { - wHeight /= scale; - wWidth = wHeight * ratio; - } else { - wWidth *= scale; - wHeight = wWidth / ratio; - } - - // height decides the actual size, ratio is given by the workarea - wHeight *= opt.WS_PREVIEW_SCALE; - wWidth *= opt.WS_PREVIEW_SCALE; - - let xOffset = 0; - let yOffset = 0; - - const yOffsetT = (opt.DASH_TOP ? dashHeight : 0) + searchHeight; - const yOffsetB = opt.DASH_BOTTOM ? dashHeight : 0; - const yAvailableSpace = (height - yOffsetT - wHeight - yOffsetB) / 2; - yOffset = yOffsetT + yAvailableSpace; - - const centeredBoxX = (width - wWidth) / 2; - - const xOffsetL = (opt.DASH_LEFT ? dashWidth : 0) + (opt.WS_TMB_LEFT ? thumbnailsWidth : 0) + 2 * spacing; - const xOffsetR = (opt.DASH_RIGHT ? dashWidth : 0) + (opt.WS_TMB_RIGHT ? thumbnailsWidth : 0) + 2 * spacing; - - this._xAlignCenter = false; - if (centeredBoxX < Math.max(xOffsetL, xOffsetR)) { - xOffset = xOffsetL + spacing + (width - xOffsetL - wWidth - xOffsetR - 2 * spacing) / 2; - } else { - xOffset = centeredBoxX; - this._xAlignCenter = true; - } - - const wsBoxX = /* startX + */xOffset; - wsBoxY = startY + yOffset; - workspaceBox.set_origin(Math.round(wsBoxX), Math.round(wsBoxY)); - workspaceBox.set_size(Math.round(wWidth), Math.round(wHeight)); - } - } - - return workspaceBox; - }, - - _getAppDisplayBoxForState(state, box, workAreaBox, searchHeight, dashWidth, dashHeight, thumbnailsWidth, startY) { - // in case the function is called from the DtD - if (startY === undefined) - workAreaBox = box; - - const [width] = box.get_size(); - const { x1: startX } = workAreaBox; - // const { y1: startY } = workAreaBox; - let height = workAreaBox.get_height(); - const appDisplayBox = new Clutter.ActorBox(); - const spacing = 12; - searchHeight = opt.SHOW_SEARCH_ENTRY ? searchHeight : 0; - - const xOffsetL = (opt.WS_TMB_LEFT ? thumbnailsWidth : 0) + (opt.DASH_LEFT ? dashWidth : 0); - const xOffsetR = (opt.WS_TMB_RIGHT ? thumbnailsWidth : 0) + (opt.DASH_RIGHT ? dashWidth : 0); - const yOffsetT = (opt.DASH_TOP ? dashHeight : 0) + (opt.SHOW_SEARCH_ENTRY ? searchHeight : 0); - const yOffsetB = opt.DASH_BOTTOM ? dashHeight : 0; - const adWidth = opt.CENTER_APP_GRID ? width - 2 * Math.max(xOffsetL, xOffsetR) - 2 * spacing : width - xOffsetL - xOffsetR - 2 * spacing; - const adHeight = height - yOffsetT - yOffsetB; - - const appDisplayX = opt.CENTER_APP_GRID ? (width - adWidth) / 2 : xOffsetL + 2 * spacing; - const appDisplayY = startY + yOffsetT; - - switch (state) { - case ControlsState.HIDDEN: - case ControlsState.WINDOW_PICKER: - // 1 - left, 2 - right, 3 - bottom, 5 - top - switch (opt.APP_GRID_ANIMATION) { - case 0: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(appDisplayY)); - break; - case 1: - appDisplayBox.set_origin(Math.round(startX + width), Math.round(appDisplayY)); - break; - case 2: - appDisplayBox.set_origin(Math.round(startX - adWidth), Math.round(appDisplayY)); - break; - case 3: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(workAreaBox.y2)); - break; - case 5: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(workAreaBox.y1 - adHeight)); - break; - } - break; - case ControlsState.APP_GRID: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(appDisplayY)); - break; - } - - appDisplayBox.set_size(Math.round(adWidth), Math.round(adHeight)); - return appDisplayBox; - }, - - vfunc_allocate(container, box) { - const childBox = new Clutter.ActorBox(); - const transitionParams = this._stateAdjustment.getStateTransitionParams(); - const spacing = 12; - const halfSpacing = spacing / 2; - const monitor = Main.layoutManager.findMonitorForActor(this._container); - const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); - const startX = workArea.x - monitor.x; - // if PANEL_OVERVIEW_ONLY, the affectStruts property is set to false to avoid stuttering - // therefore we need to add panel height to startY - let startY = workArea.y - monitor.y + opt.START_Y_OFFSET; - const workAreaBox = new Clutter.ActorBox(); - workAreaBox.set_origin(startX, startY); - workAreaBox.set_size(workArea.width, workArea.height); - box.y1 += startY; - box.x1 += startX; - let [width, height] = box.get_size(); - // if panel is at bottom position, - // compensate the height of the available box (the box size is calculated for top panel) - height = opt.PANEL_POSITION_TOP ? height : height - Main.panel.height; - let availableHeight = height; - - // Dash - const maxDashHeight = box.get_height() * DASH_MAX_SIZE_RATIO; - const maxDashWidth = maxDashHeight * 0.8; - let dashHeight = 0; - let dashWidth = 0; - - // dash cloud be overridden by the Dash to Dock clone - const dash = Main.overview.dash; - if (Me.Util.dashIsDashToDock()) { - // ensure our position variables are updated - ControlsManagerCommon._updatePositionFromDashToDock(); - // if Dash to Dock replaced the default dash and its inteli-hide is disabled we need to compensate for affected startY - if (!Main.overview.dash.get_parent()?.get_parent()?.get_parent()?._intellihideIsEnabled) { - if (Main.panel.y === monitor.y) - startY = Main.panel.height + spacing; - } - dashHeight = dash.height; - dashWidth = dash.width; - opt.DASH_VERTICAL = [1, 3].includes(dash._position); - this._dash.allocate(childBox); - } else if (this._dash.visible) { - // default dock - if (opt.DASH_VERTICAL) { - this._dash.setMaxSize(maxDashWidth, height); - [, dashWidth] = this._dash.get_preferred_width(height); - [, dashHeight] = this._dash.get_preferred_height(dashWidth); - dashWidth = Math.min(dashWidth, maxDashWidth); - dashHeight = Math.min(dashHeight, height); - } else if (!opt.WS_TMB_FULL) { - this._dash.setMaxSize(width, maxDashHeight); - [, dashHeight] = this._dash.get_preferred_height(width); - [, dashWidth] = this._dash.get_preferred_width(dashHeight); - dashHeight = Math.min(dashHeight, maxDashHeight); - dashWidth = Math.min(dashWidth, width); - } - } - - // Workspace Thumbnails - let wsTmbWidth = 0; - let wsTmbHeight = 0; - - let maxWsTmbScale = opt.MAX_THUMBNAIL_SCALE; - if (opt.SHOW_WS_TMB) { - const dashHeightReservation = !opt.WS_TMB_FULL && !opt.DASH_VERTICAL ? dashHeight : 0; - - const searchActive = this._searchController.searchActive; - if (!opt.MAX_THUMBNAIL_SCALE_STABLE && !searchActive) { - const initState = transitionParams.initialState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE; - const finalState = transitionParams.finalState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE; - maxWsTmbScale = Util.lerp(initState, finalState, transitionParams.progress); - } - - wsTmbWidth = width * maxWsTmbScale; - let totalTmbSpacing; - [totalTmbSpacing, wsTmbHeight] = this._workspacesThumbnails.get_preferred_height(wsTmbWidth); - wsTmbHeight += totalTmbSpacing; - - const wsTmbHeightMax = opt.WS_TMB_FULL - ? height - spacing - : height - dashHeightReservation - 2 * spacing; - - if (wsTmbHeight > wsTmbHeightMax) { - wsTmbHeight = wsTmbHeightMax; - wsTmbWidth = Math.round(this._workspacesThumbnails.get_preferred_width(wsTmbHeight)[1]); - } - - let wsTmbX; - if (opt.WS_TMB_RIGHT) - wsTmbX = Math.round(startX + width - (opt.DASH_RIGHT ? dashWidth : 0) - wsTmbWidth /* - halfSpacing*/); // this halfSpacing is a part od dash style - else - wsTmbX = Math.round(opt.DASH_LEFT ? dashWidth : 0/* + halfSpacing*/); // this halfSpacing is a part od dash style - - let wstOffset = (height - wsTmbHeight - (opt.DASH_VERTICAL ? 0 : dashHeightReservation)) / 2; - wstOffset -= opt.WS_TMB_POSITION_ADJUSTMENT * (wstOffset - halfSpacing); - let wsTmbY = Math.round(startY + (dashHeightReservation && opt.DASH_TOP ? dashHeight : 0) + wstOffset); - - childBox.set_origin(wsTmbX, wsTmbY); - childBox.set_size(Math.max(wsTmbWidth, 1), Math.max(wsTmbHeight, 1)); - - this._workspacesThumbnails.allocate(childBox); - } - - if (this._dash.visible) { - const wMaxWidth = width - spacing - wsTmbWidth - 2 * spacing - (opt.DASH_VERTICAL ? dashWidth + spacing : 0); - if (opt.WS_TMB_FULL && !opt.DASH_VERTICAL) { - this._dash.setMaxSize(wMaxWidth, maxDashHeight); - [, dashHeight] = this._dash.get_preferred_height(wMaxWidth); - [, dashWidth] = this._dash.get_preferred_width(dashHeight); - dashHeight = Math.min(dashHeight, maxDashHeight); - dashWidth = Math.min(dashWidth, wMaxWidth); - } - - let dashX, dashY, offset; - if (opt.DASH_RIGHT) - dashX = width - dashWidth; - else if (opt.DASH_LEFT) - dashX = 0; - - else if (opt.DASH_TOP) - dashY = startY; - else - dashY = startY + height - dashHeight; - - if (!opt.DASH_VERTICAL) { - offset = (width - ((opt.WS_TMB_FULL || opt.CENTER_DASH_WS) && !this._xAlignCenter ? wsTmbWidth : 0) - dashWidth) / 2; - offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - halfSpacing); - dashX = offset; - - if ((opt.WS_TMB_FULL || opt.CENTER_DASH_WS) && !this._xAlignCenter) { - if (!opt.WS_TMB_RIGHT) { - dashX = (wsTmbWidth ? wsTmbWidth : 0) + offset; - dashX = Math.max(dashX, wsTmbWidth ? wsTmbWidth + spacing : 0); - dashX = Math.min(dashX, width - dashWidth - spacing); - } - } - if (opt.WS_TMB_FULL && !opt.CENTER_DASH_WS) { - dashX = opt.WS_TMB_RIGHT - ? Math.min(width - wsTmbWidth - dashWidth, dashX + wsTmbWidth / 2 * (1 - Math.abs(opt.DASH_POSITION_ADJUSTMENT))) - : Math.max(wsTmbWidth, dashX - wsTmbWidth / 2 * (1 - Math.abs(opt.DASH_POSITION_ADJUSTMENT))); - } - } else { - offset = (height - dashHeight) / 2; - dashY = startY + (offset - opt.DASH_POSITION_ADJUSTMENT * (offset - halfSpacing)); - } - - childBox.set_origin(Math.round(startX + dashX), Math.round(dashY)); - childBox.set_size(Math.round(dashWidth), Math.round(dashHeight)); - this._dash.allocate(childBox); - } - - availableHeight -= opt.DASH_VERTICAL ? 0 : dashHeight + spacing; - - let [searchHeight] = this._searchEntry.get_preferred_height(width - wsTmbWidth); - - // Workspaces - let params = [box, workAreaBox, dashWidth, dashHeight, wsTmbWidth, wsTmbHeight, searchHeight, startY]; - - // Update cached boxes - for (const state of Object.values(ControlsState)) { - this._cachedWorkspaceBoxes.set( - state, this._computeWorkspacesBoxForState(state, ...params)); - } - - let workspacesBox; - if (!transitionParams.transitioning) - workspacesBox = this._cachedWorkspaceBoxes.get(transitionParams.currentState); - - if (!workspacesBox) { - const initialBox = this._cachedWorkspaceBoxes.get(transitionParams.initialState); - const finalBox = this._cachedWorkspaceBoxes.get(transitionParams.finalState); - workspacesBox = initialBox.interpolate(finalBox, transitionParams.progress); - } - - this._workspacesDisplay.allocate(workspacesBox); - - // Search entry - const searchXoffset = (opt.DASH_LEFT ? dashWidth : 0) + spacing + (opt.WS_TMB_RIGHT ? 0 : wsTmbWidth + spacing); - - // Y position under top Dash - let searchEntryX, searchEntryY; - if (opt.DASH_TOP) - searchEntryY = startY + dashHeight; - else - searchEntryY = startY; - - searchEntryX = searchXoffset; - let searchWidth = width - 2 * spacing - wsTmbWidth - (opt.DASH_VERTICAL ? dashWidth : 0); // xAlignCenter is given by wsBox - searchWidth = this._xAlignCenter ? width - 2 * (wsTmbWidth + spacing) : searchWidth; - - if (opt.CENTER_SEARCH_VIEW) { - childBox.set_origin(0, Math.round(searchEntryY)); - childBox.set_size(Math.round(width), Math.round(searchHeight)); - } else { - childBox.set_origin(Math.round(this._xAlignCenter ? 0 : searchEntryX), Math.round(searchEntryY)); - childBox.set_size(Math.round(this._xAlignCenter ? width : searchWidth - spacing), Math.round(searchHeight)); - } - - this._searchEntry.allocate(childBox); - - availableHeight -= searchHeight + spacing; - - // if (this._appDisplay.visible)... ? Can cause problems - // Calculate appDisplay always for AppGrid state WsTmb scale - let wsTmbWidthAppGrid = opt.MAX_THUMBNAIL_SCALE_APPGRID > 0 - ? wsTmbWidth / maxWsTmbScale * opt.MAX_THUMBNAIL_SCALE_APPGRID - : wsTmbWidth / maxWsTmbScale * opt.MAX_THUMBNAIL_SCALE; - params = [box, workAreaBox, searchHeight, dashWidth, dashHeight, wsTmbWidthAppGrid, startY]; // send startY, can be corrected - let appDisplayBox; - if (!transitionParams.transitioning) { - appDisplayBox = - this._getAppDisplayBoxForState(transitionParams.currentState, ...params); - } else { - const initialBox = - this._getAppDisplayBoxForState(transitionParams.initialState, ...params); - const finalBox = - this._getAppDisplayBoxForState(transitionParams.finalState, ...params); - - appDisplayBox = initialBox.interpolate(finalBox, transitionParams.progress); - } - this._appDisplay.allocate(appDisplayBox); - - // Search - if (opt.CENTER_SEARCH_VIEW) { - const dashW = (opt.DASH_VERTICAL ? dashWidth : 0) + spacing; - searchWidth = width - 2 * wsTmbWidth - 2 * dashW; - childBox.set_origin(Math.round(wsTmbWidth + dashW), Math.round(startY + (opt.DASH_TOP ? dashHeight + spacing : spacing) + searchHeight)); - } else { - childBox.set_origin(Math.round(this._xAlignCenter ? wsTmbWidth + spacing : searchXoffset), Math.round(startY + (opt.DASH_TOP ? dashHeight + spacing : spacing) + searchHeight)); - } - - childBox.set_size(Math.round(searchWidth), Math.round(availableHeight)); - this._searchController.allocate(childBox); - - this._runPostAllocation(); - }, -}; - -const ControlsManagerLayoutHorizontal = { - _computeWorkspacesBoxForState(state, box, workAreaBox, dashWidth, dashHeight, thumbnailWidth, thumbnailsHeight, searchHeight, startY) { - // in case the function is called from the DtD - if (startY === undefined) - workAreaBox = box; - - const workspaceBox = box.copy(); - let [width, height] = workspaceBox.get_size(); - const spacing = 12; - - const dash = Main.overview.dash; - // including Dash to Dock and clones properties for compatibility - if (Me.Util.dashIsDashToDock()) { - // ensure our position variables are updated - ControlsManagerCommon._updatePositionFromDashToDock(); - // Dash to Dock always affects workAreaBox - Main.layoutManager._trackedActors.forEach(actor => { - if (actor.affectsStruts && actor.actor.width === dash.width) { - if (dash._isHorizontal) { - // disabled inteli-hide don't need compensation - // startY needs to be corrected in allocate() - if (dash.get_parent()?.get_parent()?.get_parent()?._intellihideIsEnabled) - height += dash.height; - else if (opt.DASH_TOP) - height += dash.height; - } else { - width += dash.width; - } - } - }); - } - - let wWidth, wHeight, wsBoxY, wsBoxX; - - switch (state) { - case ControlsState.HIDDEN: - // if PANEL_OVERVIEW_ONLY, the affectStruts property is set to false to avoid stuttering - // therefore we added panel height to startY for the overview allocation, - // but here we need to remove the correction since the panel will be in the hidden state - if (opt.START_Y_OFFSET) { - let [x, y] = workAreaBox.get_origin(); - y -= opt.START_Y_OFFSET; - workspaceBox.set_origin(x, y); - } else { - workspaceBox.set_origin(...workAreaBox.get_origin()); - } - workspaceBox.set_size(...workAreaBox.get_size()); - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - if (opt.WS_ANIMATION && opt.SHOW_WS_TMB && state === ControlsState.APP_GRID) { - workspaceBox.set_origin(...this._workspacesThumbnails.get_position()); - workspaceBox.set_size(thumbnailWidth, thumbnailsHeight); - } else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) { - if (opt.START_Y_OFFSET) { - let [x, y] = workAreaBox.get_origin(); - y -= opt.START_Y_OFFSET; - workspaceBox.set_origin(x, y); - } else { - workspaceBox.set_origin(...workAreaBox.get_origin()); - } - workspaceBox.set_size(...workAreaBox.get_size()); - } else { - // if PANEL_OVERVIEW_ONLY, panel doesn't affect workArea height (affectStruts === false), it is necessary to compensate - height = opt.PANEL_POSITION_TOP ? height : height - Main.panel.height; - searchHeight = opt.SHOW_SEARCH_ENTRY ? searchHeight : 0; - wWidth = width - - spacing - - (opt.DASH_VERTICAL ? dashWidth : 0) - - 4 * spacing; - wHeight = height - - (opt.DASH_VERTICAL ? spacing : dashHeight) - - thumbnailsHeight - - searchHeight - - 4 * spacing; - - const ratio = width / height; - let wRatio = wWidth / wHeight; - let scale = ratio / wRatio; - - if (scale > 1) { - wHeight /= scale; - wWidth = wHeight * ratio; - } else { - wWidth *= scale; - wHeight = wWidth / ratio; - } - - // height decides the actual size, ratio is given by the workarea - wHeight *= opt.WS_PREVIEW_SCALE; - wWidth *= opt.WS_PREVIEW_SCALE; - - let xOffset = 0; - let yOffset = 0; - - const yOffsetT = (opt.DASH_TOP ? dashHeight : 0) + (opt.WS_TMB_TOP ? thumbnailsHeight : 0) + searchHeight; - const yOffsetB = (opt.DASH_BOTTOM ? dashHeight : 0) + (opt.WS_TMB_BOTTOM ? thumbnailsHeight : 0); - - const yAvailableSpace = (height - yOffsetT - wHeight - yOffsetB) / 2; - yOffset = yOffsetT + yAvailableSpace; - - const xOffsetL = (opt.DASH_LEFT ? dashWidth : 0) + spacing; - const xOffsetR = (opt.DASH_RIGHT ? dashWidth : 0) + spacing; - const centeredBoxX = (width - wWidth) / 2; - - this._xAlignCenter = false; - if (centeredBoxX < Math.max(xOffsetL, xOffsetR)) { - xOffset = xOffsetL + spacing + (width - xOffsetL - wWidth - xOffsetR) / 2; - } else { - xOffset = centeredBoxX; - this._xAlignCenter = true; - } - - wsBoxX = /* startX + */xOffset; - wsBoxY = startY + yOffset; - workspaceBox.set_origin(Math.round(wsBoxX), Math.round(wsBoxY)); - workspaceBox.set_size(Math.round(wWidth), Math.round(wHeight)); - } - } - - return workspaceBox; - }, - - _getAppDisplayBoxForState(state, box, workAreaBox, searchHeight, dashWidth, dashHeight, thumbnailsHeight, startY) { - // in case the function is called from the DtD - if (startY === undefined) { - workAreaBox = box; - } - const [width] = box.get_size(); - const { x1: startX } = workAreaBox; - // const { y1: startY } = workAreaBox; - let height = workAreaBox.get_height(); - const appDisplayBox = new Clutter.ActorBox(); - const spacing = 12; - - const yOffsetT = (opt.WS_TMB_TOP ? thumbnailsHeight + spacing : 0) + (opt.DASH_TOP ? dashHeight : 0) + (opt.SHOW_SEARCH_ENTRY ? searchHeight : 0); - const yOffsetB = (opt.WS_TMB_BOTTOM ? thumbnailsHeight + spacing : 0) + (opt.DASH_BOTTOM ? dashHeight : 0); - const xOffsetL = opt.DASH_LEFT ? dashWidth : 0; - const xOffsetR = opt.DASH_RIGHT ? dashWidth : 0; - const hSpacing = xOffsetL + xOffsetR ? spacing : 0; - const adWidth = opt.CENTER_APP_GRID ? width - 2 * Math.max(xOffsetL, xOffsetR) - 2 * hSpacing : width - xOffsetL - xOffsetR - 2 * hSpacing; - const adHeight = height - yOffsetT - yOffsetB; - - const appDisplayX = opt.CENTER_APP_GRID ? (width - adWidth) / 2 : xOffsetL + hSpacing; - const appDisplayY = startY + yOffsetT; - - switch (state) { - case ControlsState.HIDDEN: - case ControlsState.WINDOW_PICKER: - // 1 - left, 2 - right, 3 - bottom, 5 - top - switch (opt.APP_GRID_ANIMATION) { - case 0: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(appDisplayY)); - break; - case 1: - appDisplayBox.set_origin(Math.round(startX + width), Math.round(appDisplayY)); - break; - case 2: - appDisplayBox.set_origin(Math.round(startX - adWidth), Math.round(appDisplayY)); - break; - case 3: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(workAreaBox.y2)); - break; - case 5: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(workAreaBox.y1 - adHeight)); - break; - } - break; - case ControlsState.APP_GRID: - appDisplayBox.set_origin(Math.round(appDisplayX), Math.round(appDisplayY)); - break; - } - - appDisplayBox.set_size(Math.round(adWidth), Math.round(adHeight)); - return appDisplayBox; - }, - - vfunc_allocate(container, box) { - const transitionParams = this._stateAdjustment.getStateTransitionParams(); - const childBox = new Clutter.ActorBox(); - const spacing = 12; - const halfSpacing = spacing / 2; - const monitor = Main.layoutManager.findMonitorForActor(this._container); - const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); - const startX = workArea.x - monitor.x; - // if PANEL_OVERVIEW_ONLY, the affectStruts property is set to false to avoid stuttering - // therefore we need to add panel height to startY - let startY = workArea.y - monitor.y + opt.START_Y_OFFSET; - const workAreaBox = new Clutter.ActorBox(); - workAreaBox.set_origin(startX, startY); - workAreaBox.set_size(workArea.width, workArea.height); - box.y1 += startY; - box.x1 += startX; - let [width, height] = box.get_size(); - // if panel is at bottom position, - // compensate for the height of the available box (the box size is calculated for top panel) - height = opt.PANEL_POSITION_TOP ? height : height - Main.panel.height; - let availableHeight = height; - - // Dash - const maxDashHeight = box.get_height() * DASH_MAX_SIZE_RATIO; - const maxDashWidth = maxDashHeight * 0.8; - let dashHeight = 0; - let dashWidth = 0; - - // dash cloud be overridden by the Dash to Dock clone - const dash = Main.overview.dash; - if (Me.Util.dashIsDashToDock()) { - // if Dash to Dock replaced the default dash and its inteli-hide is disabled we need to compensate for affected startY - if (!Main.overview.dash.get_parent()?.get_parent()?.get_parent()?._intellihideIsEnabled) { - // if (Main.panel.y === monitor.y) - // startY = Main.panel.height + spacing; - } - dashHeight = dash.height + halfSpacing; - dashWidth = dash.width; - opt.DASH_TOP = dash._position === 0; - opt.DASH_VERTICAL = [1, 3].includes(dash._position); - this._dash.allocate(childBox); - } else if (this._dash.visible) { - // default dock - if (!opt.DASH_VERTICAL) { - this._dash.setMaxSize(width, maxDashHeight); - [, dashHeight] = this._dash.get_preferred_height(width); - [, dashWidth] = this._dash.get_preferred_width(dashHeight); - dashHeight = Math.min(dashHeight, maxDashHeight); - dashWidth = Math.min(dashWidth, width - spacing); - } else if (!opt.WS_TMB_FULL) { - this._dash.setMaxSize(maxDashWidth, height); - [, dashWidth] = this._dash.get_preferred_width(height); - [, dashHeight] = this._dash.get_preferred_height(dashWidth); - dashHeight = Math.min(dashHeight, height - spacing); - dashWidth = Math.min(dashWidth, width); - } - } - - let [searchHeight] = this._searchEntry.get_preferred_height(width); - - // Workspace Thumbnails - let wsTmbWidth = 0; - let wsTmbHeight = 0; - - let maxWsTmbScale = opt.MAX_THUMBNAIL_SCALE; - if (opt.SHOW_WS_TMB) { - const dashWidthReservation = !opt.WS_TMB_FULL && opt.DASH_VERTICAL ? dashWidth : 0; - - const searchActive = this._searchController.searchActive; - if (!opt.MAX_THUMBNAIL_SCALE_STABLE && !searchActive) { - const initState = transitionParams.initialState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE; - const finalState = transitionParams.finalState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE; - maxWsTmbScale = Util.lerp(initState, finalState, transitionParams.progress); - } - - wsTmbHeight = Math.round(height * maxWsTmbScale); - let totalTmbSpacing; - [totalTmbSpacing, wsTmbWidth] = this._workspacesThumbnails.get_preferred_width(wsTmbHeight); - wsTmbWidth += totalTmbSpacing; - - const wsTmbWidthMax = opt.WS_TMB_FULL - ? width - spacing - : width - dashWidthReservation - 2 * spacing; - - if (wsTmbWidth > wsTmbWidthMax) { - wsTmbWidth = wsTmbWidthMax; - wsTmbHeight = Math.round(this._workspacesThumbnails.get_preferred_height(wsTmbWidth)[1]); - } - - let wsTmbY; - if (opt.WS_TMB_TOP) - wsTmbY = Math.round(startY + (opt.DASH_TOP ? dashHeight : halfSpacing)); - else - wsTmbY = Math.round(startY + height - (opt.DASH_BOTTOM ? dashHeight : halfSpacing) - wsTmbHeight); - - let wstOffset = (width - wsTmbWidth) / 2; - wstOffset -= opt.WS_TMB_POSITION_ADJUSTMENT * wstOffset; - let wsTmbX = Math.round(startX + wstOffset); - if (opt.DASH_LEFT) - wsTmbX = Math.max(wsTmbX, startX + dashWidthReservation); - else if (opt.DASH_RIGHT) - wsTmbX = Math.min(wsTmbX, startX + width - wsTmbWidth - dashWidthReservation); - - childBox.set_origin(wsTmbX, wsTmbY); - childBox.set_size(Math.max(wsTmbWidth, 1), Math.max(wsTmbHeight, 1)); - - this._workspacesThumbnails.allocate(childBox); - - availableHeight -= wsTmbHeight + spacing; - } - - if (this._dash.visible) { - if (opt.WS_TMB_FULL && opt.DASH_VERTICAL) { - const wMaxHeight = height - spacing - wsTmbHeight; - this._dash.setMaxSize(maxDashWidth, wMaxHeight); - [, dashWidth] = this._dash.get_preferred_width(wMaxHeight); - [, dashHeight] = this._dash.get_preferred_height(dashWidth); - dashWidth = Math.min(dashWidth, maxDashWidth); - dashHeight = Math.min(dashHeight, wMaxHeight); - } - - let dashX, dashY, offset; - if (opt.DASH_RIGHT) - dashX = width - dashWidth; - else if (opt.DASH_LEFT) - dashX = 0; - else if (opt.DASH_TOP) - dashY = startY; - else - dashY = startY + height - dashHeight; - - if (opt.DASH_VERTICAL) { - if (opt.WS_TMB_FULL) { - offset = (height - dashHeight - wsTmbHeight) / 2; - if (opt.WS_TMB_TOP) { - offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - halfSpacing); - dashY = startY + offset + wsTmbHeight; - } else { - offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - halfSpacing); - dashY = startY + offset; - } - } else { - offset = (height - dashHeight) / 2; - offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - halfSpacing); - dashY = startY + offset; - } - } else { - offset = (width - dashWidth) / 2; - dashX = startX + (offset - opt.DASH_POSITION_ADJUSTMENT * (offset - halfSpacing)); - } - - childBox.set_origin(Math.round(startX + dashX), Math.round(dashY)); - childBox.set_size(Math.round(dashWidth), Math.round(dashHeight)); - this._dash.allocate(childBox); - } - - availableHeight -= opt.DASH_VERTICAL ? 0 : dashHeight; - - // Workspaces - let params = [box, workAreaBox, dashWidth, dashHeight, wsTmbWidth, wsTmbHeight, searchHeight, startY]; - - // Update cached boxes - for (const state of Object.values(ControlsState)) { - this._cachedWorkspaceBoxes.set( - state, this._computeWorkspacesBoxForState(state, ...params)); - } - - let workspacesBox; - if (!transitionParams.transitioning) - workspacesBox = this._cachedWorkspaceBoxes.get(transitionParams.currentState); - - if (!workspacesBox) { - const initialBox = this._cachedWorkspaceBoxes.get(transitionParams.initialState); - const finalBox = this._cachedWorkspaceBoxes.get(transitionParams.finalState); - workspacesBox = initialBox.interpolate(finalBox, transitionParams.progress); - } - - this._workspacesDisplay.allocate(workspacesBox); - - // Search entry - const searchXoffset = (opt.DASH_LEFT ? dashWidth : 0) + spacing; - - // Y position under top Dash - let searchEntryX, searchEntryY; - if (opt.DASH_TOP) - searchEntryY = startY + (opt.WS_TMB_TOP ? wsTmbHeight : 0) + dashHeight; - else - searchEntryY = startY + (opt.WS_TMB_TOP ? wsTmbHeight + spacing : 0); - - - searchEntryX = searchXoffset; - let searchWidth = width - 2 * spacing - (opt.DASH_VERTICAL ? dashWidth : 0); // xAlignCenter is given by wsBox - searchWidth = this._xAlignCenter ? width : searchWidth; - - if (opt.CENTER_SEARCH_VIEW) { - childBox.set_origin(0, Math.round(searchEntryY)); - childBox.set_size(width, Math.round(searchHeight)); - } else { - childBox.set_origin(Math.round(this._xAlignCenter ? 0 : searchEntryX), Math.round(searchEntryY)); - childBox.set_size(Math.round(this._xAlignCenter ? width : searchWidth - spacing), Math.round(searchHeight)); - } - - this._searchEntry.allocate(childBox); - - availableHeight -= searchHeight + spacing; - - // if (this._appDisplay.visible)... ? Can cause problems - // Calculate appDisplay always for AppGrid state WsTmb scale - let wsTmbHeightAppGrid = opt.MAX_THUMBNAIL_SCALE_APPGRID > 0 - ? wsTmbHeight / maxWsTmbScale * opt.MAX_THUMBNAIL_SCALE_APPGRID - : wsTmbHeight / maxWsTmbScale * opt.MAX_THUMBNAIL_SCALE; - params = [box, workAreaBox, searchHeight, dashWidth, dashHeight, wsTmbHeightAppGrid, startY]; - let appDisplayBox; - if (!transitionParams.transitioning) { - appDisplayBox = - this._getAppDisplayBoxForState(transitionParams.currentState, ...params); - } else { - const initialBox = - this._getAppDisplayBoxForState(transitionParams.initialState, ...params); - const finalBox = - this._getAppDisplayBoxForState(transitionParams.finalState, ...params); - - appDisplayBox = initialBox.interpolate(finalBox, transitionParams.progress); - } - this._appDisplay.allocate(appDisplayBox); - - // Search - if (opt.CENTER_SEARCH_VIEW) { - const dashW = (opt.DASH_VERTICAL ? dashWidth : 0) + spacing; - searchWidth = width - 2 * dashW; - childBox.set_origin(Math.round(dashW), Math.round(startY + (opt.DASH_TOP ? dashHeight + spacing : spacing) + (opt.WS_TMB_TOP ? wsTmbHeight + spacing : 0) + searchHeight)); - } else { - childBox.set_origin(Math.round(this._xAlignCenter ? spacing : searchXoffset), Math.round(startY + (opt.DASH_TOP ? dashHeight + spacing : spacing) + (opt.WS_TMB_TOP ? wsTmbHeight + spacing : 0) + searchHeight)); - } - - childBox.set_size(Math.round(searchWidth), Math.round(availableHeight)); - this._searchController.allocate(childBox); - - this._runPostAllocation(); - }, -}; - -// same copy of this function should be available in OverviewControls and WorkspacesView -function _getFitModeForState(state) { - switch (state) { - case ControlsState.HIDDEN: - case ControlsState.WINDOW_PICKER: - return FitMode.SINGLE; - case ControlsState.APP_GRID: - if (opt.WS_ANIMATION && opt.SHOW_WS_TMB) - return FitMode.ALL; - else - return FitMode.SINGLE; - default: - return FitMode.SINGLE; - } -} - -const LayoutManager = { - _startupAnimation() { - const dtdEnabled = !!((Me.Util.getEnabledExtensions('dash-to-dock').length && !Me.Util.getEnabledExtensions('dash-to-dock-vshell').length) || - Me.Util.getEnabledExtensions('ubuntu-dock').length); - if (dtdEnabled && !Meta.is_restart()) { - // DtD without V-Shell patch breaks overview on startup - // Skip animation to hide the mess - this._startupAnimationComplete(); - Main.overview._overview.controls._finishStartupSequence(); - } else if (Meta.is_restart()) { - this._startupAnimationComplete(); - } else if (Main.sessionMode.isGreeter) { - this._startupAnimationGreeter(); - } else { - this._startupAnimationSession(); - } - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/panel.js b/extensions/46/vertical-workspaces/lib/panel.js deleted file mode 100644 index f78ab6f..0000000 --- a/extensions/46/vertical-workspaces/lib/panel.js +++ /dev/null @@ -1,253 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * panel.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Overview from 'resource:///org/gnome/shell/ui/overview.js'; - -let Me; -let opt; - -const ANIMATION_TIME = Overview.ANIMATION_TIME; - -export const PanelModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - - this._showingOverviewConId = 0; - this._hidingOverviewConId = 0; - this._styleChangedConId = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this.moduleEnabled = opt.get('panelModule'); - const conflict = Me.Util.getEnabledExtensions('dash-to-panel').length || - Me.Util.getEnabledExtensions('hidetopbar').length; - - if (conflict && !reset) - console.warn(`[${Me.metadata.name}] Warning: "Panel" module disabled due to potential conflict with another extension`); - - reset = reset || !this.moduleEnabled || conflict || Main.sessionMode.isLocked; - - // don't touch 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(' PanelModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - const panelBox = Main.layoutManager.panelBox; - - this._setPanelPosition(); - this._updateStyleChangedConnection(); - - if (opt.PANEL_MODE === 0) { - this._updateOverviewConnection(true); - this._reparentPanel(false); - panelBox.translation_y = 0; - Main.panel.opacity = 255; - this._setPanelStructs(true); - } else if (opt.PANEL_MODE === 1) { - if (opt.SHOW_WS_PREVIEW_BG) { - this._reparentPanel(true); - if (opt.OVERVIEW_MODE2) { - // in OM2 if the panel has been moved to the overviewGroup move panel above all - Main.layoutManager.overviewGroup.set_child_above_sibling(panelBox, null); - this._updateOverviewConnection(); - } else { - // otherwise move the panel below overviewGroup so it can get below workspacesDisplay - Main.layoutManager.overviewGroup.set_child_below_sibling(panelBox, Main.overview._overview); - this._updateOverviewConnection(true); - } - this._showPanel(true); - } else { - // if ws preview bg is disabled, panel can stay in uiGroup - this._reparentPanel(false); - this._showPanel(false); - this._updateOverviewConnection(); - } - // _connectPanel(); - } else if (opt.PANEL_MODE === 2) { - this._updateOverviewConnection(true); - this._reparentPanel(false); - this._showPanel(false); - // _connectPanel(); - } - this._setPanelStructs(opt.PANEL_MODE === 0); - Main.layoutManager._updateHotCorners(); - - this._overrides.addOverride('ActivitiesButton', Main.panel.statusArea.activities, ActivitiesButton); - - console.debug(' PanelModule - Activated'); - } - - _disableModule() { - const reset = true; - this._setPanelPosition(reset); - this._updateOverviewConnection(reset); - this._reparentPanel(false); - - this._updateStyleChangedConnection(reset); - - const panelBox = Main.layoutManager.panelBox; - panelBox.translation_y = 0; - Main.panel.opacity = 255; - this._setPanelStructs(true); - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - console.debug(' PanelModule - Disabled'); - } - - _setPanelPosition(reset = false) { - const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor()); - const panelBox = Main.layoutManager.panelBox; - const panelHeight = Main.panel.height; // panelBox height can be 0 after shell start - - if (opt.PANEL_POSITION_TOP || reset) - panelBox.set_position(geometry.x, geometry.y); - else - panelBox.set_position(geometry.x, geometry.y + geometry.height - panelHeight); - } - - _updateStyleChangedConnection(reset = false) { - if (reset) { - if (this._styleChangedConId) { - Main.panel.disconnect(this._styleChangedConId); - this._styleChangedConId = 0; - } - } else if (!this._styleChangedConId) { - this._styleChangedConId = Main.panel.connect('style-changed', () => { - if (opt.PANEL_MODE === 1 && !opt.OVERVIEW_MODE2) - Main.panel.add_style_pseudo_class('overview'); - else if (opt.OVERVIEW_MODE2) - Main.panel.remove_style_pseudo_class('overview'); - }); - } - } - - _updateOverviewConnection(reset = false) { - if (reset) { - if (this._hidingOverviewConId) { - Main.overview.disconnect(this._hidingOverviewConId); - this._hidingOverviewConId = 0; - } - if (this._showingOverviewConId) { - Main.overview.disconnect(this._showingOverviewConId); - this._showingOverviewConId = 0; - } - } else { - if (!this._hidingOverviewConId) { - this._hidingOverviewConId = Main.overview.connect('hiding', () => { - if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2) - this._showPanel(false); - }); - } - if (!this._showingOverviewConId) { - this._showingOverviewConId = Main.overview.connect('showing', () => { - if (Main.layoutManager._startingUp) - return; - if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2 || Main.layoutManager.panelBox.translation_y) - this._showPanel(true); - }); - } - } - } - - _reparentPanel(reparent = false) { - const panel = Main.layoutManager.panelBox; - if (reparent && panel.get_parent() === Main.layoutManager.uiGroup) { - Main.layoutManager.uiGroup.remove_child(panel); - Main.layoutManager.overviewGroup.add_child(panel); - } else if (!reparent && panel.get_parent() === Main.layoutManager.overviewGroup) { - Main.layoutManager.overviewGroup.remove_child(panel); - // return the panel at default position, panel shouldn't cover objects that should be above - Main.layoutManager.uiGroup.insert_child_at_index(panel, 4); - } - } - - _setPanelStructs(state) { - Main.layoutManager._trackedActors.forEach(a => { - if (a.actor === Main.layoutManager.panelBox) - a.affectsStruts = state; - }); - - // workaround to force maximized windows to resize after removing affectsStruts - // simulation of minimal swipe gesture to the opposite direction - // todo - needs better solution!!!!!!!!!!! - // const direction = _getAppGridAnimationDirection() === 2 ? 1 : -1; - // Main.overview._swipeTracker._beginTouchSwipe(null, global.get_current_time(), 1, 1); - // Main.overview._swipeTracker._updateGesture(null, global.get_current_time(), direction, 1); - // GLib.timeout_add(0, 50, () => Main.overview._swipeTracker._endGesture(global.get_current_time(), 1, true));*/ - } - - _showPanel(show = true) { - if (show) { - Main.panel.opacity = 255; - Main.layoutManager.panelBox.ease({ - duration: ANIMATION_TIME, - translation_y: 0, - onComplete: () => { - this._setPanelStructs(opt.PANEL_MODE === 0); - }, - }); - } else { - const panelHeight = Main.panel.height; - Main.layoutManager.panelBox.ease({ - duration: ANIMATION_TIME, - translation_y: opt.PANEL_POSITION_TOP ? -panelHeight + 1 : panelHeight - 1, - onComplete: () => { - Main.panel.opacity = 0; - this._setPanelStructs(opt.PANEL_MODE === 0); - }, - }); - } - } -}; - -const ActivitiesButton = { - vfunc_event(event) { - if (event.type() === Clutter.EventType.TOUCH_END || - event.type() === Clutter.EventType.BUTTON_RELEASE) { - if (Main.overview.shouldToggleByCornerOrButton()) { - if (event.get_button() === Clutter.BUTTON_SECONDARY && !Main.overview.dash.showAppsButton.checked) { - Main.overview.show(2); - Main.overview.dash.showAppsButton.checked = true; - } else { - Main.overview.toggle(); - } - } - } - - return Main.wm.handleWorkspaceScroll(event); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/recentFilesSearchProvider.js b/extensions/46/vertical-workspaces/lib/recentFilesSearchProvider.js deleted file mode 100644 index f050cf9..0000000 --- a/extensions/46/vertical-workspaces/lib/recentFilesSearchProvider.js +++ /dev/null @@ -1,316 +0,0 @@ -/** - * Vertical Workspaces - * recentFilesSearchProvider.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import St from 'gi://St'; -import Gio from 'gi://Gio'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; - -let Me; -let opt; -// gettext -let _; - -// prefix helps to eliminate results from other search providers -// so it needs to be something less common -// needs to be accessible from vw module -export const PREFIX = 'fq//'; -const ID = 'recent-files'; - -export const RecentFilesSearchProviderModule = class { - // export for other modules - static _PREFIX = PREFIX; - constructor(me) { - Me = me; - opt = Me.opt; - _ = Me.gettext; - - this._firstActivation = true; - this.moduleEnabled = false; - this._recentFilesSearchProvider = null; - this._enableTimeoutId = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - _ = null; - } - - update(reset) { - this.moduleEnabled = opt.get('recentFilesSearchProviderModule'); - - reset = reset || !this.moduleEnabled; - - if (reset && !this._firstActivation) { - this._disableModule(); - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - if (reset && this._firstActivation) - console.debug(' RecentFilesSearchProviderModule - Keeping untouched'); - } - - _activateModule() { - // delay because Fedora had problem to register a new provider soon after Shell restarts - this._enableTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 2000, - () => { - if (!this._recentFilesSearchProvider) { - this._recentFilesSearchProvider = new RecentFilesSearchProvider(); - this._registerProvider(this._recentFilesSearchProvider); - } - this._enableTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); - - console.debug(' RecentFilesSearchProviderModule - Activated'); - } - - _disableModule() { - if (this._recentFilesSearchProvider) { - this._unregisterProvider(this._recentFilesSearchProvider); - this._recentFilesSearchProvider = null; - } - if (this._enableTimeoutId) { - GLib.source_remove(this._enableTimeoutId); - this._enableTimeoutId = 0; - } - - console.debug(' RecentFilesSearchProviderModule - Disabled'); - } - - _registerProvider(provider) { - const searchResults = Main.overview.searchController._searchResults; - provider.searchInProgress = false; - - searchResults._providers.push(provider); - - // create results display and add it to the _content - searchResults._ensureProviderDisplay.bind(searchResults)(provider); - } - - _unregisterProvider(provider) { - const searchResults = Main.overview.searchController._searchResults; - searchResults._unregisterProvider(provider); - } -}; - -class RecentFilesSearchProvider { - constructor() { - this.id = ID; - const appId = 'org.gnome.Nautilus.desktop'; - - // A real appInfo created from a commandline has often issues with overriding get_id() method, so we use dict instead - this.appInfo = { - get_id: () => appId, - get_name: () => _('Recent Files'), - get_icon: () => Gio.icon_new_for_string('focus-windows-symbolic'), - should_show: () => true, - get_commandline: () => '/usr/bin/nautilus -w recent:///', - launch: () => {}, - }; - - this.canLaunchSearch = true; - this.isRemoteProvider = false; - - this._recentFilesManager = new RecentFilesManager(); - } - - getInitialResultSet(terms/* , cancellable*/) { - const rfm = this._recentFilesManager; - rfm.loadFromFile(); - - const uris = rfm.getUris(); - const dict = {}; - for (let uri of uris) { - dict[uri] = {}; - dict[uri]['uri'] = uri; - dict[uri]['path'] = rfm.getPath(uri); - dict[uri]['filename'] = rfm.getDisplayName(uri); - dict[uri]['dir'] = rfm.getDirPath(uri); - dict[uri]['age'] = rfm.getAge(uri); - dict[uri]['appInfo'] = rfm.getDefaultAppAppInfo(uri); - } - this.files = dict; - - return new Promise(resolve => resolve(this._getResultSet(terms))); - } - - _getResultSet(terms) { - if (!terms[0].startsWith(PREFIX)) - return []; - // do not modify original terms - let termsCopy = [...terms]; - // search for terms without prefix - termsCopy[0] = termsCopy[0].replace(PREFIX, ''); - - const candidates = Object.values(this.files); - const _terms = [].concat(termsCopy); - - const term = _terms.join(' '); - - const results = []; - let m; - for (let file of candidates) { - if (opt.SEARCH_FUZZY) - m = Me.Util.fuzzyMatch(term, file.filename); - else - m = Me.Util.strictMatch(term, file.filename); - - if (m !== -1) - results.push(file); - } - - results.sort((a, b) => a.age > b.age); - - const resultIds = results.map(item => item.uri); - return resultIds; - } - - getResultMetas(resultIds/* , callback = null*/) { - const metas = resultIds.map(id => this.getResultMeta(id)); - return new Promise(resolve => resolve(metas)); - } - - getResultMeta(resultId) { - const result = this.files[resultId]; - return { - 'id': resultId, - 'name': `${Math.floor(result.age)}: ${result.filename}`, - 'description': `${result.dir}`, - 'createIcon': size => - this._recentFilesManager.getDefaultAppIcon(resultId, size), - }; - } - - launchSearch(terms, timeStamp) { - const appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/nautilus -w recent:///', 'Nautilus', null); - appInfo.launch([], global.create_app_launch_context(timeStamp, -1)); - - // unlike on 42, on 44 if a window with the same uri is already open it will not get focus/activation - // Gio.app_info_launch_default_for_uri('recent:///', global.create_app_launch_context(timeStamp, -1)); - - // following solution for some reason ignores the recent:/// uri - // this.appInfo.launch_uris(['recent:///'], global.create_app_launch_context(timeStamp, -1)); - } - - activateResult(resultId, terms, timeStamp) { - const uri = resultId; - const context = global.create_app_launch_context(timeStamp, -1); - if (Me.Util.isShiftPressed()) { - Main.overview.toggle(); - this.appInfo.launch_uris([uri], context); - } else if (Gio.app_info_launch_default_for_uri(uri, context)) { - // update recent list after successful activation - this._recentFilesManager.updateAdded(resultId); - this._recentFilesManager.saveToFile(); - } else { - this.appInfo.launch_uris([uri], context); - } - } - - filterResults(results /* , maxResults*/) { - // return results.slice(0, maxResults); - return results.slice(0, 20); - } - - getSubsearchResultSet(previousResults, terms/* , cancellable*/) { - return this.getInitialResultSet(terms); - } -} - -class RecentFilesManager { - constructor(path) { - path = path ?? GLib.build_filenamev([GLib.get_user_data_dir(), 'recently-used.xbel']); - this._recentlyUsedPath = path; - this._bookmarks = new GLib.BookmarkFile(); - } - - loadFromFile() { - try { - this._bookmarks.load_from_file(this._recentlyUsedPath); - } catch (e) { - if (!e.matches(GLib.BookmarkFileError, GLib.BookmarkFileError.FILE_NOT_FOUND)) - console.error(`Could not open recent files: ${e.message}`); - } - } - - saveToFile() { - try { - this._bookmarks.to_file(this._recentlyUsedPath); - } catch (e) { - if (!e.matches(GLib.BookmarkFileError, GLib.BookmarkFileError.FILE_NOT_FOUND)) - console.error(`Could not open recent files to save data: ${e.message}`); - } - } - - getUris() { - return this._bookmarks.get_uris(); - } - - getPath(uri) { - // GLib.filename_from_uri() removes uri schema and converts string to utf-8 - return GLib.filename_from_uri(uri)[0]; // result is array - } - - getDisplayName(uri) { - const path = this.getPath(uri); - return GLib.filename_display_basename(path); - } - - getDirPath(uri) { - const path = this.getPath(uri); - const filename = this.getDisplayName(uri); - return path.replace(`${filename}`, ''); - } - - getMimeType(uri) { - return this._bookmarks.get_mime_type(uri); - } - - getAdded(uri) { - return this._bookmarks.get_added(uri); - } - - updateAdded(uri) { - this._bookmarks.set_added_date_time(uri, GLib.DateTime.new_now_local()); - } - - // age in days (float) - getAge(uri) { - return (Date.now() / 1000 - this._bookmarks.get_added(uri)) / 60 / 60 / 24; - } - - getDefaultAppAppInfo(uri) { - const mimeType = this.getMimeType(uri); - return Gio.AppInfo.get_default_for_type(mimeType, false); - } - - getDefaultAppIcon(uri, size) { - let icon, gicon; - - const appInfo = this.getDefaultAppAppInfo(uri); - if (appInfo) - gicon = appInfo.get_icon(); - - if (gicon) - icon = new St.Icon({ gicon, icon_size: size }); - else - icon = new St.Icon({ icon_name: 'icon-missing', icon_size: size }); - - return icon; - } -} diff --git a/extensions/46/vertical-workspaces/lib/search.js b/extensions/46/vertical-workspaces/lib/search.js deleted file mode 100644 index fc15862..0000000 --- a/extensions/46/vertical-workspaces/lib/search.js +++ /dev/null @@ -1,405 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * search.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import Clutter from 'gi://Clutter'; -import St from 'gi://St'; -import Shell from 'gi://Shell'; -import GObject from 'gi://GObject'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Search from 'resource:///org/gnome/shell/ui/search.js'; -import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'; - -import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js'; -import { Highlighter } from 'resource:///org/gnome/shell/misc/util.js'; - -let Me; -// gettext -let _; -let opt; - -let SEARCH_MAX_WIDTH; - -export const SearchModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - _ = Me.gettext; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - } - - cleanGlobals() { - Me = null; - opt = null; - _ = null; - } - - update(reset) { - this.moduleEnabled = opt.get('searchModule'); - 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(' SearchModule - Keeping untouched'); - } - - _activateModule() { - this._updateSearchViewWidth(); - - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._overrides.addOverride('AppSearchProvider', AppDisplay.AppSearchProvider.prototype, AppSearchProvider); - this._overrides.addOverride('SearchResult', Search.SearchResult.prototype, SearchResult); - this._overrides.addOverride('SearchResultsView', Search.SearchResultsView.prototype, SearchResultsView); - this._overrides.addOverride('ListSearchResults', Search.ListSearchResults.prototype, ListSearchResults); - this._overrides.addOverride('ListSearchResult', Search.ListSearchResult.prototype, ListSearchResultOverride); - this._overrides.addOverride('Highlighter', Highlighter.prototype, HighlighterOverride); - - // Don't expand the search view vertically and align it to the top - // this is important in the static workspace mode when the search view bg is not transparent - // also the "Searching..." and "No Results" notifications will be closer to the search entry, with the distance given by margin-top in the stylesheet - Main.overview.searchController.y_align = Clutter.ActorAlign.START; - // Increase the maxResults for app search so that it can show more results in case the user decreases the size of the result icon - const appSearchDisplay = Main.overview.searchController._searchResults._providers.filter(p => p.id === 'applications')[0]?.display; - if (appSearchDisplay) - appSearchDisplay._maxResults = 12; - console.debug(' SearchModule - Activated'); - } - - _disableModule() { - const reset = true; - - const searchResults = Main.overview.searchController._searchResults; - if (searchResults?._searchTimeoutId) { - GLib.source_remove(searchResults._searchTimeoutId); - searchResults._searchTimeoutId = 0; - } - - this._updateSearchViewWidth(reset); - - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - Main.overview.searchController.y_align = Clutter.ActorAlign.FILL; - - console.debug(' WorkspaceSwitcherPopupModule - Disabled'); - } - - _updateSearchViewWidth(reset = false) { - const searchContent = Main.overview.searchController._searchResults._content; - if (!SEARCH_MAX_WIDTH) { // just store original value; - const themeNode = searchContent.get_theme_node(); - const width = themeNode.get_max_width(); - SEARCH_MAX_WIDTH = width; - } - - if (reset) { - searchContent.set_style(''); - } else { - let width = Math.round(SEARCH_MAX_WIDTH * opt.SEARCH_VIEW_SCALE); - searchContent.set_style(`max-width: ${width}px;`); - } - } -}; - -const ListSearchResults = { - _getMaxDisplayedResults() { - return opt.SEARCH_MAX_ROWS; - }, -}; - -// AppDisplay.AppSearchProvider -const AppSearchProvider = { - getInitialResultSet(terms, cancellable) { - // Defer until the parental controls manager is initialized, so the - // results can be filtered correctly. - if (!this._parentalControlsManager.initialized) { - return new Promise(resolve => { - let initializedId = this._parentalControlsManager.connect('app-filter-changed', async () => { - if (this._parentalControlsManager.initialized) { - this._parentalControlsManager.disconnect(initializedId); - resolve(await this.getInitialResultSet(terms, cancellable)); - } - }); - }); - } - - const pattern = terms.join(' '); - - let appInfoList = Shell.AppSystem.get_default().get_installed(); - - let weightList = {}; - appInfoList = appInfoList.filter(appInfo => { - try { - appInfo.get_id(); // catch invalid file encodings - } catch (e) { - return false; - } - - let string = ''; - let name; - let shouldShow = false; - if (appInfo.get_display_name) { - // show only launchers that should be visible in this DE - shouldShow = appInfo.should_show() && this._parentalControlsManager.shouldShowApp(appInfo); - - if (shouldShow) { - let id = appInfo.get_id().split('.'); - id = id[id.length - 2] || ''; - let baseName = appInfo.get_string('Name') || ''; - let dispName = appInfo.get_display_name() || ''; - let gName = appInfo.get_generic_name() || ''; - let description = appInfo.get_description() || ''; - let categories = appInfo.get_string('Categories')?.replace(/;/g, ' ') || ''; - let keywords = appInfo.get_string('Keywords')?.replace(/;/g, ' ') || ''; - name = `${dispName} ${id}`; - string = `${dispName} ${gName} ${baseName} ${description} ${categories} ${keywords} ${id}`; - } - } - - let m = -1; - if (shouldShow && opt.SEARCH_FUZZY) { - m = Me.Util.fuzzyMatch(pattern, name); - m = (m + Me.Util.strictMatch(pattern, string)) / 2; - } else if (shouldShow) { - m = Me.Util.strictMatch(pattern, string); - } - - if (m !== -1) - weightList[appInfo.get_id()] = m; - - return shouldShow && (m !== -1); - }); - - appInfoList.sort((a, b) => weightList[a.get_id()] > weightList[b.get_id()]); - - const usage = Shell.AppUsage.get_default(); - // sort apps by usage list - appInfoList.sort((a, b) => usage.compare(a.get_id(), b.get_id())); - // prefer apps where any word in their name starts with the pattern - appInfoList.sort((a, b) => Me.Util.isMoreRelevant(a.get_display_name(), b.get_display_name(), pattern)); - - let results = appInfoList.map(app => app.get_id()); - - results = results.concat(this._systemActions.getMatchingActions(terms)); - - return new Promise(resolve => resolve(results)); - }, - - // App search result size - createResultObject(resultMeta) { - if (resultMeta.id.endsWith('.desktop')) { - const icon = new AppDisplay.AppIcon(this._appSys.lookup_app(resultMeta['id']), { - expandTitleOnHover: false, - }); - icon.icon.setIconSize(opt.SEARCH_ICON_SIZE); - return icon; - } else { - return new SystemActionIcon(this, resultMeta); - // icon.icon._setSizeManually = true; - // icon.icon.setIconSize(opt.SEARCH_ICON_SIZE); - // return icon; - } - }, -}; - -const SystemActionIcon = GObject.registerClass( -class SystemActionIcon extends Search.GridSearchResult { - _init(provider, metaInfo, resultsView) { - super._init(provider, metaInfo, resultsView); - this.icon._setSizeManually = true; - this.icon.setIconSize(opt.SEARCH_ICON_SIZE); - } - - activate() { - SystemActions.getDefault().activateAction(this.metaInfo['id']); - Main.overview.hide(); - } -}); - -const SearchResult = { - activate() { - this.provider.activateResult(this.metaInfo.id, this._resultsView.terms); - - if (this.metaInfo.clipboardText) { - St.Clipboard.get_default().set_text( - St.ClipboardType.CLIPBOARD, this.metaInfo.clipboardText); - } - // don't close overview if Shift key is pressed - Shift moves windows to the workspace - if (!Me.Util.isShiftPressed()) - Main.overview.toggle(); - }, -}; - -const SearchResultsView = { - setTerms(terms) { - // Check for the case of making a duplicate previous search before - // setting state of the current search or cancelling the search. - // This will prevent incorrect state being as a result of a duplicate - // search while the previous search is still active. - let searchString = terms.join(' '); - let previousSearchString = this._terms.join(' '); - if (searchString === previousSearchString) - return; - - this._startingSearch = true; - - this._cancellable.cancel(); - this._cancellable.reset(); - - if (terms.length === 0) { - this._reset(); - return; - } - - let isSubSearch = false; - if (this._terms.length > 0) - isSubSearch = searchString.indexOf(previousSearchString) === 0; - - this._terms = terms; - this._isSubSearch = isSubSearch; - this._updateSearchProgress(); - - if (!this._searchTimeoutId) - this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, opt.SEARCH_DELAY, this._onSearchTimeout.bind(this)); - - this._highlighter = new Highlighter(this._terms); - - this.emit('terms-changed'); - }, - - _doSearch() { - this._startingSearch = false; - - let previousResults = this._results; - this._results = {}; - - const term0 = this._terms[0]; - const onlySupportedProviders = term0.startsWith(Me.WSP_PREFIX) || term0.startsWith(Me.ESP_PREFIX) || term0.startsWith(Me.RFSP_PREFIX); - - this._providers.forEach(provider => { - const supportedProvider = ['open-windows', 'extensions', 'recent-files'].includes(provider.id); - if (!onlySupportedProviders || (onlySupportedProviders && supportedProvider)) { - let previousProviderResults = previousResults[provider.id]; - this._doProviderSearch(provider, previousProviderResults); - } else { - // hide unwanted providers, they will show() automatically when needed - provider.display.visible = false; - } - }); - - this._updateSearchProgress(); - this._clearSearchTimeout(); - }, - - _updateSearchProgress() { - let haveResults = this._providers.some(provider => { - let display = provider.display; - return display.getFirstResult() !== null; - }); - - this._scrollView.visible = haveResults; - this._statusBin.visible = !haveResults; - - if (!haveResults) { - if (this.searchInProgress) - this._statusText.set_text(_('Searching…')); - else - this._statusText.set_text(_('No results.')); - } - }, -}; - -// Add highlighting of the "name" part of the result for all providers -const ListSearchResultOverride = { - _highlightTerms() { - let markup = this._resultsView.highlightTerms(this.metaInfo['name']); - this.label_actor.clutter_text.set_markup(markup); - markup = this._resultsView.highlightTerms(this.metaInfo['description'].split('\n')[0]); - this._descriptionLabel.clutter_text.set_markup(markup); - }, -}; - -const HighlighterOverride = { - /** - * @param {?string[]} terms - list of terms to highlight - */ - /* constructor(terms) { - if (!terms) - return; - - const escapedTerms = terms - .map(term => Shell.util_regex_escape(term)) - .filter(term => term.length > 0); - - if (escapedTerms.length === 0) - return; - - this._highlightRegex = new RegExp( - `(${escapedTerms.join('|')})`, 'gi'); - },*/ - - /** - * Highlight all occurences of the terms defined for this - * highlighter in the provided text using markup. - * - * @param {string} text - text to highlight the defined terms in - * @returns {string} - */ - highlight(text, options) { - if (!this._highlightRegex) - return GLib.markup_escape_text(text, -1); - - // force use local settings if the class is overridden by another extension (WSP, ESP) - const o = options || opt; - let escaped = []; - let lastMatchEnd = 0; - let match; - let style = ['', '']; - if (o.HIGHLIGHT_DEFAULT) - style = ['<b>', '</b>']; - // The default highlighting by the bold style causes text to be "randomly" ellipsized in cases where it's not necessary - // and also blurry - // Underscore doesn't affect label size and all looks better - else if (o.HIGHLIGHT_UNDERLINE) - style = ['<u>', '</u>']; - - while ((match = this._highlightRegex.exec(text))) { - if (match.index > lastMatchEnd) { - let unmatched = GLib.markup_escape_text( - text.slice(lastMatchEnd, match.index), -1); - escaped.push(unmatched); - } - let matched = GLib.markup_escape_text(match[0], -1); - escaped.push(`${style[0]}${matched}${style[1]}`); - lastMatchEnd = match.index + match[0].length; - } - let unmatched = GLib.markup_escape_text( - text.slice(lastMatchEnd), -1); - escaped.push(unmatched); - return escaped.join(''); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/searchController.js b/extensions/46/vertical-workspaces/lib/searchController.js deleted file mode 100644 index 1722f15..0000000 --- a/extensions/46/vertical-workspaces/lib/searchController.js +++ /dev/null @@ -1,94 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * searchController.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; - -let Me; -let opt; - -export const SearchControllerModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - this._originalOnStageKeyPress = null; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this.moduleEnabled = opt.get('searchControllerModule'); - 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(' SearchControllerModule - Keeping untouched'); - } - - _activateModule() { - if (!this._originalOnStageKeyPress) - this._originalOnStageKeyPress = Main.overview.searchController._onStageKeyPress; - - Main.overview.searchController._onStageKeyPress = SearchControllerCommon._onStageKeyPress; - console.debug(' SearchControllerModule - Activated'); - } - - _disableModule() { - if (this._originalOnStageKeyPress) - Main.overview.searchController._onStageKeyPress = this._originalOnStageKeyPress; - this._originalOnStageKeyPress = null; - - console.debug(' SearchControlerModule - Disabled'); - } -}; - -// if opt.ESC_BEHAVIOR > 0 force close the overview -const SearchControllerCommon = { - _onStageKeyPress(actor, event) { - // Ignore events while anything but the overview has - // pushed a modal (system modals, looking glass, ...) - if (Main.modalCount > 1) - return Clutter.EVENT_PROPAGATE; - - let symbol = event.get_key_symbol(); - if (symbol === Clutter.KEY_Escape) { - if (this._searchActive && !opt.ESC_BEHAVIOR) { - this.reset(); - } else if (this._showAppsButton.checked && !opt.ESC_BEHAVIOR) { - this._showAppsButton.checked = false; - } else { - this.reset(); - Main.overview.hide(); - } - - return Clutter.EVENT_STOP; - } else if (this._shouldTriggerSearch(symbol)) { - this.startSearch(event); - } - return Clutter.EVENT_PROPAGATE; - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/settings.js b/extensions/46/vertical-workspaces/lib/settings.js deleted file mode 100644 index dcfc8f9..0000000 --- a/extensions/46/vertical-workspaces/lib/settings.js +++ /dev/null @@ -1,535 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * settings.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - */ - -'use strict'; - -import GLib from 'gi://GLib'; - -let Me; - -export const Options = class Options { - constructor(me) { - Me = me; - - this._gsettings = Me.gSettings; - this._connectionIds = []; - this._writeTimeoutId = 0; - this._gsettings.delay(); - this.connect('changed', () => { - if (this._writeTimeoutId) - GLib.Source.remove(this._writeTimeoutId); - - this._writeTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 400, - () => { - this._gsettings.apply(); - this._updateCachedSettings(); - this._writeTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); - }); - this.options = { - workspaceThumbnailsPosition: ['int', 'ws-thumbnails-position'], - wsMaxSpacing: ['int', 'ws-max-spacing'], - wsPreviewScale: ['int', 'ws-preview-scale'], - secWsPreviewScale: ['int', 'secondary-ws-preview-scale'], - secWsPreviewShift: ['boolean', 'secondary-ws-preview-shift'], - wsThumbnailsFull: ['boolean', 'ws-thumbnails-full'], - secWsThumbnailsPosition: ['int', 'secondary-ws-thumbnails-position'], - dashPosition: ['int', 'dash-position'], - dashPositionAdjust: ['int', 'dash-position-adjust'], - wsTmbPositionAdjust: ['int', 'wst-position-adjust'], - showWsTmbLabels: ['int', 'show-wst-labels'], - showWsTmbLabelsOnHover: ['boolean', 'show-wst-labels-on-hover'], - closeWsButtonMode: ['int', 'close-ws-button-mode'], - secWsTmbPositionAdjust: ['int', 'sec-wst-position-adjust'], - dashMaxIconSize: ['int', 'dash-max-icon-size'], - centerDashToWs: ['boolean', 'center-dash-to-ws'], - showAppsIconPosition: ['int', 'show-app-icon-position'], - wsThumbnailScale: ['int', 'ws-thumbnail-scale'], - wsThumbnailScaleAppGrid: ['int', 'ws-thumbnail-scale-appgrid'], - secWsThumbnailScale: ['int', 'secondary-ws-thumbnail-scale'], - showSearchEntry: ['boolean', 'show-search-entry'], - centerSearch: ['boolean', 'center-search'], - centerAppGrid: ['boolean', 'center-app-grid'], - dashBgOpacity: ['int', 'dash-bg-opacity'], - dashBgColor: ['int', 'dash-bg-color'], - dashBgRadius: ['int', 'dash-bg-radius'], - dashBgGS3Style: ['boolean', 'dash-bg-gs3-style'], - runningDotStyle: ['int', 'running-dot-style'], - enablePageShortcuts: ['boolean', 'enable-page-shortcuts'], - showWsSwitcherBg: ['boolean', 'show-ws-switcher-bg'], - showWsPreviewBg: ['boolean', 'show-ws-preview-bg'], - wsPreviewBgRadius: ['int', 'ws-preview-bg-radius'], - showBgInOverview: ['boolean', 'show-bg-in-overview'], - overviewBgBrightness: ['int', 'overview-bg-brightness'], - searchBgBrightness: ['int', 'search-bg-brightness'], - overviewBgBlurSigma: ['int', 'overview-bg-blur-sigma'], - appGridBgBlurSigma: ['int', 'app-grid-bg-blur-sigma'], - smoothBlurTransitions: ['boolean', 'smooth-blur-transitions'], - appGridAnimation: ['int', 'app-grid-animation'], - searchViewAnimation: ['int', 'search-view-animation'], - workspaceAnimation: ['int', 'workspace-animation'], - animationSpeedFactor: ['int', 'animation-speed-factor'], - winPreviewIconSize: ['int', 'win-preview-icon-size'], - winTitlePosition: ['int', 'win-title-position'], - startupState: ['int', 'startup-state'], - overviewMode: ['int', 'overview-mode'], - workspaceSwitcherAnimation: ['int', 'workspace-switcher-animation'], - wsSwitcherMode: ['int', 'ws-switcher-mode'], - searchIconSize: ['int', 'search-icon-size'], - searchViewScale: ['int', 'search-width-scale'], - appGridIconSize: ['int', 'app-grid-icon-size'], - appGridColumns: ['int', 'app-grid-columns'], - appGridRows: ['int', 'app-grid-rows'], - appGridFolderIconSize: ['int', 'app-grid-folder-icon-size'], - appGridFolderColumns: ['int', 'app-grid-folder-columns'], - appGridFolderRows: ['int', 'app-grid-folder-rows'], - appGridFolderIconGrid: ['int', 'app-grid-folder-icon-grid'], - appGridContent: ['int', 'app-grid-content'], - appGridIncompletePages: ['boolean', 'app-grid-incomplete-pages'], - appGridOrder: ['int', 'app-grid-order'], - appFolderOrder: ['int', 'app-folder-order'], - appGridNamesMode: ['int', 'app-grid-names'], - appGridActivePreview: ['boolean', 'app-grid-active-preview'], - appGridFolderCenter: ['boolean', 'app-grid-folder-center'], - appGridPageWidthScale: ['int', 'app-grid-page-width-scale'], - appGridSpacing: ['int', 'app-grid-spacing'], - searchWindowsOrder: ['int', 'search-windows-order'], - searchFuzzy: ['boolean', 'search-fuzzy'], - searchMaxResultsRows: ['int', 'search-max-results-rows'], - dashShowWindowsBeforeActivation: ['int', 'dash-show-windows-before-activation'], - dashIconScroll: ['int', 'dash-icon-scroll'], - dashIsolateWorkspaces: ['boolean', 'dash-isolate-workspaces'], - searchWindowsIconScroll: ['int', 'search-windows-icon-scroll'], - panelVisibility: ['int', 'panel-visibility'], - panelPosition: ['int', 'panel-position'], - windowAttentionMode: ['int', 'window-attention-mode'], - wsSwPopupHPosition: ['int', 'ws-sw-popup-h-position'], - wsSwPopupVPosition: ['int', 'ws-sw-popup-v-position'], - wsSwPopupMode: ['int', 'ws-sw-popup-mode'], - wsSwitcherWraparound: ['boolean', 'ws-switcher-wraparound'], - wsSwitcherIgnoreLast: ['boolean', 'ws-switcher-ignore-last'], - favoritesNotify: ['int', 'favorites-notify'], - notificationPosition: ['int', 'notification-position'], - osdPosition: ['int', 'osd-position'], - hotCornerAction: ['int', 'hot-corner-action'], - hotCornerPosition: ['int', 'hot-corner-position'], - hotCornerFullscreen: ['boolean', 'hot-corner-fullscreen'], - hotCornerRipples: ['boolean', 'hot-corner-ripples'], - alwaysActivateSelectedWindow: ['boolean', 'always-activate-selected-window'], - winPreviewSecBtnAction: ['int', 'win-preview-sec-mouse-btn-action'], - winPreviewMidBtnAction: ['int', 'win-preview-mid-mouse-btn-action'], - winPreviewShowCloseButton: ['boolean', 'win-preview-show-close-button'], - windowIconClickAction: ['int', 'window-icon-click-action'], - overlayKeyPrimary: ['int', 'overlay-key-primary'], - overlayKeySecondary: ['int', 'overlay-key-secondary'], - overviewEscBehavior: ['int', 'overview-esc-behavior'], - newWindowFocusFix: ['boolean', 'new-window-focus-fix'], - newWindowMonitorFix: ['boolean', 'new-window-monitor-fix'], - appGridPerformance: ['boolean', 'app-grid-performance'], - highlightingStyle: ['int', 'highlighting-style'], - - workspaceSwitcherPopupModule: ['boolean', 'workspace-switcher-popup-module'], - workspaceAnimationModule: ['boolean', 'workspace-animation-module'], - workspaceModule: ['boolean', 'workspace-module'], - windowManagerModule: ['boolean', 'window-manager-module'], - windowPreviewModule: ['boolean', 'window-preview-module'], - windowAttentionHandlerModule: ['boolean', 'win-attention-handler-module'], - swipeTrackerModule: ['boolean', 'swipe-tracker-module'], - searchControllerModule: ['boolean', 'search-controller-module'], - searchModule: ['boolean', 'search-module'], - panelModule: ['boolean', 'panel-module'], - overlayKeyModule: ['boolean', 'overlay-key-module'], - osdWindowModule: ['boolean', 'osd-window-module'], - messageTrayModule: ['boolean', 'message-tray-module'], - layoutModule: ['boolean', 'layout-module'], - dashModule: ['boolean', 'dash-module'], - appFavoritesModule: ['boolean', 'app-favorites-module'], - appDisplayModule: ['boolean', 'app-display-module'], - - profileName1: ['string', 'profile-name-1'], - profileName2: ['string', 'profile-name-2'], - profileName3: ['string', 'profile-name-3'], - profileName4: ['string', 'profile-name-4'], - }; - this.cachedOptions = {}; - } - - connect(name, callback) { - const id = this._gsettings.connect(name, callback); - this._connectionIds.push(id); - return id; - } - - destroy() { - this._connectionIds.forEach(id => this._gsettings.disconnect(id)); - if (this._writeTimeoutId) { - GLib.source_remove(this._writeTimeoutId); - this._writeTimeoutId = 0; - } - - Me = null; - } - - _updateCachedSettings() { - Object.keys(this.options).forEach(v => this.get(v, true)); - } - - get(option, updateCache = false) { - if (!this.options[option]) { - console.error(`[${Me.metadata.name}] Error: Option ${option} is undefined.`); - return null; - } - - if (updateCache || this.cachedOptions[option] === undefined) { - const [, key, settings] = this.options[option]; - let gSettings; - if (settings !== undefined) - gSettings = settings(); - else - gSettings = this._gsettings; - - this.cachedOptions[option] = gSettings.get_value(key).deep_unpack(); - } - - return this.cachedOptions[option]; - } - - set(option, value) { - const [format, key, settings] = this.options[option]; - - let gSettings = this._gsettings; - - if (settings !== undefined) - gSettings = settings(); - - - switch (format) { - case 'boolean': - gSettings.set_boolean(key, value); - break; - case 'int': - gSettings.set_int(key, value); - break; - case 'string': - gSettings.set_string(key, value); - break; - case 'strv': - gSettings.set_strv(key, value); - break; - } - } - - getDefault(option) { - const [, key, settings] = this.options[option]; - - let gSettings = this._gsettings; - - if (settings !== undefined) - gSettings = settings(); - - - return gSettings.get_default_value(key).deep_unpack(); - } - - storeProfile(index) { - const profile = {}; - Object.keys(this.options).forEach(v => { - if (!v.startsWith('profileName')) - profile[v] = this.get(v).toString(); - }); - - this._gsettings.set_value(`profile-data-${index}`, new GLib.Variant('a{ss}', profile)); - } - - loadProfile(index) { - const options = this._gsettings.get_value(`profile-data-${index}`).deep_unpack(); - // set the aaa-loading-data so extension.js doesn't reset V-Shell after each profile item - // delayed gsettings writes are processed alphabetically, so this key will be processed first - this._gsettings.set_boolean('aaa-loading-profile', !this._gsettings.get_boolean('aaa-loading-profile')); - for (let o of Object.keys(options)) { - if (!this.options[o]) { - console.error(`[${Me.metadata.name}] Error: "${o}" is not a valid profile key -> Update your profile`); - continue; - } - const [type] = this.options[o]; - let value = options[o]; - switch (type) { - case 'string': - break; - case 'boolean': - value = value === 'true'; - break; - case 'int': - value = parseInt(value); - break; - } - - this.set(o, value); - } - } - - resetProfile(index) { - this._gsettings.reset(`profile-data-${index}`); - this._gsettings.reset(`profile-name-${index}`); - } - - _updateSettings() { - this._updateCachedSettings(); - this.DASH_BG_ALPHA = this.get('dashBgOpacity') / 100; - this.DASH_BG_OPACITY = this.get('dashBgOpacity') * 2.5; - this.DASH_BG_COLOR = this.get('dashBgColor'); - this.DASH_BG_RADIUS = this.get('dashBgRadius'); - this.DASH_BG_LIGHT = this.DASH_BG_COLOR === 1; - this.DASH_BG_GS3_STYLE = this.get('dashBgGS3Style'); - this.DASH_POSITION = this.get('dashModule') ? this.get('dashPosition') : 2; - this.DASH_TOP = this.DASH_POSITION === 0; - this.DASH_RIGHT = this.DASH_POSITION === 1; - this.DASH_BOTTOM = this.DASH_POSITION === 2; - this.DASH_LEFT = this.DASH_POSITION === 3; - this.DASH_VERTICAL = this.DASH_LEFT || this.DASH_RIGHT; - this.DASH_VISIBLE = this.DASH_POSITION !== 4; // 4 - disable - this.DASH_FOLLOW_RECENT_WIN = false; - - this.DASH_ISOLATE_WS = this.get('dashIsolateWorkspaces'); - - this.DASH_CLICK_ACTION = this.get('dashShowWindowsBeforeActivation'); - this.DASH_CLICK_SWITCH_BEFORE_ACTIVATION = this.DASH_CLICK_ACTION === 1; - this.DASH_CLICK_OPEN_NEW_WIN = this.DASH_CLICK_ACTION === 2; - this.DASH_CLICK_PREFER_WORKSPACE = this.DASH_CLICK_ACTION === 3; - - this.DASH_ICON_SCROLL = this.get('dashIconScroll'); - this.DASH_SHIFT_CLICK_MV = true; - - this.RUNNING_DOT_STYLE = this.get('runningDotStyle'); - - this.SEARCH_WINDOWS_ICON_SCROLL = this.get('searchWindowsIconScroll'); - - this.DASH_POSITION_ADJUSTMENT = this.get('dashPositionAdjust'); - this.DASH_POSITION_ADJUSTMENT = this.DASH_POSITION_ADJUSTMENT * -1 / 100; // range 1 to -1 - this.CENTER_DASH_WS = this.get('centerDashToWs'); - - this.MAX_ICON_SIZE = this.get('dashMaxIconSize'); - - this.WS_TMB_POSITION = this.get('workspaceThumbnailsPosition'); - this.ORIENTATION = this.WS_TMB_POSITION > 4 ? 0 : 1; - this.WORKSPACE_MAX_SPACING = this.get('wsMaxSpacing'); - // ORIENTATION || DASH_LEFT || DASH_RIGHT ? 350 : 80; - this.SHOW_WS_TMB = ![4, 9].includes(this.WS_TMB_POSITION); // 4, 9 - disable - this.WS_TMB_FULL = this.get('wsThumbnailsFull'); - // translate ws tmb position to 0 top, 1 right, 2 bottom, 3 left - // 0L 1R, 2LF, 3RF, 4DV, 5T, 6B, 7TF, 8BF, 9DH - this.WS_TMB_POSITION = [3, 1, 3, 1, 4, 0, 2, 0, 2, 8][this.WS_TMB_POSITION]; - this.WS_TMB_TOP = this.WS_TMB_POSITION === 0; - this.WS_TMB_RIGHT = this.WS_TMB_POSITION === 1; - this.WS_TMB_BOTTOM = this.WS_TMB_POSITION === 2; - this.WS_TMB_LEFT = this.WS_TMB_POSITION === 3; - this.WS_TMB_POSITION_ADJUSTMENT = this.get('wsTmbPositionAdjust') * -1 / 100; // range 1 to -1 - this.SEC_WS_TMB_POSITION = this.get('secWsThumbnailsPosition'); - this.SHOW_SEC_WS_TMB = this.SEC_WS_TMB_POSITION !== 3 && this.SHOW_WS_TMB; - this.SEC_WS_TMB_TOP = (this.SEC_WS_TMB_POSITION === 0 && !this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_TOP); - this.SEC_WS_TMB_RIGHT = (this.SEC_WS_TMB_POSITION === 1 && this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_RIGHT); - this.SEC_WS_TMB_BOTTOM = (this.SEC_WS_TMB_POSITION === 1 && !this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_BOTTOM); - this.SEC_WS_TMB_LEFT = (this.SEC_WS_TMB_POSITION === 0 && this.ORIENTATION) || (this.SEC_WS_TMB_POSITION === 2 && this.WS_TMB_LEFT); - - this.SEC_WS_TMB_POSITION_ADJUSTMENT = this.get('secWsTmbPositionAdjust') * -1 / 100; // range 1 to -1 - this.SEC_WS_PREVIEW_SHIFT = this.get('secWsPreviewShift'); - this.SHOW_WST_LABELS = this.get('showWsTmbLabels'); - this.SHOW_WST_LABELS_ON_HOVER = this.get('showWsTmbLabelsOnHover'); - this.CLOSE_WS_BUTTON_MODE = this.get('closeWsButtonMode'); - - this.MAX_THUMBNAIL_SCALE = this.get('wsThumbnailScale') / 100; - if (this.MAX_THUMBNAIL_SCALE === 0) { - this.MAX_THUMBNAIL_SCALE = 0.01; - this.SHOW_WS_TMB = false; - } - this.MAX_THUMBNAIL_SCALE_APPGRID = this.get('wsThumbnailScaleAppGrid') / 100; - this.SHOW_WS_TMB_APPGRID = true; - if (this.MAX_THUMBNAIL_SCALE_APPGRID === 0) { - this.MAX_THUMBNAIL_SCALE_APPGRID = 0.01; - this.SHOW_WS_TMB_APPGRID = false; - } - this.MAX_THUMBNAIL_SCALE_STABLE = this.MAX_THUMBNAIL_SCALE === this.MAX_THUMBNAIL_SCALE_APPGRID; - - this.SEC_MAX_THUMBNAIL_SCALE = this.get('secWsThumbnailScale') / 100; - if (this.SEC_MAX_THUMBNAIL_SCALE === 0) { - this.SEC_MAX_THUMBNAIL_SCALE = 0.01; - this.SHOW_SEC_WS_TMB = false; - } - - this.WS_PREVIEW_SCALE = this.get('wsPreviewScale') / 100; - this.SEC_WS_PREVIEW_SCALE = this.get('secWsPreviewScale') / 100; - // calculate number of possibly visible neighbor previews according to ws scale - this.NUMBER_OF_VISIBLE_NEIGHBORS = Math.round(1 + (1 - this.WS_PREVIEW_SCALE) / 4); - - this.SHOW_WS_TMB_BG = this.get('showWsSwitcherBg') && this.SHOW_WS_TMB; - this.WS_PREVIEW_BG_RADIUS = this.get('wsPreviewBgRadius'); - this.SHOW_WS_PREVIEW_BG = this.get('showWsPreviewBg'); - - this.CENTER_APP_GRID = this.get('centerAppGrid'); - - this.SHOW_SEARCH_ENTRY = this.get('showSearchEntry'); - this.CENTER_SEARCH_VIEW = this.get('centerSearch'); - this.APP_GRID_ANIMATION = this.get('appGridAnimation'); - if (this.APP_GRID_ANIMATION === 4) - this.APP_GRID_ANIMATION = this._getAnimationDirection(); - - this.SEARCH_VIEW_ANIMATION = this.get('searchViewAnimation'); - if (this.SEARCH_VIEW_ANIMATION === 4) - this.SEARCH_VIEW_ANIMATION = 3; - - this.WIN_PREVIEW_ICON_SIZE = [64, 48, 32, 22, 8][this.get('winPreviewIconSize')]; - this.WIN_TITLES_POSITION = this.get('winTitlePosition'); - this.ALWAYS_SHOW_WIN_TITLES = this.WIN_TITLES_POSITION === 1; - - this.STARTUP_STATE = this.get('startupState'); - this.SHOW_BG_IN_OVERVIEW = this.get('showBgInOverview'); - this.OVERVIEW_BG_BRIGHTNESS = this.get('overviewBgBrightness') / 100; - this.SEARCH_BG_BRIGHTNESS = this.get('searchBgBrightness') / 100; - this.OVERVIEW_BG_BLUR_SIGMA = this.get('overviewBgBlurSigma'); - this.APP_GRID_BG_BLUR_SIGMA = this.get('appGridBgBlurSigma'); - this.SMOOTH_BLUR_TRANSITIONS = this.get('smoothBlurTransitions'); - - this.OVERVIEW_MODE = this.get('overviewMode'); - this.OVERVIEW_MODE2 = this.OVERVIEW_MODE === 2; - this.WORKSPACE_MODE = this.OVERVIEW_MODE ? 0 : 1; - - this.STATIC_WS_SWITCHER_BG = this.get('workspaceSwitcherAnimation'); - - this.ANIMATION_TIME_FACTOR = this.get('animationSpeedFactor') / 100; - - this.SEARCH_ICON_SIZE = this.get('searchIconSize'); - this.SEARCH_VIEW_SCALE = this.get('searchViewScale') / 100; - this.SEARCH_MAX_ROWS = this.get('searchMaxResultsRows'); - this.SEARCH_FUZZY = this.get('searchFuzzy'); - this.SEARCH_DELAY = 0; - - this.APP_GRID_ALLOW_INCOMPLETE_PAGES = this.get('appGridIncompletePages'); - this.APP_GRID_ICON_SIZE = this.get('appGridIconSize'); - this.APP_GRID_COLUMNS = this.get('appGridColumns'); - this.APP_GRID_ROWS = this.get('appGridRows'); - this.APP_GRID_ADAPTIVE = !this.APP_GRID_COLUMNS && !this.APP_GRID_ROWS; - - this.APP_GRID_ORDER = this.get('appGridOrder'); - this.APP_GRID_ALPHABET = [1, 2].includes(this.APP_GRID_ORDER); - this.APP_GRID_FOLDERS_FIRST = this.APP_GRID_ORDER === 1; - this.APP_GRID_FOLDERS_LAST = this.APP_GRID_ORDER === 2; - this.APP_GRID_USAGE = this.APP_GRID_ORDER === 3; - - this.APP_FOLDER_ORDER = this.get('appFolderOrder'); - this.APP_FOLDER_ALPHABET = this.APP_FOLDER_ORDER === 1; - this.APP_FOLDER_USAGE = this.APP_FOLDER_ORDER === 2; - - this.APP_GRID_INCLUDE_DASH = this.get('appGridContent'); - /* APP_GRID_INCLUDE_DASH - 0 - Include All - 1 - Include All - Favorites and Runnings First - 2 - Exclude Favorites (Default) - 3 - Exclude Running - 4 - Exclude Favorites and Running - */ - this.APP_GRID_EXCLUDE_FAVORITES = this.APP_GRID_INCLUDE_DASH === 2 || this.APP_GRID_INCLUDE_DASH === 4; - this.APP_GRID_EXCLUDE_RUNNING = this.APP_GRID_INCLUDE_DASH === 3 || this.APP_GRID_INCLUDE_DASH === 4; - this.APP_GRID_DASH_FIRST = this.APP_GRID_INCLUDE_DASH === 1; - - this.APP_GRID_NAMES_MODE = this.get('appGridNamesMode'); - - this.APP_GRID_FOLDER_ICON_SIZE = this.get('appGridFolderIconSize'); - this.APP_GRID_FOLDER_ICON_GRID = this.get('appGridFolderIconGrid'); - this.APP_GRID_FOLDER_COLUMNS = this.get('appGridFolderColumns'); - this.APP_GRID_FOLDER_ROWS = this.get('appGridFolderRows'); - this.APP_GRID_SPACING = this.get('appGridSpacing'); - this.APP_GRID_FOLDER_DEFAULT = this.APP_GRID_FOLDER_ROWS === 3 && this.APP_GRID_FOLDER_COLUMNS === 3; - this.APP_GRID_FOLDER_ADAPTIVE = !this.APP_GRID_FOLDER_COLUMNS && !this.APP_GRID_FOLDER_ROWS; - this.APP_GRID_ACTIVE_PREVIEW = this.get('appGridActivePreview'); - this.APP_GRID_FOLDER_CENTER = this.get('appGridFolderCenter'); - this.APP_GRID_PAGE_WIDTH_SCALE = this.get('appGridPageWidthScale') / 100; - - this.APP_GRID_ICON_SIZE_DEFAULT = this.APP_GRID_ACTIVE_PREVIEW && !this.APP_GRID_USAGE ? 176 : 96; - this.APP_GRID_FOLDER_ICON_SIZE_DEFAULT = 96; - - this.APP_GRID_PERFORMANCE = this.get('appGridPerformance'); - - this.WINDOW_SEARCH_ORDER = this.get('searchWindowsOrder'); - - this.PANEL_POSITION_TOP = this.get('panelPosition') === 0; - this.PANEL_MODE = this.get('panelVisibility'); - this.PANEL_DISABLED = this.PANEL_MODE === 2; - this.PANEL_OVERVIEW_ONLY = this.PANEL_MODE === 1; - this.START_Y_OFFSET = 0; // set from main module - - this.WINDOW_ATTENTION_MODE = this.get('windowAttentionMode'); - this.WINDOW_ATTENTION_DISABLE_NOTIFICATIONS = this.WINDOW_ATTENTION_MODE === 1; - this.WINDOW_ATTENTION_FOCUS_IMMEDIATELY = this.WINDOW_ATTENTION_MODE === 2; - - this.WS_SW_POPUP_H_POSITION = this.get('wsSwPopupHPosition') / 100; - this.WS_SW_POPUP_V_POSITION = this.get('wsSwPopupVPosition') / 100; - this.WS_SW_POPUP_MODE = this.get('wsSwPopupMode'); - - this.WS_ANIMATION = this.get('workspaceAnimation'); - this.WS_WRAPAROUND = this.get('wsSwitcherWraparound'); - this.WS_IGNORE_LAST = this.get('wsSwitcherIgnoreLast'); - this.WS_SWITCHER_CURRENT_MONITOR = this.get('wsSwitcherMode') === 1; - - this.SHOW_FAV_NOTIFICATION = this.get('favoritesNotify'); - this.NOTIFICATION_POSITION = this.get('notificationPosition'); - - this.OSD_POSITION = this.get('osdPosition'); - - this.HOT_CORNER_ACTION = this.get('hotCornerAction'); - this.HOT_CORNER_POSITION = this.get('hotCornerPosition'); - if (this.HOT_CORNER_POSITION === 6 && this.DASH_VISIBLE) - this.HOT_CORNER_EDGE = true; - else - this.HOT_CORNER_EDGE = false; - if ([5, 6].includes(this.HOT_CORNER_POSITION)) { - if (this.DASH_TOP || this.DASH_LEFT) - this.HOT_CORNER_POSITION = 1; - else if (this.DASH_RIGHT) - this.HOT_CORNER_POSITION = 2; - else if (this.DASH_BOTTOM) - this.HOT_CORNER_POSITION = 3; - else - this.HOT_CORNER_POSITION = 0; - } - this.HOT_CORNER_FULLSCREEN = this.get('hotCornerFullscreen'); - this.HOT_CORNER_RIPPLES = this.get('hotCornerRipples'); - - this.ALWAYS_ACTIVATE_SELECTED_WINDOW = this.get('alwaysActivateSelectedWindow'); - this.WIN_PREVIEW_SEC_BTN_ACTION = this.get('winPreviewSecBtnAction'); - this.WIN_PREVIEW_MID_BTN_ACTION = this.get('winPreviewMidBtnAction'); - this.SHOW_CLOSE_BUTTON = this.get('winPreviewShowCloseButton'); - this.WINDOW_ICON_CLICK_ACTION = this.get('windowIconClickAction'); - - this.OVERLAY_KEY_PRIMARY = this.get('overlayKeyPrimary'); - this.OVERLAY_KEY_SECONDARY = this.get('overlayKeySecondary'); - - this.ESC_BEHAVIOR = this.get('overviewEscBehavior'); - - this.WINDOW_THUMBNAIL_ENABLED = !!Me.Util.getEnabledExtensions('window-thumbnails').length; - - this.FIX_NEW_WINDOW_FOCUS = this.get('newWindowFocusFix'); - this.FIX_NEW_WINDOW_MONITOR = this.get('newWindowMonitorFix'); - - this.HIGHLIGHTING_STYLE = this.get('highlightingStyle'); - this.HIGHLIGHT_DEFAULT = this.HIGHLIGHTING_STYLE === 0; - this.HIGHLIGHT_UNDERLINE = this.HIGHLIGHTING_STYLE === 1; - this.HIGHLIGHT_NONE = this.HIGHLIGHTING_STYLE === 2; - } - - _getAnimationDirection() { - if (this.ORIENTATION) - return this.WS_TMB_LEFT || !this.SHOW_WS_TMB ? 1 : 2; // 1 right, 2 left - else - return this.WS_TMB_TOP || !this.SHOW_WS_TMB ? 3 : 5; // 3 bottom, 5 top - } -}; diff --git a/extensions/46/vertical-workspaces/lib/swipeTracker.js b/extensions/46/vertical-workspaces/lib/swipeTracker.js deleted file mode 100644 index 560b296..0000000 --- a/extensions/46/vertical-workspaces/lib/swipeTracker.js +++ /dev/null @@ -1,116 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * swipeTracker.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; -import GObject from 'gi://GObject'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as SwipeTracker from 'resource:///org/gnome/shell/ui/swipeTracker.js'; - -let Me; -let opt; - -export const SwipeTrackerModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this.moduleEnabled = opt.get('swipeTrackerModule'); - 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(' SwipeTrackerModule - Keeping untouched'); - } - - _activateModule() { - if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL - this._setVertical(); - } else { - this._setHorizontal(); - } - console.debug(' SwipeTrackerModule - Activated'); - } - - _disableModule() { - this._setHorizontal(); - - console.debug(' SwipeTrackerModule - Disabled'); - } - - _setVertical() { - // reverse swipe gestures for enter/leave overview and ws switching - Main.overview._swipeTracker.orientation = Clutter.Orientation.HORIZONTAL; - Main.wm._workspaceAnimation._swipeTracker.orientation = Clutter.Orientation.VERTICAL; - // overview's updateGesture() function should reflect ws tmb position to match appGrid/ws animation direction - // function in connection cannot be overridden in prototype of its class because connected is actually another copy of the original function - if (!this._originalGestureUpdateId) { - this._originalGestureUpdateId = GObject.signal_handler_find(Main.overview._swipeTracker._touchpadGesture, { signalId: 'update' }); - Main.overview._swipeTracker._touchpadGesture.block_signal_handler(this._originalGestureUpdateId); - Main.overview._swipeTracker._updateGesture = SwipeTrackerVertical._updateGesture; - this._vwGestureUpdateId = Main.overview._swipeTracker._touchpadGesture.connect('update', SwipeTrackerVertical._updateGesture.bind(Main.overview._swipeTracker)); - } - } - - _setHorizontal() { - // original swipeTrackers' orientation and updateGesture function - Main.overview._swipeTracker.orientation = Clutter.Orientation.VERTICAL; - Main.wm._workspaceAnimation._swipeTracker.orientation = Clutter.Orientation.HORIZONTAL; - Main.overview._swipeTracker._updateGesture = SwipeTracker.SwipeTracker.prototype._updateGesture; - if (this._vwGestureUpdateId) { - Main.overview._swipeTracker._touchpadGesture.disconnect(this._vwGestureUpdateId); - this._vwGestureUpdateId = 0; - } - if (this._originalGestureUpdateId) { - Main.overview._swipeTracker._touchpadGesture.unblock_signal_handler(this._originalGestureUpdateId); - this._originalGestureUpdateId = 0; - } - } -}; - -const SwipeTrackerVertical = { - _updateGesture(gesture, time, delta, distance) { - if (this._state !== 1) // State.SCROLLING) - return; - - if ((this._allowedModes & Main.actionMode) === 0 || !this.enabled) { - this._interrupt(); - return; - } - - if (opt.WS_TMB_RIGHT) - delta = -delta; - this._progress += delta / distance; - this._history.append(time, delta); - - this._progress = Math.clamp(this._progress, ...this._getBounds(this._initialProgress)); - this.emit('update', this._progress); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/util.js b/extensions/46/vertical-workspaces/lib/util.js deleted file mode 100644 index ab79c48..0000000 --- a/extensions/46/vertical-workspaces/lib/util.js +++ /dev/null @@ -1,375 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * util.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import Clutter from 'gi://Clutter'; -import Meta from 'gi://Meta'; -import Shell from 'gi://Shell'; -import Gio from 'gi://Gio'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import { InjectionManager } from 'resource:///org/gnome/shell/extensions/extension.js'; - -let Me; -let _installedExtensions; - -export function init(me) { - Me = me; -} - -export function cleanGlobals() { - Me = null; - _installedExtensions = null; -} - -export class Overrides extends InjectionManager { - constructor() { - super(); - this._overrides = {}; - } - - addOverride(name, prototype, overrideList) { - const backup = this.overrideProto(prototype, overrideList, name); - // don't update originals when override's just refreshing, keep initial content - let originals = this._overrides[name]?.originals; - if (!originals) - originals = backup; - this._overrides[name] = { - originals, - prototype, - }; - } - - removeOverride(name) { - const override = this._overrides[name]; - if (!override) - return false; - - this.overrideProto(override.prototype, override.originals, name); - delete this._overrides[name]; - return true; - } - - removeAll() { - for (let name in this._overrides) { - this.removeOverride(name); - delete this._overrides[name]; - } - } - - overrideProto(proto, overrides, name) { - const backup = {}; - const originals = this._overrides[name]?.originals; - for (let symbol in overrides) { - if (symbol.startsWith('after_')) { - const actualSymbol = symbol.slice('after_'.length); - let fn; - if (originals && originals[actualSymbol]) - fn = originals[actualSymbol]; - else - fn = proto[actualSymbol]; - const afterFn = overrides[symbol]; - proto[actualSymbol] = function (...args) { - args = Array.prototype.slice.call(args); - const res = fn.apply(this, args); - afterFn.apply(this, args); - return res; - }; - backup[actualSymbol] = fn; - } else if (overrides[symbol] !== null) { - backup[symbol] = proto[symbol]; - this._installMethod(proto, symbol, overrides[symbol]); - } - } - return backup; - } -} - -export function openPreferences(metadata) { - if (!metadata) - metadata = Me.metadata; - const windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null); - let tracker = Shell.WindowTracker.get_default(); - let metaWin, isMe = null; - - for (let win of windows) { - const app = tracker.get_window_app(win); - if (win.get_title()?.includes(metadata.name) && app.get_name() === 'Extensions') { - // this is our existing window - metaWin = win; - isMe = true; - break; - } else if (win.wm_class?.includes('org.gnome.Shell.Extensions')) { - // this is prefs window of another extension - metaWin = win; - isMe = false; - } - } - - if (metaWin && !isMe) { - // other prefs window blocks opening another prefs window, so close it - metaWin.delete(global.get_current_time()); - } else if (metaWin && isMe) { - // if prefs window already exist, move it to the current WS and activate it - metaWin.change_workspace(global.workspace_manager.get_active_workspace()); - metaWin.activate(global.get_current_time()); - } - - if (!metaWin || (metaWin && !isMe)) { - // delay to avoid errors if previous prefs window has been colsed - GLib.idle_add(GLib.PRIORITY_LOW, () => { - try { - Main.extensionManager.openExtensionPrefs(metadata.uuid, '', {}); - } catch (e) { - console.error(e); - } - }); - } -} - -export function activateSearchProvider(prefix = '') { - const searchEntry = Main.overview.searchEntry; - if (!searchEntry.get_text() || !searchEntry.get_text().startsWith(prefix)) { - prefix = `${prefix} `; - const position = prefix.length; - searchEntry.set_text(prefix); - searchEntry.get_first_child().set_cursor_position(position); - searchEntry.get_first_child().set_selection(position, position); - } else { - searchEntry.set_text(''); - } -} - -export function dashNotDefault() { - return Main.overview.dash !== Main.overview._overview._controls.layoutManager._dash; -} - -export function dashIsDashToDock() { - return Main.overview.dash._isHorizontal !== undefined; -} - -// Reorder Workspaces - callback for Dash and workspacesDisplay -export function reorderWorkspace(direction = 0) { - let activeWs = global.workspace_manager.get_active_workspace(); - let activeWsIdx = activeWs.index(); - let targetIdx = activeWsIdx + direction; - if (targetIdx > -1 && targetIdx < global.workspace_manager.get_n_workspaces()) - global.workspace_manager.reorder_workspace(activeWs, targetIdx); -} - -export function activateKeyboardForWorkspaceView() { - Main.ctrlAltTabManager._items.forEach(i => { - if (i.sortGroup === 1 && i.name === 'Windows') - Main.ctrlAltTabManager.focusGroup(i); - }); -} - -export function exposeWindows(adjustment, activateKeyboard) { - // expose windows for static overview modes - if (!adjustment.value && !Main.overview._animationInProgress) { - if (adjustment.value === 0) { - adjustment.value = 0; - adjustment.ease(1, { - duration: 200, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - if (activateKeyboard) { - Main.ctrlAltTabManager._items.forEach(i => { - if (i.sortGroup === 1 && i.name === 'Windows') - Main.ctrlAltTabManager.focusGroup(i); - }); - } - }, - }); - } - } -} - -export function isShiftPressed(state = null) { - if (state === null) - [,, state] = global.get_pointer(); - return (state & Clutter.ModifierType.SHIFT_MASK) !== 0; -} - -export function isCtrlPressed(state = null) { - if (state === null) - [,, state] = global.get_pointer(); - return (state & Clutter.ModifierType.CONTROL_MASK) !== 0; -} - -export function isAltPressed(state = null) { - if (state === null) - [,, state] = global.get_pointer(); - return (state & Clutter.ModifierType.MOD1_MASK) !== 0; -} - -export function fuzzyMatch(term, text) { - let pos = -1; - const matches = []; - // convert all accented chars to their basic form and to lower case - const _text = text.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(); - const _term = term.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(); - - // if term matches the substring exactly, gains the highest weight - if (_text.includes(_term)) - return 0; - - for (let i = 0; i < _term.length; i++) { - let c = _term[i]; - let p; - if (pos > 0) - p = _term[i - 1]; - while (true) { - pos += 1; - if (pos >= _text.length) - return -1; - - if (_text[pos] === c) { - matches.push(pos); - break; - } else if (_text[pos] === p) { - matches.pop(); - matches.push(pos); - } - } - } - - // add all position to get a weight of the result - // results closer to the beginning of the text and term characters closer to each other will gain more weight. - return matches.reduce((r, p) => r + p) - matches.length * matches[0] + matches[0]; -} - -export function strictMatch(term, text) { - // remove diacritics and accents from letters - let s = text.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(); - let p = term.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(); - let ps = p.split(/ +/); - - // allows to use multiple exact patterns separated by a space in arbitrary order - for (let w of ps) { // escape regex control chars - if (!s.match(w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))) - return -1; - } - return 0; -} - -export function isMoreRelevant(stringA, stringB, pattern) { - let regex = /[^a-zA-Z\d]/; - let strSplitA = stringA.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().split(regex); - let strSplitB = stringB.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().split(regex); - let aAny = false; - strSplitA.forEach(w => { - aAny = aAny || w.startsWith(pattern); - }); - let bAny = false; - strSplitB.forEach(w => { - bAny = bAny || w.startsWith(pattern); - }); - - // if both strings contain a word that starts with the pattern - // prefer the one whose first word starts with the pattern - if (aAny && bAny) - return !strSplitA[0].startsWith(pattern) && strSplitB[0].startsWith(pattern); - else - return !aAny && bAny; -} - -export function getEnabledExtensions(pattern = '') { - let result = []; - // extensionManager is unreliable at startup because it is uncertain whether all extensions have been loaded - // also gsettings key can contain already removed extensions (user deleted them without disabling them first) - // therefore we have to check what's really installed in the filesystem - if (!_installedExtensions) { - const extensionFiles = [...collectFromDatadirs('extensions', true)]; - _installedExtensions = extensionFiles.map(({ info }) => { - let fileType = info.get_file_type(); - if (fileType !== Gio.FileType.DIRECTORY) - return null; - const uuid = info.get_name(); - return uuid; - }); - } - // _enabledExtensions contains content of the enabled-extensions key from gsettings, not actual state - const enabled = Main.extensionManager._enabledExtensions; - result = _installedExtensions.filter(ext => enabled.includes(ext)); - // _extensions contains already loaded extensions, so we can try to filter out broken or incompatible extensions - const active = Main.extensionManager._extensions; - result = result.filter(ext => { - const extension = active.get(ext); - if (extension) - return ![3, 4].includes(extension.state); // 3 - ERROR, 4 - OUT_OF_TIME (not supported by shell-version in metadata) - // extension can be enabled but not yet loaded, we just cannot see its state at this moment, so let it pass as enabled - return true; - }); - // return only extensions matching the search pattern - return result.filter(uuid => uuid !== null && uuid.includes(pattern)); -} - -function* collectFromDatadirs(subdir, includeUserDir) { - let dataDirs = GLib.get_system_data_dirs(); - if (includeUserDir) - dataDirs.unshift(GLib.get_user_data_dir()); - - for (let i = 0; i < dataDirs.length; i++) { - let path = GLib.build_filenamev([dataDirs[i], 'gnome-shell', subdir]); - let dir = Gio.File.new_for_path(path); - - let fileEnum; - try { - fileEnum = dir.enumerate_children('standard::name,standard::type', - Gio.FileQueryInfoFlags.NONE, null); - } catch (e) { - fileEnum = null; - } - if (fileEnum !== null) { - let info; - while ((info = fileEnum.next_file(null))) - yield { dir: fileEnum.get_child(info), info }; - } - } -} - -export function getScrollDirection(event) { - // scroll wheel provides two types of direction information: - // 1. Clutter.ScrollDirection.DOWN / Clutter.ScrollDirection.UP - // 2. Clutter.ScrollDirection.SMOOTH + event.get_scroll_delta() - // first SMOOTH event returns 0 delta, - // so we need to always read event.direction - // since mouse without smooth scrolling provides exactly one SMOOTH event on one wheel rotation click - // on the other hand, under X11, one wheel rotation click sometimes doesn't send direction event, only several SMOOTH events - // so we also need to convert the delta to direction - let direction = event.get_scroll_direction(); - - if (direction !== Clutter.ScrollDirection.SMOOTH) - return direction; - - let [, delta] = event.get_scroll_delta(); - - if (!delta) - return null; - - direction = delta > 0 ? Clutter.ScrollDirection.DOWN : Clutter.ScrollDirection.UP; - - return direction; -} - -export function getWindows(workspace) { - // We ignore skip-taskbar windows in switchers, but if they are attached - // to their parent, their position in the MRU list may be more appropriate - // than the parent; so start with the complete list ... - let windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, workspace); - // ... map windows to their parent where appropriate ... - return windows.map(w => { - return w.is_attached_dialog() ? w.get_transient_for() : w; - // ... and filter out skip-taskbar windows and duplicates - }).filter((w, i, a) => !w.skip_taskbar && a.indexOf(w) === i); -} diff --git a/extensions/46/vertical-workspaces/lib/windowAttentionHandler.js b/extensions/46/vertical-workspaces/lib/windowAttentionHandler.js deleted file mode 100644 index 744f5b6..0000000 --- a/extensions/46/vertical-workspaces/lib/windowAttentionHandler.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowAttentionHandler.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as MessageTray from 'resource:///org/gnome/shell/ui/messageTray.js'; - -let Me; -let opt; - -export const WindowAttentionHandlerModule = 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('windowAttentionHandlerModule'); - 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(' WindowAttentionHandlerModule - Keeping untouched'); - } - - _activateModule() { - this._updateConnections(); - console.debug(' WindowAttentionHandlerModule - Activated'); - } - - _disableModule() { - const reset = true; - this._updateConnections(reset); - - console.debug(' WindowAttentionHandlerModule - Disabled'); - } - - _updateConnections(reset) { - global.display.disconnectObject(Main.windowAttentionHandler); - - const handlerFnc = reset - ? Main.windowAttentionHandler._onWindowDemandsAttention - : WindowAttentionHandlerCommon._onWindowDemandsAttention; - - global.display.connectObject( - 'window-demands-attention', handlerFnc.bind(Main.windowAttentionHandler), - 'window-marked-urgent', handlerFnc.bind(Main.windowAttentionHandler), - Main.windowAttentionHandler); - } -}; - -const WindowAttentionHandlerCommon = { - _onWindowDemandsAttention(display, window) { - // Deny attention notifications if the App Grid is open, to avoid notification spree when opening a folder - if (Main.overview._shown && Main.overview.dash.showAppsButton.checked) { - return; - } else if (opt.WINDOW_ATTENTION_FOCUS_IMMEDIATELY) { - if (!Main.overview._shown) - Main.activateWindow(window); - return; - } - - const app = this._tracker.get_window_app(window); - // const source = new WindowAttentionHandler.WindowAttentionSource(app, window); - let args; - if (!Main.overview.dash.add_actor) // detects GS 46 - Clutter.Container has been removed - args = { title: app.get_name() }; - else - args = app.get_name(); - - const source = new MessageTray.Source(args); - new Me.Util.Overrides().addOverride('MessageSource', source, WindowAttentionSourceCommon); - source._init(app, window); - Main.messageTray.add(source); - - let [title, banner] = this._getTitleAndBanner(app, window); - - const notification = new MessageTray.Notification(source, title, banner); - notification.connect('activated', () => { - source.open(); - }); - notification.setForFeedback(true); - - if (opt.WINDOW_ATTENTION_DISABLE_NOTIFICATIONS) - // just push the notification to the message tray without showing notification - source.pushNotification(notification); - else - source.showNotification(notification); - - window.connectObject('notify::title', () => { - [title, banner] = this._getTitleAndBanner(app, window); - notification.update(title, banner); - }, source); - }, -}; - -const WindowAttentionSourceCommon = { - _init(app, window) { - this._window = window; - this._app = app; - - this._window.connectObject( - 'notify::demands-attention', this._sync.bind(this), - 'notify::urgent', this._sync.bind(this), - 'focus', () => this.destroy(), - 'unmanaged', () => this.destroy(), this); - }, - - _sync() { - if (this._window.demands_attention || this._window.urgent) - return; - this.destroy(); - }, - - _createPolicy() { - if (this._app && this._app.get_app_info()) { - let id = this._app.get_id().replace(/\.desktop$/, ''); - return new MessageTray.NotificationApplicationPolicy(id); - } else { - return new MessageTray.NotificationGenericPolicy(); - } - }, - - createIcon(size) { - return this._app.create_icon_texture(size); - }, - - destroy(params) { - this._window.disconnectObject(this); - - MessageTray.Source.prototype.destroy.bind(this)(params); - }, - - open() { - Main.activateWindow(this._window); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/windowManager.js b/extensions/46/vertical-workspaces/lib/windowManager.js deleted file mode 100644 index a6f9b09..0000000 --- a/extensions/46/vertical-workspaces/lib/windowManager.js +++ /dev/null @@ -1,380 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowManager.js - * - * @author GdH <G-dH@github.com> - * @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); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/windowPreview.js b/extensions/46/vertical-workspaces/lib/windowPreview.js deleted file mode 100644 index 3253aa5..0000000 --- a/extensions/46/vertical-workspaces/lib/windowPreview.js +++ /dev/null @@ -1,619 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowPreview.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @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 Pango from 'gi://Pango'; -import Graphene from 'gi://Graphene'; -import Atk from 'gi://Atk'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'; -import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'; -import * as WindowPreview from 'resource:///org/gnome/shell/ui/windowPreview.js'; - -let Me; -let opt; - -const WINDOW_SCALE_TIME = 200; -const WINDOW_ACTIVE_SIZE_INC = 5; -const WINDOW_OVERLAY_FADE_TIME = 200; -const WINDOW_DND_SIZE = 256; -const DRAGGING_WINDOW_OPACITY = 100; - -const ControlsState = OverviewControls.ControlsState; - -export const WindowPreviewModule = 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('windowPreviewModule'); - 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(' WindowPreviewModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._overrides.addOverride('WindowPreview', WindowPreview.WindowPreview.prototype, WindowPreviewCommon); - // 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; // incompatible - console.debug(' WindowPreviewModule - Activated'); - } - - _disableModule() { - // If WindowPreview._init was injected by another extension (like Burn My Windows) - // which enables/disables before V-Shell - // don't restore the original if it's not injected, - // because it would restore injected _init and recursion would freeze GS when extensions are enabled again. - // This can happen when all extension re-enabled, not only when screen is locked/unlocked - // If _init doesn't include "fn.apply(this, args)" when reset === true, some extension already restored the original - const skipReset = WindowPreview.WindowPreview.prototype._init.toString().includes('fn.apply(this, args)'); - if (this._overrides && skipReset) { - // skip restoring original _init() - this._overrides['_init'] = null; - } - - if (this._overrides) - this._overrides.removeAll(); - - this._overrides = null; - - console.debug(' WindowPreviewModule - Disabled'); - } -}; - -const WindowPreviewCommon = { - _init(metaWindow, workspace, overviewAdjustment) { - this.metaWindow = metaWindow; - this.metaWindow._delegate = this; - this._windowActor = metaWindow.get_compositor_private(); - this._workspace = workspace; - this._overviewAdjustment = overviewAdjustment; - - const ICON_SIZE = opt.WIN_PREVIEW_ICON_SIZE; - const ICON_OVERLAP = 0.7; - - Shell.WindowPreview.prototype._init.bind(this)({ - reactive: true, - can_focus: true, - accessible_role: Atk.Role.PUSH_BUTTON, - offscreen_redirect: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY, - }); - - const windowContainer = new Clutter.Actor({ - pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }), - }); - this.window_container = windowContainer; - - windowContainer.connect('notify::scale-x', - () => this._adjustOverlayOffsets()); - // gjs currently can't handle setting an actors layout manager during - // the initialization of the actor if that layout manager keeps track - // of its container, so set the layout manager after creating the - // container - windowContainer.layout_manager = new Shell.WindowPreviewLayout(); - this.add_child(windowContainer); - - this._addWindow(metaWindow); - - this._delegate = this; - - this._stackAbove = null; - - this._cachedBoundingBox = { - x: windowContainer.layout_manager.bounding_box.x1, - y: windowContainer.layout_manager.bounding_box.y1, - width: windowContainer.layout_manager.bounding_box.get_width(), - height: windowContainer.layout_manager.bounding_box.get_height(), - }; - - windowContainer.layout_manager.connect( - 'notify::bounding-box', layout => { - this._cachedBoundingBox = { - x: layout.bounding_box.x1, - y: layout.bounding_box.y1, - width: layout.bounding_box.get_width(), - height: layout.bounding_box.get_height(), - }; - - // A bounding box of 0x0 means all windows were removed - if (layout.bounding_box.get_area() > 0) - this.emit('size-changed'); - }); - - this._windowActor.connectObject('destroy', () => this.destroy(), this); - - this._updateAttachedDialogs(); - - let clickAction = new Clutter.ClickAction(); - clickAction.connect('clicked', act => { - const button = act.get_button(); - if (button === Clutter.BUTTON_SECONDARY) { - if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 1) { - this._closeWinAction(); - return Clutter.EVENT_STOP; - } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 2) { - this._searchAppWindowsAction(); - return Clutter.EVENT_STOP; - } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 3 && global.windowThumbnails) { - this._removeLaters(); - global.windowThumbnails?.createThumbnail(metaWindow); - return Clutter.EVENT_STOP; - } - } else if (button === Clutter.BUTTON_MIDDLE) { - if (opt.WIN_PREVIEW_MID_BTN_ACTION === 1) { - this._closeWinAction(); - return Clutter.EVENT_STOP; - } else if (opt.WIN_PREVIEW_MID_BTN_ACTION === 2) { - this._searchAppWindowsAction(); - return Clutter.EVENT_STOP; - } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 3 && global.windowThumbnails) { - this._removeLaters(); - global.windowThumbnails?.createThumbnail(metaWindow); - return Clutter.EVENT_STOP; - } - } - return this._activate(); - }); - - - if (this._onLongPress) { - clickAction.connect('long-press', this._onLongPress.bind(this)); - } else { - clickAction.connect('long-press', (action, actor, state) => { - if (state === Clutter.LongPressState.ACTIVATE) - this.showOverlay(true); - return true; - }); - } - - this.connect('destroy', this._onDestroy.bind(this)); - - this._draggable = DND.makeDraggable(this, { - restoreOnSuccess: true, - manualMode: !!this._onLongPress, - dragActorMaxSize: WINDOW_DND_SIZE, - dragActorOpacity: DRAGGING_WINDOW_OPACITY, - }); - - // _draggable.addClickAction is new in GS45 - if (this._draggable.addClickAction) - this._draggable.addClickAction(clickAction); - else - this.add_action(clickAction); - - this._draggable.connect('drag-begin', this._onDragBegin.bind(this)); - this._draggable.connect('drag-cancelled', this._onDragCancelled.bind(this)); - this._draggable.connect('drag-end', this._onDragEnd.bind(this)); - this.inDrag = false; - - this._selected = false; - this._overlayEnabled = true; - this._overlayShown = false; - this._closeRequested = false; - this._idleHideOverlayId = 0; - - const tracker = Shell.WindowTracker.get_default(); - const app = tracker.get_window_app(this.metaWindow); - this._icon = app.create_icon_texture(ICON_SIZE); - this._icon.add_style_class_name('icon-dropshadow'); - this._icon.set({ - reactive: true, - pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }), - }); - this._icon.add_constraint(new Clutter.BindConstraint({ - source: windowContainer, - coordinate: Clutter.BindCoordinate.POSITION, - })); - this._icon.add_constraint(new Clutter.AlignConstraint({ - source: windowContainer, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5, - })); - this._icon.add_constraint(new Clutter.AlignConstraint({ - source: windowContainer, - align_axis: Clutter.AlignAxis.Y_AXIS, - pivot_point: new Graphene.Point({ x: -1, y: ICON_OVERLAP }), - factor: 1, - })); - - if (opt.WINDOW_ICON_CLICK_ACTION) { - const iconClickAction = new Clutter.ClickAction(); - iconClickAction.connect('clicked', act => { - if (act.get_button() === Clutter.BUTTON_PRIMARY) { - if (opt.WINDOW_ICON_CLICK_ACTION === 1) { - this._searchAppWindowsAction(); - return Clutter.EVENT_STOP; - } else if (opt.WINDOW_ICON_CLICK_ACTION === 2 && global.windowThumbnails) { - this._removeLaters(); - global.windowThumbnails?.createThumbnail(metaWindow); - return Clutter.EVENT_STOP; - } - } /* else if (act.get_button() === Clutter.BUTTON_SECONDARY) { - return Clutter.EVENT_STOP; - }*/ - return Clutter.EVENT_PROPAGATE; - }); - this._icon.add_action(iconClickAction); - } - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - this._title = new St.Label({ - visible: false, - style_class: 'window-caption', - text: this._getCaption(), - reactive: true, - }); - this._title.clutter_text.single_line_mode = true; - this._title.add_constraint(new Clutter.BindConstraint({ - source: windowContainer, - coordinate: Clutter.BindCoordinate.X, - })); - - let offset; - if (opt.WIN_TITLES_POSITION < 2) { - // we cannot get proper title height before it gets to the stage, so 35 is estimated height + spacing - offset = -scaleFactor * (ICON_SIZE * ICON_OVERLAP + 35); - } else { - offset = scaleFactor * (ICON_SIZE * (1 - ICON_OVERLAP) + 4); - } - this._title.add_constraint(new Clutter.BindConstraint({ - source: windowContainer, - coordinate: Clutter.BindCoordinate.Y, - offset, - })); - this._title.add_constraint(new Clutter.AlignConstraint({ - source: windowContainer, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5, - })); - this._title.add_constraint(new Clutter.AlignConstraint({ - source: windowContainer, - align_axis: Clutter.AlignAxis.Y_AXIS, - pivot_point: new Graphene.Point({ x: -1, y: 0 }), - factor: 1, - })); - this._title.clutter_text.ellipsize = Pango.EllipsizeMode.END; - this.label_actor = this._title; - this.metaWindow.connectObject( - 'notify::title', () => (this._title.text = this._getCaption()), - this); - - const layout = Meta.prefs_get_button_layout(); - this._closeButtonSide = - layout.left_buttons.includes(Meta.ButtonFunction.CLOSE) - ? St.Side.LEFT : St.Side.RIGHT; - this._closeButton = new St.Button({ - visible: false, - style_class: 'window-close', - icon_name: 'preview-close-symbolic', - }); - this._closeButton.add_constraint(new Clutter.BindConstraint({ - source: windowContainer, - coordinate: Clutter.BindCoordinate.POSITION, - })); - this._closeButton.add_constraint(new Clutter.AlignConstraint({ - source: windowContainer, - align_axis: Clutter.AlignAxis.X_AXIS, - pivot_point: new Graphene.Point({ x: 0.5, y: -1 }), - factor: this._closeButtonSide === St.Side.LEFT ? 0 : 1, - })); - this._closeButton.add_constraint(new Clutter.AlignConstraint({ - source: windowContainer, - align_axis: Clutter.AlignAxis.Y_AXIS, - pivot_point: new Graphene.Point({ x: -1, y: 0.5 }), - factor: 0, - })); - this._closeButton.connect('clicked', () => this._deleteAll()); - - this.add_child(this._title); - this.add_child(this._icon); - this.add_child(this._closeButton); - - this._overviewAdjustment.connectObject( - 'notify::value', () => this._updateIconScale(), this); - this._updateIconScale(); - - this.connect('notify::realized', () => { - if (!this.realized) - return; - - this._title.ensure_style(); - this._icon.ensure_style(); - }); - - if (ICON_SIZE < 22) { - // disable app icon - this._icon.hide(); - } else { - this._updateIconScale(); - } - - - - // if window is created while the overview is shown, icon and title should be visible immediately - if (Main.overview._overview._controls._stateAdjustment.value < 1) { - this._icon.scale_x = 0; - this._icon.scale_y = 0; - this._title.opacity = 0; - } - - if (opt.ALWAYS_SHOW_WIN_TITLES) - this._title.show(); - - 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 || Main.overview._overview._controls._stateAdjustment.value < 1) - return; - - opt.WORKSPACE_MODE = 1; - const view = this._workspace.get_parent(); - view.exposeWindows(this._workspace.metaWorkspace.index()); - 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)); - } - - const metaWin = this.metaWindow; - if (opt.DASH_ISOLATE_WS && !metaWin._wsChangedConId) { - metaWin._wsChangedConId = metaWin.connect('workspace-changed', - () => Main.overview.dash._queueRedisplay()); - } else if (!opt.DASH_ISOLATE_WS && metaWin._wsChangedConId) { - metaWin.disconnect(metaWin._wsChangedConId); - } - }, - - _closeWinAction() { - this.hide(); - this._deleteAll(); - }, - - _removeLaters() { - if (this._longPressLater) { - const laters = global.compositor.get_laters(); - laters.remove(this._longPressLater); - delete this._longPressLater; - } - }, - - _searchAppWindowsAction() { - // 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 - this._removeLaters(); - const tracker = Shell.WindowTracker.get_default(); - const appName = tracker.get_window_app(this.metaWindow).get_name(); - Me.Util.activateSearchProvider(`${Me.WSP_PREFIX} ${appName}`); - }, - - _updateIconScale() { - let { currentState, initialState, finalState } = - this._overviewAdjustment.getStateTransitionParams(); - - // Current state - 0 - HIDDEN, 1 - WINDOW_PICKER, 2 - APP_GRID - const primaryMonitor = this.metaWindow.get_monitor() === global.display.get_primary_monitor(); - - const visible = - (initialState > ControlsState.HIDDEN || finalState > ControlsState.HIDDEN) && - !(finalState === ControlsState.APP_GRID && opt.WS_ANIMATION && 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 && 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) - scale = 0; - - // in static workspace mode show icon and title on windows expose - if (opt.OVERVIEW_MODE) { - if (currentState === 1) - scale = this._workspace._background._stateAdjustment.value; - else if ((finalState === 1 && !opt.WORKSPACE_MODE) || (finalState === 0 && !opt.WORKSPACE_MODE)) - return; - } - - if (!opt.WS_ANIMATION && (Main.overview.searchController.searchActive || - ((initialState === ControlsState.WINDOW_PICKER && finalState === ControlsState.APP_GRID) || - (initialState === ControlsState.APP_GRID && finalState === ControlsState.WINDOW_PICKER))) - ) - return; - - // 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 - if (scale === 1) { - this._icon.set({ - scale_x: 1, - scale_y: 1, - }); - this._title.ease({ - duration: 100, - opacity: 255, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } else { - this._title.opacity = 0; - this._icon.set({ - scale_x: scale, - scale_y: scale, - }); - } - }, - - showOverlay(animate) { - if (!this._overlayEnabled) - return; - - if (this._overlayShown) - return; - - this._overlayShown = true; - if (opt.WIN_TITLES_POSITION === 2) - this._restack(); - - // If we're supposed to animate and an animation in our direction - // is already happening, let that one continue - const ongoingTransition = this._title.get_transition('opacity'); - if (animate && - ongoingTransition && - ongoingTransition.get_interval().peek_final_value() === 255) - return; - - const toShow = this._windowCanClose() && opt.SHOW_CLOSE_BUTTON - ? [this._closeButton] - : []; - - if (!opt.ALWAYS_SHOW_WIN_TITLES) - toShow.push(this._title); - - - toShow.forEach(a => { - a.opacity = 0; - a.show(); - a.ease({ - opacity: 255, - duration: animate ? WINDOW_OVERLAY_FADE_TIME : 0, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - }); - - const [width, height] = this.window_container.get_size(); - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - const activeExtraSize = WINDOW_ACTIVE_SIZE_INC * 2 * scaleFactor; - const origSize = Math.max(width, height); - const scale = (origSize + activeExtraSize) / origSize; - - this.window_container.ease({ - scale_x: scale, - scale_y: scale, - duration: animate ? WINDOW_SCALE_TIME : 0, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - this.emit('show-chrome'); - }, - - hideOverlay(animate) { - if (!this._overlayShown) - return; - this._overlayShown = false; - - if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW && Main.overview._overview.controls._stateAdjustment.value < 1) - this._activateSelected = true; - - - if (opt.WIN_TITLES_POSITION === 2) - this._restack(); - - // If we're supposed to animate and an animation in our direction - // is already happening, let that one continue - const ongoingTransition = this._title.get_transition('opacity'); - if (animate && - ongoingTransition && - ongoingTransition.get_interval().peek_final_value() === 0) - return; - - const toHide = [this._closeButton]; - - if (!opt.ALWAYS_SHOW_WIN_TITLES) - toHide.push(this._title); - - toHide.forEach(a => { - a.opacity = 255; - a.ease({ - opacity: 0, - duration: animate ? WINDOW_OVERLAY_FADE_TIME : 0, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => a.hide(), - }); - }); - - if (this.window_container) { - this.window_container.ease({ - scale_x: 1, - scale_y: 1, - duration: animate ? WINDOW_SCALE_TIME : 0, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - }, - - _onDestroy() { - if (this._activateSelected) - this._activate(); - - this.metaWindow._delegate = null; - this._delegate = null; - this._destroyed = true; - - if (this._longPressLater) { - const laters = global.compositor.get_laters(); - laters.remove(this._longPressLater); - delete this._longPressLater; - } - - if (this._idleHideOverlayId > 0) { - GLib.source_remove(this._idleHideOverlayId); - this._idleHideOverlayId = 0; - } - - if (this.inDrag) { - this.emit('drag-end'); - this.inDrag = false; - } - - if (this._stateAdjustmentSigId) - this._workspace.stateAdjustment.disconnect(this._stateAdjustmentSigId); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/workspace.js b/extensions/46/vertical-workspaces/lib/workspace.js deleted file mode 100644 index 679a1ab..0000000 --- a/extensions/46/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 - 2024 - * @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); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/workspaceAnimation.js b/extensions/46/vertical-workspaces/lib/workspaceAnimation.js deleted file mode 100644 index e29e3ef..0000000 --- a/extensions/46/vertical-workspaces/lib/workspaceAnimation.js +++ /dev/null @@ -1,262 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspacesAnimation.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; -import GObject from 'gi://GObject'; -import St from 'gi://St'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Layout from 'resource:///org/gnome/shell/ui/layout.js'; -import * as WorkspaceSwitcherPopup from 'resource:///org/gnome/shell/ui/workspaceSwitcherPopup.js'; -import * as WorkspaceAnimation from 'resource:///org/gnome/shell/ui/workspaceAnimation.js'; -import * as Util from 'resource:///org/gnome/shell/misc/util.js'; - -let Me; -let opt; - -export const WorkspaceAnimationModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - this._overrides = null; - this._origBaseDistance = null; - this._wsAnimationSwipeBeginId = 0; - this._wsAnimationSwipeUpdateId = 0; - this._wsAnimationSwipeEndId = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this.moduleEnabled = opt.get('workspaceAnimationModule'); - const conflict = !WorkspaceAnimation.MonitorGroup; - if (conflict) - console.warn(`[${Me.metadata.name}] Warning: "WorkspaceAnimation" module disabled due to compatibility - GNOME Shell 45.1 or later is required`); - - 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(' WorkspaceAnimationModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._overrides.addOverride('MonitorGroup', WorkspaceAnimation.MonitorGroup.prototype, MonitorGroup); - this._connectWsAnimationSwipeTracker(); - - console.debug(' WorkspaceAnimationModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - const reset = true; - this._connectWsAnimationSwipeTracker(reset); - - console.debug(' WorkspaceAnimationModule - Disabled'); - } - - _connectWsAnimationSwipeTracker(reset = false) { - if (reset) { - if (this._wsAnimationSwipeBeginId) { - Main.wm._workspaceAnimation._swipeTracker.disconnect(this._wsAnimationSwipeBeginId); - this._wsAnimationSwipeBeginId = 0; - } - if (this._wsAnimationSwipeEndId) { - Main.wm._workspaceAnimation._swipeTracker.disconnect(this._wsAnimationSwipeEndId); - this._wsAnimationSwipeEndId = 0; - } - } else if (!this._wsAnimationSwipeBeginId) { - // display ws switcher popup when gesture begins and connect progress - this._wsAnimationSwipeBeginId = Main.wm._workspaceAnimation._swipeTracker.connect('begin', () => this._connectWsAnimationProgress(true)); - // we want to be sure that popup with the final ws index show up when gesture ends - this._wsAnimationSwipeEndId = Main.wm._workspaceAnimation._swipeTracker.connect('end', (tracker, duration, endProgress) => this._connectWsAnimationProgress(false, endProgress)); - } - } - - _connectWsAnimationProgress(connect, endProgress = null) { - if (Main.overview.visible) - return; - - if (connect && !this._wsAnimationSwipeUpdateId) { - this._wsAnimationSwipeUpdateId = Main.wm._workspaceAnimation._swipeTracker.connect('update', (tracker, progress) => this._showWsSwitcherPopup(progress)); - } else if (!connect && this._wsAnimationSwipeUpdateId) { - Main.wm._workspaceAnimation._swipeTracker.disconnect(this._wsAnimationSwipeUpdateId); - this._wsAnimationSwipeUpdateId = 0; - this._showWsSwitcherPopup(Math.round(endProgress)); - } - } - - _showWsSwitcherPopup(progress) { - if (Main.overview.visible) - return; - - const wsIndex = Math.round(progress); - if (Main.wm._workspaceSwitcherPopup === null) { - Main.wm._workspaceSwitcherPopup = new WorkspaceSwitcherPopup.WorkspaceSwitcherPopup(); - Main.wm._workspaceSwitcherPopup.connect('destroy', () => { - Main.wm._workspaceSwitcherPopup = null; - }); - } - - Main.wm._workspaceSwitcherPopup.display(wsIndex); - } -}; - -const MonitorGroup = { - _init(monitor, workspaceIndices, movingWindow) { - St.Widget.prototype._init.bind(this)({ - clip_to_allocation: true, - style_class: 'workspace-animation', - }); - - this._monitor = monitor; - - const constraint = new Layout.MonitorConstraint({ index: monitor.index }); - this.add_constraint(constraint); - - this._container = new Clutter.Actor(); - this.add_child(this._container); - - const stickyGroup = new WorkspaceAnimation.WorkspaceGroup(null, monitor, movingWindow); - stickyGroup._windowRecords.forEach(r => { - const metaWin = r.windowActor.metaWindow; - // conky is sticky but should never get above other windows during ws animation - // so we hide it from the overlay group, we will see the original if not covered by other windows - if (metaWin.wm_class === 'conky') - r.clone.opacity = 0; - }); - this.add_child(stickyGroup); - - this._workspaceGroups = []; - - const workspaceManager = global.workspace_manager; - const vertical = workspaceManager.layout_rows === -1; - const activeWorkspace = workspaceManager.get_active_workspace(); - - let x = 0; - let y = 0; - - for (const i of workspaceIndices) { - const ws = workspaceManager.get_workspace_by_index(i); - const fullscreen = ws.list_windows().some(w => w.get_monitor() === monitor.index && w.is_fullscreen()); - - if (i > 0 && vertical && !fullscreen && monitor.index === Main.layoutManager.primaryIndex) { - // We have to shift windows up or down by the height of the panel to prevent having a - // visible gap between the windows while switching workspaces. Since fullscreen windows - // hide the panel, they don't need to be shifted up or down. - y -= Main.panel.height; - } - - const group = new WorkspaceAnimation.WorkspaceGroup(ws, monitor, movingWindow); - - this._workspaceGroups.push(group); - this._container.add_child(group); - group.set_position(x, y); - - if (vertical) - y += this.baseDistance; - else if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL) - x -= this.baseDistance; - else - x += this.baseDistance; - } - - this.progress = this.getWorkspaceProgress(activeWorkspace); - - if (monitor.index === Main.layoutManager.primaryIndex) { - this._workspacesAdjustment = Main.createWorkspacesAdjustment(this); - this.bind_property_full('progress', - this._workspacesAdjustment, 'value', - GObject.BindingFlags.SYNC_CREATE, - (bind, source) => { - const indices = [ - workspaceIndices[Math.floor(source)], - workspaceIndices[Math.ceil(source)], - ]; - return [true, Util.lerp(...indices, source % 1.0)]; - }, - null); - - this.connect('destroy', () => { - // for some reason _workspaceAdjustment bound to the progress property in V-Shell - // causes the adjustment doesn't reach a whole number - // when switching ws up and that breaks the showing overview animation - // as a workaround round workspacesDisplay._scrollAdjustment value on destroy - // but it should be handled elsewhere as this workaround doesn't work when this module is disabled - const workspacesAdj = Main.overview._overview.controls._workspacesDisplay._scrollAdjustment; - workspacesAdj.value = Math.round(workspacesAdj.value); - delete this._workspacesAdjustment; - }); - } - - if (!opt.STATIC_WS_SWITCHER_BG) - return; - - // we have two options to implement static bg feature - // one is adding background to monitorGroup - // but this one has disadvantage - sticky windows will be always on top of animated windows - // which is bad for conky, for example, that window should be always below - /* this._bgManager = new Background.BackgroundManager({ - container: this, - monitorIndex: this._monitor.index, - controlPosition: false, - });*/ - - // the second option is to make background of the monitorGroup transparent so the real desktop content will stay visible, - // hide windows that should be animated and keep only sticky windows - // we can keep certain sticky windows bellow and also extensions like DING (icons on desktop) will stay visible - this.set_style('background-color: transparent;'); - // stickyGroup holds the Always on Visible Workspace windows to keep them static and above other windows during animation - this._hiddenWindows = []; - // remove (hide) background wallpaper from the animation, we will see the original one - this._workspaceGroups.forEach(w => { - w._background.opacity = 0; - }); - // hide (scale to 0) all non-sticky windows, their clones will be animated - global.get_window_actors().forEach(actor => { - const metaWin = actor.metaWindow; - if (metaWin?.get_monitor() === this._monitor.index && - !(metaWin?.wm_class === 'conky' && metaWin?.is_on_all_workspaces()) && - !(metaWin?.wm_class === 'Gjs' && metaWin?.is_on_all_workspaces())) { // DING extension uses window with Gjs class - // hide original window. we cannot use opacity since it also affects clones. - // scaling them to 0 works well - actor.scale_x = 0; - this._hiddenWindows.push(actor); - } - }); - - // restore all hidden windows at the end of animation - // todo - actors removed during transition need to be removed from the list to avoid access to destroyed actor - this.connect('destroy', () => { - this._hiddenWindows.forEach(actor => { - actor.scale_x = 1; - }); - }); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/workspaceSwitcherPopup.js b/extensions/46/vertical-workspaces/lib/workspaceSwitcherPopup.js deleted file mode 100644 index cf3d4c1..0000000 --- a/extensions/46/vertical-workspaces/lib/workspaceSwitcherPopup.js +++ /dev/null @@ -1,107 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspacesSwitcherPopup.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as WorkspaceSwitcherPopup from 'resource:///org/gnome/shell/ui/workspaceSwitcherPopup.js'; - -let Me; -let opt; - -export const WorkspaceSwitcherPopupModule = 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('workspaceSwitcherPopupModule'); - const conflict = Me.Util.getEnabledExtensions('workspace-switcher-manager').length || - Me.Util.getEnabledExtensions('WsSwitcherPopupManager').length; - if (conflict && !reset) - console.warn(`[${Me.metadata.name}] Warning: "WorkspaceSwitcherPopup" module disabled due to potential conflict with another extension`); - - reset = reset || !this.moduleEnabled || conflict; - - // don't touch 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(' WorkspaceSwitcherPopupModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - this._overrides.addOverride('WorkspaceSwitcherPopup', WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype, WorkspaceSwitcherPopupCommon); - console.debug(' WorkspaceSwitcherPopupModule - Activated'); - } - - _disableModule() { - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - console.debug(' WorkspaceSwitcherPopupModule - Disabled'); - } -}; - -const WorkspaceSwitcherPopupCommon = { - // injection to _init() - after__init() { - if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL - this._list.vertical = true; - this._list.add_style_class_name('ws-switcher-vertical'); - } - this._list.set_style('margin: 0;'); - if (this.get_constraints()[0]) - this.remove_constraint(this.get_constraints()[0]); - }, - - // injection to display() - after_display() { - if (opt.WS_SW_POPUP_MODE) - this._setPopupPosition(); - else - this.opacity = 0; - }, - - _setPopupPosition() { - let workArea; - if (opt.WS_SW_POPUP_MODE === 1) - workArea = global.display.get_monitor_geometry(Main.layoutManager.primaryIndex); - else - workArea = global.display.get_monitor_geometry(global.display.get_current_monitor()); - - - let [, natHeight] = this.get_preferred_height(global.screen_width); - let [, natWidth] = this.get_preferred_width(natHeight); - let h = opt.WS_SW_POPUP_H_POSITION; - let v = opt.WS_SW_POPUP_V_POSITION; - this.x = workArea.x + Math.floor((workArea.width - natWidth) * h); - this.y = workArea.y + Math.floor((workArea.height - natHeight) * v); - this.set_position(this.x, this.y); - }, -}; diff --git a/extensions/46/vertical-workspaces/lib/workspaceThumbnail.js b/extensions/46/vertical-workspaces/lib/workspaceThumbnail.js deleted file mode 100644 index d64fda2..0000000 --- a/extensions/46/vertical-workspaces/lib/workspaceThumbnail.js +++ /dev/null @@ -1,1236 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspaceThumbnail.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @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.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, -}; diff --git a/extensions/46/vertical-workspaces/lib/workspacesView.js b/extensions/46/vertical-workspaces/lib/workspacesView.js deleted file mode 100644 index 8e20db3..0000000 --- a/extensions/46/vertical-workspaces/lib/workspacesView.js +++ /dev/null @@ -1,1004 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspacesView.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2024 - * @license GPL-3.0 - * - */ - -'use strict'; - -import Clutter from 'gi://Clutter'; -import St from 'gi://St'; -import Meta from 'gi://Meta'; -import GObject from 'gi://GObject'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as Overview from 'resource:///org/gnome/shell/ui/overview.js'; -import * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'; -import * as WorkspacesView from 'resource:///org/gnome/shell/ui/workspacesView.js'; - -import * as Util from 'resource:///org/gnome/shell/misc/util.js'; - -let Me; -let opt; - -const ControlsState = OverviewControls.ControlsState; -const FitMode = WorkspacesView.FitMode; - -export const WorkspacesViewModule = 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(' WorkspacesViewModule - Keeping untouched'); - } - - _activateModule() { - if (!this._overrides) - this._overrides = new Me.Util.Overrides(); - - const desktopCubeEnabled = Me.Util.getEnabledExtensions('desktop-cube@schneegans.github.com').length; - const desktopCubeConflict = desktopCubeEnabled && !opt.ORIENTATION && !opt.OVERVIEW_MODE; - - if (!desktopCubeConflict) - this._overrides.addOverride('WorkspacesView', WorkspacesView.WorkspacesView.prototype, WorkspacesViewCommon); - - this._overrides.addOverride('WorkspacesDisplay', WorkspacesView.WorkspacesDisplay.prototype, WorkspacesDisplayCommon); - this._overrides.addOverride('ExtraWorkspaceView', WorkspacesView.ExtraWorkspaceView.prototype, ExtraWorkspaceViewCommon); - this._overrides.addOverride('SecondaryMonitorDisplayCommon', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayCommon); - - if (opt.ORIENTATION) { - // switch internal workspace orientation in GS - global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, -1, 1); - this._overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayVertical); - } else { - global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1); - this._overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayHorizontal); - } - - console.debug(' WorkspacesViewModule - Activated'); - } - - _disableModule() { - global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1); - if (this._overrides) - this._overrides.removeAll(); - this._overrides = null; - - console.debug(' WorkspacesViewModule - Disabled'); - } -}; - -const WorkspacesViewCommon = { - _getFirstFitSingleWorkspaceBox(box, spacing, vertical) { - let [width, height] = box.get_size(); - const [workspace] = this._workspaces; - - const rtl = this.text_direction === Clutter.TextDirection.RTL; - const adj = this._scrollAdjustment; - const currentWorkspace = vertical || !rtl - ? adj.value : adj.upper - adj.value - 1; - - // Single fit mode implies centered too - let [x1, y1] = box.get_origin(); - const [, workspaceWidth] = workspace ? workspace.get_preferred_width(Math.floor(height)) : [0, width]; - const [, workspaceHeight] = workspace ? workspace.get_preferred_height(workspaceWidth) : [0, height]; - - if (vertical) { - x1 += (width - workspaceWidth) / 2; - y1 -= currentWorkspace * (workspaceHeight + spacing); - } else { - x1 += (width - workspaceWidth) / 2; - x1 -= currentWorkspace * (workspaceWidth + spacing); - } - - const fitSingleBox = new Clutter.ActorBox({ x1, y1 }); - fitSingleBox.set_size(workspaceWidth, workspaceHeight); - - return fitSingleBox; - }, - - // set spacing between ws previews - _getSpacing(box, fitMode, vertical) { - const [width, height] = box.get_size(); - const [workspace] = this._workspaces; - - if (!workspace) - return 0; - - let availableSpace; - let workspaceSize; - if (vertical) { - [, workspaceSize] = workspace.get_preferred_height(width); - availableSpace = height; - } else { - [, workspaceSize] = workspace.get_preferred_width(height); - availableSpace = width; - } - - const spacing = (availableSpace - workspaceSize * 0.4) * (1 - fitMode); - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - return Math.clamp(spacing, - opt.WORKSPACE_MIN_SPACING * scaleFactor, - opt.WORKSPACE_MAX_SPACING * scaleFactor); - }, - - // this function has duplicate in OverviewControls so we use one function for both to avoid issues with syncing them - _getFitModeForState(state) { - return _getFitModeForState(state); - }, - - // normal view 0, spread windows 1 - _getWorkspaceModeForOverviewState(state) { - - switch (state) { - case ControlsState.HIDDEN: - return 0; - case ControlsState.WINDOW_PICKER: - return opt.WORKSPACE_MODE; - case ControlsState.APP_GRID: - return (this._monitorIndex !== global.display.get_primary_monitor() || !opt.WS_ANIMATION) && !opt.OVERVIEW_MODE ? 1 : 0; - } - - return 0; - }, - - _updateVisibility() { - // visibility handles _updateWorkspacesState() - }, - - // disable scaling and hide inactive workspaces - _updateWorkspacesState() { - const adj = this._scrollAdjustment; - const fitMode = this._fitModeAdjustment.value; - - let { initialState, finalState, progress, currentState } = - this._overviewAdjustment.getStateTransitionParams(); - - const workspaceMode = (1 - fitMode) * Util.lerp( - this._getWorkspaceModeForOverviewState(initialState), - this._getWorkspaceModeForOverviewState(finalState), - progress); - - const primaryMonitor = Main.layoutManager.primaryMonitor.index; - - const wsScrollProgress = adj.value % 1; - const secondaryMonitor = this._monitorIndex !== global.display.get_primary_monitor(); - const blockSecondaryAppGrid = opt.OVERVIEW_MODE && currentState > 1; - - // Hide inactive workspaces - this._workspaces.forEach((w, index) => { - if (!(blockSecondaryAppGrid && secondaryMonitor)) - w.stateAdjustment.value = workspaceMode; - - let distance = adj.value - index; - const distanceToCurrentWorkspace = Math.abs(distance); - - const scaleProgress = 1 - Math.clamp(distanceToCurrentWorkspace, 0, 1); - // const scale = Util.lerp(0.94, 1, scaleProgress); - // w.set_scale(scale, scale); - - // if we disable workspaces that we can't or don't need to see, transition animations will be noticeably smoother - // only the current ws needs to be visible during overview transition animations - // and only current and adjacent ws when switching ws - w.visible = (this._animating && wsScrollProgress && distanceToCurrentWorkspace <= (opt.NUMBER_OF_VISIBLE_NEIGHBORS + 1)) || scaleProgress === 1 || - (opt.WORKSPACE_MAX_SPACING > 340 && distanceToCurrentWorkspace <= opt.NUMBER_OF_VISIBLE_NEIGHBORS && currentState === ControlsState.WINDOW_PICKER) || - (this._monitorIndex !== primaryMonitor && distanceToCurrentWorkspace <= opt.NUMBER_OF_VISIBLE_NEIGHBORS) || (!opt.WS_ANIMATION && distanceToCurrentWorkspace < opt.NUMBER_OF_VISIBLE_NEIGHBORS) || - (opt.WORKSPACE_MAX_SPACING < 340 && distanceToCurrentWorkspace <= opt.NUMBER_OF_VISIBLE_NEIGHBORS && currentState <= ControlsState.WINDOW_PICKER && - ((initialState < ControlsState.APP_GRID && finalState < ControlsState.APP_GRID)) - ); - - // after transition from APP_GRID to WINDOW_PICKER state, - // adjacent workspaces are hidden and we need them to show up - // make them visible during animation can impact smoothness of the animation - // so we show them after the animation finished, move them to their position from outside of the monitor - if (!w.visible && distanceToCurrentWorkspace === 1 && initialState === ControlsState.APP_GRID && currentState === ControlsState.WINDOW_PICKER) { - w.visible = true; - const directionNext = distance > 0; - if (!opt.ORIENTATION) { - const width = w.width * 0.6 * opt.WS_PREVIEW_SCALE; - w.translation_x = directionNext ? -width : width; - } - if (opt.ORIENTATION) { - const height = w.height * 0.6 * opt.WS_PREVIEW_SCALE; - w.translation_y = directionNext ? -height : height; - } - - w.opacity = 10; - w.get_parent().set_child_below_sibling(w, null); - w.ease({ - duration: 300, - translation_x: 0, - translation_y: 0, - opacity: 255, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - - // force ws preview bg corner radiuses where GS doesn't do it - if (opt.SHOW_WS_PREVIEW_BG && opt.OVERVIEW_MODE === 1 && distanceToCurrentWorkspace < 2) - w._background._updateBorderRadius(Math.min(1, w._overviewAdjustment.value)); - - - // hide workspace background - if (!opt.SHOW_WS_PREVIEW_BG && w._background.opacity) - w._background.opacity = 0; - }); - }, - - exposeWindows(workspaceIndex = null, callback) { - let adjustments = []; - if (workspaceIndex === null) { - this._workspaces.forEach(ws => { - adjustments.push(ws._background._stateAdjustment); - }); - } else { - adjustments.push(this._workspaces[workspaceIndex]._background._stateAdjustment); - } - - opt.WORKSPACE_MODE = 1; - adjustments.forEach(adj => { - if (adj.value === 0) { - adj.value = 0; - adj.ease(1, { - duration: 200, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - if (callback) - callback(); - }, - }); - } - }); - }, -}; - -const SecondaryMonitorDisplayCommon = { - exposeWindows(...args) { - this._workspacesView.exposeWindows(...args); - }, -}; - -const SecondaryMonitorDisplayVertical = { - _getThumbnailParamsForState(state) { - - let opacity, scale, translationX; - switch (state) { - case ControlsState.HIDDEN: - opacity = 255; - scale = 1; - translationX = 0; - if (!Main.layoutManager._startingUp && (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2)) - translationX = this._thumbnails.width * (opt.SEC_WS_TMB_LEFT ? -1 : 1); - - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - opacity = 255; - scale = 1; - translationX = 0; - break; - default: - opacity = 255; - scale = 1; - translationX = 0; - break; - } - - return { opacity, scale, translationX }; - }, - - _getThumbnailsWidth(box, spacing) { - if (opt.SEC_WS_TMB_HIDDEN) - return 0; - - const [width, height] = box.get_size(); - const { expandFraction } = this._thumbnails; - const [, thumbnailsWidth] = this._thumbnails.get_preferred_width(height - 2 * spacing); - let scaledWidth; - if (opt.SEC_WS_PREVIEW_SHIFT && !opt.PANEL_DISABLED) - scaledWidth = ((height - Main.panel.height) * opt.SEC_MAX_THUMBNAIL_SCALE) * (width / height); - else - scaledWidth = width * opt.SEC_MAX_THUMBNAIL_SCALE; - - return Math.min( - thumbnailsWidth * expandFraction, - Math.round(scaledWidth)); - }, - - _getWorkspacesBoxForState(state, box, thumbnailsWidth, spacing, startY, panelHeight) { - // const { ControlsState } = OverviewControls; - const workspaceBox = box.copy(); - let [width, height] = workspaceBox.get_size(); - height -= panelHeight; - - let wWidth, wHeight, wsbX, wsbY, offset; - switch (state) { - case ControlsState.HIDDEN: - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) - break; - - wWidth = width - thumbnailsWidth - 5 * spacing; - wHeight = Math.min(wWidth / (width / height), height - 4 * spacing); - wWidth = Math.round(wWidth * opt.SEC_WS_PREVIEW_SCALE); - wHeight = Math.round(wHeight * opt.SEC_WS_PREVIEW_SCALE); - - offset = Math.round(width - thumbnailsWidth - wWidth) / 2; - if (opt.SEC_WS_TMB_LEFT) - wsbX = thumbnailsWidth + offset; - else - wsbX = offset; - - wsbY = Math.round((startY + height - wHeight) / 2); - - workspaceBox.set_origin(wsbX, wsbY); - workspaceBox.set_size(wWidth, wHeight); - break; - } - - return workspaceBox; - }, - - vfunc_allocate(box) { - this.set_allocation(box); - - const themeNode = this.get_theme_node(); - const contentBox = themeNode.get_content_box(box); - let [width, height] = contentBox.get_size(); - let [, startY] = contentBox.get_origin(); - // Save some resources - if (this._startY === undefined) { - this._panelHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0; - startY += opt.SEC_WS_PREVIEW_SHIFT && opt.PANEL_POSITION_TOP ? this._panelHeight : 0; - this._startY = startY; - } - - startY = this._startY; - height -= this._panelHeight; - const { expandFraction } = this._thumbnails; - const spacing = themeNode.get_length('spacing') * expandFraction; - - let thumbnailsWidth = 0; - let thumbnailsHeight = 0; - this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN; - if (this._thumbnails.visible) { - thumbnailsWidth = Math.round(width * opt.SEC_MAX_THUMBNAIL_SCALE); - - let totalTmbSpacing; - [totalTmbSpacing, thumbnailsHeight] = this._thumbnails.get_preferred_height(thumbnailsWidth); - thumbnailsHeight = Math.round(thumbnailsHeight + totalTmbSpacing); - - const thumbnailsHeightMax = height - spacing; - - if (thumbnailsHeight > thumbnailsHeightMax) { - thumbnailsHeight = thumbnailsHeightMax; - thumbnailsWidth = Math.round(this._thumbnails.get_preferred_width(thumbnailsHeight)[1]); - } - - let wsTmbX; - if (opt.SEC_WS_TMB_LEFT) { - wsTmbX = 0; - this._thumbnails._positionLeft = true; - } else { - wsTmbX = width - thumbnailsWidth; - this._thumbnails._positionLeft = false; - } - - const childBox = new Clutter.ActorBox(); - const availSpace = height - thumbnailsHeight; - - let wsTmbY = availSpace / 2; - - wsTmbY -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * (wsTmbY - spacing / 2); - wsTmbY += startY; - - childBox.set_origin(Math.round(wsTmbX), Math.round(wsTmbY)); - childBox.set_size(thumbnailsWidth, thumbnailsHeight); - this._thumbnails.allocate(childBox); - } - - const { - currentState, initialState, finalState, transitioning, progress, - } = this._overviewAdjustment.getStateTransitionParams(); - - let workspacesBox; - const workspaceParams = [contentBox, thumbnailsWidth, spacing, startY, this._panelHeight]; - if (!transitioning) { - workspacesBox = - this._getWorkspacesBoxForState(currentState, ...workspaceParams); - } else { - const initialBox = - this._getWorkspacesBoxForState(initialState, ...workspaceParams); - const finalBox = - this._getWorkspacesBoxForState(finalState, ...workspaceParams); - workspacesBox = initialBox.interpolate(finalBox, progress); - } - this._workspacesView.allocate(workspacesBox); - }, - - _updateThumbnailVisibility() { - if (opt.OVERVIEW_MODE2) - this.set_child_above_sibling(this._thumbnails, null); - - const visible = !opt.SEC_WS_TMB_HIDDEN; - - if (this._thumbnails.visible === visible) - return; - - this._thumbnails.show(); - this._updateThumbnailParams(); - this._thumbnails.ease_property('expand-fraction', visible ? 1 : 0, { - duration: Overview.ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._thumbnails.visible = visible; - this._thumbnails._indicator.visible = visible; - }, - }); - }, - - _updateThumbnailParams() { - if (opt.SEC_WS_TMB_HIDDEN) - return; - - // workaround for upstream bug - secondary thumbnails boxes don't catch 'showing' signal on the shell startup and don't populate the box with thumbnails - // the tmbBox contents is also destroyed when overview state adjustment gets above 1 when swiping gesture from window picker to app grid - if (!this._thumbnails._thumbnails.length) - this._thumbnails._createThumbnails(); - - const { initialState, finalState, progress } = - this._overviewAdjustment.getStateTransitionParams(); - - const initialParams = this._getThumbnailParamsForState(initialState); - const finalParams = this._getThumbnailParamsForState(finalState); - - /* const opacity = - Util.lerp(initialParams.opacity, finalParams.opacity, progress); - const scale = - Util.lerp(initialParams.scale, finalParams.scale, progress);*/ - - // OVERVIEW_MODE 2 should animate dash and wsTmbBox only if WORKSPACE_MODE === 0 (windows not spread) - const animateOverviewMode2 = opt.OVERVIEW_MODE2 && !(finalState === 1 && opt.WORKSPACE_MODE); - const translationX = !Main.layoutManager._startingUp && ((!opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2) || animateOverviewMode2) - ? Util.lerp(initialParams.translationX, finalParams.translationX, progress) - : 0; - - this._thumbnails.set({ - opacity: 255, - // scale_x: scale, - // scale_y: scale, - translation_x: translationX, - }); - }, - - _updateWorkspacesView() { - if (this._workspacesView) - this._workspacesView.destroy(); - - if (this._settings.get_boolean('workspaces-only-on-primary')) { - opt.SEC_WS_TMB_HIDDEN = true; - this._workspacesView = new WorkspacesView.ExtraWorkspaceView( - this._monitorIndex, - this._overviewAdjustment); - } else { - opt.SEC_WS_TMB_HIDDEN = !opt.SHOW_SEC_WS_TMB; - this._workspacesView = new WorkspacesView.WorkspacesView( - this._monitorIndex, - this._controls, - this._scrollAdjustment, - // Secondary monitors don't need FitMode.ALL since there is workspace switcher always visible - // this._fitModeAdjustment, - new St.Adjustment({ - actor: this, - value: 0, // FitMode.SINGLE, - lower: 0, // FitMode.SINGLE, - upper: 0, // FitMode.SINGLE, - }), - // secondaryOverviewAdjustment); - this._overviewAdjustment); - } - this.add_child(this._workspacesView); - this._thumbnails.opacity = 0; - }, -}; - -const SecondaryMonitorDisplayHorizontal = { - _getThumbnailParamsForState(state) { - // const { ControlsState } = OverviewControls; - - let opacity, scale, translationY; - switch (state) { - case ControlsState.HIDDEN: - opacity = 255; - scale = 1; - translationY = 0; - if (!Main.layoutManager._startingUp && (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2)) - translationY = this._thumbnails.height * (opt.SEC_WS_TMB_TOP ? -1 : 1); - - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - opacity = 255; - scale = 1; - translationY = 0; - break; - default: - opacity = 255; - scale = 1; - translationY = 0; - break; - } - - return { opacity, scale, translationY }; - }, - - _getWorkspacesBoxForState(state, box, thumbnailsHeight, spacing, startY, panelHeight) { - // const { ControlsState } = OverviewControls; - const workspaceBox = box.copy(); - let [width, height] = workspaceBox.get_size(); - height -= panelHeight; - - let wWidth, wHeight, wsbX, wsbY, offset; - switch (state) { - case ControlsState.HIDDEN: - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) - break; - - wHeight = height - (thumbnailsHeight ? thumbnailsHeight + 4 * spacing : 4 * spacing); - wWidth = Math.min(wHeight * (width / height), width - 5 * spacing); - wWidth = Math.round(wWidth * opt.SEC_WS_PREVIEW_SCALE); - wHeight = Math.round(wHeight * opt.SEC_WS_PREVIEW_SCALE); - - offset = Math.round((height - thumbnailsHeight - wHeight) / 2); - if (opt.SEC_WS_TMB_TOP) - wsbY = thumbnailsHeight + offset; - else - wsbY = offset; - - wsbY += startY; - wsbX = Math.round((width - wWidth) / 2); - - workspaceBox.set_origin(wsbX, wsbY); - workspaceBox.set_size(wWidth, wHeight); - break; - } - - return workspaceBox; - }, - - vfunc_allocate(box) { - this.set_allocation(box); - - const themeNode = this.get_theme_node(); - const contentBox = themeNode.get_content_box(box); - let [width, height] = contentBox.get_size(); - let [, startY] = contentBox.get_origin(); - // Save some resources - if (this._startY === undefined) { - this._panelHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0; - startY += opt.SEC_WS_PREVIEW_SHIFT && opt.PANEL_POSITION_TOP ? this._panelHeight : 0; - this._startY = startY; - } - startY = this._startY; - height -= this._panelHeight; - - const { expandFraction } = this._thumbnails; - const spacing = themeNode.get_length('spacing') * expandFraction; - - let thumbnailsWidth = 0; - let thumbnailsHeight = 0; - this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN; - if (this._thumbnails.visible) { - thumbnailsHeight = height * opt.SEC_MAX_THUMBNAIL_SCALE; - - let totalTmbSpacing; - [totalTmbSpacing, thumbnailsWidth] = this._thumbnails.get_preferred_width(thumbnailsHeight); - thumbnailsWidth = Math.round(thumbnailsWidth + totalTmbSpacing); - - const thumbnailsWidthMax = width - spacing; - - if (thumbnailsWidth > thumbnailsWidthMax) { - thumbnailsWidth = thumbnailsWidthMax; - thumbnailsHeight = Math.round(this._thumbnails.get_preferred_height(thumbnailsWidth)[1]); - } - - let wsTmbY; - if (opt.SEC_WS_TMB_TOP) - wsTmbY = spacing / 2 + startY; - else - wsTmbY = height - spacing / 2 - thumbnailsHeight + startY; - - const childBox = new Clutter.ActorBox(); - const availSpace = width - thumbnailsWidth; - - let wsTmbX = availSpace / 2; - wsTmbX -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbX; - - childBox.set_origin(Math.round(wsTmbX), Math.round(wsTmbY)); - childBox.set_size(thumbnailsWidth, thumbnailsHeight); - this._thumbnails.allocate(childBox); - } - - const { - currentState, initialState, finalState, transitioning, progress, - } = this._overviewAdjustment.getStateTransitionParams(); - - let workspacesBox; - const workspaceParams = [contentBox, thumbnailsHeight, spacing, startY, this._panelHeight]; - if (!transitioning) { - workspacesBox = - this._getWorkspacesBoxForState(currentState, ...workspaceParams); - } else { - const initialBox = - this._getWorkspacesBoxForState(initialState, ...workspaceParams); - const finalBox = - this._getWorkspacesBoxForState(finalState, ...workspaceParams); - workspacesBox = initialBox.interpolate(finalBox, progress); - } - this._workspacesView.allocate(workspacesBox); - }, - - _updateThumbnailVisibility: SecondaryMonitorDisplayVertical._updateThumbnailVisibility, - - _updateThumbnailParams() { - if (opt.SEC_WS_TMB_HIDDEN) - return; - - // workaround for upstream bug - secondary thumbnails boxes don't catch 'showing' signal on the shell startup and don't populate the box with thumbnails - // the tmbBox contents is also destroyed when overview state adjustment gets above 1 when swiping gesture from window picker to app grid - if (!this._thumbnails._thumbnails.length) - this._thumbnails._createThumbnails(); - - const { initialState, finalState, progress } = - this._overviewAdjustment.getStateTransitionParams(); - - const initialParams = this._getThumbnailParamsForState(initialState); - const finalParams = this._getThumbnailParamsForState(finalState); - - /* const opacity = - Util.lerp(initialParams.opacity, finalParams.opacity, progress); - const scale = - Util.lerp(initialParams.scale, finalParams.scale, progress);*/ - - // OVERVIEW_MODE 2 should animate dash and wsTmbBox only if WORKSPACE_MODE === 0 (windows not spread) - const animateOverviewMode2 = opt.OVERVIEW_MODE2 && !(finalState === 1 && opt.WORKSPACE_MODE); - const translationY = !Main.layoutManager._startingUp && ((!opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2) || animateOverviewMode2) - ? Util.lerp(initialParams.translationY, finalParams.translationY, progress) - : 0; - - this._thumbnails.set({ - opacity: 255, - // scale_x: scale, - // scale_y: scale, - translation_y: translationY, - }); - }, - - _updateWorkspacesView() { - if (this._workspacesView) - this._workspacesView.destroy(); - - if (this._settings.get_boolean('workspaces-only-on-primary')) { - opt.SEC_WS_TMB_HIDDEN = true; - this._workspacesView = new WorkspacesView.ExtraWorkspaceView( - this._monitorIndex, - this._overviewAdjustment); - } else { - opt.SEC_WS_TMB_HIDDEN = !opt.SHOW_SEC_WS_TMB; - this._workspacesView = new WorkspacesView.WorkspacesView( - this._monitorIndex, - this._controls, - this._scrollAdjustment, - // Secondary monitors don't need FitMode.ALL since there is workspace switcher always visible - // this._fitModeAdjustment, - new St.Adjustment({ - actor: this, - value: 0, // FitMode.SINGLE, - lower: 0, // FitMode.SINGLE, - upper: 0, // FitMode.SINGLE, - }), - // secondaryOverviewAdjustment); - this._overviewAdjustment); - } - this.add_child(this._workspacesView); - this._thumbnails.opacity = 0; - }, -}; - -const ExtraWorkspaceViewCommon = { - _updateWorkspaceMode() { - const overviewState = this._overviewAdjustment.value; - - const progress = Math.clamp(overviewState, - ControlsState.HIDDEN, - opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE ? ControlsState.HIDDEN : ControlsState.WINDOW_PICKER); - - this._workspace.stateAdjustment.value = progress; - - // force ws preview bg corner radiuses where GS doesn't do it - if (opt.SHOW_WS_PREVIEW_BG && opt.OVERVIEW_MODE === 1) - this._workspace._background._updateBorderRadius(Math.min(1, this._workspace._overviewAdjustment.value)); - - - // hide workspace background - if (!opt.SHOW_WS_PREVIEW_BG && this._workspace._background.opacity) - this._workspace._background.opacity = 0; - }, - - exposeWindows() { - const adjustment = this._workspace._background._stateAdjustment; - opt.WORKSPACE_MODE = 1; - if (adjustment.value === 0) { - adjustment.value = 0; - adjustment.ease(1, { - duration: 200, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - }, -}; - -const WorkspacesDisplayCommon = { - _updateWorkspacesViews() { - for (let i = 0; i < this._workspacesViews.length; i++) - this._workspacesViews[i].destroy(); - - this._primaryIndex = Main.layoutManager.primaryIndex; - this._workspacesViews = []; - let monitors = Main.layoutManager.monitors; - for (let i = 0; i < monitors.length; i++) { - let view; - if (i === this._primaryIndex) { - view = new WorkspacesView.WorkspacesView(i, - this._controls, - this._scrollAdjustment, - this._fitModeAdjustment, - this._overviewAdjustment); - - view.visible = this._primaryVisible; - this.bind_property('opacity', view, 'opacity', GObject.BindingFlags.SYNC_CREATE); - this.add_child(view); - } else { - view = new WorkspacesView.SecondaryMonitorDisplay(i, - this._controls, - this._scrollAdjustment, - // Secondary monitors don't need FitMode.ALL since there is workspace switcher always visible - // this._fitModeAdjustment, - new St.Adjustment({ - actor: this, - value: 0, // FitMode.SINGLE, - lower: 0, // FitMode.SINGLE, - upper: 0, // FitMode.SINGLE, - }), - this._overviewAdjustment); - Main.layoutManager.overviewGroup.add_child(view); - } - - this._workspacesViews.push(view); - } - }, - - _onScrollEvent(actor, event) { - if (this._swipeTracker.canHandleScrollEvent(event)) - return Clutter.EVENT_PROPAGATE; - - if (!this.mapped) - return Clutter.EVENT_PROPAGATE; - - if (this._workspacesOnlyOnPrimary && - this._getMonitorIndexForEvent(event) !== this._primaryIndex) - return Clutter.EVENT_PROPAGATE; - - if (opt.PANEL_MODE === 1) { - const panelBox = Main.layoutManager.panelBox; - const [, y] = global.get_pointer(); - if (y > panelBox.allocation.y1 && y < panelBox.allocation.y2) - return Clutter.EVENT_STOP; - } - - if (Me.Util.isShiftPressed()) { - let direction = Me.Util.getScrollDirection(event); - if (direction === null || (Date.now() - this._lastScrollTime) < 150) - return Clutter.EVENT_STOP; - this._lastScrollTime = Date.now(); - - if (direction === Clutter.ScrollDirection.UP) - direction = -1; - - else if (direction === Clutter.ScrollDirection.DOWN) - direction = 1; - else - direction = 0; - - if (direction) { - Me.Util.reorderWorkspace(direction); - // make all workspaces on primary monitor visible for case the new position is hidden - const primaryMonitorIndex = global.display.get_primary_monitor(); - Main.overview._overview._controls._workspacesDisplay._workspacesViews[primaryMonitorIndex]._workspaces.forEach(w => { - w.visible = true; - }); - return Clutter.EVENT_STOP; - } - } - - return Main.wm.handleWorkspaceScroll(event); - }, - - _onKeyPressEvent(actor, event) { - const symbol = event.get_key_symbol(); - /* const { ControlsState } = OverviewControls; - if (this._overviewAdjustment.value !== ControlsState.WINDOW_PICKER && symbol !== Clutter.KEY_space) - return Clutter.EVENT_PROPAGATE;*/ - - /* if (!this.reactive) - return Clutter.EVENT_PROPAGATE; */ - const { workspaceManager } = global; - const vertical = workspaceManager.layout_rows === -1; - const rtl = this.get_text_direction() === Clutter.TextDirection.RTL; - const state = this._overviewAdjustment.value; - - let which; - switch (symbol) { - case Clutter.KEY_Return: - case Clutter.KEY_KP_Enter: - if (Me.Util.isCtrlPressed()) { - Main.ctrlAltTabManager._items.forEach(i => { - if (i.sortGroup === 1 && i.name === 'Dash') - Main.ctrlAltTabManager.focusGroup(i); - }); - } - return Clutter.EVENT_STOP; - case Clutter.KEY_Page_Up: - if (vertical) - which = Meta.MotionDirection.UP; - else if (rtl) - which = Meta.MotionDirection.RIGHT; - else - which = Meta.MotionDirection.LEFT; - break; - case Clutter.KEY_Page_Down: - if (vertical) - which = Meta.MotionDirection.DOWN; - else if (rtl) - which = Meta.MotionDirection.LEFT; - else - which = Meta.MotionDirection.RIGHT; - break; - case Clutter.KEY_Home: - which = 0; - break; - case Clutter.KEY_End: - which = workspaceManager.n_workspaces - 1; - break; - case Clutter.KEY_space: - if (Me.Util.isCtrlPressed() && Me.Util.isShiftPressed()) { - Me.Util.openPreferences(); - } else if (Me.Util.isAltPressed()) { - Main.ctrlAltTabManager._items.forEach(i => { - if (i.sortGroup === 1 && i.name === 'Dash') - Main.ctrlAltTabManager.focusGroup(i); - }); - } else if (Me.Util.getEnabledExtensions('extensions-search-provider').length && Me.Util.isCtrlPressed()) { - Me.Util.activateSearchProvider(Me.ESP_PREFIX); - } else if (Me.Util.getEnabledExtensions('windows-search-provider').length) { - Me.Util.activateSearchProvider(Me.WSP_PREFIX); - } - - return Clutter.EVENT_STOP; - case Clutter.KEY_Down: - case Clutter.KEY_Left: - case Clutter.KEY_Right: - case Clutter.KEY_Up: - case Clutter.KEY_Tab: - if (Main.overview.searchController.searchActive) { - Main.overview.searchEntry.grab_key_focus(); - } else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && state === 1) { - // expose windows by "clicking" on ws thumbnail - // in this case overview stateAdjustment will be used for transition - Main.overview._overview.controls._thumbnailsBox._activateThumbnailAtPoint(0, 0, global.get_current_time(), true); - Main.ctrlAltTabManager._items.forEach(i => { - if (i.sortGroup === 1 && i.name === 'Windows') - Main.ctrlAltTabManager.focusGroup(i); - }); - } else if (opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE && state === 1) { - // expose windows for OVERVIEW_MODE 1 - const wsIndex = global.workspace_manager.get_active_workspace().index(); - // after expose animation activate keyboard for window selection - const callback = Me.Util.activateKeyboardForWorkspaceView; - this._workspacesViews.forEach( - view => { - view.exposeWindows(wsIndex, callback); - } - ); - } else { - if (state === 2) - return Clutter.EVENT_PROPAGATE; - Me.Util.activateKeyboardForWorkspaceView(); - } - - return Clutter.EVENT_STOP; - default: - return Clutter.EVENT_PROPAGATE; - } - - if (state === 2) - return Clutter.EVENT_PROPAGATE; - - let ws; - if (which < 0) - // Negative workspace numbers are directions - ws = workspaceManager.get_active_workspace().get_neighbor(which); - else - // Otherwise it is a workspace index - ws = workspaceManager.get_workspace_by_index(which); - - if (Me.Util.isShiftPressed()) { - let direction; - if (which === Meta.MotionDirection.UP || which === Meta.MotionDirection.LEFT) - direction = -1; - else if (which === Meta.MotionDirection.DOWN || which === Meta.MotionDirection.RIGHT) - direction = 1; - if (direction) - Me.Util.reorderWorkspace(direction); - // make all workspaces on primary monitor visible for case the new position is hidden - Main.overview._overview._controls._workspacesDisplay._workspacesViews[0]._workspaces.forEach(w => { - w.visible = true; - }); - return Clutter.EVENT_STOP; - } - - if (ws) - Main.wm.actionMoveWorkspace(ws); - - return Clutter.EVENT_STOP; - }, -}; - -// same copy of this function should be available in OverviewControls and WorkspacesView -function _getFitModeForState(state) { - switch (state) { - case ControlsState.HIDDEN: - case ControlsState.WINDOW_PICKER: - return FitMode.SINGLE; - case ControlsState.APP_GRID: - if (opt.WS_ANIMATION && opt.SHOW_WS_TMB) - return FitMode.ALL; - else - return FitMode.SINGLE; - default: - return FitMode.SINGLE; - } -} |