diff options
Diffstat (limited to 'extensions/vertical-workspaces/lib')
26 files changed, 0 insertions, 10933 deletions
diff --git a/extensions/vertical-workspaces/lib/appDisplay.js b/extensions/vertical-workspaces/lib/appDisplay.js deleted file mode 100644 index 2ac70b1..0000000 --- a/extensions/vertical-workspaces/lib/appDisplay.js +++ /dev/null @@ -1,1474 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * appDisplay.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Clutter, GLib, GObject, Meta, Shell, St, Graphene, Pango } = imports.gi; - -const DND = imports.ui.dnd; -const Main = imports.ui.main; -const AppDisplay = imports.ui.appDisplay; -const IconGrid = imports.ui.iconGrid; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const IconGridOverride = Me.imports.lib.iconGrid; -const _Util = Me.imports.lib.util; - -const DIALOG_SHADE_NORMAL = Clutter.Color.from_pixel(0x00000022); -const DIALOG_SHADE_HIGHLIGHT = Clutter.Color.from_pixel(0x00000000); - -// gettext -const _ = Me.imports.lib.settings._; - -let _overrides; - -let _appGridLayoutSettings; -let _appDisplayScrollConId; -let _appSystemStateConId; -let _appGridLayoutConId; -let _origAppViewItemAcceptDrop; -let _updateFolderIcons; - -let opt; -let shellVersion = _Util.shellVersion; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('appDisplayModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - if (reset) { - _setAppDisplayOrientation(false); - _updateAppGridProperties(reset); - _updateAppGridDND(reset); - _restoreOverviewGroup(); - _overrides = null; - opt = null; - return; - } - - _overrides = new _Util.Overrides(); - - if (opt.ORIENTATION === Clutter.Orientation.VERTICAL) { - _overrides.addOverride('AppDisplayVertical', AppDisplay.AppDisplay.prototype, AppDisplayVertical); - _overrides.addOverride('BaseAppViewVertical', AppDisplay.BaseAppView.prototype, BaseAppViewVertical); - } - - // Custom App Grid - _overrides.addOverride('AppFolderDialog', AppDisplay.AppFolderDialog.prototype, AppFolderDialog); - if (shellVersion >= 43) { - // const defined class needs to be touched before real access - AppDisplay.BaseAppViewGridLayout; - _overrides.addOverride('BaseAppViewGridLayout', AppDisplay.BaseAppViewGridLayout.prototype, BaseAppViewGridLayout); - } - _overrides.addOverride('FolderView', AppDisplay.FolderView.prototype, FolderView); - _overrides.addOverride('FolderIcon', AppDisplay.FolderIcon.prototype, FolderIcon); - _overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIcon); - _overrides.addOverride('AppDisplay', AppDisplay.AppDisplay.prototype, AppDisplayCommon); - _overrides.addOverride('AppViewItem', AppDisplay.AppViewItem.prototype, AppViewItemCommon); - _overrides.addOverride('BaseAppViewCommon', AppDisplay.BaseAppView.prototype, BaseAppViewCommon); - - _setAppDisplayOrientation(opt.ORIENTATION === Clutter.Orientation.VERTICAL); - _updateAppGridProperties(); - _updateAppGridDND(); - opt._appGridNeedsRedisplay = true; -} - -function _setAppDisplayOrientation(vertical = false) { - const CLUTTER_ORIENTATION = vertical ? Clutter.Orientation.VERTICAL : Clutter.Orientation.HORIZONTAL; - const scroll = vertical ? 'vscroll' : 'hscroll'; - // 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 - // needs corrections in appgrid page calculations, e.g. appDisplay.adaptToSize() fnc, - // which complicates use of super call inside the function - 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; - - const scrollContainer = appDisplay._scrollView.get_parent(); - if (shellVersion < 43) { - // remove touch friendly side navigation bars / arrows - if (appDisplay._hintContainer && appDisplay._hintContainer.get_parent()) - scrollContainer.remove_child(appDisplay._hintContainer); - } else { - // 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 (_appDisplayScrollConId) { - appDisplay._adjustment.disconnect(_appDisplayScrollConId); - _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 bars/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 = appDisplay._scrollView[scroll].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 - _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 -function _updateAppGridProperties(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.setGridModes(); - if (_appGridLayoutSettings) { - _appGridLayoutSettings.disconnect(_appGridLayoutConId); - _appGridLayoutConId = 0; - _appGridLayoutSettings = null; - } - appDisplay._redisplay(); - - appDisplay._grid.set_style(''); - _resetAppGrid(); - } else { - // update grid on layout reset - if (!_appGridLayoutSettings) { - _appGridLayoutSettings = ExtensionUtils.getSettings('org.gnome.shell'); - _appGridLayoutConId = _appGridLayoutSettings.connect('changed::app-picker-layout', _resetAppGrid); - } - - 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;`); - - // force redisplay - appDisplay._grid._currentMode = -1; - appDisplay._grid.setGridModes(); - appDisplay._grid.layoutManager.fixedIconSize = opt.APP_GRID_ICON_SIZE; - // appDisplay._folderIcons.forEach(folder => folder._dialog?._updateFolderSize()); - _resetAppGrid(); - } -} - -function _updateAppGridDND(reset) { - if (!reset) { - if (!_appSystemStateConId && opt.APP_GRID_INCLUDE_DASH >= 3) { - _appSystemStateConId = Shell.AppSystem.get_default().connect( - 'app-state-changed', - () => { - _updateFolderIcons = true; - Main.overview._overview._controls._appDisplay._redisplay(); - } - ); - } - } else if (_appSystemStateConId) { - Shell.AppSystem.get_default().disconnect(_appSystemStateConId); - _appSystemStateConId = 0; - } - if (opt.APP_GRID_ORDER && !reset) { - if (!_origAppViewItemAcceptDrop) - _origAppViewItemAcceptDrop = AppDisplay.AppViewItem.prototype.acceptDrop; - AppDisplay.AppViewItem.prototype.acceptDrop = () => false; - } else if (_origAppViewItemAcceptDrop) { - AppDisplay.AppViewItem.prototype.acceptDrop = _origAppViewItemAcceptDrop; - } -} - -function _restoreOverviewGroup() { - Main.overview.dash.showAppsButton.checked = false; - Main.layoutManager.overviewGroup.opacity = 255; - Main.layoutManager.overviewGroup.scale_x = 1; - Main.layoutManager.overviewGroup.hide(); -} - -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); - }, -}; - -const AppDisplayCommon = { - _ensureDefaultFolders() { - // disable creation of default folders if user deleted them - }, - - _redisplay() { - this._folderIcons.forEach(icon => { - icon.view._redisplay(); - }); - - BaseAppViewCommon._redisplay.bind(this)(); - }, - - // 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_ORDER) { - 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 (_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 - _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_ORDER && 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); - if (shellVersion < 43) - this._slideSidePages(AppDisplay.SidePages.PREVIOUS | AppDisplay.SidePages.NEXT | AppDisplay.SidePages.DND); - else - 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 preview - acceptDrop(source) { - if (opt.APP_GRID_ORDER) - return false; - if (source._sourceItem) - source = source._sourceItem; - - let dropTarget = null; - if (shellVersion >= 43) { - dropTarget = this._dropTarget; - delete this._dropTarget; - } - - if (!this._canAccept(source)) - return false; - - if ((shellVersion < 43 && this._dropPage) || - (shellVersion >= 43 && (dropTarget === this._prevPageIndicator || - dropTarget === this._nextPageIndicator))) { - let increment; - - if (shellVersion < 43) - increment = this._dropPage === AppDisplay.SidePages.NEXT ? 1 : -1; - else - 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) { - log(`Warning:${e}`); - } - this._removeDelayedMove(); - } - - this._savePages(); - - 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;'); - const scrollContainer = this._scrollView.get_parent(); - if (shellVersion < 43) { - // remove touch friendly side navigation bars / arrows - if (this._hintContainer && this._hintContainer.get_parent()) - scrollContainer.remove_child(this._hintContainer); - } else { - // 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.vscroll.adjustment; - - this._adjustment.connect('notify::value', adj => { - const value = adj.value / adj.page_size; - this._pageIndicators.setCurrentPosition(value); - }); - }, - // <= 42 only, this fixes dnd from appDisplay to the workspace thumbnail on the left if appDisplay is on page 1 because of appgrid left overshoot - _pageForCoords() { - return AppDisplay.SidePages.NONE; - }, -}; - -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) { - log(`Warning:${e}`); - } - }); - }, - - // adds sorting options and option to add favorites and running apps - _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 - } - }); - - // sort all alphabetically - if (opt.APP_GRID_ORDER > 0) { - // const { itemsPerPage } = this._grid; - let appIcons = this._orderedItems; - this._sortOrderedItemsAlphabetically(appIcons); - // appIcons.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase())); - // then sort used apps by usage - if (opt.APP_GRID_ORDER === 2) - 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) - appIcons.sort((a, b) => a.app.get_state() !== Shell.AppState.RUNNING && b.app.get_state() === Shell.AppState.RUNNING); - - 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 opt.APP_GRID_ORDER ? false : source instanceof AppDisplay.AppViewItem; - }, - - // support active preview icons - acceptDrop(source) { - if (!this._canAccept(source)) - return false; - - if (source._sourceItem) - source = source._sourceItem; - - - if (this._dropPage) { - const increment = this._dropPage === AppDisplay.SidePages.NEXT ? 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; - - this._moveItem(source, page, position); - 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 (shellVersion < 43) { - this._dropPage = this._pageForCoords(dragEvent.x, dragEvent.y); - if (this._dropPage && - this._dropPage === AppDisplay.SidePages.PREVIOUS && - this._grid.currentPage === 0) { - delete this._dropPage; - return DND.DragMotionResult.NO_DROP; - } - } - - if (appIcon instanceof AppDisplay.AppViewItem) { - if (shellVersion < 44) { - // Handle the drag overshoot. When dragging to above the - // icon grid, move to the page above; when dragging below, - // move to the page below. - this._handleDragOvershoot(dragEvent); - } else 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(); - } - } - - this._maybeMoveItem(dragEvent); - - return DND.DragMotionResult.CONTINUE; - }, - - // adjustable page width for GS <= 42 - adaptToSize(width, height, isFolder = false) { - let box = new Clutter.ActorBox({ - x2: width, - y2: height, - }); - box = this.get_theme_node().get_content_box(box); - box = this._scrollView.get_theme_node().get_content_box(box); - box = this._grid.get_theme_node().get_content_box(box); - - const availWidth = box.get_width(); - const availHeight = box.get_height(); - - let pageWidth, pageHeight; - - pageHeight = availHeight; - pageWidth = Math.ceil(availWidth * (isFolder ? 1 : opt.APP_GRID_PAGE_WIDTH_SCALE)); - // subtract space for navigation arrows in horizontal mode - pageWidth -= opt.ORIENTATION ? 0 : 128; - - this._grid.layout_manager.pagePadding.left = - Math.floor(availWidth * 0.02); - this._grid.layout_manager.pagePadding.right = - Math.ceil(availWidth * 0.02); - - this._grid.adaptToSize(pageWidth, pageHeight); - - const leftPadding = Math.floor( - (availWidth - this._grid.layout_manager.pageWidth) / 2); - const rightPadding = Math.ceil( - (availWidth - this._grid.layout_manager.pageWidth) / 2); - const topPadding = Math.floor( - (availHeight - this._grid.layout_manager.pageHeight) / 2); - const bottomPadding = Math.ceil( - (availHeight - this._grid.layout_manager.pageHeight) / 2); - - this._scrollView.content_padding = new Clutter.Margin({ - left: leftPadding, - right: rightPadding, - top: topPadding, - bottom: bottomPadding, - }); - - this._availWidth = availWidth; - this._availHeight = availHeight; - - this._pageIndicatorOffset = leftPadding; - this._pageArrowOffset = Math.max( - leftPadding - 80, 0); // 80 is AppDisplay.PAGE_PREVIEW_MAX_ARROW_OFFSET - }, -}; - -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; - - // build the folders now to avoid node errors when dragging active folder preview icons - if (this.visible && opt.APP_GRID_ACTIVE_PREVIEW) - this._ensureFolderDialog(); - }, - - open() { - this._ensureFolderDialog(); - if (this._dialog._designCapacity !== this.view._orderedItems.length) - this._dialog._updateFolderSize(); - - this.view._scrollView.vscroll.adjustment.value = 0; - this._dialog.popup(); - }, -}; - -const FolderView = { - _createGrid() { - let grid; - if (shellVersion < 43) - grid = new FolderGrid(); - else - grid = new FolderGrid43(); - - // IconGrid algorithm for adaptive icon size - // counts with different default(max) size for folders - grid.layoutManager._isFolder = true; - 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 ActiveFolderIcon(app); - child._sourceItem = this._orderedItems[i]; - child._sourceFolder = this; - child.icon.style_class = ''; - child.icon.set_style('margin: 0; padding: 0;'); - child.icon.setIconSize(subSize); - - bin.child = child; - - bin.connect('enter-event', () => { - bin.ease({ - duration: 100, - scale_x: 1.14, - scale_y: 1.14, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - }); - bin.connect('leave-event', () => { - bin.ease({ - duration: 100, - scale_x: 1, - scale_y: 1, - 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 - if (this._dialog && this._dialog._designCapacity !== this._orderedItems.length) - this._dialog._updateFolderSize(); - - return icon; - }, - - // this just overrides _redisplay() for GS < 44 - _redisplay() { - // super._redisplay(); - super doesn't work in my overrides - AppDisplay.BaseAppView.prototype._redisplay.bind(this)(); - }, - - _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 (!AppDisplay._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); - }); - 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); - }, -}; - -// folder columns and rows -const FolderGrid = GObject.registerClass( -class FolderGrid extends IconGrid.IconGrid { - _init() { - super._init({ - allow_incomplete_pages: false, - // For adaptive size (0), set the numbers high enough to fit all the icons - // to avoid splitting the icons to pages - 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, - }); - - // if (!opt.APP_GRID_FOLDER_DEFAULT) - const spacing = opt.APP_GRID_SPACING; - this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`); - this.layout_manager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE; - } - - adaptToSize(width, height) { - this.layout_manager.adaptToSize(width, height); - } -}); - - -let FolderGrid43; -// first reference to constant defined using const in other module returns undefined, the AppGrid const will remain empty and unused -const AppGrid = AppDisplay.AppGrid; -if (AppDisplay.AppGrid) { - FolderGrid43 = GObject.registerClass( - class FolderGrid43 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, - }); - - const spacing = opt.APP_GRID_SPACING; - this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`); - this.layout_manager.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() { - // 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); - }, - - popup() { - if (this._isOpen) - return; - - /* if (!this._correctSize) { - // update folder with the precise app item size when the dialog is realized - GLib.idle_add(0, () => this._updateFolderSize(true)); - this._correctSize = true; - }*/ - - 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; - this.show(); - - this.emit('open-state-changed', true); - }, - - _updateFolderSize() { - // adapt folder size according to the settings and number of icons - const view = this._view; - view._grid.layoutManager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE; - view._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`); - - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - const dialogMargin = 30; - const nItems = view._orderedItems.length; - let columns = opt.APP_GRID_FOLDER_COLUMNS; - let rows = opt.APP_GRID_FOLDER_ROWS; - let spacing = opt.APP_GRID_SPACING; - const monitor = global.display.get_monitor_geometry(global.display.get_primary_monitor()); - - if (!columns && !rows) { - 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; - let itemSize = iconSize + 53; // 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._notFirstRun) { - const [firstItem] = view._grid.layoutManager._container; - firstItem.icon.setIconSize(iconSize); - const [firstItemWidth] = firstItem.get_preferred_size(); - const realSize = firstItemWidth / scaleFactor; - if (realSize > iconSize) - itemSize = realSize; - } else { - this._needsUpdateSize = true; - this._notFirstRun = true; - } - - - let width = columns * (itemSize + spacing) + /* padding for nav arrows*/64; - width = Math.round(width + (opt.ORIENTATION || !opt.APP_GRID_FOLDER_COLUMNS ? 100 : 160/* space for navigation arrows*/)); - let height = rows * (itemSize + spacing) + /* header*/75 + /* padding*/100; - - // folder must fit the primary monitor - // reduce columns/rows if needed and count with the scaled values - while (width * scaleFactor > monitor.width - 2 * dialogMargin) { - width -= itemSize + spacing; - columns -= 1; - } - while (height * scaleFactor > monitor.height - 2 * dialogMargin) { - height -= itemSize + spacing; - rows -= 1; - } - width = Math.max(540, width); - - 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; - if (!opt.APP_GRID_FOLDER_CENTER) { - const appDisplay = this._source._parentView; - - dialogTargetX = Math.round(sourceCenterX - this.child.width / 2); - dialogTargetY = Math.round(sourceCenterY - this.child.height / 2); - - // keep the dialog in appDisplay area if possible - dialogTargetX = Math.clamp( - dialogTargetX, - this.x + appDisplay.x, - this.x + appDisplay.x + appDisplay.width - this.child.width - ); - - dialogTargetY = Math.clamp( - dialogTargetY, - this.y + appDisplay.y, - this.y + appDisplay.y + appDisplay.height - this.child.height - ); - // or at least in the monitor area - const monitor = global.display.get_monitor_geometry(global.display.get_primary_monitor()); - dialogTargetX = Math.clamp( - dialogTargetX, - this.x + monitor.x, - this.x + monitor.x + monitor.width - this.child.width - ); - - dialogTargetY = Math.clamp( - dialogTargetY, - this.y + monitor.y, - this.y + monitor.y + monitor.height - this.child.height - ); - } - const dialogOffsetX = -dialogX + dialogTargetX; - const dialogOffsetY = -dialogY + dialogTargetY; - - 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.ease({ - background_color: DIALOG_SHADE_NORMAL, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - 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, - onComplete: () => { - // if the folder grid was build with the estimated icon item size because the real size wasn't available - // rebuild it with the real size now, after the folder was realized - if (this._needsUpdateSize) { - this._updateFolderSize(); - this._view._redisplay(); - this._needsUpdateSize = false; - } - }, - }); - - 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; - } - - let [sourceX, sourceY] = - this._source.get_transformed_position(); - let [dialogX, dialogY] = - this.child.get_transformed_position(); - - this.ease({ - background_color: Clutter.Color.from_pixel(0x00000000), - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - - 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 = []; - }, - }); - - this._needsZoomAndFade = false; - }, - - _setLighterBackground(lighter) { - const backgroundColor = lighter - ? DIALOG_SHADE_HIGHLIGHT - : DIALOG_SHADE_NORMAL; - - this.ease({ - backgroundColor, - duration: FOLDER_DIALOG_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - }, -}; - -// just make app grid to update all invalid positions that may be result of grid/icon size change -function _updateIconPositions() { - const appDisplay = Main.overview._overview._controls._appDisplay; - const icons = [...appDisplay._orderedItems]; - for (let i = 0; i < icons.length; i++) - appDisplay._moveItem(icons[i], -1, -1); -} - -function _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 = []; -} - -function _resetAppGrid(settings) { - 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 - if (settings) { - const currentValue = JSON.stringify(global.settings.get_value('app-picker-layout').deep_unpack()); - const emptyValue = JSON.stringify([]); - const customLayout = currentValue !== emptyValue; - // appDisplay._customLayout = customLayout; - if (customLayout) - return; - else - opt._appGridNeedsRedisplay = true; - } - - // 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); - _removeIcons(); - appDisplay._redisplay(); - // force appDisplay to move all icons to proper positions and update all properties - GLib.idle_add(0, () => { - _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); - } else { - appDisplay._removeItem(appDisplay._orderedItems[0]); - appDisplay._redisplay(); - } - - appDisplay._redisplay(); - }); -} - -function _getWindowApp(metaWin) { - const tracker = Shell.WindowTracker.get_default(); - return tracker.get_window_app(metaWin); -} - -function _getAppLastUsedWindow(app) { - let recentWin; - global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => { - const winApp = _getWindowApp(metaWin); - if (!recentWin && winApp === app) - recentWin = metaWin; - }); - return recentWin; -} - -function _getAppRecentWorkspace(app) { - const recentWin = _getAppLastUsedWindow(app); - if (recentWin) - return recentWin.get_workspace(); - - return null; -} - -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_ORDER); - }, -}; - -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 - ? AppDisplay.APP_ICON_TITLE_EXPAND_TIME - : AppDisplay.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_ORDER) - 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; - }, - -}; - -const ActiveFolderIcon = GObject.registerClass( -class ActiveFolderIcon extends AppDisplay.AppIcon { - _init(app) { - super._init(app, { - setSizeManually: true, - showLabel: false, - }); - } - - handleDragOver() { - return DND.DragMotionResult.CONTINUE; - } - - acceptDrop() { - return false; - } - - _onDragEnd() { - this._dragging = false; - this.undoScaleAndFade(); - Main.overview.endItemDrag(this._sourceItem.icon); - } -}); diff --git a/extensions/vertical-workspaces/lib/appFavorites.js b/extensions/vertical-workspaces/lib/appFavorites.js deleted file mode 100644 index 50ebce9..0000000 --- a/extensions/vertical-workspaces/lib/appFavorites.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * appFavorites.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Shell } = imports.gi; -const AppFavorites = imports.ui.appFavorites; -const Main = imports.ui.main; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -let opt; -let _overrides; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('appFavoritesModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - - // if notifications are enabled no override is needed - if (reset || opt.SHOW_FAV_NOTIFICATION) { - _overrides = null; - opt = null; - return; - } - - _overrides = new _Util.Overrides(); - - // AppFavorites.AppFavorites is const, first access returns undefined - const dummy = AppFavorites.AppFavorites; - _overrides.addOverride('AppFavorites', AppFavorites.AppFavorites.prototype, AppFavoritesCommon); -} - -const AppFavoritesCommon = { - addFavoriteAtPos(appId, pos) { - this._addFavorite(appId, pos); - }, - - removeFavorite(appId) { - this._removeFavorite(appId); - }, -}; diff --git a/extensions/vertical-workspaces/lib/dash.js b/extensions/vertical-workspaces/lib/dash.js deleted file mode 100644 index bf832bd..0000000 --- a/extensions/vertical-workspaces/lib/dash.js +++ /dev/null @@ -1,1186 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * dash.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022-2023 - * @license GPL-3.0 - * modified dash module of https://github.com/RensAlthuis/vertical-overview extension - */ - -const { Clutter, GObject, St, Shell, Meta } = imports.gi; -const AppDisplay = imports.ui.appDisplay; -const AppFavorites = imports.ui.appFavorites; -const DND = imports.ui.dnd; -const IconGrid = imports.ui.iconGrid; -const Main = imports.ui.main; -const Overview = imports.ui.overview; -const Dash = imports.ui.dash; -const PopupMenu = imports.ui.popupMenu; -const { AppMenu } = imports.ui.appMenu; -const BoxPointer = imports.ui.boxpointer; -const AltTab = imports.ui.altTab; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Util = Me.imports.lib.util; -const _ = Me.imports.lib.settings._; - -const shellVersion = Util.shellVersion; -let _origWorkId; -let _newWorkId; -let _showAppsIconBtnPressId; - -// added values to achieve a better ability to scale down according to available space -var BaseIconSizes = [16, 24, 32, 40, 44, 48, 56, 64, 72, 80, 96, 112, 128]; - -const RecentFilesSearchProviderPrefix = Me.imports.lib.recentFilesSearchProvider.prefix; -const WindowSearchProviderPrefix = Me.imports.lib.windowSearchProvider.prefix; - -let _overrides; -let opt; -let _firstRun = true; - -const DASH_ITEM_LABEL_SHOW_TIME = 150; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('dashModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - - const dash = Main.overview._overview._controls.layoutManager._dash; - - setToHorizontal(); - - dash.remove_style_class_name('vertical'); - dash.remove_style_class_name('vertical-left'); - dash.remove_style_class_name('vertical-right'); - - if (reset) { - _moveDashAppGridIcon(reset); - _connectShowAppsIcon(reset); - _updateSearchWindowsIcon(false); - _updateRecentFilesIcon(false); - dash.visible = true; - dash._background.opacity = 255; - dash._background.remove_style_class_name('v-shell-dash-background'); - _overrides = null; - opt = null; - return; - } - - _overrides = new Util.Overrides(); - - _overrides.addOverride('DashItemContainer', Dash.DashItemContainer.prototype, DashItemContainerCommon); - _overrides.addOverride('DashCommon', Dash.Dash.prototype, DashCommon); - _overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIconCommon); - _overrides.addOverride('DashIcon', Dash.DashIcon.prototype, DashIconCommon); - - if (opt.DASH_VERTICAL) { - _overrides.addOverride('Dash', Dash.Dash.prototype, DashOverride); - setToVertical(); - dash.add_style_class_name('vertical'); - - if (!_newWorkId) { - _origWorkId = dash._workId; - dash._workId = Main.initializeDeferredWork(dash._box, dash._redisplay.bind(dash)); - _newWorkId = dash._workId; - } else { - dash._workId = _newWorkId; - } - } else { - setToHorizontal(); - if (_origWorkId) - dash._workId = _origWorkId; - } - - _updateSearchWindowsIcon(); - _updateRecentFilesIcon(); - _moveDashAppGridIcon(); - _connectShowAppsIcon(); - - if (dash._showWindowsIcon && !dash._showWindowsIconClickedId) - dash._showWindowsIconClickedId = dash._showWindowsIcon.toggleButton.connect('clicked', (a, c) => c && Util.activateSearchProvider(WindowSearchProviderPrefix)); - - if (dash._recentFilesIcon && !dash._recentFilesIconClickedId) - dash._recentFilesIconClickedId = dash._recentFilesIcon.toggleButton.connect('clicked', (a, c) => c && Util.activateSearchProvider(RecentFilesSearchProviderPrefix)); - - dash.visible = opt.DASH_VISIBLE; - dash._background.add_style_class_name('v-shell-dash-background'); - dash._redisplay(); -} - -function setToVertical() { - let dash = Main.overview._overview._controls.layoutManager._dash; - - dash._box.layout_manager.orientation = Clutter.Orientation.VERTICAL; - dash._dashContainer.layout_manager.orientation = Clutter.Orientation.VERTICAL; - dash._dashContainer.y_expand = false; - dash._dashContainer.x_expand = true; - dash.x_align = Clutter.ActorAlign.START; - dash.y_align = Clutter.ActorAlign.CENTER; - - let sizerBox = dash._background.get_children()[0]; - sizerBox.clear_constraints(); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: dash._showAppsIcon.icon, - coordinate: Clutter.BindCoordinate.WIDTH, - })); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: dash._dashContainer, - coordinate: Clutter.BindCoordinate.HEIGHT, - })); - dash._box.remove_all_children(); - dash._separator = null; - dash._queueRedisplay(); - dash._adjustIconSize(); - - dash.add_style_class_name(opt.DASH_LEFT ? 'vertical-left' : 'vertical-right'); -} - -function setToHorizontal() { - let dash = Main.overview._overview._controls.layoutManager._dash; - if (_origWorkId) - dash._workId = _origWorkId; // pretty sure this is a leak, but there no provided way to disconnect these... - dash._box.layout_manager.orientation = Clutter.Orientation.HORIZONTAL; - dash._dashContainer.layout_manager.orientation = Clutter.Orientation.HORIZONTAL; - dash._dashContainer.y_expand = true; - dash._dashContainer.x_expand = false; - dash.x_align = Clutter.ActorAlign.CENTER; - dash.y_align = 0; - - let sizerBox = dash._background.get_children()[0]; - sizerBox.clear_constraints(); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: dash._showAppsIcon.icon, - coordinate: Clutter.BindCoordinate.HEIGHT, - })); - sizerBox.add_constraint(new Clutter.BindConstraint({ - source: dash._dashContainer, - coordinate: Clutter.BindCoordinate.WIDTH, - })); - - dash._box.remove_all_children(); - dash._separator = null; - dash._queueRedisplay(); - dash._adjustIconSize(); -} - -function _moveDashAppGridIcon(reset = false) { - // move dash app grid icon to the front - const dash = Main.overview._overview._controls.layoutManager._dash; - - const appIconPosition = opt.get('showAppsIconPosition', true); - 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; - } -} - -function _connectShowAppsIcon(reset = false) { - if (!reset) { - if (_showAppsIconBtnPressId || Util.dashIsDashToDock()) { - // button is already connected || dash is Dash to Dock - return; - } - - Main.overview.dash._showAppsIcon.reactive = true; - _showAppsIconBtnPressId = Main.overview.dash._showAppsIcon.connect('button-press-event', (actor, event) => { - const button = event.get_button(); - if (button === Clutter.BUTTON_MIDDLE) - Util.openPreferences(); - else if (button === Clutter.BUTTON_SECONDARY) - Util.activateSearchProvider(WindowSearchProviderPrefix); - else - return Clutter.EVENT_PROPAGATE; - return Clutter.EVENT_STOP; - }); - } else if (_showAppsIconBtnPressId) { - Main.overview.dash._showAppsIcon.disconnect(_showAppsIconBtnPressId); - _showAppsIconBtnPressId = 0; - Main.overview.dash._showAppsIcon.reactive = false; - } -} - -const DashOverride = { - handleDragOver(source, actor, _x, y, _time) { - let app = Dash.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 boxHeight = this._box.height; - - // 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) { - boxHeight -= this._dragPlaceholder.height; - numChildren--; - } - - // Same with the separator - if (this._separator) { - boxHeight -= this._separator.height; - numChildren--; - } - - let pos; - if (!this._emptyDropTarget) - pos = Math.floor(y * numChildren / boxHeight); - else - pos = 0; // always insert at the top when dash is empty - - // 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(); - this._dragPlaceholder.child.set_width(this.iconSize / 2); - this._dragPlaceholder.child.set_height(this.iconSize); - 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; - }, - - _redisplay() { - let favorites = AppFavorites.getAppFavorites().getFavoriteMap(); - - let running = this._appSystem.get_running(); - - 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: this.iconSize, - height: 1, - }); - this._box.add_child(this._separator); - } - - // FIXME: separator placement is broken (also in original dash) - let pos = nFavorites; - 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; - indicator.x_align = opt.DASH_LEFT ? Clutter.ActorAlign.START : Clutter.ActorAlign.END; - indicator.y_align = Clutter.ActorAlign.CENTER; - - 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; - }, -}; - -const DashItemContainerCommon = { - // move labels according dash position - showLabel() { - if (!this._labelText) - return; - - this.label.set_text(this._labelText); - 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); - - let node = this.label.get_theme_node(); - let y; - - if (opt.DASH_TOP) { - const yOffset = itemHeight - labelHeight + 3 * node.get_length('-y-offset'); - 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 = 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 = 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 = { - // 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); - - if (this._showWindowsIcon) - iconChildren.push(this._showWindowsIcon); - - if (this._recentFilesIcon) - iconChildren.push(this._recentFilesIcon); - - - 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; - }, -}; - -const DashIconCommon = { - after__init() { - if (opt.DASH_ICON_SCROLL) { - this._scrollConId = this.connect('scroll-event', _onScrollEvent.bind(this)); - this._leaveConId = this.connect('leave-event', _onLeaveEvent.bind(this)); - } - }, -}; - -function _onScrollEvent(source, event) { - if ((this.app && !opt.DASH_ICON_SCROLL) || (this._isSearchWindowsIcon && !opt.SEARCH_WINDOWS_ICON_SCROLL)) { - if (this._scrollConId) - this.disconnect(this._scrollConId); - if (this._leaveConId) - this.disconnect(this._leaveConId); - return Clutter.EVENT_PROPAGATE; - } - - let direction = 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(); - - _switchWindow.bind(this)(direction); - return Clutter.EVENT_STOP; -} - -function _onLeaveEvent() { - if (!this._selectedMetaWin || this.has_pointer || this.toggleButton?.has_pointer) - return; - - this._selectedPreview._activateSelected = false; - this._selectedMetaWin = null; - this._scrolledWindows = null; - _showWindowPreview.bind(this)(null); -} - -function _switchWindow(direction) { - if (!this._scrolledWindows) { - // source is app icon - if (this.app) { - this._scrolledWindows = this.app.get_windows(); - 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 = AltTab.getWindows(null); - else - this._scrolledWindows = AltTab.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 + direction; - - if (targetIdx > windows.length - 1) - targetIdx = 0; - else if (targetIdx < 0) - targetIdx = windows.length - 1; - - const metaWin = windows[targetIdx]; - _showWindowPreview.bind(this)(metaWin); - this._selectedMetaWin = metaWin; -} - -function _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()); - - 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 = { - activate(button) { - const event = Clutter.get_current_event(); - const state = event ? event.get_state() : 0; - const isMiddleButton = button && button === Clutter.BUTTON_MIDDLE; - const isCtrlPressed = Util.isCtrlPressed(state); - const isShiftPressed = Util.isShiftPressed(state); - const openNewWindow = (this.app.can_open_new_window() && - this.app.state === Shell.AppState.RUNNING && - (isCtrlPressed || isMiddleButton) && !opt.DASH_CLICK_ACTION === 2) || - (opt.DASH_CLICK_ACTION === 2 && !this._selectedMetaWin && !isMiddleButton); - - const currentWS = global.workspace_manager.get_active_workspace(); - const appRecentWorkspace = _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); - } - ); - } - - 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)*/) { - // this._scroll = true; - // this._scrollTime = Date.now(); - 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_MODE && !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 && this.app.get_windows().length) { - this._moveAppToCurrentWorkspace(); - 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) { - if (shellVersion >= 42) - 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(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_actor(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++); - } - }]); - } - - if (/* opt.APP_MENU_MV_TO_WS && */this._windowsOnOtherWs()) - popupItems.push([_('Move App to Current Workspace ( Shift + Click )'), this._moveAppToCurrentWorkspace]); - } - - 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)); - 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; - }, -}; - -function _getWindowApp(metaWin) { - const tracker = Shell.WindowTracker.get_default(); - return tracker.get_window_app(metaWin); -} - -function _getAppLastUsedWindow(app) { - let recentWin; - global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => { - const winApp = _getWindowApp(metaWin); - if (!recentWin && winApp === app) - recentWin = metaWin; - }); - return recentWin; -} - -function _getAppRecentWorkspace(app) { - const recentWin = _getAppLastUsedWindow(app); - if (recentWin) - return recentWin.get_workspace(); - - return null; -} - -function _updateSearchWindowsIcon(show = opt.SHOW_WINDOWS_ICON) { - const dash = Main.overview._overview._controls.layoutManager._dash; - const dashContainer = dash._dashContainer; - - if (dash._showWindowsIcon) { - dashContainer.remove_child(dash._showWindowsIcon); - if (dash._showWindowsIconClickedId) - dash._showWindowsIcon.toggleButton.disconnect(dash._showWindowsIconClickedId); - dash._showWindowsIconClickedId = undefined; - if (dash._showWindowsIcon) - dash._showWindowsIcon.destroy(); - dash._showWindowsIcon = undefined; - } - - if (!show || !opt.WINDOW_SEARCH_PROVIDER_ENABLED) - return; - - if (!dash._showWindowsIcon) { - dash._showWindowsIcon = new ShowWindowsIcon(); - dash._showWindowsIcon.show(false); - dashContainer.add_child(dash._showWindowsIcon); - dash._hookUpLabel(dash._showWindowsIcon); - } - - dash._showWindowsIcon.icon.setIconSize(dash.iconSize); - if (opt.SHOW_WINDOWS_ICON === 1) { - dashContainer.set_child_at_index(dash._showWindowsIcon, 0); - } else if (opt.SHOW_WINDOWS_ICON === 2) { - const index = dashContainer.get_children().length - 1; - dashContainer.set_child_at_index(dash._showWindowsIcon, index); - } - - Main.overview._overview._controls.layoutManager._dash._adjustIconSize(); -} - -const ShowWindowsIcon = GObject.registerClass( -class ShowWindowsIcon extends Dash.DashItemContainer { - _init() { - super._init(); - - this._isSearchWindowsIcon = true; - this._labelText = _('Search Open Windows (Hotkey: Space)'); - this.toggleButton = new St.Button({ - style_class: 'show-apps', - track_hover: true, - can_focus: true, - toggle_mode: false, - }); - - this._iconActor = null; - this.icon = new IconGrid.BaseIcon(this.labelText, { - setSizeManually: true, - showLabel: false, - createIcon: this._createIcon.bind(this), - }); - this.icon.y_align = Clutter.ActorAlign.CENTER; - - this.toggleButton.add_actor(this.icon); - this.toggleButton._delegate = this; - - this.setChild(this.toggleButton); - - if (opt.SEARCH_WINDOWS_ICON_SCROLL) { - this.reactive = true; - this._scrollConId = this.connect('scroll-event', _onScrollEvent.bind(this)); - this._leaveConId = this.connect('leave-event', _onLeaveEvent.bind(this)); - } - } - - _createIcon(size) { - this._iconActor = new St.Icon({ - icon_name: 'focus-windows-symbolic', - icon_size: size, - style_class: 'show-apps-icon', - track_hover: true, - }); - return this._iconActor; - } -}); - -function _updateRecentFilesIcon(show = opt.SHOW_RECENT_FILES_ICON) { - const dash = Main.overview._overview._controls.layoutManager._dash; - const dashContainer = dash._dashContainer; - - if (dash._recentFilesIcon) { - dashContainer.remove_child(dash._recentFilesIcon); - if (dash._recentFilesIconClickedId) - dash._recentFilesIcon.toggleButton.disconnect(dash._recentFilesIconClickedId); - dash._recentFilesIconClickedId = undefined; - if (dash._recentFilesIcon) - dash._recentFilesIcon.destroy(); - dash._recentFilesIcon = undefined; - } - - if (!show || !opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED) - return; - - if (!dash._recentFilesIcon) { - dash._recentFilesIcon = new ShowRecentFilesIcon(); - dash._recentFilesIcon.show(false); - dashContainer.add_child(dash._recentFilesIcon); - dash._hookUpLabel(dash._recentFilesIcon); - } - - dash._recentFilesIcon.icon.setIconSize(dash.iconSize); - if (opt.SHOW_RECENT_FILES_ICON === 1) { - dashContainer.set_child_at_index(dash._recentFilesIcon, 0); - } else if (opt.SHOW_RECENT_FILES_ICON === 2) { - const index = dashContainer.get_children().length - 1; - dashContainer.set_child_at_index(dash._recentFilesIcon, index); - } - - Main.overview._overview._controls.layoutManager._dash._adjustIconSize(); -} - -const ShowRecentFilesIcon = GObject.registerClass( -class ShowRecentFilesIcon extends Dash.DashItemContainer { - _init() { - super._init(); - - this._labelText = _('Search Recent Files (Hotkey: Ctrl + Space)'); - this.toggleButton = new St.Button({ - style_class: 'show-apps', - track_hover: true, - can_focus: true, - toggle_mode: false, - }); - - this._iconActor = null; - this.icon = new IconGrid.BaseIcon(this.labelText, { - setSizeManually: true, - showLabel: false, - createIcon: this._createIcon.bind(this), - }); - this.icon.y_align = Clutter.ActorAlign.CENTER; - - this.toggleButton.add_actor(this.icon); - this.toggleButton._delegate = this; - - this.setChild(this.toggleButton); - } - - _createIcon(size) { - this._iconActor = new St.Icon({ - icon_name: 'document-open-recent-symbolic', - icon_size: size, - style_class: 'show-apps-icon', - track_hover: true, - }); - return this._iconActor; - } -}); diff --git a/extensions/vertical-workspaces/lib/iconGrid.js b/extensions/vertical-workspaces/lib/iconGrid.js deleted file mode 100644 index 1aa980e..0000000 --- a/extensions/vertical-workspaces/lib/iconGrid.js +++ /dev/null @@ -1,314 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * iconGrid.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; -const { GLib, St, Meta } = imports.gi; -const IconGrid = imports.ui.iconGrid; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; -const shellVersion = _Util.shellVersion; - -// 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, - 48: 48, - TINY: 32, -}; - -const PAGE_WIDTH_CORRECTION = 100; - -let opt; -let _overrides; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('appDisplayModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - - if (reset) { - _overrides = null; - opt = null; - return; - } - - _overrides = new _Util.Overrides(); - - if (shellVersion < 43 && IconGridCommon._findBestModeForSize) { - IconGridCommon['findBestModeForSize'] = IconGridCommon._findBestModeForSize; - IconGridCommon['_findBestModeForSize'] = undefined; - } - _overrides.addOverride('IconGrid', IconGrid.IconGrid.prototype, IconGridCommon); - _overrides.addOverride('IconGridLayout', IconGrid.IconGridLayout.prototype, IconGridLayoutCommon); -} -// workaround - silence page -2 error on gnome 43 while cleaning app grid - -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 = 53 * 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; - - const spacing = opt.APP_GRID_SPACING; - const iconSize = (opt.APP_GRID_ICON_SIZE > 0 ? opt.APP_GRID_ICON_SIZE : opt.APP_GRID_ICON_SIZE_DEFAULT) * scaleFactor; - // 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) { - columns = Math.floor(width / (iconSize + iconPadding)) + 1; - while (unusedSpaceH < 0) { - columns -= 1; - unusedSpaceH = width - columns * (iconSize + iconPadding) - (columns - 1) * spacing; - } - } - if (!rows) { - rows = Math.floor(height / (iconSize + iconPadding)) + 1; - while (unusedSpaceV < 0) { - rows -= 1; - unusedSpaceV = height - rows * (iconSize + iconPadding) - (rows - 1) * spacing; - } - } - - this._gridModes = [{ columns, rows }]; - // } - - this._setGridMode(0); - }, -}; - -const IconGridLayoutCommon = { - _findBestIconSize() { - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - const nColumns = this.columnsPerPage; - const nRows = this.rowsPerPage; - const columnSpacingPerPage = opt.APP_GRID_SPACING * (nColumns - 1); - const rowSpacingPerPage = opt.APP_GRID_SPACING * (nRows - 1); - const iconPadding = 53 * 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 (this.fixedIconSize !== -1) - return this.fixedIconSize; - - /* 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, the whole range is for the main grid with active folders - if (this._isFolder) - iconSizes = iconSizes.slice(iconSizes.indexOf(IconSize.LARGE), -1); - - let sizeInvalid = false; - for (const size of iconSizes) { - let usedWidth, usedHeight; - - if (firstItem) { - firstItem.icon.setIconSize(size); - const [firstItemWidth, firstItemHeight] = - firstItem.get_preferred_size(); - - const itemSize = Math.max(firstItemWidth, firstItemHeight); - 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)) { - log(`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)) { - log(`iconGrid: Item ${item} already added to IconGridLayout`); - return; - // throw new Error(`Item ${item} already added to IconGridLayout`); - } - - if (page > this._pages.length) { - log(`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)) { - log(`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/vertical-workspaces/lib/layout.js b/extensions/vertical-workspaces/lib/layout.js deleted file mode 100644 index f6562fd..0000000 --- a/extensions/vertical-workspaces/lib/layout.js +++ /dev/null @@ -1,380 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * layout.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Meta, GLib, Shell, Clutter, GObject } = imports.gi; - -const Main = imports.ui.main; -const Layout = imports.ui.layout; -const Ripples = imports.ui.ripples; -const DND = imports.ui.dnd; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -let _overrides; -let _timeouts; -let opt; -let _firstRun = true; -let _originalUpdateHotCorners; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('layoutModule', true); - const conflict = _Util.getEnabledExtensions('custom-hot-corners').length || - _Util.getEnabledExtensions('dash-to-panel').length; - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled or in conflict - if (_firstRun && (reset || conflict)) - return; - - _firstRun = false; - - if (!_originalUpdateHotCorners) - _originalUpdateHotCorners = Layout.LayoutManager.prototype._updateHotCorners; - - if (_overrides) - _overrides.removeAll(); - - if (_timeouts) { - Object.values(_timeouts).forEach(t => { - if (t) - GLib.source_remove(t); - }); - } - - if (reset) { - _overrides = null; - opt = null; - _timeouts = null; - Main.layoutManager._updateHotCorners = _originalUpdateHotCorners; - Main.layoutManager._updateHotCorners(); - return; - } - - _timeouts = {}; - - _overrides = new _Util.Overrides(); - _overrides.addOverride('LayoutManager', Layout.LayoutManager.prototype, LayoutManagerCommon); - - Main.layoutManager._updateHotCorners = LayoutManagerCommon._updateHotCorners.bind(Main.layoutManager); - - Main.layoutManager._updatePanelBarrier(); - Main.layoutManager._updateHotCorners(); -} - -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) - return; - - if (this.panelBox.height) { - let primary = this.primaryMonitor; - if ([0, 1, 3].includes(opt.HOT_CORNER_POSITION)) { - this._rightPanelBarrier = new Meta.Barrier({ - display: global.display, - 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, - }); - } - - if ([2, 4].includes(opt.HOT_CORNER_POSITION)) { - this._leftPanelBarrier = new Meta.Barrier({ - display: global.display, - x1: primary.x, y1: this.panelBox.allocation.y1, - x2: primary.x, y2: this.panelBox.allocation.y2, - directions: Meta.BarrierDirection.POSITIVE_X, - }); - } - } - }, - - _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; - - // 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 HotCorner(this, monitor, cornerX, cornerY); - corner.setBarrierSize(size); - this.hotCorners.push(corner); - } else { - this.hotCorners.push(null); - } - } - - this.emit('hot-corners-changed'); - }, -}; - -var HotCorner = GObject.registerClass( -class HotCorner extends Layout.HotCorner { - _init(layoutManager, monitor, x, y) { - super._init(layoutManager, monitor, x, y); - - 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) { - 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_EDGE && opt.DASH_VERTICAL && monitor.index === primaryMonitor; - const extendH = opt && opt.HOT_CORNER_EDGE && !opt.DASH_VERTICAL && monitor.index === primaryMonitor; - - if (opt.HOT_CORNER_POSITION <= 1) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y + (extendV ? monitor.height : size), - directions: Meta.BarrierDirection.POSITIVE_X, - }); - this._horizontalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x + (extendH ? monitor.width : size), y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.POSITIVE_Y, - }); - } else if (opt.HOT_CORNER_POSITION === 2) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y + (extendV ? monitor.height : size), - directions: Meta.BarrierDirection.NEGATIVE_X, - }); - this._horizontalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x - size, x2: this._x, y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.POSITIVE_Y, - }); - } else if (opt.HOT_CORNER_POSITION === 3) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y - size, - directions: Meta.BarrierDirection.POSITIVE_X, - }); - this._horizontalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x + (extendH ? monitor.width : size), y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.NEGATIVE_Y, - }); - } else if (opt.HOT_CORNER_POSITION === 4) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y - size, - directions: Meta.BarrierDirection.NEGATIVE_X, - }); - this._horizontalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x - size, y1: this._y, y2: this._y, - directions: Meta.BarrierDirection.NEGATIVE_Y, - }); - } - - 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 ((opt.HOT_CORNER_ACTION === 1 && !_Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 2 && _Util.isCtrlPressed())) - this._toggleWindowPicker(true); - else if ((opt.HOT_CORNER_ACTION === 2 && !_Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 1 && _Util.isCtrlPressed()) || (opt.HOT_CORNER_ACTION === 3 && _Util.isCtrlPressed())) - this._toggleApplications(true); - else if (opt.HOT_CORNER_ACTION === 3 && !_Util.isCtrlPressed()) - this._toggleWindowSearchProvider(); - if (opt.HOT_CORNER_RIPPLES && Main.overview.animationInProgress) - this._ripples.playAnimation(this._x, this._y); - } - } - - _toggleWindowPicker(leaveOverview = 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(); - - _timeouts.releaseKeyboardTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); - } else { - Main.overview.show(); - } - } - } - - _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._overview._controls._searchController._searchActive) { - this._toggleWindowPicker(); - const prefix = 'wq// '; - 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/vertical-workspaces/lib/messageTray.js b/extensions/vertical-workspaces/lib/messageTray.js deleted file mode 100644 index b35541a..0000000 --- a/extensions/vertical-workspaces/lib/messageTray.js +++ /dev/null @@ -1,67 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * messageTray.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Clutter } = imports.gi; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const Main = imports.ui.main; - -let opt; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('messageTrayModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (reset) { - opt = null; - setNotificationPosition(1); - return; - } - - setNotificationPosition(opt.NOTIFICATION_POSITION); -} - -function 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/vertical-workspaces/lib/optionsFactory.js b/extensions/vertical-workspaces/lib/optionsFactory.js deleted file mode 100644 index da62dd1..0000000 --- a/extensions/vertical-workspaces/lib/optionsFactory.js +++ /dev/null @@ -1,645 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * optionsFactory.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - */ - -'use strict'; - -const { Gtk, Gio, GObject } = imports.gi; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Settings = Me.imports.lib.settings; - -const shellVersion = Settings.shellVersion; - -// gettext -const _ = Settings._; - -const ProfileNames = [ - _('GNOME 3'), - _('GNOME 40+ - Bottom Hot Edge'), - _('Hot Corner Centric - Top Left Hot Corner'), - _('Dock Overview - Bottom Hot Edge'), -]; - -// libadwaita is available starting with GNOME Shell 42. -let Adw = null; -try { - Adw = imports.gi.Adw; -} catch (e) {} - -function _newImageFromIconName(name) { - return Gtk.Image.new_from_icon_name(name); -} - -var ItemFactory = class ItemFactory { - constructor(gOptions) { - this._gOptions = gOptions; - this._settings = this._gOptions._gsettings; - } - - getRowWidget(text, caption, widget, variable, options = []) { - 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 && this._gOptions.options[variable]) { - const opt = this._gOptions.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); - } - - 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 = this._gOptions.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; - } - this._gOptions.connect(`changed::${key}`, () => { - widget.set_active_iter(widget._comboMap[this._gOptions.get(variable, true)]); - }); - widget.connect('changed', () => { - const [success, iter] = widget.get_active_iter(); - - if (!success) - return; - - this._gOptions.set(variable, model.get_value(iter, 1)); - }); - } - - _connectDropDown(widget, key, variable, options) { - const model = widget.get_model(); - const currentValue = this._gOptions.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(); - this._gOptions.set(variable, item.id); - }); - - this._gOptions.connect(`changed::${key}`, () => { - const newId = this._gOptions.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({ - label: shellVersion < 42 ? 'Click Me!' : '', - uri, - halign: Gtk.Align.END, - valign: Gtk.Align.CENTER, - hexpand: true, - }); - 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); - entry.connect('icon-press', e => e.set_text('')); - entry.connect('changed', e => opt.set(`profileName${profileIndex}`, e.get_text())); - - const resetProfile = this.newButton(); - resetProfile.set({ - tooltip_text: _('Reset profile to defaults'), - icon_name: 'edit-delete-symbolic', - hexpand: false, - css_classes: ['destructive-action'], - }); - - function setName() { - let name = opt.get(`profileName${profileIndex}`, true); - if (!name) - name = ProfileNames[profileIndex - 1]; - entry.set_text(name); - } - - setName(); - 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: 'edit-delete-symbolic', - }); - - btn.connect('clicked', () => { - const settings = this._settings; - settings.list_keys().forEach( - key => settings.reset(key) - ); - }); - btn._activatable = false; - return btn; - } -}; - -var AdwPrefs = class { - constructor(gOptions) { - this._gOptions = 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 = 840; - 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; - } -}; - -var LegacyPrefs = class { - constructor(gOptions) { - this._gOptions = gOptions; - } - - getPrefsWidget(pages) { - const prefsWidget = new Gtk.Box({ - orientation: Gtk.Orientation.VERTICAL, - }); - const stack = new Gtk.Stack({ - hexpand: true, - }); - const stackSwitcher = new Gtk.StackSwitcher({ - halign: Gtk.Align.CENTER, - hexpand: true, - }); - - const context = stackSwitcher.get_style_context(); - context.add_class('caption'); - - stackSwitcher.set_stack(stack); - stack.set_transition_duration(300); - stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT_RIGHT); - - const pageProperties = { - hscrollbar_policy: Gtk.PolicyType.NEVER, - vscrollbar_policy: Gtk.PolicyType.AUTOMATIC, - vexpand: true, - hexpand: true, - visible: true, - }; - - const pagesBtns = []; - - for (let page of pages) { - const name = page.name; - const title = page.title; - const iconName = page.iconName; - const optionList = page.optionList; - - stack.add_named(this._getLegacyPage(optionList, pageProperties), name); - pagesBtns.push( - [new Gtk.Label({ label: title }), _newImageFromIconName(iconName, Gtk.IconSize.BUTTON)] - ); - } - - let stBtn = stackSwitcher.get_first_child ? stackSwitcher.get_first_child() : null; - for (let i = 0; i < pagesBtns.length; i++) { - const box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, spacing: 6, visible: true }); - const icon = pagesBtns[i][1]; - icon.margin_start = 30; - icon.margin_end = 30; - box.append(icon); - box.append(pagesBtns[i][0]); - if (stackSwitcher.get_children) { - stBtn = stackSwitcher.get_children()[i]; - stBtn.add(box); - } else { - stBtn.set_child(box); - stBtn.visible = true; - stBtn = stBtn.get_next_sibling(); - } - } - - if (stack.show_all) - stack.show_all(); - if (stackSwitcher.show_all) - stackSwitcher.show_all(); - - prefsWidget.append(stack); - - if (prefsWidget.show_all) - prefsWidget.show_all(); - - prefsWidget._stackSwitcher = stackSwitcher; - - return prefsWidget; - } - - _getLegacyPage(optionList, pageProperties) { - const page = new Gtk.ScrolledWindow(pageProperties); - const mainBox = new Gtk.Box({ - orientation: Gtk.Orientation.VERTICAL, - spacing: 5, - homogeneous: false, - margin_start: 30, - margin_end: 30, - margin_top: 12, - margin_bottom: 12, - }); - - let context = page.get_style_context(); - context.add_class('background'); - - let frame; - let frameBox; - 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) { - const lbl = new Gtk.Label({ - label: option, - xalign: 0, - margin_bottom: 4, - }); - - context = lbl.get_style_context(); - context.add_class('heading'); - - mainBox.append(lbl); - - frame = new Gtk.Frame({ - margin_bottom: 16, - }); - - frameBox = new Gtk.ListBox({ - selection_mode: null, - }); - - mainBox.append(frame); - frame.set_child(frameBox); - continue; - } - - 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, - }); - - grid.attach(option, 0, 0, 5, 1); - - if (widget) - grid.attach(widget, 5, 0, 2, 1); - - frameBox.append(grid); - } - page.set_child(mainBox); - - return page; - } -}; - -const DropDownItem = GObject.registerClass({ - GTypeName: 'DropdownItem', - 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, - 0, 100, 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/vertical-workspaces/lib/osdWindow.js b/extensions/vertical-workspaces/lib/osdWindow.js deleted file mode 100644 index a010558..0000000 --- a/extensions/vertical-workspaces/lib/osdWindow.js +++ /dev/null @@ -1,93 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * osdWindow.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Clutter } = imports.gi; -const Main = imports.ui.main; -const OsdWindow = imports.ui.osdWindow; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -const 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, - }, -}; - -let _overrides; -let opt; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('osdWindowModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - if (reset || !moduleEnabled) { - updateExistingOsdWindows(6); - _overrides = null; - opt = null; - return; - } - - _overrides = new _Util.Overrides(); - _overrides.addOverride('osdWindow', OsdWindow.OsdWindow.prototype, OsdWindowCommon); -} - -function 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/vertical-workspaces/lib/overlayKey.js b/extensions/vertical-workspaces/lib/overlayKey.js deleted file mode 100644 index e0fc11d..0000000 --- a/extensions/vertical-workspaces/lib/overlayKey.js +++ /dev/null @@ -1,108 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * overlayKey.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; -const { GObject, Gio, GLib, Meta, St } = imports.gi; - -const Main = imports.ui.main; -const Overview = imports.ui.overview; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -const _ = Me.imports.lib.settings._; -const shellVersion = _Util.shellVersion; -const WIN_SEARCH_PREFIX = Me.imports.lib.windowSearchProvider.prefix; -const RECENT_FILES_PREFIX = Me.imports.lib.recentFilesSearchProvider.prefix; -const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard'; - -let opt; -let _firstRun = true; - -let _originalOverlayKeyHandlerId; -let _overlayKeyHandlerId; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('overlayKeyModule', true); - reset = reset || (!_firstRun && !moduleEnabled); - - // don't even touch this module if disabled - if (_firstRun && !moduleEnabled) - return; - - _firstRun = false; - - if (reset) { - _updateOverlayKey(reset); - opt = null; - return; - } - - _updateOverlayKey(); -} - -function _updateOverlayKey(reset = false) { - if (reset) { - _restoreOverlayKeyHandler(); - } else if (!_originalOverlayKeyHandlerId) { - _originalOverlayKeyHandlerId = GObject.signal_handler_find(global.display, { signalId: 'overlay-key' }); - if (_originalOverlayKeyHandlerId !== null) - global.display.block_signal_handler(_originalOverlayKeyHandlerId); - _connectOverlayKey.bind(Main.overview._overview.controls)(); - } -} - -function _restoreOverlayKeyHandler() { - // Disconnect modified overlay key handler - if (_overlayKeyHandlerId !== null) { - global.display.disconnect(_overlayKeyHandlerId); - _overlayKeyHandlerId = null; - } - - // Unblock original overlay key handler - if (_originalOverlayKeyHandlerId !== null) { - global.display.unblock_signal_handler(_originalOverlayKeyHandlerId); - _originalOverlayKeyHandlerId = null; - } -} - -function _connectOverlayKey() { - this._a11ySettings = new Gio.Settings({ schema_id: A11Y_SCHEMA }); - - this._lastOverlayKeyTime = 0; - _overlayKeyHandlerId = global.display.connect('overlay-key', () => { - 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) { - if (mode === 1) - this._shiftState(Meta.MotionDirection.UP); - else if (mode === 2) - _Util.activateSearchProvider(WIN_SEARCH_PREFIX); - else if (mode === 3) - _Util.activateSearchProvider(RECENT_FILES_PREFIX); - } else { - Main.overview.toggle(); - } - }); -} diff --git a/extensions/vertical-workspaces/lib/overview.js b/extensions/vertical-workspaces/lib/overview.js deleted file mode 100644 index 2f23d05..0000000 --- a/extensions/vertical-workspaces/lib/overview.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * overview.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const Overview = imports.ui.overview; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -let _overrides; -let opt; - -function update(reset = false) { - if (_overrides) - _overrides.removeAll(); - - - if (reset) { - _overrides = null; - opt = null; - return; - } - - opt = Me.imports.lib.settings.opt; - _overrides = new _Util.Overrides(); - - _overrides.addOverride('Overview', Overview.Overview.prototype, OverviewCommon); -} - -const OverviewCommon = { - _showDone() { - this._animationInProgress = false; - this._coverPane.hide(); - - this.emit('shown'); - // Handle any calls to hide* while we were showing - if (!this._shown) - this._animateNotVisible(); - - this._syncGrab(); - - // 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; - } - }, -}; diff --git a/extensions/vertical-workspaces/lib/overviewControls.js b/extensions/vertical-workspaces/lib/overviewControls.js deleted file mode 100644 index 4959b83..0000000 --- a/extensions/vertical-workspaces/lib/overviewControls.js +++ /dev/null @@ -1,1464 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * overviewControls.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Clutter, GLib, GObject, St } = imports.gi; -const Main = imports.ui.main; -const Util = imports.misc.util; -const OverviewControls = imports.ui.overviewControls; -const WorkspaceThumbnail = imports.ui.workspaceThumbnail; - -const ControlsState = imports.ui.overviewControls.ControlsState; -const FitMode = imports.ui.workspacesView.FitMode; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const _Util = Me.imports.lib.util; - -let _overrides; -let opt; - -const ANIMATION_TIME = imports.ui.overview.ANIMATION_TIME; -const DASH_MAX_SIZE_RATIO = 0.25; - -let _originalSearchControllerSigId; -let _searchControllerSigId; -let _timeouts; -let _startupInitComplete = false; - -function update(reset = false) { - if (_overrides) - _overrides.removeAll(); - - if (_timeouts) { - Object.values(_timeouts).forEach(id => { - if (id) - GLib.source_remove(id); - }); - } - - _replaceOnSearchChanged(reset); - - if (reset) { - _overrides = null; - opt = null; - _timeouts = null; - return; - } - - _timeouts = {}; - - opt = Me.imports.lib.settings.opt; - _overrides = new _Util.Overrides(); - - _overrides.addOverride('ControlsManager', OverviewControls.ControlsManager.prototype, ControlsManager); - - if (opt.ORIENTATION === Clutter.Orientation.VERTICAL) - _overrides.addOverride('ControlsManagerLayout', OverviewControls.ControlsManagerLayout.prototype, ControlsManagerLayoutVertical); - else - _overrides.addOverride('ControlsManagerLayout', OverviewControls.ControlsManagerLayout.prototype, ControlsManagerLayoutHorizontal); -} - -function _replaceOnSearchChanged(reset = false) { - const searchController = Main.overview._overview.controls._searchController; - if (reset) { - if (_searchControllerSigId) { - searchController.disconnect(_searchControllerSigId); - _searchControllerSigId = 0; - } - if (_originalSearchControllerSigId) { - searchController.unblock_signal_handler(_originalSearchControllerSigId); - _originalSearchControllerSigId = 0; - } - Main.overview._overview._controls.layoutManager._searchController._searchResults.translation_x = 0; - Main.overview._overview._controls.layoutManager._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) - _originalSearchControllerSigId = GObject.signal_handler_find(searchController, { signalId: 'notify', detail: 'search-active' }); - if (_originalSearchControllerSigId) - searchController.block_signal_handler(_originalSearchControllerSigId); - - _searchControllerSigId = searchController.connect('notify::search-active', ControlsManager._onSearchChanged.bind(Main.overview._overview.controls)); - } -} - -const ControlsManager = { - // 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 { shouldShow } = this._thumbnailsBox; - const thumbnailsBoxVisible = shouldShow; - 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._updateWorkspacesDisplay(); - }, - - // this function is pure addition to the original code and handles wsDisp transition to APP_GRID view - _updateWorkspacesDisplay() { - 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/* && !(searchActive)*/; - - // 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/* finalState === 0 && progress === 1*/ && opt.OVERVIEW_MODE && opt.WORKSPACE_MODE) - opt.WORKSPACE_MODE = 0; - - if (currentState < 2 && currentState > 1) - WorkspaceThumbnail.RESCALE_ANIMATION_TIME = 0; - else - WorkspaceThumbnail.RESCALE_ANIMATION_TIME = 200; - - 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 = _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 [tmbTranslationX, tmbTranslationY, dashTranslationX, dashTranslationY, searchTranslationY] = _Util.getOverviewTranslations(opt, 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 (!_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 (!_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; - - // update App Grid after settings changed - // only if the App Grid is currently visible on the screen, the paging updates correctly - if (currentState === ControlsState.APP_GRID && this._appDisplay.visible && opt._appGridNeedsRedisplay) { - Me.imports.lib.appDisplay._updateAppGridProperties(); - opt._appGridNeedsRedisplay = 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() { - 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 { - this._searchController.show(); - entry.visible = true; - entry.opacity = 255; - } - - this._searchTransition = true; - - this._searchController._searchResults.translation_x = 0; - this._searchController._searchResults.translation_y = 0; - this._searchController.opacity = 255; - this._searchController.visible = true; - - if (opt.SEARCH_VIEW_ANIMATION && !this.dash.showAppsButton.checked && ![4, 8].includes(opt.WS_TMB_POSITION) /* && !opt.OVERVIEW_MODE2*/) { - this._updateAppDisplayVisibility(); - - this._searchController.opacity = searchActive ? 255 : 0; - let translationX = 0; - let translationY = 0; - const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor()); - - if (currentState < ControlsState.APP_GRID) { - 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({ - 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._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._updateAppDisplayVisibility(); - this._workspacesDisplay.setPrimaryWorkspaceVisible(true); - /* this._workspacesDisplay.ease({ - opacity: searchActive ? 0 : 255, - duration: searchActive ? SIDE_CONTROLS_ANIMATION_TIME / 2 : 0, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._workspacesDisplay.reactive = !searchActive; - this._workspacesDisplay.setPrimaryWorkspaceVisible(!searchActive); - }, - });*/ - - this._searchController.opacity = searchActive ? 0 : 255; - this._searchController.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) { - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.remove_style_class_name('search-section-content-om2'); - Main.overview.searchEntry.remove_style_class_name('search-entry-om2'); - 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 || (opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE) ? 80 : SIDE_CONTROLS_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._workspacesDisplay.setPrimaryWorkspaceVisible(!searchActive); - }, - }); - } 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 - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.add_style_class_name('search-section-content-om2'); - Main.overview.searchEntry.add_style_class_name('search-entry-om2'); - } else { - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.remove_style_class_name('search-section-content-om2'); - Main.overview.searchEntry.remove_style_class_name('search-entry-om2'); - } - }, - - async runStartupAnimation(callback) { - this._ignoreShowAppsButtonToggle = true; - this._searchController.prepareToEnterOverview(); - this._workspacesDisplay.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 = 0; - - // We can't run the animation before the first allocation happens - await this.layout_manager.ensureAllocation(); - - const { STARTUP_ANIMATION_TIME } = imports.ui.layout; - - // Opacity - this.ease({ - opacity: 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 [tmbTranslationX, tmbTranslationY, dashTranslationX, dashTranslationY, searchTranslationY] = - _Util.getOverviewTranslations(opt, dash, tmbBox, searchEntryBin); - - const onComplete = function () { - // running init callback again causes issues (multiple connections) - if (!_startupInitComplete) - callback(); - _startupInitComplete = true; - - // force app grid to build before the first visible animation to remove possible stuttering - this._appDisplay.opacity = 1; - - const [x, y] = this._appDisplay.get_position(); - const translationX = -x; - const translationY = -y; - this._appDisplay.translation_x = translationX; - this._appDisplay.translation_y = translationY; - GLib.idle_add(0, () => { - this._appDisplay._removeItem(this._appDisplay._orderedItems[0]); - this._appDisplay._redisplay(); - }); - - // let the main loop realize previous changes before continuing - _timeouts.startupAnim1 = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 10, - () => { - GLib.idle_add(0, () => { - this._appDisplay._removeItem(this._appDisplay._orderedItems[0]); - this._appDisplay._redisplay(); - }); - this._appDisplay.translation_x = 0; - this._appDisplay.translation_y = 0; - this._appDisplay.visible = false; - if (opt.STARTUP_STATE === 1) { - Main.overview.hide(); - } else if (opt.STARTUP_STATE === 2) { - this._appDisplay.opacity = 255; - this.dash.showAppsButton.checked = true; - } - _timeouts.startupAnim1 = 0; - return GLib.SOURCE_REMOVE; - } - ); - }.bind(this); - - if (dash.visible && !_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: () => { - 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(); - _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; - - _Util.getOverviewTranslations(opt, dash, secTmbBox, searchEntryBin); - 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, - }); - } - } - } - }, - - animateToOverview(state, callback) { - this._ignoreShowAppsButtonToggle = true; - this._searchTransition = false; - - this._searchController.prepareToEnterOverview(); - this._workspacesDisplay.prepareToEnterOverview(); - - 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; - }, -}; - -const ControlsManagerLayoutVertical = { - _computeWorkspacesBoxForState(state, box, workAreaBox, dashWidth, dashHeight, thumbnailsWidth, searchHeight, startY) { - const workspaceBox = box.copy(); - let [width, height] = workspaceBox.get_size(); - // const { x1: startX/* y1: startY*/ } = workAreaBox; - const { spacing } = this; - // const { expandFraction } = this._workspacesThumbnails; - - const dash = Main.overview.dash; - // including Dash to Dock and clones properties for compatibility - - if (_Util.dashIsDashToDock()) { - // 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(...this._workspacesThumbnails.get_size()); - } 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 ? dash.width : 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 = Math.round(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) { - 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 } = this; - - 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) - 4 * spacing : width - xOffsetL - xOffsetR - 4 * spacing; - const adHeight = height - yOffsetT - yOffsetB - 4 * spacing; - - const appDisplayX = opt.CENTER_APP_GRID ? (width - adWidth) / 2 : xOffsetL + 2 * spacing; - const appDisplayY = startY + yOffsetT + 2 * spacing; - - 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(appDisplayX, appDisplayY); - break; - case 1: - appDisplayBox.set_origin(startX + width, appDisplayY); - break; - case 2: - appDisplayBox.set_origin(startX - adWidth, appDisplayY); - break; - case 3: - appDisplayBox.set_origin(appDisplayX, workAreaBox.y2); - break; - case 5: - appDisplayBox.set_origin(appDisplayX, workAreaBox.y1 - adHeight); - break; - } - break; - case ControlsState.APP_GRID: - appDisplayBox.set_origin(appDisplayX, appDisplayY); - break; - } - - appDisplayBox.set_size(adWidth, adHeight); - return appDisplayBox; - }, - - vfunc_allocate(container, box) { - const childBox = new Clutter.ActorBox(); - - const { spacing } = this; - - 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 = Math.round(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 (_Util.dashIsDashToDock()) { - // if Dash to Dock replaced the default dash and its inteli-hide id 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); - } - } - - const transitionParams = this._stateAdjustment.getStateTransitionParams(); - - // Workspace Thumbnails - let wsTmbWidth = 0; - let wsTmbHeight = 0; - - if (this._workspacesThumbnails.visible) { - // const { expandFraction } = this._workspacesThumbnails; - const dashHeightReservation = !opt.WS_TMB_FULL && !opt.DASH_VERTICAL ? dashHeight : 0; - - let maxScale = opt.MAX_THUMBNAIL_SCALE; - if (!opt.MAX_THUMBNAIL_SCALE_STABLE) { - 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; - maxScale = Util.lerp(initState, finalState, transitionParams.progress); - } - - wsTmbWidth = width * maxScale; - let totalTmbSpacing; - [totalTmbSpacing, wsTmbHeight] = this._workspacesThumbnails.get_preferred_custom_height(wsTmbWidth); - wsTmbHeight += totalTmbSpacing; - - const wsTmbHeightMax = height - dashHeightReservation; - - if (wsTmbHeight > wsTmbHeightMax) { - wsTmbHeight = wsTmbHeightMax; - wsTmbWidth = this._workspacesThumbnails.get_preferred_custom_width(wsTmbHeight)[1]; - } - - let wsTmbX; - if (opt.WS_TMB_RIGHT) - wsTmbX = Math.round(startX + width - (opt.DASH_RIGHT ? dashWidth : 0) - wsTmbWidth - spacing / 2); - else - wsTmbX = Math.round((opt.DASH_LEFT ? dashWidth : 0) + spacing / 2); - - - let wstOffset = (height - wsTmbHeight - (opt.DASH_VERTICAL ? 0 : dashHeightReservation)) / 2; - wstOffset -= opt.WS_TMB_POSITION_ADJUSTMENT * (wstOffset - spacing / 2); - let wsTmbY = Math.round(startY + (dashHeightReservation && opt.DASH_TOP ? dashHeight : 0) + wstOffset); - - childBox.set_origin(wsTmbX, wsTmbY); - childBox.set_size(Math.round(wsTmbWidth), Math.round(wsTmbHeight)); - - 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.round(Math.min(dashHeight, maxDashHeight)); - dashWidth = Math.round(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 - spacing / 2); - 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); - } - - childBox.set_origin(Math.round(startX + dashX), Math.round(dashY)); - childBox.set_size(dashWidth, 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, 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 - spacing; - 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, searchEntryY); - childBox.set_size(width, searchHeight); - } else { - childBox.set_origin(this._xAlignCenter ? 0 : searchEntryX, searchEntryY); - childBox.set_size(this._xAlignCenter ? width : searchWidth - spacing, searchHeight); - } - - this._searchEntry.allocate(childBox); - - availableHeight -= searchHeight + spacing; - - // if (this._appDisplay.visible)... ? Can cause problems - params = [box, workAreaBox, searchHeight, dashWidth, dashHeight, wsTmbWidth, 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(wsTmbWidth + dashW, startY + (opt.DASH_TOP ? dashHeight : spacing) + searchHeight); - } else { - childBox.set_origin(this._xAlignCenter ? wsTmbWidth + spacing : searchXoffset, startY + (opt.DASH_TOP ? dashHeight : spacing) + searchHeight); - } - - childBox.set_size(searchWidth, availableHeight); - this._searchController.allocate(childBox); - - this._runPostAllocation(); - }, -}; - -const ControlsManagerLayoutHorizontal = { - _computeWorkspacesBoxForState(state, box, workAreaBox, dashWidth, dashHeight, thumbnailsHeight, searchHeight, startY) { - const workspaceBox = box.copy(); - let [width, height] = workspaceBox.get_size(); - // let { x1: startX/* , y1: startY*/ } = workAreaBox; - const { spacing } = this; - // const { expandFraction } = this._workspacesThumbnails; - - const dash = Main.overview.dash; - // including Dash to Dock and clones properties for compatibility - if (_Util.dashIsDashToDock()) { - // 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(...this._workspacesThumbnails.get_size()); - } 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 = Math.round(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) { - 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 } = this; - - const yOffsetT = (opt.WS_TMB_TOP ? thumbnailsHeight : 0) + (opt.DASH_TOP ? dashHeight : 0) + (opt.SHOW_SEARCH_ENTRY ? searchHeight : 0) + 2 * spacing; - const yOffsetB = (opt.WS_TMB_BOTTOM ? thumbnailsHeight : 0) + (opt.DASH_BOTTOM ? dashHeight : 0); - const xOffsetL = opt.DASH_LEFT ? dashWidth : 0; - const xOffsetR = opt.DASH_RIGHT ? dashWidth : 0; - const hSpacing = xOffsetL + xOffsetR ? 2 * 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 - 4 * spacing; - - const appDisplayX = opt.CENTER_APP_GRID ? (width - adWidth) / 2 : xOffsetL + hSpacing; - const appDisplayY = startY + yOffsetT + hSpacing; - - 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(appDisplayX, appDisplayY); - break; - case 1: - appDisplayBox.set_origin(startX + width, appDisplayY); - break; - case 2: - appDisplayBox.set_origin(startX - adWidth, appDisplayY); - break; - case 3: - appDisplayBox.set_origin(appDisplayX, workAreaBox.y2); - break; - case 5: - appDisplayBox.set_origin(appDisplayX, workAreaBox.y1 - adHeight); - break; - } - break; - case ControlsState.APP_GRID: - appDisplayBox.set_origin(appDisplayX, appDisplayY); - break; - } - - appDisplayBox.set_size(adWidth, adHeight); - return appDisplayBox; - }, - - vfunc_allocate(container, box) { - const childBox = new Clutter.ActorBox(); - - const { spacing } = this; - - 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 = Math.round(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 (_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; - 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); - - const transitionParams = this._stateAdjustment.getStateTransitionParams(); - - // Workspace Thumbnails - let wsTmbWidth = 0; - let wsTmbHeight = 0; - - if (this._workspacesThumbnails.visible) { - // const { expandFraction } = this._workspacesThumbnails; - const dashWidthReservation = !opt.WS_TMB_FULL && opt.DASH_VERTICAL ? dashWidth : 0; - - let maxScale = opt.MAX_THUMBNAIL_SCALE; - if (!opt.MAX_THUMBNAIL_SCALE_STABLE) { - 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; - maxScale = Util.lerp(initState, finalState, transitionParams.progress); - } - - wsTmbHeight = height * maxScale; - let totalTmbSpacing; - [totalTmbSpacing, wsTmbWidth] = this._workspacesThumbnails.get_preferred_custom_width(wsTmbHeight); - wsTmbWidth += totalTmbSpacing; - - const wsTmbWidthMax = opt.WS_TMB_FULL - ? width - : width - (opt.DASH_VERTICAL ? 0 : dashWidthReservation); - - if (wsTmbWidth > wsTmbWidthMax) { - wsTmbWidth = wsTmbWidthMax; - wsTmbHeight = this._workspacesThumbnails.get_preferred_custom_height(wsTmbWidth)[1]; - } - - let wsTmbY; - if (opt.WS_TMB_TOP) - wsTmbY = Math.round(startY + /* searchHeight + */(opt.DASH_TOP ? dashHeight : spacing / 2)); - else - wsTmbY = Math.round(startY + height - (opt.DASH_BOTTOM ? dashHeight : 0) - wsTmbHeight); - - let wstOffset = (width - wsTmbWidth) / 2; - wstOffset -= opt.WS_TMB_POSITION_ADJUSTMENT * (wstOffset - spacing / 2); - let wsTmbX = Math.round(Math.clamp( - startX + wstOffset, - startX + (opt.DASH_LEFT ? dashWidthReservation : 0), - width - wsTmbWidth - startX - (opt.DASH_RIGHT ? dashWidthReservation : 0) - )); - - childBox.set_origin(wsTmbX, wsTmbY); - childBox.set_size(Math.round(wsTmbWidth), Math.round(wsTmbHeight)); - - 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.round(Math.min(dashWidth, maxDashWidth)); - dashHeight = Math.round(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 - spacing / 2); - dashY = startY + offset + wsTmbHeight; - } else { - offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - spacing / 2); - dashY = startY + offset; - } - } else { - offset = (height - dashHeight) / 2; - offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - spacing / 2); - dashY = startY + offset; - } - } else { - offset = (width - dashWidth) / 2; - dashX = startX + (offset - opt.DASH_POSITION_ADJUSTMENT * (offset - spacing)); - } - - childBox.set_origin(Math.round(startX + dashX), Math.round(dashY)); - childBox.set_size(dashWidth, dashHeight); - this._dash.allocate(childBox); - } - - availableHeight -= opt.DASH_VERTICAL ? 0 : dashHeight; - - // Workspaces - let params = [box, workAreaBox, dashWidth, dashHeight, 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 - spacing; - 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, searchEntryY); - childBox.set_size(width, searchHeight); - } else { - childBox.set_origin(this._xAlignCenter ? 0 : searchEntryX, searchEntryY); - childBox.set_size(this._xAlignCenter ? width : searchWidth - spacing, searchHeight); - } - - this._searchEntry.allocate(childBox); - - availableHeight -= searchHeight + spacing; - - // if (this._appDisplay.visible)... ? Can cause problems - params = [box, workAreaBox, searchHeight, dashWidth, dashHeight, wsTmbHeight, 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(dashW, startY + (opt.DASH_TOP ? dashHeight : spacing) + (opt.WS_TMB_TOP ? wsTmbHeight + spacing : 0) + searchHeight); - } else { - childBox.set_origin(this._xAlignCenter ? spacing : searchXoffset, startY + (opt.DASH_TOP ? dashHeight : spacing) + (opt.WS_TMB_TOP ? wsTmbHeight + spacing : 0) + searchHeight); - } - - childBox.set_size(searchWidth, 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; - } -} diff --git a/extensions/vertical-workspaces/lib/panel.js b/extensions/vertical-workspaces/lib/panel.js deleted file mode 100644 index 3f44ae7..0000000 --- a/extensions/vertical-workspaces/lib/panel.js +++ /dev/null @@ -1,197 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * panel.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { GLib } = imports.gi; -const Main = imports.ui.main; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -const ANIMATION_TIME = imports.ui.overview.ANIMATION_TIME; - -let opt; -let _firstRun = true; - -let _showingOverviewConId; -let _hidingOverviewConId; -let _styleChangedConId; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('panelModule', true); - // Avoid conflict with other extensions - const conflict = _Util.getEnabledExtensions('dash-to-panel').length || - _Util.getEnabledExtensions('hidetopbar').length; - reset = reset || (!_firstRun && !moduleEnabled); - - // don't even touch this module if disabled or in potential conflict - if (_firstRun && (reset || conflict)) - return; - - _firstRun = false; - - const panelBox = Main.layoutManager.panelBox; - if (reset || !moduleEnabled) { - // _disconnectPanel(); - reset = true; - _setPanelPosition(reset); - _updateOverviewConnection(reset); - _reparentPanel(false); - - _updateStyleChangedConnection(reset); - - panelBox.translation_y = 0; - Main.panel.opacity = 255; - _setPanelStructs(true); - return; - } - - _setPanelPosition(); - _updateStyleChangedConnection(); - - if (opt.PANEL_MODE === 0) { - _updateOverviewConnection(true); - _reparentPanel(false); - panelBox.translation_y = 0; - Main.panel.opacity = 255; - _setPanelStructs(true); - } else if (opt.PANEL_MODE === 1) { - if (opt.SHOW_WS_PREVIEW_BG) { - _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); - _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); - _updateOverviewConnection(true); - } - _showPanel(true); - } else { - // if ws preview bg is disabled, panel can stay in uiGroup - _reparentPanel(false); - _showPanel(false); - _updateOverviewConnection(); - } - // _connectPanel(); - } else if (opt.PANEL_MODE === 2) { - _updateOverviewConnection(true); - _reparentPanel(false); - _showPanel(false); - // _connectPanel(); - } - _setPanelStructs(opt.PANEL_MODE === 0); - Main.layoutManager._updateHotCorners(); -} - -function _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); -} - -function _updateStyleChangedConnection(reset = false) { - if (reset) { - if (_styleChangedConId) { - Main.panel.disconnect(_styleChangedConId); - _styleChangedConId = 0; - } - } else if (!_styleChangedConId) { - Main.panel.connect('style-changed', () => { - if (opt.PANEL_MODE === 1) - Main.panel.add_style_pseudo_class('overview'); - else if (opt.OVERVIEW_MODE2) - Main.panel.remove_style_pseudo_class('overview'); - }); - } -} - -function _updateOverviewConnection(reset = false) { - if (reset) { - if (_hidingOverviewConId) { - Main.overview.disconnect(_hidingOverviewConId); - _hidingOverviewConId = 0; - } - if (_showingOverviewConId) { - Main.overview.disconnect(_showingOverviewConId); - _showingOverviewConId = 0; - } - } else { - if (!_hidingOverviewConId) { - _hidingOverviewConId = Main.overview.connect('hiding', () => { - if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2) - _showPanel(false); - }); - } - if (!_showingOverviewConId) { - _showingOverviewConId = Main.overview.connect('showing', () => { - if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2 || Main.layoutManager.panelBox.translation_y) - _showPanel(true); - }); - } - } -} - -function _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); - } -} - -function _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));*/ -} - -function _showPanel(show = true) { - if (show) { - Main.panel.opacity = 255; - Main.layoutManager.panelBox.ease({ - duration: ANIMATION_TIME, - translation_y: 0, - onComplete: () => { - _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; - _setPanelStructs(opt.PANEL_MODE === 0); - }, - }); - } -} diff --git a/extensions/vertical-workspaces/lib/recentFilesSearchProvider.js b/extensions/vertical-workspaces/lib/recentFilesSearchProvider.js deleted file mode 100644 index 86e38f4..0000000 --- a/extensions/vertical-workspaces/lib/recentFilesSearchProvider.js +++ /dev/null @@ -1,260 +0,0 @@ -/** - * Vertical Workspaces - * recentFilesSearchProvider.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - */ - -'use strict'; - -const { GLib, Gio, Meta, St, Shell, Gtk } = imports.gi; - -const Main = imports.ui.main; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Settings = Me.imports.lib.settings; -const _Util = Me.imports.lib.util; - -// gettext -const _ = Settings._; - -const shellVersion = Settings.shellVersion; - -const ModifierType = imports.gi.Clutter.ModifierType; - -let recentFilesSearchProvider; -let _enableTimeoutId = 0; - -// prefix helps to eliminate results from other search providers -// so it needs to be something less common -// needs to be accessible from vw module -var prefix = 'fq//'; - -var opt; - -function getOverviewSearchResult() { - return Main.overview._overview.controls._searchController._searchResults; -} - - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - if (!reset && opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED && !recentFilesSearchProvider) { - enable(); - } else if (reset || !opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED) { - disable(); - opt = null; - } -} - -function enable() { - // delay because Fedora had problem to register a new provider soon after Shell restarts - _enableTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 2000, - () => { - if (!recentFilesSearchProvider) { - recentFilesSearchProvider = new RecentFilesSearchProvider(opt); - getOverviewSearchResult()._registerProvider(recentFilesSearchProvider); - } - _enableTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); -} - -function disable() { - if (recentFilesSearchProvider) { - getOverviewSearchResult()._unregisterProvider(recentFilesSearchProvider); - recentFilesSearchProvider = null; - } - if (_enableTimeoutId) { - GLib.source_remove(_enableTimeoutId); - _enableTimeoutId = 0; - } -} - -function makeResult(window, i) { - const app = Shell.WindowTracker.get_default().get_window_app(window); - const appName = app ? app.get_name() : 'Unknown'; - const windowTitle = window.get_title(); - const wsIndex = window.get_workspace().index(); - - return { - 'id': i, - // convert all accented chars to their basic form and lower case for search - 'name': `${wsIndex + 1}: ${windowTitle} ${appName}`.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(), - appName, - windowTitle, - window, - }; -} - -const closeSelectedRegex = /^\/x!$/; -const closeAllResultsRegex = /^\/xa!$/; -const moveToWsRegex = /^\/m[0-9]+$/; -const moveAllToWsRegex = /^\/ma[0-9]+$/; - -const RecentFilesSearchProvider = class RecentFilesSearchProvider { - constructor() { - this.id = 'org.gnome.Nautilus.desktop'; - this.appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/nautilus -ws recent:///', 'Recent Files', null); - // this.appInfo = Shell.AppSystem.get_default().lookup_app('org.gnome.Nautilus.desktop').appInfo; - this.appInfo.get_description = () => _('Search recent files'); - this.appInfo.get_name = () => _('Recent Files'); - this.appInfo.get_id = () => this.id; - this.appInfo.get_icon = () => Gio.icon_new_for_string('document-open-recent-symbolic'); - this.appInfo.should_show = () => true; - - this.canLaunchSearch = true; - this.isRemoteProvider = false; - } - - _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 = this.files; - const _terms = [].concat(termsCopy); - // let match; - - const term = _terms.join(' '); - /* match = s => { - return fuzzyMatch(term, s); - }; */ - - const results = []; - let m; - for (let id in candidates) { - const file = this.files[id]; - const name = `${file.get_age()}d: ${file.get_display_name()} ${file.get_uri_display().replace(`/${file.get_display_name()}`, '')}`; - if (opt.SEARCH_FUZZY) - m = _Util.fuzzyMatch(term, name); - else - m = _Util.strictMatch(term, name); - - if (m !== -1) - results.push({ weight: m, id }); - } - - results.sort((a, b) => this.files[a.id].get_visited() < this.files[b.id].get_visited()); - - this.resultIds = results.map(item => item.id); - return this.resultIds; - } - - getResultMetas(resultIds, callback = null) { - const metas = resultIds.map(id => this.getResultMeta(id)); - if (shellVersion >= 43) - return new Promise(resolve => resolve(metas)); - else if (callback) - callback(metas); - return null; - } - - getResultMeta(resultId) { - const result = this.files[resultId]; - return { - 'id': resultId, - 'name': `${result.get_age()}: ${result.get_display_name()}`, - 'description': `${result.get_uri_display().replace(`/${result.get_display_name()}`, '')}`, - 'createIcon': size => { - let icon = this.getIcon(result, size); - return icon; - }, - }; - } - - getIcon(result, size) { - let file = Gio.File.new_for_uri(result.get_uri()); - let info = file.query_info(Gio.FILE_ATTRIBUTE_THUMBNAIL_PATH, - Gio.FileQueryInfoFlags.NONE, null); - let path = info.get_attribute_byte_string( - Gio.FILE_ATTRIBUTE_THUMBNAIL_PATH); - - let icon, gicon; - - if (path) { - gicon = Gio.FileIcon.new(Gio.File.new_for_path(path)); - } else { - const appInfo = Gio.AppInfo.get_default_for_type(result.get_mime_type(), false); - 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; - } - - launchSearch(/* terms, timeStamp */) { - this._openNautilus('recent:///'); - } - - _openNautilus(uri) { - try { - GLib.spawn_command_line_async(`nautilus -ws ${uri}`); - } catch (e) { - log(e); - } - } - - activateResult(resultId /* , terms, timeStamp */) { - const file = this.files[resultId]; - - if (_Util.isShiftPressed()) { - Main.overview.toggle(); - this._openNautilus(file.get_uri()); - } else { - const appInfo = Gio.AppInfo.get_default_for_type(file.get_mime_type(), false); - if (!(appInfo && appInfo.launch_uris([file.get_uri()], null))) - this._openNautilus(file.get_uri()); - } - } - - getInitialResultSet(terms, callback /* , cancellable = null*/) { - // In GS 43 callback arg has been removed - /* if (shellVersion >= 43) - cancellable = callback; */ - - const filesDict = {}; - const files = Gtk.RecentManager.get_default().get_items().filter(f => f.exists()); - - for (let file of files) - filesDict[file.get_uri()] = file; - - - this.files = filesDict; - - if (shellVersion >= 43) - return new Promise(resolve => resolve(this._getResultSet(terms))); - else - callback(this._getResultSet(terms)); - - return null; - } - - filterResults(results, maxResults) { - return results.slice(0, 20); - // return results.slice(0, maxResults); - } - - getSubsearchResultSet(previousResults, terms, callback /* , cancellable*/) { - // if we return previous results, quick typers get non-actual results - callback(this._getResultSet(terms)); - } - - /* createResultObject(resultMeta) { - return this.files[resultMeta.id]; - }*/ -}; diff --git a/extensions/vertical-workspaces/lib/search.js b/extensions/vertical-workspaces/lib/search.js deleted file mode 100644 index 8540626..0000000 --- a/extensions/vertical-workspaces/lib/search.js +++ /dev/null @@ -1,206 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * search.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; -const { Shell, Gio, St, Clutter } = imports.gi; -const Main = imports.ui.main; - -const AppDisplay = imports.ui.appDisplay; -const Search = imports.ui.search; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -const _ = Me.imports.lib.settings._; -const shellVersion = _Util.shellVersion; - -let opt; -let _overrides; -let _firstRun = true; - -let SEARCH_MAX_WIDTH; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('searchModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - _updateSearchViewWidth(reset); - - if (reset) { - Main.overview._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.FILL; - opt = null; - _overrides = null; - return; - } - - _overrides = new _Util.Overrides(); - - _overrides.addOverride('AppSearchProvider', AppDisplay.AppSearchProvider.prototype, AppSearchProvider); - _overrides.addOverride('SearchResult', Search.SearchResult.prototype, SearchResult); - _overrides.addOverride('SearchResultsView', Search.SearchResultsView.prototype, SearchResultsView); - - // 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._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.START; -} - -function _updateSearchViewWidth(reset = false) { - const searchContent = Main.overview._overview._controls.layoutManager._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;`); - } -} - -// AppDisplay.AppSearchProvider -const AppSearchProvider = { - getInitialResultSet(terms, callback, _cancellable) { - // Defer until the parental controls manager is initialized, so the - // results can be filtered correctly. - if (!this._parentalControlsManager.initialized) { - let initializedId = this._parentalControlsManager.connect('app-filter-changed', () => { - if (this._parentalControlsManager.initialized) { - this._parentalControlsManager.disconnect(initializedId); - this.getInitialResultSet(terms, callback, _cancellable); - } - }); - return; - } - - - 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 dispName = appInfo.get_display_name() || ''; - let gName = appInfo.get_generic_name() || ''; - let description = appInfo.get_description() || ''; - let categories = appInfo.get_string('Categories') || ''; - let keywords = appInfo.get_string('Keywords') || ''; - name = dispName; - string = `${dispName} ${gName} ${description} ${categories} ${keywords}`; - } - } - - let m = -1; - if (shouldShow && opt.SEARCH_FUZZY) { - m = _Util.fuzzyMatch(pattern, name); - m = (m + _Util.strictMatch(pattern, string)) / 2; - } else if (shouldShow) { - m = _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) => _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)); - - if (shellVersion < 43) - callback(results); - else - 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 { - const icon = new AppDisplay.SystemActionIcon(this, resultMeta); - icon.icon._setSizeManually = true; - icon.icon.setIconSize(opt.SEARCH_ICON_SIZE); - return icon; - } - }, -}; - -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 (!_Util.isShiftPressed()) - Main.overview.toggle(); - }, -}; - -const SearchResultsView = { - _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.')); - } - }, -}; diff --git a/extensions/vertical-workspaces/lib/settings.js b/extensions/vertical-workspaces/lib/settings.js deleted file mode 100644 index 66f3a45..0000000 --- a/extensions/vertical-workspaces/lib/settings.js +++ /dev/null @@ -1,469 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * settings.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - */ - -'use strict'; - -const { GLib } = imports.gi; - -const Config = imports.misc.config; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -var shellVersion = parseFloat(Config.PACKAGE_VERSION); - -const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); -var _ = Gettext.gettext; -const _schema = Me.metadata['settings-schema']; - -// common instance of Options accessible from all modules -var opt; - -var Options = class Options { - constructor() { - this._gsettings = ExtensionUtils.getSettings(_schema); - 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: ['bool', 'secondary-ws-preview-shift'], - wsThumbnailsFull: ['bool', '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'], - dashShowWindowsIcon: ['int', 'dash-show-windows-icon'], - dashShowRecentFilesIcon: ['int', 'dash-show-recent-files-icon'], - 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'], - dashBgRadius: ['int', 'dash-bg-radius'], - 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'], - 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'], - fixUbuntuDock: ['boolean', 'fix-ubuntu-dock'], - winPreviewIconSize: ['int', 'win-preview-icon-size'], - alwaysShowWinTitles: ['boolean', 'always-show-win-titles'], - startupState: ['int', 'startup-state'], - overviewMode: ['int', 'overview-mode'], - workspaceSwitcherAnimation: ['int', 'workspace-switcher-animation'], - 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'], - 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'], - searchWindowsEnable: ['boolean', 'search-windows-enable'], - searchRecentFilesEnable: ['boolean', 'search-recent-files-enable'], - searchFuzzy: ['boolean', 'search-fuzzy'], - searchMaxResultsRows: ['int', 'search-max-results-rows'], - dashShowWindowsBeforeActivation: ['int', 'dash-show-windows-before-activation'], - dashIconScroll: ['int', 'dash-icon-scroll'], - 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'], - 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'], - windowIconClickSearch: ['boolean', 'window-icon-click-search'], - overlayKeySecondary: ['int', 'overlay-key-secondary'], - - workspaceThumbnailsModule: ['boolean', 'workspace-thumbnails-module'], - 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'], - winAttentionHandlerModule: ['boolean', 'win-attention-handler-module'], - swipeTrackerModule: ['boolean', 'swipe-tracker-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 = {}; - - this.shellVersion = shellVersion; - // this.storeProfile(0); - } - - 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; - } - } - - _updateCachedSettings() { - Object.keys(this.options).forEach(v => this.get(v, true)); - } - - get(option, updateCache = false) { - if (!this.options[option]) { - log(`[${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 => { - 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(); - this._gsettings.set_boolean('aaa-loading-profile', !this._gsettings.get_boolean('aaa-loading-profile')); - for (let o of Object.keys(options)) { - 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.DASH_POSITION = this.get('dashPosition', true); - 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_CLICK_ACTION = this.get('dashShowWindowsBeforeActivation', true); - this.DASH_ICON_SCROLL = this.get('dashIconScroll', true); - this.DASH_SHIFT_CLICK_MV = true; - - this.SEARCH_WINDOWS_ICON_SCROLL = this.get('searchWindowsIconScroll', true); - - this.DASH_POSITION_ADJUSTMENT = this.get('dashPositionAdjust', true); - this.DASH_POSITION_ADJUSTMENT = this.DASH_POSITION_ADJUSTMENT * -1 / 100; // range 1 to -1 - this.CENTER_DASH_WS = this.get('centerDashToWs', true); - - this.MAX_ICON_SIZE = 64; // updates from main module - this.SHOW_WINDOWS_ICON = this.get('dashShowWindowsIcon', true); - this.SHOW_RECENT_FILES_ICON = this.get('dashShowRecentFilesIcon', true); - - this.WS_TMB_POSITION = this.get('workspaceThumbnailsPosition', true); - this.ORIENTATION = this.WS_TMB_POSITION > 4 ? 0 : 1; - this.WORKSPACE_MAX_SPACING = this.get('wsMaxSpacing', true); - // 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', true); - // 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', true) * -1 / 100; // range 1 to -1 - this.SEC_WS_TMB_POSITION = this.get('secWsThumbnailsPosition', true); - 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', true) * -1 / 100; // range 1 to -1 - this.SEC_WS_PREVIEW_SHIFT = this.get('secWsPreviewShift', true); - this.SHOW_WST_LABELS = this.get('showWsTmbLabels', true); - this.SHOW_WST_LABELS_ON_HOVER = this.get('showWsTmbLabelsOnHover', true); - this.CLOSE_WS_BUTTON_MODE = this.get('closeWsButtonMode', true); - - this.MAX_THUMBNAIL_SCALE = this.get('wsThumbnailScale', true) / 100; - this.MAX_THUMBNAIL_SCALE_APPGRID = this.get('wsThumbnailScaleAppGrid', true) / 100; - if (this.MAX_THUMBNAIL_SCALE_APPGRID === 0) - this.MAX_THUMBNAIL_SCALE_APPGRID = this.MAX_THUMBNAIL_SCALE; - this.MAX_THUMBNAIL_SCALE_STABLE = this.MAX_THUMBNAIL_SCALE === this.MAX_THUMBNAIL_SCALE_APPGRID; - this.SEC_MAX_THUMBNAIL_SCALE = this.get('secWsThumbnailScale', true) / 100; - - this.WS_PREVIEW_SCALE = this.get('wsPreviewScale', true) / 100; - this.SEC_WS_PREVIEW_SCALE = this.get('secWsPreviewScale', true) / 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', true) && this.SHOW_WS_TMB; - this.WS_PREVIEW_BG_RADIUS = this.get('wsPreviewBgRadius', true); - this.SHOW_WS_PREVIEW_BG = this.get('showWsPreviewBg', true); - - this.CENTER_APP_GRID = this.get('centerAppGrid', true); - - this.SHOW_SEARCH_ENTRY = this.get('showSearchEntry', true); - this.CENTER_SEARCH_VIEW = this.get('centerSearch', true); - this.APP_GRID_ANIMATION = this.get('appGridAnimation', true); - if (this.APP_GRID_ANIMATION === 4) - this.APP_GRID_ANIMATION = this._getAnimationDirection(); - - this.SEARCH_VIEW_ANIMATION = this.get('searchViewAnimation', true); - if (this.SEARCH_VIEW_ANIMATION === 4) - this.SEARCH_VIEW_ANIMATION = 3; - - this.WS_ANIMATION = this.get('workspaceAnimation', true); - - this.WIN_PREVIEW_ICON_SIZE = [64, 48, 32, 22, 8][this.get('winPreviewIconSize', true)]; - this.ALWAYS_SHOW_WIN_TITLES = this.get('alwaysShowWinTitles', true); - - this.STARTUP_STATE = this.get('startupState', true); - this.SHOW_BG_IN_OVERVIEW = this.get('showBgInOverview', true); - this.OVERVIEW_BG_BRIGHTNESS = this.get('overviewBgBrightness', true) / 100; - this.OVERVIEW_BG_BLUR_SIGMA = this.get('overviewBgBlurSigma', true); - this.APP_GRID_BG_BLUR_SIGMA = this.get('appGridBgBlurSigma', true); - this.SMOOTH_BLUR_TRANSITIONS = this.get('smoothBlurTransitions', true); - - this.OVERVIEW_MODE = this.get('overviewMode', true); - this.OVERVIEW_MODE2 = this.OVERVIEW_MODE === 2; - this.WORKSPACE_MODE = this.OVERVIEW_MODE ? 0 : 1; - - this.STATIC_WS_SWITCHER_BG = this.get('workspaceSwitcherAnimation', true); - - this.ANIMATION_TIME_FACTOR = this.get('animationSpeedFactor', true) / 100; - - this.SEARCH_ICON_SIZE = this.get('searchIconSize', true); - this.SEARCH_VIEW_SCALE = this.get('searchViewScale', true) / 100; - this.SEARCH_MAX_ROWS = this.get('searchMaxResultsRows', true); - this.SEARCH_FUZZY = this.get('searchFuzzy', true); - - this.APP_GRID_ALLOW_INCOMPLETE_PAGES = this.get('appGridIncompletePages', true); - this.APP_GRID_ICON_SIZE = this.get('appGridIconSize', true); - this.APP_GRID_COLUMNS = this.get('appGridColumns', true); - this.APP_GRID_ROWS = this.get('appGridRows', true); - this.APP_GRID_ADAPTIVE = !this.APP_GRID_COLUMNS && !this.APP_GRID_ROWS; - this.APP_GRID_ORDER = this.get('appGridOrder', true); - - this.APP_GRID_INCLUDE_DASH = this.get('appGridContent', true); - /* 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', true); - - this.APP_GRID_FOLDER_ICON_SIZE = this.get('appGridFolderIconSize', true); - this.APP_GRID_FOLDER_ICON_GRID = this.get('appGridFolderIconGrid', true); - this.APP_GRID_FOLDER_COLUMNS = this.get('appGridFolderColumns', true); - this.APP_GRID_FOLDER_ROWS = this.get('appGridFolderRows', true); - this.APP_GRID_SPACING = this.get('appGridSpacing', true); - this.APP_GRID_FOLDER_DEFAULT = this.APP_GRID_FOLDER_ROWS === 3 && this.APP_GRID_FOLDER_COLUMNS === 3; - this.APP_GRID_ACTIVE_PREVIEW = this.get('appGridActivePreview', true); - this.APP_GRID_FOLDER_CENTER = this.get('appGridFolderCenter', true); - this.APP_GRID_PAGE_WIDTH_SCALE = this.get('appGridPageWidthScale', true) / 100; - - this.APP_GRID_ICON_SIZE_DEFAULT = this.APP_GRID_ACTIVE_PREVIEW && !this.APP_GRID_ORDER ? 176 : 96; - this.APP_GRID_FOLDER_ICON_SIZE_DEFAULT = 96; - - this.WINDOW_SEARCH_PROVIDER_ENABLED = this.get('searchWindowsEnable', true); - this.RECENT_FILES_SEARCH_PROVIDER_ENABLED = this.get('searchRecentFilesEnable', true); - - this.PANEL_POSITION_TOP = this.get('panelPosition', true) === 0; - this.PANEL_MODE = this.get('panelVisibility', true); - 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.FIX_UBUNTU_DOCK = this.get('fixUbuntuDock', true); - - this.WINDOW_ATTENTION_MODE = this.get('windowAttentionMode', true); - 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', true) / 100; - this.WS_SW_POPUP_V_POSITION = this.get('wsSwPopupVPosition', true) / 100; - this.WS_SW_POPUP_MODE = this.get('wsSwPopupMode', true); - - this.SHOW_FAV_NOTIFICATION = this.get('favoritesNotify', true); - this.NOTIFICATION_POSITION = this.get('notificationPosition', true); - - this.OSD_POSITION = this.get('osdPosition', true); - - this.HOT_CORNER_ACTION = this.get('hotCornerAction', true); - this.HOT_CORNER_POSITION = this.get('hotCornerPosition', true); - 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', true); - this.HOT_CORNER_RIPPLES = this.get('hotCornerRipples', true); - - this.ALWAYS_ACTIVATE_SELECTED_WINDOW = this.get('alwaysActivateSelectedWindow', true); - this.WINDOW_ICON_CLICK_SEARCH = this.get('windowIconClickSearch', true); - - this.OVERLAY_KEY_SECONDARY = this.get('overlayKeySecondary', true); - } - - _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/vertical-workspaces/lib/swipeTracker.js b/extensions/vertical-workspaces/lib/swipeTracker.js deleted file mode 100644 index d9c3407..0000000 --- a/extensions/vertical-workspaces/lib/swipeTracker.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * swipeTracker.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Clutter, GObject } = imports.gi; -const Main = imports.ui.main; -const SwipeTracker = imports.ui.swipeTracker; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); - -let opt; -let _firstRun = true; - -let _vwGestureUpdateId; -let _originalGestureUpdateId; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('swipeTrackerModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (reset || !opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL - // 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 (_vwGestureUpdateId) { - Main.overview._swipeTracker._touchpadGesture.disconnect(_vwGestureUpdateId); - _vwGestureUpdateId = 0; - } - if (_originalGestureUpdateId) { - Main.overview._swipeTracker._touchpadGesture.unblock_signal_handler(_originalGestureUpdateId); - _originalGestureUpdateId = 0; - } - - opt = null; - return; - } - - if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL - // 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 (!_originalGestureUpdateId) { - _originalGestureUpdateId = GObject.signal_handler_find(Main.overview._swipeTracker._touchpadGesture, { signalId: 'update' }); - Main.overview._swipeTracker._touchpadGesture.block_signal_handler(_originalGestureUpdateId); - Main.overview._swipeTracker._updateGesture = SwipeTrackerVertical._updateGesture; - _vwGestureUpdateId = Main.overview._swipeTracker._touchpadGesture.connect('update', SwipeTrackerVertical._updateGesture.bind(Main.overview._swipeTracker)); - } - } -} - -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/vertical-workspaces/lib/util.js b/extensions/vertical-workspaces/lib/util.js deleted file mode 100644 index 5f5c069..0000000 --- a/extensions/vertical-workspaces/lib/util.js +++ /dev/null @@ -1,364 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * util.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const Gi = imports._gi; -const { Shell, Meta, Clutter } = imports.gi; - -const Config = imports.misc.config; -const Main = imports.ui.main; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -var shellVersion = parseFloat(Config.PACKAGE_VERSION); - -var Overrides = class { - constructor() { - this._overrides = {}; - } - - addOverride(name, prototype, overrideList) { - this._overrides[name] = { - originals: this.overrideProto(prototype, overrideList), - prototype, - }; - } - - removeOverride(name) { - const override = this._overrides[name]; - if (!override) - return false; - - this.overrideProto(override.prototype, override.originals); - this._overrides[name] = undefined; - return true; - } - - removeAll() { - for (let name in this._overrides) { - this.removeOverride(name); - this._overrides[name] = undefined; - } - } - - hookVfunc(proto, symbol, func) { - proto[Gi.hook_up_vfunc_symbol](symbol, func); - } - - overrideProto(proto, overrides) { - const backup = {}; - - for (let symbol in overrides) { - if (symbol.startsWith('after_')) { - const actualSymbol = symbol.slice('after_'.length); - const 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 { - backup[symbol] = proto[symbol]; - if (symbol.startsWith('vfunc')) { - if (shellVersion < 42) - this.hookVfunc(proto, symbol.slice(6), overrides[symbol]); - else - this.hookVfunc(proto[Gi.gobject_prototype_symbol], symbol.slice(6), overrides[symbol]); - } else { - proto[symbol] = overrides[symbol]; - } - } - } - return backup; - } -}; - -function getOverviewTranslations(opt, dash, tmbBox, searchEntryBin) { - // const tmbBox = Main.overview._overview._controls._thumbnailsBox; - 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) { - switch (opt.WS_TMB_POSITION) { - case 3: // left - offset = 10 + (dash?.visible && opt.DASH_LEFT ? dash.width : 0); - tmbTranslationX = -tmbBox.width - offset; - tmbTranslationY = 0; - break; - case 1: // right - offset = 10 + (dash?.visible && opt.DASH_RIGHT ? dash.width : 0); - tmbTranslationX = tmbBox.width + offset; - tmbTranslationY = 0; - break; - case 0: // top - offset = 10 + (dash?.visible && opt.DASH_TOP ? dash.height : 0) + Main.panel.height; - tmbTranslationX = 0; - tmbTranslationY = -tmbBox.height - 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 = tmbBox.height + offset; - break; - } - } - - let dashTranslationX = 0; - let dashTranslationY = 0; - let position = opt.DASH_POSITION; - // if DtD replaced the original Dash, read its position - if (dashIsDashToDock()) - position = dash._position; - - if (dash?.visible) { - switch (position) { - case 0: // top - dashTranslationX = 0; - dashTranslationY = -dash.height - dash.margin_bottom - Main.panel.height; - break; - case 1: // right - dashTranslationX = dash.width; - dashTranslationY = 0; - break; - case 2: // bottom - dashTranslationX = 0; - dashTranslationY = dash.height + dash.margin_bottom + Main.panel.height; - break; - case 3: // left - dashTranslationX = -dash.width; - dashTranslationY = 0; - break; - } - } - - return [tmbTranslationX, tmbTranslationY, dashTranslationX, dashTranslationY, searchTranslationY]; -} - -function openPreferences() { - const windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null); - let tracker = Shell.WindowTracker.get_default(); - let metaWin, isVW = null; - - for (let win of windows) { - const app = tracker.get_window_app(win); - if (win.get_title().includes(Me.metadata.name) && app.get_name() === 'Extensions') { - // this is our existing window - metaWin = win; - isVW = true; - break; - } else if (win.wm_class.includes('org.gnome.Shell.Extensions')) { - // this is prefs window of another extension - metaWin = win; - isVW = false; - } - } - - if (metaWin && !isVW) { - // other prefs window blocks opening another prefs window, so close it - metaWin.delete(global.get_current_time()); - } else if (metaWin && isVW) { - // 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 && !isVW)) { - try { - Main.extensionManager.openExtensionPrefs(Me.metadata.uuid, '', {}); - } catch (e) { - log(e); - } - } -} - -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(''); - } -} - -function dashNotDefault() { - return Main.overview.dash !== Main.overview._overview._controls.layoutManager._dash; -} - -function dashIsDashToDock() { - return Main.overview.dash._isHorizontal !== undefined; -} - -// Reorder Workspaces - callback for Dash and workspacesDisplay -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); -} - -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); - }); - } - }, - }); - } - } -} - -function isShiftPressed(state = null) { - if (state === null) - [,, state] = global.get_pointer(); - return (state & Clutter.ModifierType.SHIFT_MASK) !== 0; -} - -function isCtrlPressed(state = null) { - if (state === null) - [,, state] = global.get_pointer(); - return (state & Clutter.ModifierType.CONTROL_MASK) !== 0; -} - -function isAltPressed(state = null) { - if (state === null) - [,, state] = global.get_pointer(); - return (state & Clutter.ModifierType.MOD1_MASK) !== 0; -} - -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]; -} - -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; -} - -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; -} - -function getEnabledExtensions(uuid = '') { - let extensions = []; - Main.extensionManager._extensions.forEach(e => { - if (e.state === 1 && e.uuid.includes(uuid)) - extensions.push(e); - }); - return extensions; -} - -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; -} diff --git a/extensions/vertical-workspaces/lib/windowAttentionHandler.js b/extensions/vertical-workspaces/lib/windowAttentionHandler.js deleted file mode 100644 index 10703c2..0000000 --- a/extensions/vertical-workspaces/lib/windowAttentionHandler.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowAttentionHandler.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const Main = imports.ui.main; -const WindowAttentionHandler = imports.ui.windowAttentionHandler; -const MessageTray = imports.ui.messageTray; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const _Util = Me.imports.lib.util; - -let opt; -let _firstRun = false; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('winAttentionHandlerModule', true); - reset = reset || !moduleEnabled; - - if (_firstRun && reset) - return; - - _firstRun = false; - if (reset) { - reset = true; - _updateConnections(reset); - opt = null; - return; - } - - _updateConnections(); -} - -function _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); - 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); - }, -}; diff --git a/extensions/vertical-workspaces/lib/windowManager.js b/extensions/vertical-workspaces/lib/windowManager.js deleted file mode 100644 index 2d46b0b..0000000 --- a/extensions/vertical-workspaces/lib/windowManager.js +++ /dev/null @@ -1,217 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowManager.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { GObject, Clutter, Meta } = imports.gi; - -const Main = imports.ui.main; -const WindowManager = imports.ui.windowManager; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; -let _overrides; - -const MINIMIZE_WINDOW_ANIMATION_TIME = WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME; -const MINIMIZE_WINDOW_ANIMATION_MODE = WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE; - -let opt; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('windowManagerModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - - _replaceMinimizeFunction(reset); - - - if (reset) { - _overrides = null; - opt = null; - return; - } - - _overrides = new _Util.Overrides(); - - _overrides.addOverride('WindowManager', WindowManager.WindowManager.prototype, WindowManagerCommon); -} - -// ------------- Fix and adapt minimize/unminimize animations -------------------------------------- - -let _originalMinimizeSigId; -let _minimizeSigId; -let _originalUnminimizeSigId; -let _unminimizeSigId; - -function _replaceMinimizeFunction(reset = false) { - if (reset) { - Main.wm._shellwm.disconnect(_minimizeSigId); - _minimizeSigId = 0; - Main.wm._shellwm.unblock_signal_handler(_originalMinimizeSigId); - _originalMinimizeSigId = 0; - - Main.wm._shellwm.disconnect(_unminimizeSigId); - _unminimizeSigId = 0; - Main.wm._shellwm.unblock_signal_handler(_originalUnminimizeSigId); - _originalUnminimizeSigId = 0; - } else if (!_minimizeSigId) { - _originalMinimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'minimize' }); - if (_originalMinimizeSigId) { - Main.wm._shellwm.block_signal_handler(_originalMinimizeSigId); - _minimizeSigId = Main.wm._shellwm.connect('minimize', WindowManagerCommon._minimizeWindow.bind(Main.wm)); - } - - _originalUnminimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'unminimize' }); - if (_originalUnminimizeSigId) { - Main.wm._shellwm.block_signal_handler(_originalUnminimizeSigId); - _unminimizeSigId = Main.wm._shellwm.connect('unminimize', WindowManagerCommon._unminimizeWindow.bind(Main.wm)); - } - } -} - -// 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 -const WindowManagerCommon = { - _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), - }); - // } - }, -}; diff --git a/extensions/vertical-workspaces/lib/windowPreview.js b/extensions/vertical-workspaces/lib/windowPreview.js deleted file mode 100644 index 5d2bd61..0000000 --- a/extensions/vertical-workspaces/lib/windowPreview.js +++ /dev/null @@ -1,379 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowPreview.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { Clutter, GLib, GObject, Graphene, Meta, Shell, St } = imports.gi; - -const Main = imports.ui.main; -const WindowPreview = imports.ui.windowPreview; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const _Util = Me.imports.lib.util; -const shellVersion = _Util.shellVersion; - -let _overrides; - -const WINDOW_SCALE_TIME = imports.ui.windowPreview.WINDOW_SCALE_TIME; -const WINDOW_ACTIVE_SIZE_INC = imports.ui.windowPreview.WINDOW_ACTIVE_SIZE_INC; -const WINDOW_OVERLAY_FADE_TIME = imports.ui.windowPreview.WINDOW_OVERLAY_FADE_TIME; -const SEARCH_WINDOWS_PREFIX = Me.imports.lib.windowSearchProvider.prefix; - -const ControlsState = imports.ui.overviewControls.ControlsState; - -let opt; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('windowPreviewModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - - if (reset) { - _overrides = null; - opt = null; - WindowPreview.WINDOW_OVERLAY_IDLE_HIDE_TIMEOUT = 750; - return; - } - - _overrides = new _Util.Overrides(); - - _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; -} - -const WindowPreviewCommon = { - // injection to _init() - after__init() { - const ICON_OVERLAP = 0.7; - - if (opt.WIN_PREVIEW_ICON_SIZE < 64) { - this.remove_child(this._icon); - this._icon.destroy(); - const tracker = Shell.WindowTracker.get_default(); - const app = tracker.get_window_app(this.metaWindow); - this._icon = app.create_icon_texture(opt.WIN_PREVIEW_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: this.windowContainer, - coordinate: Clutter.BindCoordinate.POSITION, - })); - this._icon.add_constraint(new Clutter.AlignConstraint({ - source: this.windowContainer, - align_axis: Clutter.AlignAxis.X_AXIS, - factor: 0.5, - })); - this._icon.add_constraint(new Clutter.AlignConstraint({ - source: this.windowContainer, - align_axis: Clutter.AlignAxis.Y_AXIS, - pivot_point: new Graphene.Point({ x: -1, y: ICON_OVERLAP }), - factor: 1, - })); - this.add_child(this._icon); - if (opt.WIN_PREVIEW_ICON_SIZE < 22) { - // disable app icon - this._icon.hide(); - } - this._iconSize = opt.WIN_PREVIEW_ICON_SIZE; - } - - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); - const iconOverlap = opt.WIN_PREVIEW_ICON_SIZE * ICON_OVERLAP; - // we cannot get proper title height before it gets to the stage, so 35 is estimated height + spacing - this._title.get_constraints()[1].offset = scaleFactor * (-iconOverlap - 35); - this.set_child_above_sibling(this._title, null); - // if window is created while the overview is shown, icon and title should be visible immediately - if (Main.overview._overview._controls._stateAdjustment.value < 1) { - 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; - - const adjustment = this._workspace._background._stateAdjustment; - opt.WORKSPACE_MODE = 1; - _Util.exposeWindows(adjustment, false); - this.disconnect(this._wsStateConId); - }); - } - - if (opt.OVERVIEW_MODE) { - // show window icon and title on ws windows spread - this._stateAdjustmentSigId = this._workspace.stateAdjustment.connect('notify::value', this._updateIconScale.bind(this)); - } - - // replace click action with custom one - const action = this.get_actions()[0]; - - const handlerId = GObject.signal_handler_find(action, { signalId: 'clicked' }); - if (handlerId) - action.disconnect(handlerId); - - action.connect('clicked', act => { - const button = act.get_button(); - if (button === Clutter.BUTTON_PRIMARY) { - this._activate(); - return Clutter.EVENT_STOP; - } else if (button === Clutter.BUTTON_SECONDARY) { - // this action cancels long-press event and the 'long-press-cancel' event is used by the Shell to actually initiate DnD - // so the dnd initiation needs to be removed - if (this._longPressLater) { - if (shellVersion >= 44) { - const laters = global.compositor.get_laters(); - laters.remove(this._longPressLater); - } else { - Meta.later_remove(this._longPressLater); - delete this._longPressLater; - } - } - const tracker = Shell.WindowTracker.get_default(); - const appName = tracker.get_window_app(this.metaWindow).get_name(); - _Util.activateSearchProvider(`${SEARCH_WINDOWS_PREFIX} ${appName}`); - return Clutter.EVENT_STOP; - } - return Clutter.EVENT_PROPAGATE; - }); - - if (opt.WINDOW_ICON_CLICK_SEARCH) { - const iconClickAction = new Clutter.ClickAction(); - iconClickAction.connect('clicked', act => { - if (act.get_button() === Clutter.BUTTON_PRIMARY) { - const tracker = Shell.WindowTracker.get_default(); - const appName = tracker.get_window_app(this.metaWindow).get_name(); - _Util.activateSearchProvider(`${SEARCH_WINDOWS_PREFIX} ${appName}`); - return Clutter.EVENT_STOP; - } - return Clutter.EVENT_PROPAGATE; - }); - this._icon.add_action(iconClickAction); - } - }, - - _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 && 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 = opt.WORKSPACE_MODE; - else if (finalState === 1 || (finalState === 0 && !opt.WORKSPACE_MODE)) - return; - } - - if (scale === 1) { - this._icon.ease({ - duration: 50, - scale_x: scale, - scale_y: scale, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - this._title.ease({ - duration: 100, - opacity: 255, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } else if (this._icon.scale_x !== 0) { - this._icon.set({ - scale_x: 0, - scale_y: 0, - }); - this._title.opacity = 0; - } - - // if titles are in 'always show' mode, we need to add transition between visible/invisible state - // but the transition is quite expensive, - // showing the titles at the end of the transition is good enough and workspace preview transition is much smoother - }, - - showOverlay(animate) { - if (!this._overlayEnabled) - return; - - if (this._overlayShown) - return; - - this._overlayShown = true; - if (!opt.ALWAYS_ACTIVATE_SELECTED_WINDOW) - this._restack(); - - // If we're supposed to animate and an animation in our direction - // is already happening, let that one continue - const ongoingTransition = this._title.get_transition('opacity'); - if (animate && - ongoingTransition && - ongoingTransition.get_interval().peek_final_value() === 255) - return; - - const toShow = this._windowCanClose() - ? [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.get_parent()?.set_child_above_sibling(this, null); - this._activateSelected = true; - } - - if (!opt.ALWAYS_ACTIVATE_SELECTED_WINDOW) - this._restack(); - - // If we're supposed to animate and an animation in our direction - // is already happening, let that one continue - 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() { - // workaround for upstream bug - hideOverlay is called after windowPreview is destroyed, from the leave event callback - // hiding the preview now avoids firing the post-mortem leave event - this.hide(); - if (this._activateSelected) - this._activate(); - - this.metaWindow._delegate = null; - this._delegate = null; - - if (this._longPressLater) { - if (shellVersion >= 44) { - const laters = global.compositor.get_laters(); - laters.remove(this._longPressLater); - delete this._longPressLater; - } else { - Meta.later_remove(this._longPressLater); - delete this._longPressLater; - } - } - - if (this._idleHideOverlayId > 0) { - 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/vertical-workspaces/lib/windowSearchProvider.js b/extensions/vertical-workspaces/lib/windowSearchProvider.js deleted file mode 100644 index 5f90784..0000000 --- a/extensions/vertical-workspaces/lib/windowSearchProvider.js +++ /dev/null @@ -1,305 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowSearchProvider.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 -2023 - * @license GPL-3.0 - */ - -'use strict'; - -const { GLib, Gio, Meta, St, Shell } = imports.gi; - -const Main = imports.ui.main; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const Settings = Me.imports.lib.settings; -const _Util = Me.imports.lib.util; - -// gettext -const _ = Settings._; - -const shellVersion = Settings.shellVersion; - -const ModifierType = imports.gi.Clutter.ModifierType; - -let windowSearchProvider; -let _enableTimeoutId = 0; - -// prefix helps to eliminate results from other search providers -// so it needs to be something less common -// needs to be accessible from vw module -var prefix = 'wq//'; - -let opt; - -const Action = { - NONE: 0, - CLOSE: 1, - CLOSE_ALL: 2, - MOVE_TO_WS: 3, - MOVE_ALL_TO_WS: 4, -}; - -function getOverviewSearchResult() { - return Main.overview._overview.controls._searchController._searchResults; -} - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - if (!reset && opt.WINDOW_SEARCH_PROVIDER_ENABLED && !windowSearchProvider) { - enable(); - } else if (reset || !opt.WINDOW_SEARCH_PROVIDER_ENABLED) { - disable(); - opt = null; - } -} - -function enable() { - // delay because Fedora had problem to register a new provider soon after Shell restarts - _enableTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 2000, - () => { - if (!windowSearchProvider) { - windowSearchProvider = new WindowSearchProvider(opt); - getOverviewSearchResult()._registerProvider( - windowSearchProvider - ); - } - _enableTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); -} - -function disable() { - if (windowSearchProvider) { - getOverviewSearchResult()._unregisterProvider( - windowSearchProvider - ); - windowSearchProvider = null; - } - if (_enableTimeoutId) { - GLib.source_remove(_enableTimeoutId); - _enableTimeoutId = 0; - } -} - -function makeResult(window, i) { - const app = Shell.WindowTracker.get_default().get_window_app(window); - const appName = app ? app.get_name() : 'Unknown'; - const windowTitle = window.get_title(); - const wsIndex = window.get_workspace().index(); - - return { - 'id': i, - // convert all accented chars to their basic form and lower case for search - 'name': `${wsIndex + 1}: ${windowTitle} ${appName}`.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase(), - appName, - windowTitle, - window, - }; -} - -const closeSelectedRegex = /^\/x!$/; -const closeAllResultsRegex = /^\/xa!$/; -const moveToWsRegex = /^\/m[0-9]+$/; -const moveAllToWsRegex = /^\/ma[0-9]+$/; - -const WindowSearchProvider = class WindowSearchProvider { - constructor() { - this.id = `open-windows@${Me.metadata.uuid}`; - this.appInfo = Gio.AppInfo.create_from_commandline('true', _('Open Windows'), null); - this.appInfo.get_description = () => _('List of open windows'); - this.appInfo.get_name = () => _('Open Windows'); - this.appInfo.get_id = () => this.id; - this.appInfo.get_icon = () => Gio.icon_new_for_string('focus-windows-symbolic'); - this.appInfo.should_show = () => true; - - this.canLaunchSearch = true; - this.isRemoteProvider = false; - - this.action = 0; - } - - _getResultSet(terms) { - // do not modify original terms - let termsCopy = [...terms]; - // search for terms without prefix - termsCopy[0] = termsCopy[0].replace(prefix, ''); - - /* if (gOptions.get('searchWindowsCommands')) { - this.action = 0; - this.targetWs = 0; - - const lastTerm = terms[terms.length - 1]; - if (lastTerm.match(closeSelectedRegex)) { - this.action = Action.CLOSE; - } else if (lastTerm.match(closeAllResultsRegex)) { - this.action = Action.CLOSE_ALL; - } else if (lastTerm.match(moveToWsRegex)) { - this.action = Action.MOVE_TO_WS; - } else if (lastTerm.match(moveAllToWsRegex)) { - this.action = Action.MOVE_ALL_TO_WS; - } - if (this.action) { - terms.pop(); - if (this.action === Action.MOVE_TO_WS || this.action === Action.MOVE_ALL_TO_WS) { - this.targetWs = parseInt(lastTerm.replace(/^[^0-9]+/, '')) - 1; - } - } else if (lastTerm.startsWith('/')) { - terms.pop(); - } - }*/ - - const candidates = this.windows; - const _terms = [].concat(termsCopy); - // let match; - - const term = _terms.join(' '); - /* match = s => { - return fuzzyMatch(term, s); - }; */ - - const results = []; - let m; - for (let key in candidates) { - if (opt.SEARCH_FUZZY) - m = _Util.fuzzyMatch(term, candidates[key].name); - else - m = _Util.strictMatch(term, candidates[key].name); - - if (m !== -1) - results.push({ weight: m, id: key }); - } - - results.sort((a, b) => a.weight > b.weight); - const currentWs = global.workspace_manager.get_active_workspace_index(); - // prefer current workspace - results.sort((a, b) => (this.windows[a.id].window.get_workspace().index() !== currentWs) && (this.windows[b.id].window.get_workspace().index() === currentWs)); - results.sort((a, b) => (_terms !== ' ') && (a.weight > 0 && b.weight === 0)); - - this.resultIds = results.map(item => item.id); - return this.resultIds; - } - - getResultMetas(resultIds, callback = null) { - const metas = resultIds.map(id => this.getResultMeta(id)); - if (shellVersion >= 43) - return new Promise(resolve => resolve(metas)); - else - callback(metas); - return null; - } - - getResultMeta(resultId) { - const result = this.windows[resultId]; - const wsIndex = result.window.get_workspace().index(); - const app = Shell.WindowTracker.get_default().get_window_app(result.window); - return { - 'id': resultId, - 'name': `${wsIndex + 1}: ${result.windowTitle}`, - 'description': result.appName, - 'createIcon': size => { - return app - ? app.create_icon_texture(size) - : new St.Icon({ icon_name: 'icon-missing', icon_size: size }); - }, - }; - } - - launchSearch(/* terms, timeStamp*/) { - } - - activateResult(resultId/* , terms, timeStamp*/) { - const isCtrlPressed = _Util.isCtrlPressed(); - const isShiftPressed = _Util.isShiftPressed(); - - this.action = 0; - this.targetWs = 0; - - this.targetWs = global.workspaceManager.get_active_workspace().index() + 1; - if (isShiftPressed && !isCtrlPressed) - this.action = Action.MOVE_TO_WS; - else if (isShiftPressed && isCtrlPressed) - this.action = Action.MOVE_ALL_TO_WS; - - - if (!this.action) { - const result = this.windows[resultId]; - Main.activateWindow(result.window); - return; - } - - switch (this.action) { - case Action.CLOSE: - this._closeWindows([resultId]); - break; - case Action.CLOSE_ALL: - this._closeWindows(this.resultIds); - break; - case Action.MOVE_TO_WS: - this._moveWindowsToWs(resultId, [resultId]); - break; - case Action.MOVE_ALL_TO_WS: - this._moveWindowsToWs(resultId, this.resultIds); - break; - } - } - - _closeWindows(ids) { - let time = global.get_current_time(); - for (let i = 0; i < ids.length; i++) - this.windows[ids[i]].window.delete(time + i); - - Main.notify('Window Search Provider', `Closed ${ids.length} windows.`); - } - - _moveWindowsToWs(selectedId, resultIds) { - const workspace = global.workspaceManager.get_active_workspace(); - - for (let i = 0; i < resultIds.length; i++) - this.windows[resultIds[i]].window.change_workspace(workspace); - - const selectedWin = this.windows[selectedId].window; - selectedWin.activate_with_workspace(global.get_current_time(), workspace); - } - - getInitialResultSet(terms, callback/* , cancellable = null*/) { - // In GS 43 callback arg has been removed - /* if (shellVersion >= 43) - cancellable = callback;*/ - - let windows; - this.windows = windows = {}; - global.display.get_tab_list(Meta.TabList.NORMAL, null).filter(w => w.get_workspace() !== null).map( - (v, i) => { - windows[`${i}-${v.get_id()}`] = makeResult(v, `${i}-${v.get_id()}`); - return windows[`${i}-${v.get_id()}`]; - } - ); - - if (shellVersion >= 43) - return new Promise(resolve => resolve(this._getResultSet(terms))); - else - callback(this._getResultSet(terms)); - return null; - } - - filterResults(results /* , maxResults*/) { - // return results.slice(0, maxResults); - return results; - } - - getSubsearchResultSet(previousResults, terms, callback/* , cancellable*/) { - // if we return previous results, quick typers get non-actual results - callback(this._getResultSet(terms)); - } - - /* createResultObject(resultMeta) { - const app = Shell.WindowTracker.get_default().get_window_app(resultMeta.id); - return new AppIcon(app); - }*/ -}; diff --git a/extensions/vertical-workspaces/lib/workspace.js b/extensions/vertical-workspaces/lib/workspace.js deleted file mode 100644 index 3b61a6d..0000000 --- a/extensions/vertical-workspaces/lib/workspace.js +++ /dev/null @@ -1,152 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspace.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { St, Graphene } = imports.gi; - -const Main = imports.ui.main; -const Util = imports.misc.util; -const Workspace = imports.ui.workspace; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const _Util = Me.imports.lib.util; - -let _overrides; -let opt; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('workspaceModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - - if (reset) { - Workspace.WINDOW_PREVIEW_MAXIMUM_SCALE = 0.95; - _overrides = null; - opt = null; - return; - } - - _overrides = new _Util.Overrides(); - - _overrides.addOverride('WorkspaceBackground', Workspace.WorkspaceBackground.prototype, WorkspaceBackground); - - // fix overlay base for Vertical Workspaces - _overrides.addOverride('WorkspaceLayout', Workspace.WorkspaceLayout.prototype, WorkspaceLayout); -} - - -// 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) { - 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 !== this.WINDOW_PREVIEW_MAXIMUM_SCALE) { - this.WINDOW_PREVIEW_MAXIMUM_SCALE = scale; - // when transition to ws state 1 (WINDOW_PICKER) begins, replace the constant with the original one - Workspace.WINDOW_PREVIEW_MAXIMUM_SCALE = scale; - // 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]; - }, -}; - -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/vertical-workspaces/lib/workspaceAnimation.js b/extensions/vertical-workspaces/lib/workspaceAnimation.js deleted file mode 100644 index 07008c6..0000000 --- a/extensions/vertical-workspaces/lib/workspaceAnimation.js +++ /dev/null @@ -1,184 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspacesAnimation.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; -const Main = imports.ui.main; -const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup; -const WorkspaceAnimation = imports.ui.workspaceAnimation; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const _Util = Me.imports.lib.util; - -// first reference to constant defined using const in other module returns undefined, the MonitorGroup const will remain empty and unused -let MonitorGroupDummy = WorkspaceAnimation.MonitorGroup; -MonitorGroupDummy = null; - -let _origBaseDistance; -let _wsAnimationSwipeBeginId; -let _wsAnimationSwipeUpdateId; -let _wsAnimationSwipeEndId; - -let _overrides; -let opt; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('workspaceAnimationModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - if (reset || !moduleEnabled) { - _connectWsAnimationSwipeTracker(true); - _overrideMonitorGroupProperty(true); - _overrides = null; - opt = null; - return; - } - - if (opt.STATIC_WS_SWITCHER_BG) { - _overrides = new _Util.Overrides(); - _overrideMonitorGroupProperty(); - _overrides.addOverride('WorkspaceAnimationMonitorGroup', WorkspaceAnimation.MonitorGroup.prototype, MonitorGroup); - } - - _connectWsAnimationSwipeTracker(); -} - -// remove spacing between workspaces during transition to remove flashing wallpaper between workspaces with maximized windows -function _overrideMonitorGroupProperty(reset = false) { - if (!_origBaseDistance) - _origBaseDistance = Object.getOwnPropertyDescriptor(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance').get; - - let getter; - if (reset) { - if (_origBaseDistance) - getter = { get: _origBaseDistance }; - } else { - getter = { - get() { - // const spacing = 100 * imports.gi.St.ThemeContext.get_for_stage(global.stage).scale_factor; - const spacing = 0; - if (global.workspace_manager.layout_rows === -1) - return this._monitor.height + spacing + (opt.PANEL_MODE ? Main.panel.height : 0); // compensation for hidden panel - else - return this._monitor.width + spacing; - }, - }; - } - - if (getter) - Object.defineProperty(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance', getter); -} - -const MonitorGroup = { - // injection to _init() - after__init() { - // 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 - const stickyGroup = this.get_children()[1]; - 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._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())) { //* && !w.is_on_all_workspaces()*/) { - // 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; - }); - }); - }, -}; - -function _connectWsAnimationSwipeTracker(reset = false) { - if (reset) { - if (_wsAnimationSwipeBeginId) { - Main.wm._workspaceAnimation._swipeTracker.disconnect(_wsAnimationSwipeBeginId); - _wsAnimationSwipeBeginId = 0; - } - if (_wsAnimationSwipeEndId) { - Main.wm._workspaceAnimation._swipeTracker.disconnect(_wsAnimationSwipeEndId); - _wsAnimationSwipeEndId = 0; - } - } else if (!_wsAnimationSwipeBeginId) { - // display ws switcher popup when gesture begins and connect progress - _wsAnimationSwipeBeginId = Main.wm._workspaceAnimation._swipeTracker.connect('begin', () => _connectWsAnimationProgress(true)); - // we want to be sure that popup with the final ws index show up when gesture ends - _wsAnimationSwipeEndId = Main.wm._workspaceAnimation._swipeTracker.connect('end', (tracker, duration, endProgress) => _connectWsAnimationProgress(false, endProgress)); - } -} - -function _connectWsAnimationProgress(connect, endProgress = null) { - if (Main.overview.visible) - return; - - if (connect && !_wsAnimationSwipeUpdateId) { - _wsAnimationSwipeUpdateId = Main.wm._workspaceAnimation._swipeTracker.connect('update', (tracker, progress) => _showWsSwitcherPopup(progress)); - } else if (!connect && _wsAnimationSwipeUpdateId) { - Main.wm._workspaceAnimation._swipeTracker.disconnect(_wsAnimationSwipeUpdateId); - _wsAnimationSwipeUpdateId = 0; - _showWsSwitcherPopup(Math.round(endProgress)); - } -} - -function _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); -} diff --git a/extensions/vertical-workspaces/lib/workspaceSwitcherPopup.js b/extensions/vertical-workspaces/lib/workspaceSwitcherPopup.js deleted file mode 100644 index 972f35e..0000000 --- a/extensions/vertical-workspaces/lib/workspaceSwitcherPopup.js +++ /dev/null @@ -1,90 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspacesSwitcherPopup.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const Main = imports.ui.main; -const WorkspaceSwitcherPopup = imports.ui.workspaceSwitcherPopup; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const _Util = Me.imports.lib.util; -let _overrides; - -let opt; -let _firstRun = true; - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - const moduleEnabled = opt.get('workspaceSwitcherPopupModule', true); - reset = reset || !moduleEnabled; - - // don't even touch this module if disabled - if (_firstRun && reset) - return; - - _firstRun = false; - - if (_overrides) - _overrides.removeAll(); - - if (reset) { - _overrides = null; - opt = null; - return; - } - - _overrides = new _Util.Overrides(); - - const enabled = global.settings.get_strv('enabled-extensions'); - const allowWsPopupInjection = !(enabled.includes('workspace-switcher-manager@G-dH.github.com') || enabled.includes('WsSwitcherPopupManager@G-dH.github.com-dev')); - if (allowWsPopupInjection) { // 1-VERTICAL, 0-HORIZONTAL - _overrides.addOverride('WorkspaceSwitcherPopup', WorkspaceSwitcherPopup.WorkspaceSwitcherPopup.prototype, WorkspaceSwitcherPopupOverride); - } -} - -const WorkspaceSwitcherPopupOverride = { - // injection to _init() - after__init() { - if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL - this._list.vertical = true; - } - this._list.set_style('margin: 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 = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);*/ - workArea = global.display.get_monitor_geometry(Main.layoutManager.primaryIndex); - } else { - // workArea = Main.layoutManager.getWorkAreaForMonitor(global.display.get_current_monitor()); - 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/vertical-workspaces/lib/workspaceThumbnail.js b/extensions/vertical-workspaces/lib/workspaceThumbnail.js deleted file mode 100644 index d0bc206..0000000 --- a/extensions/vertical-workspaces/lib/workspaceThumbnail.js +++ /dev/null @@ -1,1148 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspaceThumbnail.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { GLib, Clutter, Graphene, Meta, Shell, St } = imports.gi; -const DND = imports.ui.dnd; -const Main = imports.ui.main; -const Background = imports.ui.background; -const WorkspaceThumbnail = imports.ui.workspaceThumbnail; -const ThumbnailState = WorkspaceThumbnail.ThumbnailState; - -const ControlsState = imports.ui.overviewControls.ControlsState; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -// gettext -const _ = Me.imports.lib.settings._; - -const _Util = Me.imports.lib.util; -const shellVersion = _Util.shellVersion; - -let _overrides; - -const WORKSPACE_CUT_SIZE = 10; -const _originalMaxThumbnailScale = WorkspaceThumbnail.MAX_THUMBNAIL_SCALE; - -let opt = null; - -function update(reset = false) { - if (_overrides) - _overrides.removeAll(); - - - if (reset) { - if (_originalMaxThumbnailScale) - WorkspaceThumbnail.MAX_THUMBNAIL_SCALE = _originalMaxThumbnailScale; - _overrides = null; - opt = null; - return; - } - - opt = Me.imports.lib.settings.opt; - _overrides = new _Util.Overrides(); - - // don't limit max thumbnail scale for other clients than overview, for example AATWS. - WorkspaceThumbnail.MAX_THUMBNAIL_SCALE = 1; - - _overrides.addOverride('WorkspaceThumbnail', WorkspaceThumbnail.WorkspaceThumbnail.prototype, WorkspaceThumbnailCommon); - _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; -} - -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'); - - // 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 = ExtensionUtils.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', () => { - // wait for new information - 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 && _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); - - this.connect('destroy', () => { - if (this._bgManager) - this._bgManager.destroy(); - this._bgManager = 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 && !_Util.isCtrlPressed()) { - return; - } - - // close windows on this monitor - const windows = global.display.get_tab_list(0, null).filter( - w => w.get_monitor() === this.monitorIndex && w.get_workspace() === this.metaWorkspace - ); - - for (let i = 0; i < windows.length; i++) { - if (!windows[i].is_on_all_workspaces()) - windows[i].delete(global.get_current_time() + i); - } - }, - - activate(time) { - if (this.state > ThumbnailState.NORMAL) - return; - - // if Static Workspace overview mode active, a click on the already active workspace should activate the window picker mode - const wsIndex = this.metaWorkspace.index(); - const lastWsIndex = global.display.get_workspace_manager().get_n_workspaces() - 1; - const stateAdjustment = Main.overview._overview.controls._stateAdjustment; - - if (stateAdjustment.value === ControlsState.APP_GRID) { - if (this.metaWorkspace.active) { - Main.overview._overview.controls._shiftState(Meta.MotionDirection.DOWN); - // if searchActive, hide it immediately - Main.overview.searchEntry.set_text(''); - } else { - this.metaWorkspace.activate(time); - } - } else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && wsIndex < lastWsIndex) { - if (stateAdjustment.value > 1) - stateAdjustment.value = 1; - - - // spread windows - // in OVERVIEW MODE 2 windows are not spread and workspace is not scaled - // we need to repeat transition to the overview state 1 (window picker), but with spreading windows animation - if (this.metaWorkspace.active) { - Main.overview._overview.controls._searchController._setSearchActive(false); - opt.WORKSPACE_MODE = 1; - // setting value to 0 would reset WORKSPACE_MODE - stateAdjustment.value = 0.01; - stateAdjustment.ease(1, { - duration: 200, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } else { - // switch ws - this.metaWorkspace.activate(time); - } - // a click on the current workspace should go back to the main view - } else if (this.metaWorkspace.active) { - Main.overview.hide(); - } else { - this.metaWorkspace.activate(time); - } - }, - - // Draggable target interface used only by ThumbnailsBox - handleDragOverInternal(source, actor, time) { - if (source === Main.xdndHandler) { - this.metaWorkspace.activate(time); - return DND.DragMotionResult.CONTINUE; - } - - if (this.state > ThumbnailState.NORMAL) - return DND.DragMotionResult.CONTINUE; - - if (source.metaWindow && - !this._isMyWindow(source.metaWindow.get_compositor_private())) - return DND.DragMotionResult.MOVE_DROP; - if (source.app && source.app.can_open_new_window()) - return DND.DragMotionResult.COPY_DROP; - if (!source.app && source.shellWorkspaceLaunch) - return DND.DragMotionResult.COPY_DROP; - - if (source instanceof imports.ui.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 imports.ui.appDisplay.FolderIcon) { - if (shellVersion >= 44) { - for (let app of source.view._apps) { - // const app = Shell.AppSystem.get_default().lookup_app(id); - app.open_new_window(this.metaWorkspace.index()); - } - } else { - for (let id of source.view._appIds) { - 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 imports.ui.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 imports.ui.appDisplay.FolderIcon) { - if (shellVersion >= 44) { - for (let app of source.view._apps) { - // const app = Shell.AppSystem.get_default().lookup_app(id); - app.open_new_window(newWorkspaceIndex); - } - } else { - for (let id of source.view._appIds) { - 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), - WorkspaceThumbnail.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 imports.ui.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; - }, - - _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); - }, - - get_preferred_custom_width(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical.get_preferred_custom_width.bind(this)(...args); - else - return ThumbnailsBoxHorizontal.get_preferred_custom_width.bind(this)(...args); - }, - - get_preferred_custom_height(...args) { - if (this._boxOrientation) - return ThumbnailsBoxVertical.get_preferred_custom_height.bind(this)(...args); - else - return ThumbnailsBoxHorizontal.get_preferred_custom_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: function(forHeight) { - // override of this vfunc doesn't work for some reason (tested on Ubuntu and Fedora), it's not reachable - get_preferred_custom_width(forHeight) { - if (!this.visible) - return [0, 0]; - - if (forHeight === -1) - return this.get_preferred_custom_height(forHeight); - - 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; - // scale = Math.min(scale, opt.MAX_THUMBNAIL_SCALE); - - const width = Math.round(this._porthole.width * scale); - return themeNode.adjust_preferred_height(width, width); - }, - - get_preferred_custom_height(_forWidth) { - if (!this.visible) - return [0, 0]; - - // Note that for getPreferredHeight/Width we cheat a bit and skip propagating - // the size request to our children because we know how big they are and know - // that the actors aren't depending on the virtual functions being called. - 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, 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()); - - if (shellVersion >= 44) { - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.hide(); - }); - } else { - Meta.later_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); - - if (shellVersion >= 44) { - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.show(); - }); - } else { - Meta.later_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; - }, - - get_preferred_custom_height(forWidth) { - 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; - // scale = Math.min(scale, opt.MAX_THUMBNAIL_SCALE); - - const height = Math.round(this._porthole.height * scale); - return themeNode.adjust_preferred_height(height, height); - }, - - get_preferred_custom_width(_forHeight) { - // Note that for getPreferredHeight/Width we cheat a bit and skip propagating - // the size request to our children because we know how big they are and know - // that the actors aren't depending on the virtual functions being called. - if (!this.visible) - return [0, 0]; - - 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()); - - if (shellVersion >= 44) { - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.hide(); - }); - } else { - Meta.later_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); - - if (shellVersion >= 44) { - const laters = global.compositor.get_laters(); - laters.add(Meta.LaterType.BEFORE_REDRAW, () => { - this._dropPlaceholder.show(); - }); - } else { - Meta.later_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/vertical-workspaces/lib/workspacesView.js b/extensions/vertical-workspaces/lib/workspacesView.js deleted file mode 100644 index e3575f1..0000000 --- a/extensions/vertical-workspaces/lib/workspacesView.js +++ /dev/null @@ -1,934 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * workspacesView.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - * - */ - -'use strict'; - -const { GObject, Clutter, Meta, St } = imports.gi; - -const Main = imports.ui.main; -const Util = imports.misc.util; -const WorkspacesView = imports.ui.workspacesView; -// first reference to constant defined using const in other module returns undefined, the SecondaryMonitorDisplay const will remain empty and unused -const SecondaryMonitorDisplay = WorkspacesView.SecondaryMonitorDisplay; -const ControlsState = imports.ui.overviewControls.ControlsState; -const FitMode = imports.ui.workspacesView.FitMode; - -const SIDE_CONTROLS_ANIMATION_TIME = imports.ui.overview.ANIMATION_TIME; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const SEARCH_WINDOWS_PREFIX = Me.imports.lib.windowSearchProvider.prefix; -const SEARCH_RECENT_FILES_PREFIX = Me.imports.lib.recentFilesSearchProvider.prefix; - -const _Util = Me.imports.lib.util; -let _overrides; - -let opt; - - -function update(reset = false) { - opt = Me.imports.lib.settings.opt; - opt.DESKTOP_CUBE_ENABLED = Main.extensionManager._enabledExtensions.includes('desktop-cube@schneegans.github.com'); - const cubeSupported = opt.DESKTOP_CUBE_ENABLED && !opt.ORIENTATION && !opt.OVERVIEW_MODE; - - // if desktop cube extension is enabled while V-Shell is loaded, removeAll() would override its code - if (_overrides && !cubeSupported) { - _overrides.removeAll(); - global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, 1, -1); - } - - if (reset) { - _overrides = null; - opt = null; - return; - } - - - _overrides = new _Util.Overrides(); - - if (!cubeSupported) - _overrides.addOverride('WorkspacesView', WorkspacesView.WorkspacesView.prototype, WorkspacesViewCommon); - - _overrides.addOverride('WorkspacesDisplay', WorkspacesView.WorkspacesDisplay.prototype, WorkspacesDisplay); - _overrides.addOverride('ExtraWorkspaceView', WorkspacesView.ExtraWorkspaceView.prototype, ExtraWorkspaceView); - - if (opt.ORIENTATION) { - // switch internal workspace orientation in GS - global.workspace_manager.override_workspace_layout(Meta.DisplayCorner.TOPLEFT, false, -1, 1); - _overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayVertical); - } else { - _overrides.addOverride('SecondaryMonitorDisplay', WorkspacesView.SecondaryMonitorDisplay.prototype, SecondaryMonitorDisplayHorizontal); - } -} - -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() { - // replaced in _updateWorkspacesState - /* let workspaceManager = global.workspace_manager; - let active = workspaceManager.get_active_workspace_index(); - - const fitMode = this._fitModeAdjustment.value; - const singleFitMode = fitMode === FitMode.SINGLE; - - for (let w = 0; w < this._workspaces.length; w++) { - let workspace = this._workspaces[w]; - - if (this._animating || this._gestureActive || !singleFitMode) - workspace.show(); - else - workspace.visible = Math.abs(w - active) <= opt.NUMBER_OF_VISIBLE_NEIGHBORS; - }*/ - }, - - // 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; - - // define the transition values here to save time in each ws - let scaleX, scaleY; - if (opt.ORIENTATION) { // vertical 1 / horizontal 0 - scaleX = 1; - scaleY = 0.1; - } else { - scaleX = 0.1; - scaleY = 1; - } - - 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; - - const distanceToCurrentWorkspace = Math.abs(adj.value - index); - - const scaleProgress = 1 - Math.clamp(distanceToCurrentWorkspace, 0, 1); - - // 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, scaling animation will make impression that they move in from outside the monitor - if (!w.visible && distanceToCurrentWorkspace === 1 && initialState === ControlsState.APP_GRID && currentState === ControlsState.WINDOW_PICKER) { - w.scale_x = scaleX; - w.scale_y = scaleY; - w.visible = true; - w.ease({ - duration: 100, - scale_x: 1, - scale_y: 1, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } else if (!w.visible && distanceToCurrentWorkspace <= opt.NUMBER_OF_VISIBLE_NEIGHBORS && currentState === ControlsState.WINDOW_PICKER) { - w.set({ - scale_x: 1, - scale_y: 1, - }); - } - - // 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; - }); - }, -}; - -// SecondaryMonitorDisplay Vertical -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_custom_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, padding, thumbnailsWidth, spacing) { - // const { ControlsState } = OverviewControls; - const workspaceBox = box.copy(); - const [width, height] = workspaceBox.get_size(); - - let wWidth, wHeight, wsbX, wsbY, offset, yShift; - switch (state) { - case ControlsState.HIDDEN: - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) - break; - - yShift = 0; - if (opt.SEC_WS_PREVIEW_SHIFT && !opt.PANEL_DISABLED) { - if (opt.PANEL_POSITION_TOP) - yShift = Main.panel.height; - else - yShift = -Main.panel.height; - } - - wWidth = width - thumbnailsWidth - 5 * spacing; - wHeight = Math.min(wWidth / (width / height) - Math.abs(yShift), 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((height - wHeight - Math.abs(yShift)) / 2 + yShift); - - 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); - const [width, height] = contentBox.get_size(); - const { expandFraction } = this._thumbnails; - const spacing = themeNode.get_length('spacing') * expandFraction; - const padding = Math.round(0.1 * height); - - let thumbnailsWidth = this._getThumbnailsWidth(contentBox, spacing); - let [, thumbnailsHeight] = this._thumbnails.get_preferred_custom_height(thumbnailsWidth); - thumbnailsHeight = Math.min(thumbnailsHeight, height - 2 * spacing); - - this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN; - if (this._thumbnails.visible) { - let wsTmbX; - if (opt.SEC_WS_TMB_LEFT) { // left - wsTmbX = Math.round(spacing / 4); - this._thumbnails._positionLeft = true; - } else { - wsTmbX = Math.round(width - spacing / 4 - thumbnailsWidth); - this._thumbnails._positionLeft = false; - } - - const childBox = new Clutter.ActorBox(); - const availSpace = height - thumbnailsHeight - 2 * spacing; - - let wsTmbY = availSpace / 2; - wsTmbY -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbY - spacing; - - 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, padding, thumbnailsWidth, spacing]; - 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: SIDE_CONTROLS_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; - }, -}; - -// SecondaryMonitorDisplay Horizontal -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, padding, thumbnailsHeight, spacing) { - // const { ControlsState } = OverviewControls; - const workspaceBox = box.copy(); - const [width, height] = workspaceBox.get_size(); - - let wWidth, wHeight, wsbX, wsbY, offset, yShift; - switch (state) { - case ControlsState.HIDDEN: - break; - case ControlsState.WINDOW_PICKER: - case ControlsState.APP_GRID: - if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) - break; - - yShift = 0; - if (opt.SEC_WS_PREVIEW_SHIFT && !opt.PANEL_DISABLED) { - if (opt.PANEL_POSITION_TOP) - yShift = Main.panel.height; - else - yShift = -Main.panel.height; - } - - wHeight = height - Math.abs(yShift) - (thumbnailsHeight ? thumbnailsHeight + 4 * spacing : padding); - 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 - Math.abs(yShift)) / 2); - if (opt.SEC_WS_TMB_TOP) - wsbY = thumbnailsHeight + offset; - else - wsbY = offset; - - wsbY += yShift; - wsbX = Math.round((width - wWidth) / 2); - - workspaceBox.set_origin(wsbX, wsbY); - workspaceBox.set_size(wWidth, wHeight); - break; - } - - return workspaceBox; - }, - - _getThumbnailsHeight(box) { - if (opt.SEC_WS_TMB_HIDDEN) - return 0; - - const [width, height] = box.get_size(); - const { expandFraction } = this._thumbnails; - const [thumbnailsHeight] = this._thumbnails.get_preferred_height(width); - return Math.min( - thumbnailsHeight * expandFraction, - height * opt.SEC_MAX_THUMBNAIL_SCALE); - }, - - vfunc_allocate(box) { - this.set_allocation(box); - - const themeNode = this.get_theme_node(); - const contentBox = themeNode.get_content_box(box); - const [width, height] = contentBox.get_size(); - const { expandFraction } = this._thumbnails; - const spacing = themeNode.get_length('spacing') * expandFraction; - const padding = Math.round(0.1 * height); - - let thumbnailsHeight = this._getThumbnailsHeight(contentBox); - let [, thumbnailsWidth] = this._thumbnails.get_preferred_custom_width(thumbnailsHeight); - thumbnailsWidth = Math.min(thumbnailsWidth, width - 2 * spacing); - - this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN; - if (this._thumbnails.visible) { - let wsTmbY; - if (opt.SEC_WS_TMB_TOP) - wsTmbY = Math.round(spacing / 4); - else - wsTmbY = Math.round(height - spacing / 4 - thumbnailsHeight); - - - const childBox = new Clutter.ActorBox(); - const availSpace = width - thumbnailsWidth - 2 * spacing; - - let wsTmbX = availSpace / 2; - wsTmbX -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbX - spacing; - - 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, padding, thumbnailsHeight, spacing]; - 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 ExtraWorkspaceView = { - _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; - }, -}; - -const WorkspacesDisplay = { - _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_actor(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 (_Util.isShiftPressed()) { - let direction = _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) { - _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; - } - } - - 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 (_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 (_Util.isCtrlPressed() && _Util.isShiftPressed()) { - _Util.openPreferences(); - } else if (_Util.isAltPressed()) { - Main.ctrlAltTabManager._items.forEach(i => { - if (i.sortGroup === 1 && i.name === 'Dash') - Main.ctrlAltTabManager.focusGroup(i); - }); - } else if (opt.RECENT_FILES_SEARCH_PROVIDER_ENABLED && _Util.isCtrlPressed()) { - _Util.activateSearchProvider(SEARCH_RECENT_FILES_PREFIX); - } else if (opt.WINDOW_SEARCH_PROVIDER_ENABLED) { - _Util.activateSearchProvider(SEARCH_WINDOWS_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._overview._controls._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 adjustment = this._workspacesViews[0]._workspaces[global.workspace_manager.get_active_workspace().index()]._background._stateAdjustment; - opt.WORKSPACE_MODE = 1; - _Util.exposeWindows(adjustment, true); - } else { - if (state === 2) - return Clutter.EVENT_PROPAGATE; - Main.ctrlAltTabManager._items.forEach(i => { - if (i.sortGroup === 1 && i.name === 'Windows') - Main.ctrlAltTabManager.focusGroup(i); - }); - } - - 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 (_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) - _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; - } -} |