diff options
Diffstat (limited to 'extensions/45/vertical-workspaces/lib')
29 files changed, 854 insertions, 1970 deletions
diff --git a/extensions/45/vertical-workspaces/lib/appDisplay.js b/extensions/45/vertical-workspaces/lib/appDisplay.js index 22640c6..c33cf0d 100644 --- a/extensions/45/vertical-workspaces/lib/appDisplay.js +++ b/extensions/45/vertical-workspaces/lib/appDisplay.js @@ -3,7 +3,7 @@ * appDisplay.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -34,6 +34,8 @@ let _timeouts; const APP_ICON_TITLE_EXPAND_TIME = 200; const APP_ICON_TITLE_COLLAPSE_TIME = 100; +const shellVersion46 = !Clutter.Container; // Container has been removed in 46 + function _getCategories(info) { let categoriesStr = info.get_categories(); if (!categoriesStr) @@ -187,7 +189,6 @@ export const AppDisplayModule = class { _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; @@ -247,7 +248,9 @@ export const AppDisplayModule = class { } // value for page indicator is calculated from scroll adjustment, horizontal needs to be replaced by vertical - appDisplay._adjustment = appDisplay._scrollView[scroll].adjustment; + appDisplay._adjustment = vertical + ? appDisplay._scrollView.get_vscroll_bar().adjustment + : appDisplay._scrollView.get_hscroll_bar().adjustment; // no need to connect already connected signal (wasn't removed the original one before) if (!vertical) { @@ -754,7 +757,7 @@ const BaseAppViewVertical = { this._nextPageArrow.scale_x = 0; this._prevPageArrow.scale_x = 0; - this._adjustment = this._scrollView.vscroll.adjustment; + this._adjustment = this._scrollView.get_vscroll_bar().adjustment; this._adjustment.connect('notify::value', adj => { const value = adj.value / adj.page_size; @@ -972,12 +975,17 @@ const FolderIcon = { : St.ButtonMask.ONE | St.ButtonMask.TWO; this.button_mask = buttonMask;*/ this.button_mask = St.ButtonMask.ONE | St.ButtonMask.TWO; + if (shellVersion46) + this.add_style_class_name('app-folder-46'); + else + this.add_style_class_name('app-folder-45'); }, open() { this._ensureFolderDialog(); + this._dialog._updateFolderSize(); // always open folder with the first page - this.view._scrollView.vscroll.adjustment.value = 0; + this.view._scrollView.get_vscroll_bar().adjustment.value = 0; this._dialog.popup(); }, }; @@ -1043,6 +1051,7 @@ const FolderView = { child._sourceItem = this._orderedItems[i]; child._sourceFolder = this; child.icon.style_class = ''; + child.set_style_class_name(''); child.icon.set_style('margin: 0; padding: 0;'); child._dot.set_style('margin-bottom: 1px;'); child.icon.setIconSize(subSize); @@ -1052,16 +1061,14 @@ const FolderView = { bin.connect('enter-event', () => { bin.ease({ duration: 100, - scale_x: 1.14, - scale_y: 1.14, + translation_y: -3, mode: Clutter.AnimationMode.EASE_OUT_QUAD, }); }); bin.connect('leave-event', () => { bin.ease({ duration: 100, - scale_x: 1, - scale_y: 1, + translation_y: 0, mode: Clutter.AnimationMode.EASE_OUT_QUAD, }); }); @@ -1072,8 +1079,8 @@ const FolderView = { } // if folder content changed, update folder size, but not if it's empty - if (this._dialog && this._dialog._designCapacity !== this._orderedItems.length && this._orderedItems.length) - this._dialog._updateFolderSize(); + /* if (this._dialog && this._dialog._designCapacity !== this._orderedItems.length && this._orderedItems.length) + this._dialog._updateFolderSize();*/ return icon; }, @@ -1201,6 +1208,11 @@ const AppFolderDialog = { // injection to _init() after__init() { this._viewBox.add_style_class_name('app-folder-dialog-vshell'); + // GS 46 changed the aligning to CENTER which restricts max folder dialog size + this._viewBox.set({ + x_align: Clutter.ActorAlign.FILL, + y_align: Clutter.ActorAlign.FILL, + }); // delegate this dialog to the FolderIcon._view // so its _createFolderIcon function can update the dialog if folder content changed @@ -1224,9 +1236,14 @@ const AppFolderDialog = { }, after__addFolderNameEntry() { + // edit-folder-button class has been replaced with icon-button class which is not transparent in 46 + this._editButton.add_style_class_name('edit-folder-button'); + if (shellVersion46) + this._editButton.add_style_class_name('edit-folder-button-46'); + // Edit button this._removeButton = new St.Button({ - style_class: 'edit-folder-button', + style_class: 'icon-button edit-folder-button', button_mask: St.ButtonMask.ONE, toggle_mode: false, reactive: true, diff --git a/extensions/45/vertical-workspaces/lib/appFavorites.js b/extensions/45/vertical-workspaces/lib/appFavorites.js index 94f67e2..977e65a 100644 --- a/extensions/45/vertical-workspaces/lib/appFavorites.js +++ b/extensions/45/vertical-workspaces/lib/appFavorites.js @@ -3,7 +3,7 @@ * appFavorites.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/dash.js b/extensions/45/vertical-workspaces/lib/dash.js index f26151d..719c3de 100644 --- a/extensions/45/vertical-workspaces/lib/dash.js +++ b/extensions/45/vertical-workspaces/lib/dash.js @@ -3,10 +3,9 @@ * dash.js * * @author GdH <G-dH@github.com> - * @copyright 2022-2023 + * @copyright 2022-2024 * @license GPL-3.0 - * modified dash module of https://github.com/RensAlthuis/vertical-overview extension - */ + */ 'use strict'; @@ -23,7 +22,6 @@ import * as AppFavorites from 'resource:///org/gnome/shell/ui/appFavorites.js'; import * as AppMenu from 'resource:///org/gnome/shell/ui/appMenu.js'; import * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js'; import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'; -import * as IconGrid from 'resource:///org/gnome/shell/ui/iconGrid.js'; import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; let Me; @@ -39,6 +37,8 @@ export const BaseIconSizes = [16, 24, 32, 40, 44, 48, 56, 64, 72, 80, 96, 112, 1 const DASH_ITEM_LABEL_SHOW_TIME = 150; +const shellVersion46 = !Clutter.Container; // Container has been removed in 46 + export const DashModule = class { constructor(me) { Me = me; @@ -130,32 +130,53 @@ export const DashModule = class { this._overrides.addOverride('DashIcon', Dash.DashIcon.prototype, DashIconCommon); this._overrides.addOverride('AppMenu', AppMenu.AppMenu.prototype, AppMenuCommon); + if (shellVersion46) + dash.add_style_class_name('dash-46'); + if (opt.DASH_VERTICAL) { // this._overrides.addOverride('Dash', Dash.Dash.prototype, DashVerticalOverride); - dash.add_style_class_name('vertical'); + dash.add_style_class_name(shellVersion46 + ? 'vertical-46' + : 'vertical' + ); this._setOrientation(Clutter.Orientation.VERTICAL); } else { this._setOrientation(Clutter.Orientation.HORIZONTAL); } + if (opt.DASH_VERTICAL && opt.DASH_BG_GS3_STYLE) { + if (opt.DASH_LEFT) { + dash.add_style_class_name(shellVersion46 + ? 'vertical-46-gs3-left' + : 'vertical-gs3-left'); + } else if (opt.DASH_RIGHT) { + dash.add_style_class_name(shellVersion46 + ? 'vertical-46-gs3-right' + : 'vertical-gs3-right'); + } + } else { + dash.remove_style_class_name('vertical-gs3-left'); + dash.remove_style_class_name('vertical-gs3-right'); + dash.remove_style_class_name('vertical-46-gs3-left'); + dash.remove_style_class_name('vertical-46-gs3-right'); + } + if (!this._customWorkId) this._customWorkId = Main.initializeDeferredWork(dash._box, dash._redisplay.bind(dash)); dash._workId = this._customWorkId; - this._updateSearchWindowsIcon(); - this._updateRecentFilesIcon(); - this._updateExtensionsIcon(); this._moveDashAppGridIcon(); this._connectShowAppsIcon(); dash.visible = opt.DASH_VISIBLE; - dash._background.add_style_class_name('dash-background-reduced'); + // dash._background.add_style_class_name('dash-background-reduced'); dash._queueRedisplay(); if (opt.DASH_ISOLATE_WS && !this._wmSwitchWsConId) { this._wmSwitchWsConId = global.windowManager.connect('switch-workspace', () => dash._queueRedisplay()); this._newWindowConId = global.display.connect_after('window-created', () => dash._queueRedisplay()); } + console.debug(' DashModule - Activated'); } @@ -181,9 +202,7 @@ export const DashModule = class { this._setOrientation(Clutter.Orientation.HORIZONTAL); this._moveDashAppGridIcon(reset); this._connectShowAppsIcon(reset); - this._updateSearchWindowsIcon(false); - this._updateRecentFilesIcon(false); - this._updateExtensionsIcon(false); + this._resetStyle(dash); dash.visible = !this._conflict; dash._background.opacity = 255; @@ -194,8 +213,11 @@ export const DashModule = class { _resetStyle(dash) { dash.remove_style_class_name('vertical'); + dash.remove_style_class_name('vertical-46'); dash.remove_style_class_name('vertical-gs3-left'); dash.remove_style_class_name('vertical-gs3-right'); + dash.remove_style_class_name('vertical-46-gs3-left'); + dash.remove_style_class_name('vertical-46-gs3-right'); dash.remove_style_class_name('vertical-left'); dash.remove_style_class_name('vertical-right'); dash._background.remove_style_class_name('dash-background-light'); @@ -237,16 +259,6 @@ export const DashModule = class { dash._separator = null; dash._queueRedisplay(); dash._adjustIconSize(); - - if (orientation && opt.DASH_BG_GS3_STYLE) { - if (opt.DASH_LEFT) - dash.add_style_class_name('vertical-gs3-left'); - else if (opt.DASH_RIGHT) - dash.add_style_class_name('vertical-gs3-right'); - } else { - dash.remove_style_class_name('vertical-gs3-left'); - dash.remove_style_class_name('vertical-gs3-right'); - } } _moveDashAppGridIcon(reset = false) { @@ -295,141 +307,6 @@ export const DashModule = class { dash._showAppsIcon.reactive = false; } } - - _updateSearchWindowsIcon(show = opt.SHOW_WINDOWS_ICON, dash) { - dash = 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 = 0; - } - delete dash._showWindowsIconClickedId; - if (dash._showWindowsIcon) - dash._showWindowsIcon.destroy(); - delete dash._showWindowsIcon; - } - - if (!show || !opt.get('windowSearchProviderModule')) - return; - - if (!dash._showWindowsIcon) { - dash._showWindowsIcon = new Dash.DashItemContainer(); - new Me.Util.Overrides().addOverride('showWindowsIcon', dash._showWindowsIcon, ShowWindowsIcon); - dash._showWindowsIcon._afterInit(); - 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(); - - if (dash._showWindowsIcon && !dash._showWindowsIconClickedId) { - dash._showWindowsIconClickedId = dash._showWindowsIcon.toggleButton.connect('clicked', () => { - Me.Util.activateSearchProvider(Me.WSP_PREFIX); - }); - } - } - - _updateRecentFilesIcon(show = opt.SHOW_RECENT_FILES_ICON, dash) { - dash = 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 = 0; - } - delete dash._recentFilesIconClickedId; - if (dash._recentFilesIcon) - dash._recentFilesIcon.destroy(); - delete dash._recentFilesIcon; - } - - if (!show || !opt.get('recentFilesSearchProviderModule')) - return; - - if (!dash._recentFilesIcon) { - dash._recentFilesIcon = new Dash.DashItemContainer(); - new Me.Util.Overrides().addOverride('recentFilesIcon', dash._recentFilesIcon, ShowRecentFilesIcon); - dash._recentFilesIcon._afterInit(); - 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(); - - if (dash._recentFilesIcon && !dash._recentFilesIconClickedId) { - dash._recentFilesIconClickedId = dash._recentFilesIcon.toggleButton.connect('clicked', () => { - Me.Util.activateSearchProvider(Me.RFSP_PREFIX); - }); - } - } - - _updateExtensionsIcon(show = opt.SHOW_EXTENSIONS_ICON, dash) { - dash = dash ?? Main.overview._overview._controls.layoutManager._dash; - const dashContainer = dash._dashContainer; - - if (dash._extensionsIcon) { - dashContainer.remove_child(dash._extensionsIcon); - if (dash._extensionsIconClickedId) { - dash._extensionsIcon.toggleButton.disconnect(dash._extensionsIconClickedId); - dash._extensionsIconClickedId = 0; - } - delete dash._extensionsIconClickedId; - if (dash._extensionsIcon) - dash._extensionsIcon.destroy(); - delete dash._extensionsIcon; - } - - if (!show || !opt.get('extensionsSearchProviderModule')) - return; - - if (!dash._extensionsIcon) { - dash._extensionsIcon = new Dash.DashItemContainer(); - new Me.Util.Overrides().addOverride('extensionsIcon', dash._extensionsIcon, ShowExtensionsIcon); - dash._extensionsIcon._afterInit(); - dash._extensionsIcon.show(false); - dashContainer.add_child(dash._extensionsIcon); - dash._hookUpLabel(dash._extensionsIcon); - } - - dash._extensionsIcon.icon.setIconSize(dash.iconSize); - if (opt.SHOW_EXTENSIONS_ICON === 1) { - dashContainer.set_child_at_index(dash._extensionsIcon, 0); - } else if (opt.SHOW_EXTENSIONS_ICON === 2) { - const index = dashContainer.get_children().length - 1; - dashContainer.set_child_at_index(dash._extensionsIcon, index); - } - - Main.overview._overview._controls.layoutManager._dash._adjustIconSize(); - - if (dash._extensionsIcon && !dash._extensionsIconClickedId) { - dash._extensionsIconClickedId = dash._extensionsIcon.toggleButton.connect('clicked', () => { - Me.Util.activateSearchProvider(Me.ESP_PREFIX); - }); - } - } }; function getAppFromSource(source) { @@ -475,20 +352,20 @@ const DashItemContainerCommon = { let y; if (opt.DASH_TOP) { - const yOffset = 0.75 * itemHeight + 3 * node.get_length('-y-offset'); + const yOffset = itemHeight + (shellVersion46 ? 0 : -3); y = stageY + yOffset; } else if (opt.DASH_BOTTOM) { const yOffset = node.get_length('-y-offset'); y = stageY - this.label.height - yOffset; } else if (opt.DASH_RIGHT) { const yOffset = Math.floor((itemHeight - labelHeight) / 2); - xOffset = 4; + xOffset = shellVersion46 ? 8 : 4; x = stageX - xOffset - this.label.width; y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight); } else if (opt.DASH_LEFT) { const yOffset = Math.floor((itemHeight - labelHeight) / 2); - xOffset = 4; + xOffset = shellVersion46 ? 8 : 4; x = stageX + this.width + xOffset; y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight); @@ -744,15 +621,15 @@ const DashCommon = { if (this._showAppsIcon.visible) iconChildren.push(this._showAppsIcon); + + // showWindowsIcon and extensionsIcon can be provided by the WSP and ESP extensions if (this._showWindowsIcon) iconChildren.push(this._showWindowsIcon); - if (this._recentFilesIcon) - iconChildren.push(this._recentFilesIcon); - if (this._extensionsIcon) iconChildren.push(this._extensionsIcon); + if (!iconChildren.length) return; @@ -967,12 +844,15 @@ const DashIconCommon = { this._scrollConId = this.connect('scroll-event', DashExtensions.onScrollEvent.bind(this)); this._leaveConId = this.connect('leave-event', DashExtensions.onLeaveEvent.bind(this)); } + + if (this._updateRunningDotStyle) + this._updateRunningDotStyle(); }, - popupMenu() { + /* popupMenu() { const side = opt.DASH_VERTICAL ? St.Side.LEFT : St.Side.BOTTOM; AppIconCommon.popupMenu.bind(this)(side); - }, + },*/ _updateRunningStyle() { const currentWs = global.workspace_manager.get_active_workspace(); @@ -985,193 +865,27 @@ const DashIconCommon = { else this._dot.hide(); }, -}; - -const DashExtensions = { - onScrollEvent(source, event) { - if ((this.app && !opt.DASH_ICON_SCROLL) || (this._isSearchWindowsIcon && !opt.SEARCH_WINDOWS_ICON_SCROLL)) { - if (this._scrollConId) { - this.disconnect(this._scrollConId); - this._scrollConId = 0; - } - if (this._leaveConId) { - this.disconnect(this._leaveConId); - this._leaveConId = 0; - } - return Clutter.EVENT_PROPAGATE; - } - - if (Main.overview._overview.controls._stateAdjustment.value > 1) - return Clutter.EVENT_PROPAGATE; - - let direction = Me.Util.getScrollDirection(event); - if (direction === Clutter.ScrollDirection.UP) - direction = 1; - else if (direction === Clutter.ScrollDirection.DOWN) - direction = -1; - else - return Clutter.EVENT_STOP; - - // avoid uncontrollable switching if smooth scroll wheel or trackpad is used - if (this._lastScroll && Date.now() - this._lastScroll < 160) - return Clutter.EVENT_STOP; - - this._lastScroll = Date.now(); - - DashExtensions.switchWindow.bind(this)(direction); - return Clutter.EVENT_STOP; - }, - - onLeaveEvent() { - if (!this._selectedMetaWin || this.has_pointer || this.toggleButton?.has_pointer) - return; - - this._selectedPreview._activateSelected = false; - this._selectedMetaWin = null; - this._scrolledWindows = null; - DashExtensions.showWindowPreview.bind(this)(null); - }, - - - switchWindow(direction) { - if (!this._scrolledWindows) { - this._initialSelection = true; - // source is app icon - if (this.app) { - this._scrolledWindows = this.app.get_windows(); - if (opt.DASH_ISOLATE_WS) { - const currentWs = global.workspaceManager.get_active_workspace(); - this._scrolledWindows = this._scrolledWindows.filter(w => w.get_workspace() === currentWs); - } - - const wsList = []; - this._scrolledWindows.forEach(w => { - const ws = w.get_workspace(); - if (!wsList.includes(ws)) - wsList.push(ws); - }); - - // sort windows by workspaces in MRU order - this._scrolledWindows.sort((a, b) => wsList.indexOf(a.get_workspace()) > wsList.indexOf(b.get_workspace())); - // source is Search Windows icon - } else if (this._isSearchWindowsIcon) { - if (opt.SEARCH_WINDOWS_ICON_SCROLL === 1) // all windows - this._scrolledWindows = Me.Util.getWindows(null); - else - this._scrolledWindows = Me.Util.getWindows(global.workspace_manager.get_active_workspace()); - } - } - - let windows = this._scrolledWindows; - - if (!windows.length) - return; - - // if window selection is in the process, the previewed window must be the current one - let currentWin = this._selectedMetaWin ? this._selectedMetaWin : windows[0]; - - const currentIdx = windows.indexOf(currentWin); - let targetIdx = currentIdx; - // const focusWindow = Me.Util.getWindows(null)[0]; // incompatible 45 - const focusWindow = Me.Util.getWindows(null)[0]; - const appFocused = this._scrolledWindows[0] === focusWindow && this._scrolledWindows[0].get_workspace() === global.workspace_manager.get_active_workspace(); - // only if the app has focus, immediately switch to the previous window - // otherwise just set the current window above others - if (!this._initialSelection || appFocused) - targetIdx += direction; - else - this._initialSelection = false; - - if (targetIdx > windows.length - 1) - targetIdx = 0; - else if (targetIdx < 0) - targetIdx = windows.length - 1; - - const metaWin = windows[targetIdx]; - DashExtensions.showWindowPreview.bind(this)(metaWin); - this._selectedMetaWin = metaWin; - }, - - showWindowPreview(metaWin) { - const views = Main.overview._overview.controls._workspacesDisplay._workspacesViews; - const viewsIter = [views[0]]; - // secondary monitors use different structure - views.forEach(v => { - if (v._workspacesView) - viewsIter.push(v._workspacesView); - }); - - viewsIter.forEach(view => { - // if workspaces are on primary monitor only - if (!view || !view._workspaces) - return; - - view._workspaces.forEach(ws => { - ws._windows.forEach(windowPreview => { - // metaWin === null resets opacity - let opacity = metaWin ? 50 : 255; - windowPreview._activateSelected = false; - - // minimized windows are invisible if windows are not exposed (WORKSPACE_MODE === 0) - if (!windowPreview.opacity) - windowPreview.opacity = 255; - - // app windows set to lower opacity, so they can be recognized - if (this._scrolledWindows && this._scrolledWindows.includes(windowPreview.metaWindow)) { - if (opt.DASH_ICON_SCROLL === 2) - opacity = 254; - } - if (windowPreview.metaWindow === metaWin) { - if (metaWin && metaWin.get_workspace() !== global.workspace_manager.get_active_workspace()) { - Main.wm.actionMoveWorkspace(metaWin.get_workspace()); - if (_timeouts.wsSwitcherAnimation) - GLib.source_remove(_timeouts.wsSwitcherAnimation); - // setting window preview above siblings before workspace switcher animation has no effect - // we need to set the window above after the ws preview become visible on the screen - // the default switcher animation time is 250, 200 ms delay should be enough - _timeouts.wsSwitcherAnimation = GLib.timeout_add(0, 200 * St.Settings.get().slow_down_factor, () => { - windowPreview.get_parent().set_child_above_sibling(windowPreview, null); - _timeouts.wsSwitcherAnimation = 0; - return GLib.SOURCE_REMOVE; - }); - } else { - windowPreview.get_parent().set_child_above_sibling(windowPreview, null); - } - - opacity = 255; - this._selectedPreview = windowPreview; - windowPreview._activateSelected = true; - } - - // if windows are exposed, highlight selected using opacity - if ((opt.OVERVIEW_MODE && opt.WORKSPACE_MODE) || !opt.OVERVIEW_MODE) { - if (metaWin && opacity === 255) - windowPreview.showOverlay(true); - else - windowPreview.hideOverlay(true); - windowPreview.ease({ - duration: 200, - opacity, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - }); - } - }); - }); - }); - }, -}; -const AppIconCommon = { - after__init() { + /* after__init() { if (this._updateRunningDotStyle) this._updateRunningDotStyle(); - }, + },*/ _updateRunningDotStyle() { if (opt.RUNNING_DOT_STYLE) this._dot.add_style_class_name('app-well-app-running-dot-custom'); else this._dot.remove_style_class_name('app-well-app-running-dot-custom'); + + if (!this.label && shellVersion46) { + if (opt.DASH_VERTICAL) { + this._dot.translation_y = 0; + this._dot.translation_x = 0; // opt.DASH_LEFT ? -4 : 4; + } else { + this._dot.translation_y = 8; + this._dot.translation_x = 0; + } + } }, activate(button) { @@ -1243,6 +957,9 @@ const AppIconCommon = { }, popupMenu(side = St.Side.LEFT) { + side = opt.DASH_VERTICAL ? St.Side.LEFT : St.Side.BOTTOM; + // AppIconCommon.popupMenu.bind(this)(side); + this.setForcedHighlight(true); this._removeMenuTimeout(); this.fake_release(); @@ -1277,7 +994,7 @@ const AppIconCommon = { this._hidingSigId = Main.overview.connect('hiding', () => this._menu.close(), this); - Main.uiGroup.add_actor(this._menu.actor); + Main.uiGroup.add_child(this._menu.actor); this._menuManager.addMenu(this._menu); } @@ -1310,10 +1027,12 @@ const AppIconCommon = { }]); } + popupItems.push([_('Move App to Current Workspace ( Shift + Click )'), this._moveAppToCurrentWorkspace]); - if (opt.WINDOW_THUMBNAIL_ENABLED) { - popupItems.push([_('Create Window Thumbnail - PIP'), () => { - Me.Modules.winTmbModule.createThumbnail(this.app.get_windows()[0]); + // WTMB (Windows Thumbnails) extension required + if (global.windowThumbnails) { + popupItems.push([_('Create Window Thumbnail/PiP'), () => { + global.windowThumbnails?.createThumbnail(this.app.get_windows()[0]); }]); } } @@ -1362,115 +1081,191 @@ const AppIconCommon = { }, }; -const ShowWindowsIcon = { - _afterInit() { - 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, - }); +const DashExtensions = { + onScrollEvent(source, event) { + if ((this.app && !opt.DASH_ICON_SCROLL) || (this._isSearchWindowsIcon && !opt.SEARCH_WINDOWS_ICON_SCROLL)) { + if (this._scrollConId) { + this.disconnect(this._scrollConId); + this._scrollConId = 0; + } + if (this._leaveConId) { + this.disconnect(this._leaveConId); + this._leaveConId = 0; + } + return Clutter.EVENT_PROPAGATE; + } - 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; + if (Main.overview._overview.controls._stateAdjustment.value > 1) + return Clutter.EVENT_PROPAGATE; - this.toggleButton.add_actor(this.icon); - this.toggleButton._delegate = this; + let direction = Me.Util.getScrollDirection(event); + if (direction === Clutter.ScrollDirection.UP) + direction = 1; + else if (direction === Clutter.ScrollDirection.DOWN) + direction = -1; + else + return Clutter.EVENT_STOP; - this.setChild(this.toggleButton); + // avoid uncontrollable switching if smooth scroll wheel or trackpad is used + if (this._lastScroll && Date.now() - this._lastScroll < 160) + return Clutter.EVENT_STOP; - if (opt.SEARCH_WINDOWS_ICON_SCROLL) { - this.reactive = true; - this._scrollConId = this.connect('scroll-event', DashExtensions.onScrollEvent.bind(this)); - this._leaveConId = this.connect('leave-event', DashExtensions.onLeaveEvent.bind(this)); - } + this._lastScroll = Date.now(); + + DashExtensions.switchWindow.bind(this)(direction); + return Clutter.EVENT_STOP; }, - _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; + onLeaveEvent() { + if (!this._selectedMetaWin || this.has_pointer || this.toggleButton?.has_pointer) + return; + + this._selectedPreview._activateSelected = false; + this._selectedMetaWin = null; + this._scrolledWindows = null; + DashExtensions.showWindowPreview.bind(this)(null); }, -}; -const ShowRecentFilesIcon = { - _afterInit() { - 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; + switchWindow(direction) { + if (!this._scrolledWindows) { + this._initialSelection = true; + // source is app icon + if (this.app) { + this._scrolledWindows = this.app.get_windows(); + if (opt.DASH_ISOLATE_WS) { + const currentWs = global.workspaceManager.get_active_workspace(); + this._scrolledWindows = this._scrolledWindows.filter(w => w.get_workspace() === currentWs); + } - this.toggleButton.add_actor(this.icon); - this.toggleButton._delegate = this; + const wsList = []; + this._scrolledWindows.forEach(w => { + const ws = w.get_workspace(); + if (!wsList.includes(ws)) + wsList.push(ws); + }); - this.setChild(this.toggleButton); - }, + // sort windows by workspaces in MRU order + this._scrolledWindows.sort((a, b) => wsList.indexOf(a.get_workspace()) > wsList.indexOf(b.get_workspace())); + // source is Search Windows icon + } else if (this._isSearchWindowsIcon) { + if (opt.SEARCH_WINDOWS_ICON_SCROLL === 1) // all windows + this._scrolledWindows = Me.Util.getWindows(null); + else + this._scrolledWindows = Me.Util.getWindows(global.workspace_manager.get_active_workspace()); + } + } - _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; + let windows = this._scrolledWindows; + + if (!windows.length) + return; + + // if window selection is in the process, the previewed window must be the current one + let currentWin = this._selectedMetaWin ? this._selectedMetaWin : windows[0]; + + const currentIdx = windows.indexOf(currentWin); + let targetIdx = currentIdx; + // const focusWindow = Me.Util.getWindows(null)[0]; // incompatible 45 + const focusWindow = Me.Util.getWindows(null)[0]; + const appFocused = this._scrolledWindows[0] === focusWindow && this._scrolledWindows[0].get_workspace() === global.workspace_manager.get_active_workspace(); + // only if the app has focus, immediately switch to the previous window + // otherwise just set the current window above others + if (!this._initialSelection || appFocused) + targetIdx += direction; + else + this._initialSelection = false; + + if (targetIdx > windows.length - 1) + targetIdx = 0; + else if (targetIdx < 0) + targetIdx = windows.length - 1; + + const metaWin = windows[targetIdx]; + DashExtensions.showWindowPreview.bind(this)(metaWin); + this._selectedMetaWin = metaWin; }, -}; -const ShowExtensionsIcon = { - _afterInit() { - this._labelText = _('Search Extensions (Hotkey: Ctrl + Shift + Space)'); - this.toggleButton = new St.Button({ - style_class: 'show-apps', - track_hover: true, - can_focus: true, - toggle_mode: false, + 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); }); - 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; + viewsIter.forEach(view => { + // if workspaces are on primary monitor only + if (!view || !view._workspaces) + return; - this.toggleButton.add_actor(this.icon); - this.toggleButton._delegate = this; + view._workspaces.forEach(ws => { + ws._windows.forEach(windowPreview => { + // metaWin === null resets opacity + let opacity = metaWin ? 50 : 255; + windowPreview._activateSelected = false; - this.setChild(this.toggleButton); - }, + // minimized windows are invisible if windows are not exposed (WORKSPACE_MODE === 0) + if (!windowPreview.opacity) + windowPreview.opacity = 255; + + // app windows set to lower opacity, so they can be recognized + if (this._scrolledWindows && this._scrolledWindows.includes(windowPreview.metaWindow)) { + if (opt.DASH_ICON_SCROLL === 2) + opacity = 254; + } + if (windowPreview.metaWindow === metaWin) { + if (metaWin && metaWin.get_workspace() !== global.workspace_manager.get_active_workspace()) { + Main.wm.actionMoveWorkspace(metaWin.get_workspace()); + if (_timeouts.wsSwitcherAnimation) + GLib.source_remove(_timeouts.wsSwitcherAnimation); + // setting window preview above siblings before workspace switcher animation has no effect + // we need to set the window above after the ws preview become visible on the screen + // the default switcher animation time is 250, 200 ms delay should be enough + _timeouts.wsSwitcherAnimation = GLib.timeout_add(0, 200 * St.Settings.get().slow_down_factor, () => { + windowPreview.get_parent().set_child_above_sibling(windowPreview, null); + _timeouts.wsSwitcherAnimation = 0; + return GLib.SOURCE_REMOVE; + }); + } else { + windowPreview.get_parent().set_child_above_sibling(windowPreview, null); + } - _createIcon(size) { - this._iconActor = new St.Icon({ - icon_name: 'application-x-addon-symbolic', - icon_size: size, - style_class: 'show-apps-icon', - track_hover: true, + 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, + }); + } + }); + }); }); - return this._iconActor; + }, +}; + +const AppIconCommon = { + after__init() { + if (this._updateRunningDotStyle) + this._updateRunningDotStyle(); + }, + + _updateRunningDotStyle() { + if (opt.RUNNING_DOT_STYLE) + this._dot.add_style_class_name('app-well-app-running-dot-custom'); + else + this._dot.remove_style_class_name('app-well-app-running-dot-custom'); }, }; diff --git a/extensions/45/vertical-workspaces/lib/extensionsSearchProvider.js b/extensions/45/vertical-workspaces/lib/extensionsSearchProvider.js deleted file mode 100644 index 30d9960..0000000 --- a/extensions/45/vertical-workspaces/lib/extensionsSearchProvider.js +++ /dev/null @@ -1,406 +0,0 @@ -/** -* V-Shell (Vertical Workspaces) - * extensionsSearchProvider.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 - * @license GPL-3.0 - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import St from 'gi://St'; -import Gio from 'gi://Gio'; -import Shell from 'gi://Shell'; -import GObject from 'gi://GObject'; -import Clutter from 'gi://Clutter'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; - -const ExtensionState = { - 1: 'ENABLED', - 2: 'DISABLED', - 3: 'ERROR', - 4: 'INCOMPATIBLE', - 5: 'DOWNLOADING', - 6: 'INITIALIZED', - 7: 'DISABLING', - 8: 'ENABLING', -}; - -let Me; -let opt; -// gettext -let _; -let _toggleTimeout; - -// prefix helps to eliminate results from other search providers -// so it needs to be something less common -// needs to be accessible from vw module -export const PREFIX = 'eq//'; - -export class ExtensionsSearchProviderModule { - // export for other modules - static _PREFIX = PREFIX; - constructor(me) { - Me = me; - opt = Me.opt; - _ = Me.gettext; - - this._firstActivation = true; - this.moduleEnabled = false; - this._extensionsSearchProvider = null; - this._enableTimeoutId = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - _ = null; - } - - update(reset) { - if (_toggleTimeout) - GLib.source_remove(_toggleTimeout); - - this.moduleEnabled = opt.get('extensionsSearchProviderModule'); - - reset = reset || !this.moduleEnabled; - - if (reset && !this._firstActivation) { - this._disableModule(); - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - if (reset && this._firstActivation) - console.debug(' ExtensionsSearchProviderModule - Keeping untouched'); - } - - _activateModule() { - // delay because Fedora had problem to register a new provider soon after Shell restarts - this._enableTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 2000, - () => { - if (!this._extensionsSearchProvider) { - this._extensionsSearchProvider = new extensionsSearchProvider(opt); - this._getOverviewSearchResult()._registerProvider(this._extensionsSearchProvider); - } - this._enableTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); - console.debug(' ExtensionsSearchProviderModule - Activated'); - } - - _disableModule() { - if (this._enableTimeoutId) { - GLib.source_remove(this._enableTimeoutId); - this._enableTimeoutId = 0; - } - - if (this._extensionsSearchProvider) { - this._getOverviewSearchResult()._unregisterProvider(this._extensionsSearchProvider); - this._extensionsSearchProvider = null; - } - - - console.debug(' ExtensionsSearchProviderModule - Disabled'); - } - - _getOverviewSearchResult() { - return Main.overview._overview.controls._searchController._searchResults; - } -} - -class extensionsSearchProvider { - constructor() { - this.id = 'extensions'; - const appSystem = Shell.AppSystem.get_default(); - let appInfo = appSystem.lookup_app('com.matjakeman.ExtensionManager.desktop')?.get_app_info(); - if (!appInfo) - appInfo = appSystem.lookup_app('org.gnome.Extensions.desktop')?.get_app_info(); - if (!appInfo) - appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/gnome-extensions-app', 'Extensions', null); - appInfo.get_description = () => _('Search extensions'); - appInfo.get_name = () => _('Extensions'); - appInfo.get_id = () => 'org.gnome.Extensions.desktop'; - appInfo.get_icon = () => Gio.icon_new_for_string('application-x-addon'); - appInfo.should_show = () => true; - - this.appInfo = appInfo; - this.canLaunchSearch = true; - this.isRemoteProvider = false; - } - - getInitialResultSet(terms/* , callback*/) { - const extensions = {}; - Main.extensionManager._extensions.forEach( - e => { - extensions[e.uuid] = e; - } - ); - this.extensions = extensions; - - return new Promise(resolve => resolve(this._getResultSet(terms))); - } - - _getResultSet(terms) { - // do not modify original terms - let termsCopy = [...terms]; - // search for terms without prefix - termsCopy[0] = termsCopy[0].replace(PREFIX, ''); - - const candidates = this.extensions; - const _terms = [].concat(termsCopy); - - const term = _terms.join(' '); - - const results = []; - let m; - for (let id in candidates) { - const extension = this.extensions[id]; - const text = extension.metadata.name + (extension.state === 1 ? 'enabled' : '') + ([6, 2].includes(extension.state) ? 'disabled' : ''); - if (opt.SEARCH_FUZZY) - m = Me.Util.fuzzyMatch(term, text); - else - m = Me.Util.strictMatch(term, text); - - if (m !== -1) - results.push({ weight: m, id }); - } - - // sort alphabetically - results.sort((a, b) => this.extensions[a.id].metadata.name.localeCompare(this.extensions[b.id].metadata.name)); - // enabled first - // results.sort((a, b) => this.extensions[a.id].state !== 1 && this.extensions[b.id].state === 1); - // incompatible last - results.sort((a, b) => this.extensions[a.id].state === 4 && this.extensions[b.id].state !== 4); - - const resultIds = results.map(item => item.id); - return resultIds; - } - - getResultMetas(resultIds/* , callback = null*/) { - const metas = resultIds.map(id => this.getResultMeta(id)); - return new Promise(resolve => resolve(metas)); - } - - getResultMeta(resultId) { - const result = this.extensions[resultId]; - - const versionName = result.metadata['version-name'] ?? ''; - let version = result.metadata['version'] ?? ''; - version = versionName && version ? `/${version}` : version; - const versionStr = `${versionName}${version}`; - - return { - 'id': resultId, - 'name': `${result.metadata.name}`, - 'version': versionStr, - 'description': versionStr, // description will be updated in result object - 'createIcon': size => { - let icon = this.getIcon(result, size); - return icon; - }, - }; - } - - getIcon(extension, size) { - let opacity = 0; - let iconName = 'process-stop-symbolic'; - - switch (extension.state) { - case 1: - if (extension.hasUpdate) - iconName = 'software-update-available'; // 'software-update-available-symbolic'; - else - iconName = 'object-select-symbolic';// 'object-select-symbolic'; - - opacity = 255; - break; - case 3: - if (Main.extensionManager._enabledExtensions.includes(extension.uuid)) - iconName = 'emblem-ok-symbolic'; - else - iconName = 'dialog-error'; - opacity = 100; - break; - case 4: - iconName = 'software-update-urgent'; // 'software-update-urgent-symbolic'; - opacity = 100; - break; - } - - if (extension.hasUpdate) { - iconName = 'software-update-available'; // 'software-update-available-symbolic'; - opacity = 100; - } - - const icon = new St.Icon({ icon_name: iconName, icon_size: size }); - icon.set({ - opacity, - }); - - return icon; - } - - createResultObject(meta) { - return new ListSearchResult(this, meta, this.extensions[meta.id]); - } - - launchSearch(terms, timeStamp) { - this.appInfo.launch([], global.create_app_launch_context(timeStamp, -1), null); - } - - activateResult(resultId/* terms, timeStamp*/) { - const extension = this.extensions[resultId]; - if (Me.Util.isShiftPressed()) - this._toggleExtension(extension); - else if (extension.hasPrefs) - Me.Util.openPreferences(extension.metadata); - } - - filterResults(results /* , maxResults*/) { - // return results.slice(0, maxResults); - return results; - } - - getSubsearchResultSet(previousResults, terms/* , callback*/) { - return this.getInitialResultSet(terms); - } - - getSubsearchResultSet42(terms, callback) { - callback(this._getResultSet(terms)); - } -} - -const ListSearchResult = GObject.registerClass( -class ListSearchResult extends St.Button { - _init(provider, metaInfo, extension) { - this.provider = provider; - this.metaInfo = metaInfo; - this.extension = extension; - - super._init({ - reactive: true, - can_focus: true, - track_hover: true, - }); - - this.style_class = 'list-search-result'; - - let content = new St.BoxLayout({ - style_class: 'list-search-result-content', - vertical: false, - x_align: Clutter.ActorAlign.START, - x_expand: true, - y_expand: true, - }); - this.set_child(content); - - let titleBox = new St.BoxLayout({ - style_class: 'list-search-result-title', - y_align: Clutter.ActorAlign.CENTER, - }); - - content.add_child(titleBox); - - // An icon for, or thumbnail of, content - let icon = this.metaInfo['createIcon'](this.ICON_SIZE); - let iconBox = new St.Button(); - iconBox.set_child(icon); - titleBox.add(iconBox); - iconBox.set_style('border: 1px solid rgba(200,200,200,0.2); padding: 2px; border-radius: 8px;'); - this._iconBox = iconBox; - this.icon = icon; - - iconBox.connect('clicked', () => { - this._toggleExtension(); - return Clutter.EVENT_STOP; - }); - - let title = new St.Label({ - text: this.metaInfo['name'], - y_align: Clutter.ActorAlign.CENTER, - opacity: extension.hasPrefs ? 255 : 150, - }); - titleBox.add_child(title); - - this.label_actor = title; - - this._descriptionLabel = new St.Label({ - style_class: 'list-search-result-description', - y_align: Clutter.ActorAlign.CENTER, - }); - content.add_child(this._descriptionLabel); - - this._highlightTerms(); - - this.connect('destroy', () => { - if (_toggleTimeout) { - GLib.source_remove(_toggleTimeout); - _toggleTimeout = 0; - } - }); - } - - _toggleExtension() { - const state = this.extension.state; - if (![1, 2, 6, 3].includes(state) || this.extension.metadata.name.includes('vertical-workspaces')) - return; - - if ([2, 6].includes(state)) - Main.extensionManager.enableExtension(this.extension.uuid); - else if ([1, 3].includes(state)) - Main.extensionManager.disableExtension(this.extension.uuid); - - if (_toggleTimeout) - GLib.source_remove(_toggleTimeout); - - _toggleTimeout = GLib.timeout_add(GLib.PRIORITY_LOW, 200, - () => { - if ([7, 8].includes(this.extension.state)) - return GLib.SOURCE_CONTINUE; - - this.icon?.destroy(); - this.icon = this.metaInfo['createIcon'](this.ICON_SIZE); - this._iconBox.set_child(this.icon); - this._highlightTerms(); - - _toggleTimeout = 0; - return GLib.SOURCE_REMOVE; - } - ); - } - - get ICON_SIZE() { - return 24; - } - - _highlightTerms() { - const extension = this.extension; - const state = extension.state === 4 ? ExtensionState[this.extension.state] : ''; - const error = extension.state === 3 ? ` ERROR: ${this.extension.error}` : ''; - const update = extension.hasUpdate ? ' | UPDATE PENDING' : ''; - const text = `${this.metaInfo.version} ${state}${error}${update}`; - let markup = text;// this.metaInfo['description'].split('\n')[0]; - this._descriptionLabel.clutter_text.set_markup(markup); - } - - vfunc_clicked() { - this.activate(); - } - - activate() { - this.provider.activateResult(this.metaInfo.id); - - if (this.metaInfo.clipboardText) { - St.Clipboard.get_default().set_text( - St.ClipboardType.CLIPBOARD, this.metaInfo.clipboardText); - } - Main.overview.toggle(); - } -}); diff --git a/extensions/45/vertical-workspaces/lib/iconGrid.js b/extensions/45/vertical-workspaces/lib/iconGrid.js index 09ec25e..87f6adb 100644 --- a/extensions/45/vertical-workspaces/lib/iconGrid.js +++ b/extensions/45/vertical-workspaces/lib/iconGrid.js @@ -3,7 +3,7 @@ * iconGrid.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/layout.js b/extensions/45/vertical-workspaces/lib/layout.js index d8f8fdc..807f9e0 100644 --- a/extensions/45/vertical-workspaces/lib/layout.js +++ b/extensions/45/vertical-workspaces/lib/layout.js @@ -3,7 +3,7 @@ * layout.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -127,23 +127,30 @@ const LayoutManagerCommon = { return; if (this.panelBox.height) { + const backend = !!Meta.Barrier.prototype.backend; + let params = {}; + if (backend) + params['backend'] = global.backend; + else + params['display'] = global.display; + let primary = this.primaryMonitor; if ([0, 1, 3].includes(opt.HOT_CORNER_POSITION)) { - this._rightPanelBarrier = new Meta.Barrier({ - display: global.display, + params = Object.assign({}, params, { x1: primary.x + primary.width, y1: this.panelBox.allocation.y1, x2: primary.x + primary.width, y2: this.panelBox.allocation.y2, directions: Meta.BarrierDirection.NEGATIVE_X, }); + this._rightPanelBarrier = new Meta.Barrier(params); } if ([2, 4].includes(opt.HOT_CORNER_POSITION)) { - this._leftPanelBarrier = new Meta.Barrier({ - display: global.display, + params = Object.assign({}, params, { x1: primary.x, y1: this.panelBox.allocation.y1, x2: primary.x, y2: this.panelBox.allocation.y2, directions: Meta.BarrierDirection.POSITIVE_X, }); + this._leftPanelBarrier = new Meta.Barrier(params); } } }, @@ -276,50 +283,65 @@ const HotCornerCommon = { const extendV = opt && opt.HOT_CORNER_ACTION && opt.HOT_CORNER_EDGE && opt.DASH_VERTICAL && monitor.index === primaryMonitor; const extendH = opt && opt.HOT_CORNER_ACTION && opt.HOT_CORNER_EDGE && !opt.DASH_VERTICAL && monitor.index === primaryMonitor; + const backend = !!Meta.Barrier.prototype.backend; + let params = {}; + if (backend) + params['backend'] = global.backend; + else + params['display'] = global.display; + if (opt.HOT_CORNER_POSITION <= 1) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y + (extendV ? monitor.height : size), + params = Object.assign({}, params, { + x1: this._x, x2: this._x, + y1: this._y, y2: this._y + (extendV ? monitor.height : size), directions: Meta.BarrierDirection.POSITIVE_X, }); - this._horizontalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x + (extendH ? monitor.width : size), y1: this._y, y2: this._y, + this._verticalBarrier = new Meta.Barrier(params); + params = Object.assign({}, params, { + x1: this._x, x2: this._x + (extendH ? monitor.width : size), + y1: this._y, y2: this._y, directions: Meta.BarrierDirection.POSITIVE_Y, }); + this._horizontalBarrier = new Meta.Barrier(params); } else if (opt.HOT_CORNER_POSITION === 2) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y + (extendV ? monitor.height : size), + params = Object.assign({}, params, { + x1: this._x, x2: this._x, + y1: this._y, y2: this._y + (extendV ? monitor.height : size), directions: Meta.BarrierDirection.NEGATIVE_X, }); - this._horizontalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x - size, x2: this._x, y1: this._y, y2: this._y, + this._verticalBarrier = new Meta.Barrier(params); + params = Object.assign({}, params, { + x1: this._x - size, x2: this._x, + y1: this._y, y2: this._y, directions: Meta.BarrierDirection.POSITIVE_Y, }); + this._horizontalBarrier = new Meta.Barrier(params); } else if (opt.HOT_CORNER_POSITION === 3) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y - size, + params = Object.assign({}, params, { + 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, + this._verticalBarrier = new Meta.Barrier(params); + params = Object.assign({}, params, { + x1: this._x, x2: this._x + (extendH ? monitor.width : size), + y1: this._y, y2: this._y, directions: Meta.BarrierDirection.NEGATIVE_Y, }); + this._horizontalBarrier = new Meta.Barrier(params); } else if (opt.HOT_CORNER_POSITION === 4) { - this._verticalBarrier = new Meta.Barrier({ - display: global.display, - x1: this._x, x2: this._x, y1: this._y, y2: this._y - size, + params = Object.assign({}, params, { + 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, + this._verticalBarrier = new Meta.Barrier(params); + params = Object.assign({}, params, { + x1: this._x, x2: this._x - size, + y1: this._y, y2: this._y, directions: Meta.BarrierDirection.NEGATIVE_Y, }); + this._horizontalBarrier = new Meta.Barrier(params); } this._pressureBarrier.addBarrier(this._verticalBarrier); @@ -431,7 +453,7 @@ const HotCornerCommon = { }, _toggleWindowSearchProvider() { - if (!Main.overview._overview._controls._searchController._searchActive) { + if (!Main.overview.searchController._searchActive) { opt.OVERVIEW_MODE = 2; opt.OVERVIEW_MODE2 = true; opt.WORKSPACE_MODE = 0; diff --git a/extensions/45/vertical-workspaces/lib/messageTray.js b/extensions/45/vertical-workspaces/lib/messageTray.js index 07f9541..28d6b1d 100644 --- a/extensions/45/vertical-workspaces/lib/messageTray.js +++ b/extensions/45/vertical-workspaces/lib/messageTray.js @@ -3,7 +3,7 @@ * messageTray.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/optionsFactory.js b/extensions/45/vertical-workspaces/lib/optionsFactory.js index c20885e..05e14b0 100644 --- a/extensions/45/vertical-workspaces/lib/optionsFactory.js +++ b/extensions/45/vertical-workspaces/lib/optionsFactory.js @@ -3,7 +3,7 @@ * optionsFactory.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 */ @@ -130,7 +130,7 @@ export const ItemFactory = class ItemFactory { for (let i = 0; i < options.length; i++) { const text = options[i][0]; const id = options[i][1]; - model.append(new DropDownItemVW({ text, id })); + model.append(new DropDownItem({ text, id })); if (id === currentValue) widget.set_selected(i); } @@ -205,7 +205,7 @@ export const ItemFactory = class ItemFactory { newDropDown() { const dropDown = new Gtk.DropDown({ model: new Gio.ListStore({ - item_type: DropDownItemVW, + item_type: DropDownItem, }), halign: Gtk.Align.END, valign: Gtk.Align.CENTER, @@ -457,8 +457,9 @@ export const AdwPrefs = class { } }; -const DropDownItemVW = GObject.registerClass({ - GTypeName: 'DropDownItemVW', +const DropDownItem = GObject.registerClass({ + // Registered name should be unique + GTypeName: `DropDownItem${Math.floor(Math.random() * 1000)}`, Properties: { 'text': GObject.ParamSpec.string( 'text', @@ -476,7 +477,7 @@ const DropDownItemVW = GObject.registerClass({ -2147483648, 2147483647, 0 ), }, -}, class DropDownItemVW extends GObject.Object { +}, class DropDownItem extends GObject.Object { get text() { return this._text; } diff --git a/extensions/45/vertical-workspaces/lib/osdWindow.js b/extensions/45/vertical-workspaces/lib/osdWindow.js index 2298c34..a06a331 100644 --- a/extensions/45/vertical-workspaces/lib/osdWindow.js +++ b/extensions/45/vertical-workspaces/lib/osdWindow.js @@ -3,7 +3,7 @@ * osdWindow.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/overlayKey.js b/extensions/45/vertical-workspaces/lib/overlayKey.js index 77264c1..5ffd973 100644 --- a/extensions/45/vertical-workspaces/lib/overlayKey.js +++ b/extensions/45/vertical-workspaces/lib/overlayKey.js @@ -3,7 +3,7 @@ * overlayKey.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -40,8 +40,10 @@ export const OverlayKeyModule = class { update(reset) { this.moduleEnabled = opt.get('overlayKeyModule'); const conflict = false; + // Avoid modifying the overlay key if its configuration is consistent with the GNOME default + const defaultConfig = opt.OVERVIEW_MODE === 0 && opt.OVERLAY_KEY_PRIMARY === 2 && opt.OVERLAY_KEY_SECONDARY === 1; - reset = reset || !this.moduleEnabled || conflict; + reset = reset || !this.moduleEnabled || conflict || defaultConfig; if (reset && !this._firstActivation) { this._disableModule(); @@ -135,7 +137,7 @@ export const OverlayKeyModule = class { opt.OVERVIEW_MODE2 = false; opt.WORKSPACE_MODE = 1; break; - case 3: // Default overview + case 3: // App grid if (Main.overview._shown) Main.overview.hide(); else diff --git a/extensions/45/vertical-workspaces/lib/overview.js b/extensions/45/vertical-workspaces/lib/overview.js index 449e9c8..30cc5db 100644 --- a/extensions/45/vertical-workspaces/lib/overview.js +++ b/extensions/45/vertical-workspaces/lib/overview.js @@ -3,7 +3,7 @@ * overview.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/overviewControls.js b/extensions/45/vertical-workspaces/lib/overviewControls.js index df5b371..41db47f 100644 --- a/extensions/45/vertical-workspaces/lib/overviewControls.js +++ b/extensions/45/vertical-workspaces/lib/overviewControls.js @@ -3,7 +3,7 @@ * overviewControls.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -118,7 +118,7 @@ export const OverviewControlsModule = class { } _replaceOnSearchChanged(reset) { - const searchController = Main.overview._overview.controls._searchController; + const searchController = Main.overview.searchController; if (reset) { if (_searchControllerSigId) { searchController.disconnect(_searchControllerSigId); @@ -128,8 +128,8 @@ export const OverviewControlsModule = class { 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.searchController._searchResults.translation_x = 0; + Main.overview.searchController._searchResults.translation_y = 0; Main.overview.searchEntry.visible = true; Main.overview.searchEntry.opacity = 255; } else { @@ -320,6 +320,9 @@ const ControlsManagerCommon = { }, _onSearchChanged() { + // something is somewhere setting the opacity to 0 if V-Shell is rebased while in overview / search + this._searchController.opacity = 255; + const { finalState, currentState } = this._stateAdjustment.getStateTransitionParams(); const { searchActive } = this._searchController; @@ -366,14 +369,12 @@ const ControlsManagerCommon = { 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 && ![4, 8].includes(opt.WS_TMB_POSITION)) { this._updateAppDisplayVisibility(); - this.layoutManager._searchController._searchResults._statusBin.opacity = 1; + this._searchController._searchResults._statusBin.opacity = 1; - this._searchController.opacity = searchActive ? 255 : 0; let translationX = 0; let translationY = 0; const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor()); @@ -407,6 +408,8 @@ const ControlsManagerCommon = { } this._searchController._searchResults.ease({ + delay: 150, // wait for results + opacity: searchActive ? 255 : 0, translation_x: searchActive ? 0 : translationX, translation_y: searchActive ? 0 : translationY, duration: SIDE_CONTROLS_ANIMATION_TIME, @@ -414,7 +417,7 @@ const ControlsManagerCommon = { onComplete: () => { this._searchController.visible = searchActive; this._searchTransition = false; - this.layoutManager._searchController._searchResults._statusBin.opacity = 255; + this._searchController._searchResults._statusBin.opacity = 255; }, }); @@ -431,10 +434,9 @@ const ControlsManagerCommon = { this._workspacesDisplay.setPrimaryWorkspaceVisible(true); - this._searchController.opacity = searchActive ? 0 : 255; - this._searchController.ease({ + this._searchController._searchResults.ease({ opacity: searchActive ? 255 : 0, - duration: searchActive ? SIDE_CONTROLS_ANIMATION_TIME : 0, + duration: searchActive ? SIDE_CONTROLS_ANIMATION_TIME / 2 : 0, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => (this._searchController.visible = searchActive), }); @@ -442,10 +444,10 @@ const ControlsManagerCommon = { // 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-bg-om2'); - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.add_style_class_name('search-section-content-bg'); - Main.overview.searchEntry.remove_style_class_name('search-entry-om2'); - const duration = opt.SEARCH_VIEW_ANIMATION ? 150 : 0; + this._searchController._searchResults._content.remove_style_class_name('search-section-content-bg-om2'); + this._searchController._searchResults._content.add_style_class_name('search-section-content-bg'); + this._searchEntry.remove_style_class_name('search-entry-om2'); + const duration = opt.SEARCH_VIEW_ANIMATION ? 140 : 0; this._stateAdjustment.ease(searchActive ? ControlsState.APP_GRID : ControlsState.WINDOW_PICKER, { // shorter animation time when entering search view can avoid stuttering in transition // collecting search results take some time and the problematic part is the realization of the object on the screen @@ -455,17 +457,20 @@ const ControlsManagerCommon = { mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { this._workspacesDisplay.setPrimaryWorkspaceVisible(!searchActive); + // Set the delay before processing a new search entry to 150 on deactivation, so search providers can't make make the workspace animation stuttering + // set it back to 0 after in-animation, so the search can be snappy + opt.SEARCH_DELAY = searchActive || !opt.SEARCH_VIEW_ANIMATION ? 0 : 150; }, }); } else if (opt.OVERVIEW_MODE2 && !(opt.WORKSPACE_MODE || this.dash.showAppsButton.checked)) { // add background to search results and make searchEntry border thicker for better visibility - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.remove_style_class_name('search-section-content-bg'); - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.add_style_class_name('search-section-content-bg-om2'); + this._searchController._searchResults._content.remove_style_class_name('search-section-content-bg'); + this._searchController._searchResults._content.add_style_class_name('search-section-content-bg-om2'); Main.overview.searchEntry.add_style_class_name('search-entry-om2'); } else { - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.add_style_class_name('search-section-content-bg'); - Main.overview._overview._controls.layoutManager._searchController._searchResults._content.remove_style_class_name('search-section-content-bg-om2'); - Main.overview.searchEntry.remove_style_class_name('search-entry-om2'); + this._searchController._searchResults._content.add_style_class_name('search-section-content-bg'); + this._searchController._searchResults._content.remove_style_class_name('search-section-content-bg-om2'); + this._searchEntry.remove_style_class_name('search-entry-om2'); } }, @@ -662,7 +667,7 @@ const ControlsManagerCommon = { _getOverviewTranslations(dash, tmbBox, searchEntryBin) { // const tmbBox = Main.overview._overview._controls._thumbnailsBox; - const animationsDisabled = !St.Settings.get().enable_animations || (opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2); + const animationsDisabled = !St.Settings.get().enable_animations || ((opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2) && !Main.layoutManager._startingUp); if (animationsDisabled) return [0, 0, 0, 0, 0]; @@ -840,13 +845,16 @@ const ControlsManagerCommon = { if (!blurEffect) { blurEffect = new Shell.BlurEffect({ brightness: 1, - sigma: 0, mode: Shell.BlurMode.ACTOR, }); bgManager.backgroundActor.add_effect_with_name('blur', blurEffect); } - const searchActive = Main.overview._overview.controls._searchController.searchActive; + // In GNOME 46 the "sigma" property has been renamed to "radius" + const radius = blurEffect.sigma !== undefined ? 'sigma' : 'radius'; + blurEffect[radius] = 0; + + const searchActive = this._searchController.searchActive; if (searchActive) BRIGHTNESS = opt.SEARCH_BG_BRIGHTNESS; @@ -877,48 +885,61 @@ const ControlsManagerCommon = { const step = opt.SMOOTH_BLUR_TRANSITIONS ? 0.05 : 0.2; const progress = stateValue - (stateValue % step); if (opt.SHOW_WS_PREVIEW_BG && stateValue < 1 && !searchActive) { // no need to animate transition, unless appGrid state is involved, static bg is covered by the ws preview bg - if (blurEffect.sigma !== opt.OVERVIEW_BG_BLUR_SIGMA) - blurEffect.sigma = opt.OVERVIEW_BG_BLUR_SIGMA; + if (blurEffect[radius] !== opt.OVERVIEW_BG_BLUR_SIGMA) + blurEffect[radius] = opt.OVERVIEW_BG_BLUR_SIGMA; } else if (stateValue < 1 && !searchActive && !(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)) { const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress)); - if (sigma !== blurEffect.sigma) - blurEffect.sigma = sigma; - } else if (stateValue < 1 && !searchActive && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && blurEffect.sigma)) { + if (sigma !== blurEffect[radius]) + blurEffect[radius] = sigma; + } else if (stateValue < 1 && !searchActive && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && blurEffect[radius])) { const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress)); - if (sigma !== blurEffect.sigma) - blurEffect.sigma = sigma; + if (sigma !== blurEffect[radius]) + blurEffect[radius] = sigma; } else if (stateValue > 1 && !searchActive && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && finalState === 1)) { const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress % 1)); - if (sigma !== blurEffect.sigma) - blurEffect.sigma = sigma; + if (sigma !== blurEffect[radius]) + blurEffect[radius] = sigma; } else if ((stateValue > 1 && bgManager._primary) || searchActive) { const sigma = Math.round(Util.lerp(opt.OVERVIEW_BG_BLUR_SIGMA, opt.APP_GRID_BG_BLUR_SIGMA, progress % 1)); - if (sigma !== blurEffect.sigma) - blurEffect.sigma = sigma; + if (sigma !== blurEffect[radius]) + blurEffect[radius] = sigma; } else if (stateValue === 1 && !(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)) { - blurEffect.sigma = opt.OVERVIEW_BG_BLUR_SIGMA; + blurEffect[radius] = opt.OVERVIEW_BG_BLUR_SIGMA; } else if (stateValue === 0 || (stateValue === 1 && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE))) { - blurEffect.sigma = 0; + blurEffect[radius] = 0; } } } }, + + _updatePositionFromDashToDock() { + // update variables that cannot be processed within settings + const dash = Main.overview.dash; + opt.DASH_POSITION = dash._position; + opt.DASH_TOP = opt.DASH_POSITION === 0; + opt.DASH_RIGHT = opt.DASH_POSITION === 1; + opt.DASH_BOTTOM = opt.DASH_POSITION === 2; + opt.DASH_LEFT = opt.DASH_POSITION === 3; + opt.DASH_VERTICAL = opt.DASH_LEFT || opt.DASH_RIGHT; + }, }; const ControlsManagerLayoutVertical = { _computeWorkspacesBoxForState(state, box, workAreaBox, dashWidth, dashHeight, thumbnailsWidth, thumbnailsHeight, searchHeight, startY) { // in case the function is called from the DtD - if (startY === undefined) { + if (startY === undefined) workAreaBox = box; - } + const workspaceBox = box.copy(); let [width, height] = workspaceBox.get_size(); - const { spacing } = this; + const spacing = 12; const dash = Main.overview.dash; // including Dash to Dock and clones properties for compatibility if (Me.Util.dashIsDashToDock()) { + // ensure or position variables are updated + ControlsManagerCommon._updatePositionFromDashToDock(); // Dash to Dock also always affects workAreaBox Main.layoutManager._trackedActors.forEach(actor => { if (actor.affectsStruts && actor.actor.width === dash.width) { @@ -1028,15 +1049,15 @@ const ControlsManagerLayoutVertical = { _getAppDisplayBoxForState(state, box, workAreaBox, searchHeight, dashWidth, dashHeight, thumbnailsWidth, startY) { // in case the function is called from the DtD - if (startY === undefined) { + if (startY === undefined) workAreaBox = box; - } + const [width] = box.get_size(); const { x1: startX } = workAreaBox; // const { y1: startY } = workAreaBox; let height = workAreaBox.get_height(); const appDisplayBox = new Clutter.ActorBox(); - const { spacing } = this; + const spacing = 12; searchHeight = opt.SHOW_SEARCH_ENTRY ? searchHeight : 0; const xOffsetL = (opt.WS_TMB_LEFT ? thumbnailsWidth : 0) + (opt.DASH_LEFT ? dashWidth : 0); @@ -1083,7 +1104,7 @@ const ControlsManagerLayoutVertical = { vfunc_allocate(container, box) { const childBox = new Clutter.ActorBox(); const transitionParams = this._stateAdjustment.getStateTransitionParams(); - const { spacing } = this; + const spacing = 12; const halfSpacing = spacing / 2; const monitor = Main.layoutManager.findMonitorForActor(this._container); const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); @@ -1111,6 +1132,8 @@ const ControlsManagerLayoutVertical = { // dash cloud be overridden by the Dash to Dock clone const dash = Main.overview.dash; if (Me.Util.dashIsDashToDock()) { + // ensure our position variables are updated + ControlsManagerCommon._updatePositionFromDashToDock(); // if Dash to Dock replaced the default dash and its inteli-hide is disabled we need to compensate for affected startY if (!Main.overview.dash.get_parent()?.get_parent()?.get_parent()?._intellihideIsEnabled) { if (Main.panel.y === monitor.y) @@ -1320,16 +1343,18 @@ const ControlsManagerLayoutVertical = { const ControlsManagerLayoutHorizontal = { _computeWorkspacesBoxForState(state, box, workAreaBox, dashWidth, dashHeight, thumbnailWidth, thumbnailsHeight, searchHeight, startY) { // in case the function is called from the DtD - if (startY === undefined) { + if (startY === undefined) workAreaBox = box; - } + const workspaceBox = box.copy(); let [width, height] = workspaceBox.get_size(); - const { spacing } = this; + const spacing = 12; const dash = Main.overview.dash; // including Dash to Dock and clones properties for compatibility if (Me.Util.dashIsDashToDock()) { + // ensure our position variables are updated + ControlsManagerCommon._updatePositionFromDashToDock(); // Dash to Dock always affects workAreaBox Main.layoutManager._trackedActors.forEach(actor => { if (actor.affectsStruts && actor.actor.width === dash.width) { @@ -1448,7 +1473,7 @@ const ControlsManagerLayoutHorizontal = { // const { y1: startY } = workAreaBox; let height = workAreaBox.get_height(); const appDisplayBox = new Clutter.ActorBox(); - const { spacing } = this; + const spacing = 12; const yOffsetT = (opt.WS_TMB_TOP ? thumbnailsHeight + spacing : 0) + (opt.DASH_TOP ? dashHeight : 0) + (opt.SHOW_SEARCH_ENTRY ? searchHeight : 0); const yOffsetB = (opt.WS_TMB_BOTTOM ? thumbnailsHeight + spacing : 0) + (opt.DASH_BOTTOM ? dashHeight : 0); @@ -1495,7 +1520,7 @@ const ControlsManagerLayoutHorizontal = { vfunc_allocate(container, box) { const transitionParams = this._stateAdjustment.getStateTransitionParams(); const childBox = new Clutter.ActorBox(); - const { spacing } = this; + const spacing = 12; const halfSpacing = spacing / 2; const monitor = Main.layoutManager.findMonitorForActor(this._container); const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); @@ -1528,7 +1553,7 @@ const ControlsManagerLayoutHorizontal = { // if (Main.panel.y === monitor.y) // startY = Main.panel.height + spacing; } - dashHeight = dash.height; + dashHeight = dash.height + halfSpacing; dashWidth = dash.width; opt.DASH_TOP = dash._position === 0; opt.DASH_VERTICAL = [1, 3].includes(dash._position); @@ -1587,9 +1612,13 @@ const ControlsManagerLayoutHorizontal = { else wsTmbY = Math.round(startY + height - (opt.DASH_BOTTOM ? dashHeight : halfSpacing) - wsTmbHeight); - let wstOffset = (width - wsTmbWidth - dashWidthReservation) / 2; + let wstOffset = (width - wsTmbWidth) / 2; wstOffset -= opt.WS_TMB_POSITION_ADJUSTMENT * wstOffset; - let wsTmbX = Math.round(startX + (opt.DASH_LEFT ? dashWidthReservation : 0) + wstOffset); + let wsTmbX = Math.round(startX + wstOffset); + if (opt.DASH_LEFT) + wsTmbX = Math.max(wsTmbX, startX + dashWidthReservation); + else if (opt.DASH_RIGHT) + wsTmbX = Math.min(wsTmbX, startX + width - wsTmbWidth - dashWidthReservation); childBox.set_origin(wsTmbX, wsTmbY); childBox.set_size(Math.max(wsTmbWidth, 1), Math.max(wsTmbHeight, 1)); @@ -1748,8 +1777,10 @@ function _getFitModeForState(state) { const LayoutManager = { _startupAnimation() { - if (Me.Util.dashIsDashToDock() && !Meta.is_restart()) { - // DtD breaks overview on startup + const dtdEnabled = !!((Me.Util.getEnabledExtensions('dash-to-dock').length && !Me.Util.getEnabledExtensions('dash-to-dock-vshell').length) || + Me.Util.getEnabledExtensions('ubuntu-dock').length); + if (dtdEnabled && !Meta.is_restart()) { + // DtD without V-Shell patch breaks overview on startup // Skip animation to hide the mess this._startupAnimationComplete(); Main.overview._overview.controls._finishStartupSequence(); diff --git a/extensions/45/vertical-workspaces/lib/panel.js b/extensions/45/vertical-workspaces/lib/panel.js index a148612..f78ab6f 100644 --- a/extensions/45/vertical-workspaces/lib/panel.js +++ b/extensions/45/vertical-workspaces/lib/panel.js @@ -3,7 +3,7 @@ * panel.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/recentFilesSearchProvider.js b/extensions/45/vertical-workspaces/lib/recentFilesSearchProvider.js index 6dfec0a..f050cf9 100644 --- a/extensions/45/vertical-workspaces/lib/recentFilesSearchProvider.js +++ b/extensions/45/vertical-workspaces/lib/recentFilesSearchProvider.js @@ -3,7 +3,7 @@ * recentFilesSearchProvider.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 */ @@ -12,7 +12,6 @@ import GLib from 'gi://GLib'; import St from 'gi://St'; import Gio from 'gi://Gio'; -import Shell from 'gi://Shell'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; @@ -25,6 +24,7 @@ let _; // so it needs to be something less common // needs to be accessible from vw module export const PREFIX = 'fq//'; +const ID = 'recent-files'; export const RecentFilesSearchProviderModule = class { // export for other modules @@ -68,8 +68,8 @@ export const RecentFilesSearchProviderModule = class { 2000, () => { if (!this._recentFilesSearchProvider) { - this._recentFilesSearchProvider = new RecentFilesSearchProvider(opt); - this._getOverviewSearchResult()._registerProvider(this._recentFilesSearchProvider); + this._recentFilesSearchProvider = new RecentFilesSearchProvider(); + this._registerProvider(this._recentFilesSearchProvider); } this._enableTimeoutId = 0; return GLib.SOURCE_REMOVE; @@ -81,7 +81,7 @@ export const RecentFilesSearchProviderModule = class { _disableModule() { if (this._recentFilesSearchProvider) { - this._getOverviewSearchResult()._unregisterProvider(this._recentFilesSearchProvider); + this._unregisterProvider(this._recentFilesSearchProvider); this._recentFilesSearchProvider = null; } if (this._enableTimeoutId) { @@ -92,32 +92,44 @@ export const RecentFilesSearchProviderModule = class { console.debug(' RecentFilesSearchProviderModule - Disabled'); } - _getOverviewSearchResult() { - return Main.overview._overview.controls._searchController._searchResults; + _registerProvider(provider) { + const searchResults = Main.overview.searchController._searchResults; + provider.searchInProgress = false; + + searchResults._providers.push(provider); + + // create results display and add it to the _content + searchResults._ensureProviderDisplay.bind(searchResults)(provider); + } + + _unregisterProvider(provider) { + const searchResults = Main.overview.searchController._searchResults; + searchResults._unregisterProvider(provider); } }; class RecentFilesSearchProvider { constructor() { - this.id = 'recent-files'; - const appSystem = Shell.AppSystem.get_default(); - let appInfo = appSystem.lookup_app('org.gnome.Nautilus.desktop')?.get_app_info(); - if (!appInfo) - appInfo = Gio.AppInfo.create_from_commandline('/usr/bin/nautilus -w', _('Recent Files'), null); - appInfo.get_description = () => _('Search recent files'); - appInfo.get_name = () => _('Recent Files'); - appInfo.get_id = () => 'org.gnome.Nautilus.desktop'; - appInfo.get_icon = () => Gio.icon_new_for_string('document-open-recent-symbolic'); - appInfo.should_show = () => true; - - this.appInfo = appInfo; + this.id = ID; + const appId = 'org.gnome.Nautilus.desktop'; + + // A real appInfo created from a commandline has often issues with overriding get_id() method, so we use dict instead + this.appInfo = { + get_id: () => appId, + get_name: () => _('Recent Files'), + get_icon: () => Gio.icon_new_for_string('focus-windows-symbolic'), + should_show: () => true, + get_commandline: () => '/usr/bin/nautilus -w recent:///', + launch: () => {}, + }; + this.canLaunchSearch = true; this.isRemoteProvider = false; this._recentFilesManager = new RecentFilesManager(); } - getInitialResultSet(terms/* , callback*/) { + getInitialResultSet(terms/* , cancellable*/) { const rfm = this._recentFilesManager; rfm.loadFromFile(); @@ -215,13 +227,9 @@ class RecentFilesSearchProvider { return results.slice(0, 20); } - getSubsearchResultSet(previousResults, terms/* , callback*/) { + getSubsearchResultSet(previousResults, terms/* , cancellable*/) { return this.getInitialResultSet(terms); } - - getSubsearchResultSet42(terms, callback) { - callback(this._getResultSet(terms)); - } } class RecentFilesManager { diff --git a/extensions/45/vertical-workspaces/lib/search.js b/extensions/45/vertical-workspaces/lib/search.js index e961893..fc15862 100644 --- a/extensions/45/vertical-workspaces/lib/search.js +++ b/extensions/45/vertical-workspaces/lib/search.js @@ -3,13 +3,14 @@ * search.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ 'use strict'; +import GLib from 'gi://GLib'; import Clutter from 'gi://Clutter'; import St from 'gi://St'; import Shell from 'gi://Shell'; @@ -20,6 +21,7 @@ import * as Search from 'resource:///org/gnome/shell/ui/search.js'; import * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'; import * as SystemActions from 'resource:///org/gnome/shell/misc/systemActions.js'; +import { Highlighter } from 'resource:///org/gnome/shell/misc/util.js'; let Me; // gettext @@ -72,31 +74,42 @@ export const SearchModule = class { this._overrides.addOverride('SearchResult', Search.SearchResult.prototype, SearchResult); this._overrides.addOverride('SearchResultsView', Search.SearchResultsView.prototype, SearchResultsView); this._overrides.addOverride('ListSearchResults', Search.ListSearchResults.prototype, ListSearchResults); - // this._overrides.addOverride('ProviderInfo', Search.ProviderInfo.prototype, ProviderInfo); + this._overrides.addOverride('ListSearchResult', Search.ListSearchResult.prototype, ListSearchResultOverride); + this._overrides.addOverride('Highlighter', Highlighter.prototype, HighlighterOverride); // Don't expand the search view vertically and align it to the top // this is important in the static workspace mode when the search view bg is not transparent // also the "Searching..." and "No Results" notifications will be closer to the search entry, with the distance given by margin-top in the stylesheet - Main.overview._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.START; + Main.overview.searchController.y_align = Clutter.ActorAlign.START; + // Increase the maxResults for app search so that it can show more results in case the user decreases the size of the result icon + const appSearchDisplay = Main.overview.searchController._searchResults._providers.filter(p => p.id === 'applications')[0]?.display; + if (appSearchDisplay) + appSearchDisplay._maxResults = 12; console.debug(' SearchModule - Activated'); } _disableModule() { const reset = true; + + const searchResults = Main.overview.searchController._searchResults; + if (searchResults?._searchTimeoutId) { + GLib.source_remove(searchResults._searchTimeoutId); + searchResults._searchTimeoutId = 0; + } + this._updateSearchViewWidth(reset); if (this._overrides) this._overrides.removeAll(); this._overrides = null; - Main.overview._overview._controls.layoutManager._searchController.y_align = Clutter.ActorAlign.FILL; - + Main.overview.searchController.y_align = Clutter.ActorAlign.FILL; console.debug(' WorkspaceSwitcherPopupModule - Disabled'); } _updateSearchViewWidth(reset = false) { - const searchContent = Main.overview._overview._controls.layoutManager._searchController._searchResults._content; + const searchContent = Main.overview.searchController._searchResults._content; if (!SEARCH_MAX_WIDTH) { // just store original value; const themeNode = searchContent.get_theme_node(); const width = themeNode.get_max_width(); @@ -160,8 +173,8 @@ const AppSearchProvider = { 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') || ''; + let categories = appInfo.get_string('Categories')?.replace(/;/g, ' ') || ''; + let keywords = appInfo.get_string('Keywords')?.replace(/;/g, ' ') || ''; name = `${dispName} ${id}`; string = `${dispName} ${gName} ${baseName} ${description} ${categories} ${keywords} ${id}`; } @@ -242,22 +255,63 @@ const SearchResult = { }; const SearchResultsView = { + setTerms(terms) { + // Check for the case of making a duplicate previous search before + // setting state of the current search or cancelling the search. + // This will prevent incorrect state being as a result of a duplicate + // search while the previous search is still active. + let searchString = terms.join(' '); + let previousSearchString = this._terms.join(' '); + if (searchString === previousSearchString) + return; + + this._startingSearch = true; + + this._cancellable.cancel(); + this._cancellable.reset(); + + if (terms.length === 0) { + this._reset(); + return; + } + + let isSubSearch = false; + if (this._terms.length > 0) + isSubSearch = searchString.indexOf(previousSearchString) === 0; + + this._terms = terms; + this._isSubSearch = isSubSearch; + this._updateSearchProgress(); + + if (!this._searchTimeoutId) + this._searchTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, opt.SEARCH_DELAY, this._onSearchTimeout.bind(this)); + + this._highlighter = new Highlighter(this._terms); + + this.emit('terms-changed'); + }, + _doSearch() { this._startingSearch = false; let previousResults = this._results; this._results = {}; + const term0 = this._terms[0]; + const onlySupportedProviders = term0.startsWith(Me.WSP_PREFIX) || term0.startsWith(Me.ESP_PREFIX) || term0.startsWith(Me.RFSP_PREFIX); + this._providers.forEach(provider => { - const onlyVShellProviders = this._terms.includes('wq//') || this._terms.includes('fq//'); - if (!onlyVShellProviders || (onlyVShellProviders && (provider.id.includes('open-windows') || provider.id.includes('recent-files')))) { + const supportedProvider = ['open-windows', 'extensions', 'recent-files'].includes(provider.id); + if (!onlySupportedProviders || (onlySupportedProviders && supportedProvider)) { let previousProviderResults = previousResults[provider.id]; this._doProviderSearch(provider, previousProviderResults); + } else { + // hide unwanted providers, they will show() automatically when needed + provider.display.visible = false; } }); this._updateSearchProgress(); - this._clearSearchTimeout(); }, @@ -279,13 +333,73 @@ const SearchResultsView = { }, }; -// fixes app is null error if search provider id is not a desktop app id. -// is not accessible in 45 -/* const ProviderInfo = { - animateLaunch() { - let appSys = Shell.AppSystem.get_default(); - let app = appSys.lookup_app(this.provider.appInfo.get_id()); - if (app && app.state === Shell.AppState.STOPPED) - IconGrid.zoomOutActor(this._content); +// Add highlighting of the "name" part of the result for all providers +const ListSearchResultOverride = { + _highlightTerms() { + let markup = this._resultsView.highlightTerms(this.metaInfo['name']); + this.label_actor.clutter_text.set_markup(markup); + markup = this._resultsView.highlightTerms(this.metaInfo['description'].split('\n')[0]); + this._descriptionLabel.clutter_text.set_markup(markup); + }, +}; + +const HighlighterOverride = { + /** + * @param {?string[]} terms - list of terms to highlight + */ + /* constructor(terms) { + if (!terms) + return; + + const escapedTerms = terms + .map(term => Shell.util_regex_escape(term)) + .filter(term => term.length > 0); + + if (escapedTerms.length === 0) + return; + + this._highlightRegex = new RegExp( + `(${escapedTerms.join('|')})`, 'gi'); + },*/ + + /** + * Highlight all occurences of the terms defined for this + * highlighter in the provided text using markup. + * + * @param {string} text - text to highlight the defined terms in + * @returns {string} + */ + highlight(text, options) { + if (!this._highlightRegex) + return GLib.markup_escape_text(text, -1); + + // force use local settings if the class is overridden by another extension (WSP, ESP) + const o = options || opt; + let escaped = []; + let lastMatchEnd = 0; + let match; + let style = ['', '']; + if (o.HIGHLIGHT_DEFAULT) + style = ['<b>', '</b>']; + // The default highlighting by the bold style causes text to be "randomly" ellipsized in cases where it's not necessary + // and also blurry + // Underscore doesn't affect label size and all looks better + else if (o.HIGHLIGHT_UNDERLINE) + style = ['<u>', '</u>']; + + while ((match = this._highlightRegex.exec(text))) { + if (match.index > lastMatchEnd) { + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd, match.index), -1); + escaped.push(unmatched); + } + let matched = GLib.markup_escape_text(match[0], -1); + escaped.push(`${style[0]}${matched}${style[1]}`); + lastMatchEnd = match.index + match[0].length; + } + let unmatched = GLib.markup_escape_text( + text.slice(lastMatchEnd), -1); + escaped.push(unmatched); + return escaped.join(''); }, -};*/ +}; diff --git a/extensions/45/vertical-workspaces/lib/searchController.js b/extensions/45/vertical-workspaces/lib/searchController.js index e69bc90..1722f15 100644 --- a/extensions/45/vertical-workspaces/lib/searchController.js +++ b/extensions/45/vertical-workspaces/lib/searchController.js @@ -3,7 +3,7 @@ * searchController.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -51,15 +51,15 @@ export const SearchControllerModule = class { _activateModule() { if (!this._originalOnStageKeyPress) - this._originalOnStageKeyPress = Main.overview._overview.controls._searchController._onStageKeyPress; + this._originalOnStageKeyPress = Main.overview.searchController._onStageKeyPress; - Main.overview._overview.controls._searchController._onStageKeyPress = SearchControllerCommon._onStageKeyPress; + Main.overview.searchController._onStageKeyPress = SearchControllerCommon._onStageKeyPress; console.debug(' SearchControllerModule - Activated'); } _disableModule() { if (this._originalOnStageKeyPress) - Main.overview._overview.controls._searchController._onStageKeyPress = this._originalOnStageKeyPress; + Main.overview.searchController._onStageKeyPress = this._originalOnStageKeyPress; this._originalOnStageKeyPress = null; console.debug(' SearchControlerModule - Disabled'); diff --git a/extensions/45/vertical-workspaces/lib/settings.js b/extensions/45/vertical-workspaces/lib/settings.js index d8bb99c..dcfc8f9 100644 --- a/extensions/45/vertical-workspaces/lib/settings.js +++ b/extensions/45/vertical-workspaces/lib/settings.js @@ -3,7 +3,7 @@ * settings.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 */ @@ -52,9 +52,6 @@ export const Options = class Options { 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'], - dashShowExtensionsIcon: ['int', 'dash-show-extensions-icon'], centerDashToWs: ['boolean', 'center-dash-to-ws'], showAppsIconPosition: ['int', 'show-app-icon-position'], wsThumbnailScale: ['int', 'ws-thumbnail-scale'], @@ -87,6 +84,7 @@ export const Options = class Options { startupState: ['int', 'startup-state'], overviewMode: ['int', 'overview-mode'], workspaceSwitcherAnimation: ['int', 'workspace-switcher-animation'], + wsSwitcherMode: ['int', 'ws-switcher-mode'], searchIconSize: ['int', 'search-icon-size'], searchViewScale: ['int', 'search-width-scale'], appGridIconSize: ['int', 'app-grid-icon-size'], @@ -136,8 +134,9 @@ export const Options = class Options { overlayKeySecondary: ['int', 'overlay-key-secondary'], overviewEscBehavior: ['int', 'overview-esc-behavior'], newWindowFocusFix: ['boolean', 'new-window-focus-fix'], + newWindowMonitorFix: ['boolean', 'new-window-monitor-fix'], appGridPerformance: ['boolean', 'app-grid-performance'], - windowThumbnailScale: ['int', 'window-thumbnail-scale'], + highlightingStyle: ['int', 'highlighting-style'], workspaceSwitcherPopupModule: ['boolean', 'workspace-switcher-popup-module'], workspaceAnimationModule: ['boolean', 'workspace-animation-module'], @@ -145,7 +144,6 @@ export const Options = class Options { windowManagerModule: ['boolean', 'window-manager-module'], windowPreviewModule: ['boolean', 'window-preview-module'], windowAttentionHandlerModule: ['boolean', 'win-attention-handler-module'], - windowThumbnailModule: ['boolean', 'window-thumbnail-module'], swipeTrackerModule: ['boolean', 'swipe-tracker-module'], searchControllerModule: ['boolean', 'search-controller-module'], searchModule: ['boolean', 'search-module'], @@ -157,9 +155,6 @@ export const Options = class Options { dashModule: ['boolean', 'dash-module'], appFavoritesModule: ['boolean', 'app-favorites-module'], appDisplayModule: ['boolean', 'app-display-module'], - windowSearchProviderModule: ['boolean', 'window-search-provider-module'], - recentFilesSearchProviderModule: ['boolean', 'recent-files-search-provider-module'], - extensionsSearchProviderModule: ['boolean', 'extensions-search-provider-module'], profileName1: ['string', 'profile-name-1'], profileName2: ['string', 'profile-name-2'], @@ -324,9 +319,6 @@ export const Options = class Options { this.CENTER_DASH_WS = this.get('centerDashToWs'); this.MAX_ICON_SIZE = this.get('dashMaxIconSize'); - this.SHOW_WINDOWS_ICON = this.get('dashShowWindowsIcon'); - this.SHOW_RECENT_FILES_ICON = this.get('dashShowRecentFilesIcon'); - this.SHOW_EXTENSIONS_ICON = this.get('dashShowExtensionsIcon'); this.WS_TMB_POSITION = this.get('workspaceThumbnailsPosition'); this.ORIENTATION = this.WS_TMB_POSITION > 4 ? 0 : 1; @@ -395,8 +387,6 @@ export const Options = class Options { if (this.SEARCH_VIEW_ANIMATION === 4) this.SEARCH_VIEW_ANIMATION = 3; - this.WS_ANIMATION = this.get('workspaceAnimation'); - this.WIN_PREVIEW_ICON_SIZE = [64, 48, 32, 22, 8][this.get('winPreviewIconSize')]; this.WIN_TITLES_POSITION = this.get('winTitlePosition'); this.ALWAYS_SHOW_WIN_TITLES = this.WIN_TITLES_POSITION === 1; @@ -421,6 +411,7 @@ export const Options = class Options { this.SEARCH_VIEW_SCALE = this.get('searchViewScale') / 100; this.SEARCH_MAX_ROWS = this.get('searchMaxResultsRows'); this.SEARCH_FUZZY = this.get('searchFuzzy'); + this.SEARCH_DELAY = 0; this.APP_GRID_ALLOW_INCOMPLETE_PAGES = this.get('appGridIncompletePages'); this.APP_GRID_ICON_SIZE = this.get('appGridIconSize'); @@ -484,8 +475,10 @@ export const Options = class Options { this.WS_SW_POPUP_V_POSITION = this.get('wsSwPopupVPosition') / 100; this.WS_SW_POPUP_MODE = this.get('wsSwPopupMode'); + this.WS_ANIMATION = this.get('workspaceAnimation'); this.WS_WRAPAROUND = this.get('wsSwitcherWraparound'); this.WS_IGNORE_LAST = this.get('wsSwitcherIgnoreLast'); + this.WS_SWITCHER_CURRENT_MONITOR = this.get('wsSwitcherMode') === 1; this.SHOW_FAV_NOTIFICATION = this.get('favoritesNotify'); this.NOTIFICATION_POSITION = this.get('notificationPosition'); @@ -522,10 +515,15 @@ export const Options = class Options { this.ESC_BEHAVIOR = this.get('overviewEscBehavior'); - this.WINDOW_THUMBNAIL_ENABLED = this.get('windowThumbnailModule'); - this.WINDOW_THUMBNAIL_SCALE = this.get('windowThumbnailScale') / 100; + this.WINDOW_THUMBNAIL_ENABLED = !!Me.Util.getEnabledExtensions('window-thumbnails').length; this.FIX_NEW_WINDOW_FOCUS = this.get('newWindowFocusFix'); + this.FIX_NEW_WINDOW_MONITOR = this.get('newWindowMonitorFix'); + + this.HIGHLIGHTING_STYLE = this.get('highlightingStyle'); + this.HIGHLIGHT_DEFAULT = this.HIGHLIGHTING_STYLE === 0; + this.HIGHLIGHT_UNDERLINE = this.HIGHLIGHTING_STYLE === 1; + this.HIGHLIGHT_NONE = this.HIGHLIGHTING_STYLE === 2; } _getAnimationDirection() { diff --git a/extensions/45/vertical-workspaces/lib/swipeTracker.js b/extensions/45/vertical-workspaces/lib/swipeTracker.js index 354f1e0..560b296 100644 --- a/extensions/45/vertical-workspaces/lib/swipeTracker.js +++ b/extensions/45/vertical-workspaces/lib/swipeTracker.js @@ -3,7 +3,7 @@ * swipeTracker.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/util.js b/extensions/45/vertical-workspaces/lib/util.js index 38ca6cd..ab79c48 100644 --- a/extensions/45/vertical-workspaces/lib/util.js +++ b/extensions/45/vertical-workspaces/lib/util.js @@ -3,7 +3,7 @@ * util.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -285,9 +285,9 @@ export function isMoreRelevant(stringA, stringB, pattern) { export function getEnabledExtensions(pattern = '') { let result = []; - // extensionManager is unreliable at startup (if not all extensions were loaded) - // but gsettings key can contain removed extensions... - // therefore we have to look into filesystem, what's really installed + // extensionManager is unreliable at startup because it is uncertain whether all extensions have been loaded + // also gsettings key can contain already removed extensions (user deleted them without disabling them first) + // therefore we have to check what's really installed in the filesystem if (!_installedExtensions) { const extensionFiles = [...collectFromDatadirs('extensions', true)]; _installedExtensions = extensionFiles.map(({ info }) => { @@ -298,8 +298,19 @@ export function getEnabledExtensions(pattern = '') { return uuid; }); } + // _enabledExtensions contains content of the enabled-extensions key from gsettings, not actual state const enabled = Main.extensionManager._enabledExtensions; result = _installedExtensions.filter(ext => enabled.includes(ext)); + // _extensions contains already loaded extensions, so we can try to filter out broken or incompatible extensions + const active = Main.extensionManager._extensions; + result = result.filter(ext => { + const extension = active.get(ext); + if (extension) + return ![3, 4].includes(extension.state); // 3 - ERROR, 4 - OUT_OF_TIME (not supported by shell-version in metadata) + // extension can be enabled but not yet loaded, we just cannot see its state at this moment, so let it pass as enabled + return true; + }); + // return only extensions matching the search pattern return result.filter(uuid => uuid !== null && uuid.includes(pattern)); } diff --git a/extensions/45/vertical-workspaces/lib/winTmb.js b/extensions/45/vertical-workspaces/lib/winTmb.js deleted file mode 100644 index 4205822..0000000 --- a/extensions/45/vertical-workspaces/lib/winTmb.js +++ /dev/null @@ -1,525 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * WinTmb - * - * @author GdH <G-dH@github.com> - * @copyright 2021-2023 - * @license GPL-3.0 - */ - -'use strict'; - -import GLib from 'gi://GLib'; -import Clutter from 'gi://Clutter'; -import St from 'gi://St'; -import Meta from 'gi://Meta'; -import GObject from 'gi://GObject'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; -import * as DND from 'resource:///org/gnome/shell/ui/dnd.js'; -import * as AltTab from 'resource:///org/gnome/shell/ui/altTab.js'; - -let Me; -let opt; - -const SCROLL_ICON_OPACITY = 240; -const DRAG_OPACITY = 200; -const CLOSE_BTN_OPACITY = 240; - - -export const WinTmbModule = class { - constructor(me) { - Me = me; - opt = Me.opt; - - this._firstActivation = true; - this.moduleEnabled = false; - } - - cleanGlobals() { - Me = null; - opt = null; - } - - update(reset) { - this._removeTimeouts(); - - this.moduleEnabled = opt.get('windowThumbnailModule'); - - reset = reset || !this.moduleEnabled; - - // don't touch the original code if module disabled - if (reset && !this._firstActivation) { - this._disableModule(); - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - if (reset && this._firstActivation) - console.debug(' WinTmb - Keeping untouched'); - } - - _activateModule() { - this._timeouts = {}; - if (!this._windowThumbnails) - this._windowThumbnails = []; - - Main.overview.connectObject('hidden', () => this.showThumbnails(), this); - console.debug(' WinTmb - Activated'); - } - - _disableModule() { - Main.overview.disconnectObject(this); - this._disconnectStateAdjustment(); - this.removeAllThumbnails(); - console.debug(' WinTmb - Disabled'); - } - - _removeTimeouts() { - if (this._timeouts) { - Object.values(this._timeouts).forEach(t => { - if (t) - GLib.source_remove(t); - }); - this._timeouts = null; - } - } - - createThumbnail(metaWin) { - const thumbnail = new WindowThumbnail(metaWin, { - 'height': Math.floor(opt.WINDOW_THUMBNAIL_SCALE * global.display.get_monitor_geometry(global.display.get_current_monitor()).height), - 'thumbnailsOnScreen': this._windowThumbnails.length, - }); - - this._windowThumbnails.push(thumbnail); - thumbnail.connect('removed', tmb => { - this._windowThumbnails.splice(this._windowThumbnails.indexOf(tmb), 1); - tmb.destroy(); - if (!this._windowThumbnails.length) - this._disconnectStateAdjustment(); - }); - - if (!this._stateAdjustmentConId) { - this._stateAdjustmentConId = Main.overview._overview.controls._stateAdjustment.connectObject('notify::value', () => { - if (!this._thumbnailsHidden && (!opt.OVERVIEW_MODE2 || opt.WORKSPACE_MODE)) - this.hideThumbnails(); - }, this); - } - } - - hideThumbnails() { - this._windowThumbnails.forEach(tmb => { - tmb.ease({ - opacity: 0, - duration: 200, - mode: Clutter.AnimationMode.LINEAR, - onComplete: () => tmb.hide(), - }); - }); - this._thumbnailsHidden = true; - } - - showThumbnails() { - this._windowThumbnails.forEach(tmb => { - tmb.show(); - tmb.ease({ - opacity: 255, - duration: 100, - mode: Clutter.AnimationMode.LINEAR, - }); - }); - this._thumbnailsHidden = false; - } - - removeAllThumbnails() { - this._windowThumbnails.forEach(tmb => tmb.remove()); - this._windowThumbnails = []; - } - - _disconnectStateAdjustment() { - Main.overview._overview.controls._stateAdjustment.disconnectObject(this); - } -}; - -const WindowThumbnail = GObject.registerClass({ - Signals: { 'removed': {} }, -}, class WindowThumbnail extends St.Widget { - _init(metaWin, args) { - this._hoverShowsPreview = false; - this._customOpacity = 255; - this._initTmbHeight = args.height; - this._minimumHeight = Math.floor(5 / 100 * global.display.get_monitor_geometry(global.display.get_current_monitor()).height); - this._scrollTimeout = 100; - this._positionOffset = args.thumbnailsOnScreen; - this._reverseTmbWheelFunc = false; - this._click_count = 1; - this._prevBtnPressTime = 0; - this.w = metaWin; - super._init({ - layout_manager: new Clutter.BinLayout(), - visible: true, - reactive: true, - can_focus: true, - track_hover: true, - }); - this.connect('button-release-event', this._onBtnReleased.bind(this)); - this.connect('scroll-event', this._onScrollEvent.bind(this)); - // this.connect('motion-event', this._onMouseMove.bind(this)); // may be useful in the future.. - - this._delegate = this; - this._draggable = DND.makeDraggable(this, { dragActorOpacity: DRAG_OPACITY }); - this._draggable.connect('drag-end', this._end_drag.bind(this)); - this._draggable.connect('drag-cancelled', this._end_drag.bind(this)); - this._draggable._animateDragEnd = eventTime => { - this._draggable._animationInProgress = true; - this._draggable._onAnimationComplete(this._draggable._dragActor, eventTime); - this.opacity = this._customOpacity; - }; - - this.clone = new Clutter.Clone({ reactive: true }); - Main.layoutManager.addChrome(this); - - this.window = this.w.get_compositor_private(); - - this.clone.set_source(this.window); - - this.add_child(this.clone); - this._addCloseButton(); - this._addScrollModeIcon(); - - this.connect('enter-event', () => { - global.display.set_cursor(Meta.Cursor.POINTING_HAND); - this._closeButton.opacity = CLOSE_BTN_OPACITY; - this._scrollModeBin.opacity = SCROLL_ICON_OPACITY; - if (this._hoverShowsPreview && !Main.overview._shown) { - this._closeButton.opacity = 50; - this._showWindowPreview(false, true); - } - }); - - this.connect('leave-event', () => { - global.display.set_cursor(Meta.Cursor.DEFAULT); - this._closeButton.opacity = 0; - this._scrollModeBin.opacity = 0; - if (this._winPreview) - this._destroyWindowPreview(); - }); - - this._setSize(true); - this.set_position(...this._getInitialPosition()); - this.show(); - this.window_id = this.w.get_id(); - this.tmbRedrawDirection = true; - - // remove thumbnail content and hide thumbnail if its window is destroyed - this.windowConnect = this.window.connect('destroy', () => { - if (this) - this.remove(); - }); - } - - _getInitialPosition() { - const offset = 20; - let monitor = Main.layoutManager.monitors[global.display.get_current_monitor()]; - let x = Math.min(monitor.x + monitor.width - (this.window.width * this.scale) - offset); - let y = Math.min(monitor.y + monitor.height - (this.window.height * this.scale) - offset - ((this._positionOffset * this._initTmbHeight) % (monitor.height - this._initTmbHeight))); - return [x, y]; - } - - _setSize(resetScale = false) { - if (resetScale) - this.scale = Math.min(1.0, this._initTmbHeight / this.window.height); - - const width = this.window.width * this.scale; - const height = this.window.height * this.scale; - this.set_size(width, height); - /* if (this.icon) { - this.icon.scale_x = this.scale; - this.icon.scale_y = this.scale; - }*/ - - // when the scale of this. actor change, this.clone resize accordingly, - // but the reactive area of the actor doesn't change until the actor is redrawn - // this updates the actor's input region area: - Main.layoutManager._queueUpdateRegions(); - } - - /* _onMouseMove(actor, event) { - let [pos_x, pos_y] = event.get_coords(); - let state = event.get_state(); - if (this._ctrlPressed(state)) { - } - }*/ - - _onBtnReleased(actor, event) { - // Clutter.Event.click_count property in no longer available, since GS42 - if ((event.get_time() - this._prevBtnPressTime) < Clutter.Settings.get_default().double_click_time) - this._click_count += 1; - else - this._click_count = 1; - - this._prevBtnPressTime = event.get_time(); - - if (this._click_count === 2 && event.get_button() === Clutter.BUTTON_PRIMARY) - this.w.activate(global.get_current_time()); - - - const button = event.get_button(); - const state = event.get_state(); - switch (button) { - case Clutter.BUTTON_PRIMARY: - if (this._ctrlPressed(state)) { - this._setSize(); - } else { - this._reverseTmbWheelFunc = !this._reverseTmbWheelFunc; - this._scrollModeBin.set_child(this._reverseTmbWheelFunc ? this._scrollModeSourceIcon : this._scrollModeResizeIcon); - } - return Clutter.EVENT_STOP; - case Clutter.BUTTON_SECONDARY: - if (this._ctrlPressed(state)) { - this.remove(); - } else { - this._hoverShowsPreview = !this._hoverShowsPreview; - this._showWindowPreview(); - } - return Clutter.EVENT_STOP; - case Clutter.BUTTON_MIDDLE: - if (this._ctrlPressed(state)) - this.w.delete(global.get_current_time()); - return Clutter.EVENT_STOP; - default: - return Clutter.EVENT_PROPAGATE; - } - } - - _onScrollEvent(actor, event) { - let direction = Me.Util.getScrollDirection(event); - - if (this._actionTimeoutActive()) - return Clutter.EVENT_PROPAGATE; - let state = event.get_state(); - switch (direction) { - case Clutter.ScrollDirection.UP: - if (this._shiftPressed(state)) { - this.opacity = Math.min(255, this.opacity + 24); - this._customOpacity = this.opacity; - } else if (this._reverseTmbWheelFunc !== this._ctrlPressed(state)) { - this._switchSourceWin(-1); - } else if (this._reverseTmbWheelFunc === this._ctrlPressed(state)) { - this.scale = Math.max(0.05, this.scale - 0.025); - } - break; - case Clutter.ScrollDirection.DOWN: - if (this._shiftPressed(state)) { - this.opacity = Math.max(48, this.opacity - 24); - this._customOpacity = this.opacity; - } else if (this._reverseTmbWheelFunc !== this._ctrlPressed(state)) { - this._switchSourceWin(+1); - } else if (this._reverseTmbWheelFunc === this._ctrlPressed(state)) { - this.scale = Math.min(1, this.scale + 0.025); - } - break; - default: - return Clutter.EVENT_PROPAGATE; - } - this._setSize(); - return Clutter.EVENT_STOP; - } - - remove() { - if (this.clone) { - this.window.disconnect(this.windowConnect); - this.clone.set_source(null); - } - if (this._winPreview) - this._destroyWindowPreview(); - - this.emit('removed'); - } - - _end_drag() { - this.set_position(this._draggable._dragOffsetX + this._draggable._dragX, this._draggable._dragOffsetY + this._draggable._dragY); - this._setSize(); - } - - _ctrlPressed(state) { - return (state & Clutter.ModifierType.CONTROL_MASK) !== 0; - } - - _shiftPressed(state) { - return (state & Clutter.ModifierType.SHIFT_MASK) !== 0; - } - - _switchSourceWin(direction) { - let windows = global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null); - windows = windows.filter(w => !(w.skip_taskbar || w.minimized)); - let idx = -1; - for (let i = 0; i < windows.length; i++) { - if (windows[i] === this.w) { - idx = i + direction; - break; - } - } - idx = idx >= windows.length ? 0 : idx; - idx = idx < 0 ? windows.length - 1 : idx; - let w = windows[idx]; - let win = w.get_compositor_private(); - this.clone.set_source(win); - this.window.disconnect(this.windowConnect); - // the new thumbnail should be the same height as the previous one - this.scale = (this.scale * this.window.height) / win.height; - this.window = win; - this.windowConnect = this.window.connect('destroy', () => { - if (this) - this.remove(); - }); - this.w = w; - - if (this._winPreview) - this._showWindowPreview(true); - } - - _actionTimeoutActive() { - const timeout = this._reverseTmbWheelFunc ? this._scrollTimeout : this._scrollTimeout / 4; - if (!this._lastActionTime || Date.now() - this._lastActionTime > timeout) { - this._lastActionTime = Date.now(); - return false; - } - return true; - } - - /* _setIcon() { - let tracker = Shell.WindowTracker.get_default(); - let app = tracker.get_window_app(this.w); - let icon = app - ? app.create_icon_texture(this.height) - : new St.Icon({ icon_name: 'icon-missing', icon_size: this.height }); - icon.x_expand = icon.y_expand = true; - if (this.icon) - this.icon.destroy(); - this.icon = icon; - }*/ - - _addCloseButton() { - const closeButton = new St.Button({ - opacity: 0, - style_class: 'window-close', - child: new St.Icon({ icon_name: 'preview-close-symbolic' }), - x_align: Clutter.ActorAlign.END, - y_align: Clutter.ActorAlign.START, - x_expand: true, - y_expand: true, - }); - - closeButton.set_style(` - margin: 3px; - background-color: rgba(200, 0, 0, 0.9); - `); - - closeButton.connect('clicked', () => { - this.remove(); - return Clutter.EVENT_STOP; - }); - - this._closeButton = closeButton; - this.add_child(this._closeButton); - } - - _addScrollModeIcon() { - this._scrollModeBin = new St.Bin({ - x_expand: true, - y_expand: true, - }); - this._scrollModeResizeIcon = new St.Icon({ - icon_name: 'view-fullscreen-symbolic', - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.END, - x_expand: true, - y_expand: true, - opacity: SCROLL_ICON_OPACITY, - style_class: 'icon-dropshadow', - scale_x: 0.5, - scale_y: 0.5, - }); - this._scrollModeResizeIcon.set_style(` - margin: 13px; - color: rgb(255, 255, 255); - box-shadow: 0 0 40px 40px rgba(0,0,0,0.7); - `); - this._scrollModeSourceIcon = new St.Icon({ - icon_name: 'media-skip-forward-symbolic', - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.END, - x_expand: true, - y_expand: true, - opacity: SCROLL_ICON_OPACITY, - style_class: 'icon-dropshadow', - scale_x: 0.5, - scale_y: 0.5, - }); - this._scrollModeSourceIcon.set_style(` - margin: 13px; - color: rgb(255, 255, 255); - box-shadow: 0 0 40px 40px rgba(0,0,0,0.7); - `); - this._scrollModeBin.set_child(this._scrollModeResizeIcon); - this.add_child(this._scrollModeBin); - this._scrollModeBin.opacity = 0; - } - - _showWindowPreview(update = false, dontDestroy = false) { - if (this._winPreview && !dontDestroy) { - this._destroyWindowPreview(); - this._previewCreationTime = 0; - this._closeButton.opacity = CLOSE_BTN_OPACITY; - if (!update) - return; - } - - if (!this._winPreview) { - this._winPreview = new AltTab.CyclerHighlight(); - global.window_group.add_actor(this._winPreview); - [this._winPreview._xPointer, this._winPreview._yPointer] = global.get_pointer(); - } - - if (!update) { - this._winPreview.opacity = 0; - this._winPreview.ease({ - opacity: 255, - duration: 70, - mode: Clutter.AnimationMode.LINEAR, - /* onComplete: () => { - this._closeButton.opacity = 50; - },*/ - }); - - this.ease({ - opacity: Math.min(50, this._customOpacity), - duration: 70, - mode: Clutter.AnimationMode.LINEAR, - onComplete: () => { - }, - }); - } else { - this._winPreview.opacity = 255; - } - this._winPreview.window = this.w; - this._winPreview._window = this.w; - global.window_group.set_child_above_sibling(this._winPreview, null); - } - - _destroyWindowPreview() { - if (this._winPreview) { - this._winPreview.ease({ - opacity: 0, - duration: 100, - mode: Clutter.AnimationMode.LINEAR, - onComplete: () => { - this._winPreview.destroy(); - this._winPreview = null; - this.opacity = this._customOpacity; - }, - }); - } - } -}); diff --git a/extensions/45/vertical-workspaces/lib/windowAttentionHandler.js b/extensions/45/vertical-workspaces/lib/windowAttentionHandler.js index d49c1ad..744f5b6 100644 --- a/extensions/45/vertical-workspaces/lib/windowAttentionHandler.js +++ b/extensions/45/vertical-workspaces/lib/windowAttentionHandler.js @@ -3,7 +3,7 @@ * windowAttentionHandler.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -87,7 +87,13 @@ const WindowAttentionHandlerCommon = { const app = this._tracker.get_window_app(window); // const source = new WindowAttentionHandler.WindowAttentionSource(app, window); - const source = new MessageTray.Source(app.get_name()); + let args; + if (!Main.overview.dash.add_actor) // detects GS 46 - Clutter.Container has been removed + args = { title: app.get_name() }; + else + args = app.get_name(); + + const source = new MessageTray.Source(args); new Me.Util.Overrides().addOverride('MessageSource', source, WindowAttentionSourceCommon); source._init(app, window); Main.messageTray.add(source); diff --git a/extensions/45/vertical-workspaces/lib/windowManager.js b/extensions/45/vertical-workspaces/lib/windowManager.js index dd467cb..a6f9b09 100644 --- a/extensions/45/vertical-workspaces/lib/windowManager.js +++ b/extensions/45/vertical-workspaces/lib/windowManager.js @@ -3,7 +3,7 @@ * windowManager.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -16,6 +16,10 @@ import GObject from 'gi://GObject'; import * as Main from 'resource:///org/gnome/shell/ui/main.js'; import * as WindowManager from 'resource:///org/gnome/shell/ui/windowManager.js'; +import * as WorkspaceAnimation from 'resource:///org/gnome/shell/ui/workspaceAnimation.js'; + +const MINIMIZE_WINDOW_ANIMATION_TIME = 400; // windowManager.MINIMIZE_WINDOW_ANIMATION_TIME +const MINIMIZE_WINDOW_ANIMATION_MODE = Clutter.AnimationMode.EASE_OUT_EXPO; // WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE let Me; let opt; @@ -62,6 +66,8 @@ export const WindowManagerModule = class { this._overrides = new Me.Util.Overrides(); this._overrides.addOverride('WindowManager', WindowManager.WindowManager.prototype, WindowManagerCommon); + if (opt.WS_SWITCHER_CURRENT_MONITOR) + this._overrides.addOverride('WorkspaceAnimationController', WorkspaceAnimation.WorkspaceAnimationController.prototype, WorkspaceAnimationController); if (!this._minimizeSigId) { this._originalMinimizeSigId = GObject.signal_handler_find(Main.wm._shellwm, { signalId: 'minimize' }); @@ -106,11 +112,108 @@ export const WindowManagerModule = class { } }; -// 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 = { + actionMoveWorkspace(workspace) { + if (!Main.sessionMode.hasWorkspaces) + return; + + if (opt.WS_SWITCHER_CURRENT_MONITOR) + this._switchWorkspaceCurrentMonitor(workspace); + else if (!workspace.active) + workspace.activate(global.get_current_time()); + }, + + actionMoveWindow(window, workspace) { + if (!Main.sessionMode.hasWorkspaces) + return; + + if (!workspace.active) { + // This won't have any effect for "always sticky" windows + // (like desktop windows or docks) + + this._workspaceAnimation.movingWindow = window; + window.change_workspace(workspace); + + global.display.clear_mouse_mode(); + + if (opt.SWITCH_ONLY_CURRENT_MONITOR_WS) { + this._switchWorkspaceCurrentMonitor(workspace, window.get_monitor()); + window.activate(global.get_current_time()); + } else { + workspace.activate_with_focus(window, global.get_current_time()); + } + } + }, + + _switchWorkspaceCurrentMonitor(workspace, monitor) { + // const focusedWindow = global.display.get_focus_window(); + // const currentMonitor = focusedWindow ? focusedWindow.get_monitor() : global.display.get_current_monitor(); + // using focused window to determine the current monitor can lead to inconsistent behavior and switching monitors between switches + // depending on which window takes focus on each workspace + // mouse pointer is more stable and predictable source + const currentMonitor = monitor ? monitor : global.display.get_current_monitor(); + const primaryMonitor = currentMonitor === Main.layoutManager.primaryIndex; + const nMonitors = Main.layoutManager.monitors.length; + const lastIndexCorrection = Meta.prefs_get_dynamic_workspaces() ? 2 : 1; + const lastIndex = global.workspaceManager.get_n_workspaces() - lastIndexCorrection; + const targetWsIndex = workspace.index(); + const activeWs = global.workspaceManager.get_active_workspace(); + const activeWsIndex = activeWs.index(); + const diff = activeWsIndex - targetWsIndex; + + let direction = diff > 0 ? Meta.MotionDirection.UP : Meta.MotionDirection.DOWN; + if (diff === 0) { + // no actual ws to switch, but secondary monitors are always in wraparound mode so we need to get direction + direction = activeWsIndex >= lastIndex ? Meta.MotionDirection.DOWN : Meta.MotionDirection.UP; + } + if (Math.abs(diff) > 1) { + // workspace is probably in wraparound mode and just wrapped so so we need to translate direction + direction = diff > 0 ? Meta.MotionDirection.DOWN : Meta.MotionDirection.UP; + } + + if (!primaryMonitor) { + this._rotateWorkspaces(direction, currentMonitor); + return; + } + + // avoid ws rotations if the last empty dynamic workspace is involved, but allow to rotate from the last to the first, if wraparound is enabled + if (workspace !== activeWs && !((targetWsIndex > lastIndex && direction === Meta.MotionDirection.DOWN) || (activeWsIndex > lastIndex && targetWsIndex >= lastIndex))) { + for (let i = 0; i < nMonitors; i++) { + if (i !== currentMonitor) { + const oppositeDirection = direction === Meta.MotionDirection.UP ? Meta.MotionDirection.DOWN : Meta.MotionDirection.UP; + this._rotateWorkspaces(oppositeDirection, i); + } + } + } + workspace.activate(global.get_current_time()); + }, + + _rotateWorkspaces(direction = 0, monitorIndex = -1, step = 1) { + step = direction === Meta.MotionDirection.UP ? Number(step) : -step; + const monitor = monitorIndex > -1 ? monitorIndex : global.display.get_current_monitor(); + // don't move windows to the last empty workspace if dynamic workspaces are enabled + const lastIndexCorrection = Meta.prefs_get_dynamic_workspaces() ? 2 : 1; + const lastIndex = global.workspaceManager.get_n_workspaces() - lastIndexCorrection; + let windows = Me.Util.getWindows(null); + for (let win of windows.reverse()) { + // avoid moving modal windows as they move with their parents (and vice versa) immediately, before we move the parent window. + if (win.get_monitor() === monitor && !win.is_always_on_all_workspaces() && !win.is_attached_dialog() && !win.get_transient_for()) { + let wWs = win.get_workspace().index(); + wWs += step; + if (wWs < 0) + wWs = lastIndex; + if (wWs > lastIndex) + wWs = 0; + const ws = global.workspaceManager.get_workspace_by_index(wWs); + win.change_workspace(ws); + } + } + }, + + // fix for mainstream bug - fullscreen windows should minimize using opacity transition + // but its being applied directly on window actor and that doesn't work + // anyway, animation is better, even if the Activities button is not visible... + // and also add support for bottom position of the panel _minimizeWindow(shellwm, actor) { const types = [ Meta.WindowType.NORMAL, @@ -129,8 +232,8 @@ const WindowManagerCommon = { /* if (actor.meta_window.is_monitor_sized()) { actor.get_first_child().ease({ opacity: 0, - duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME, - mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, onStopped: () => this._minimizeWindowDone(shellwm, actor), }); } else { */ @@ -160,8 +263,8 @@ const WindowManagerCommon = { scale_y: yScale, x: xDest, y: yDest, - duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME, - mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, onStopped: () => this._minimizeWindowDone(shellwm, actor), }); // } @@ -196,8 +299,8 @@ const WindowManagerCommon = { actor.set_scale(1.0, 1.0); actor.ease({ opacity: 255, - duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME, - mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, onStopped: () => this._unminimizeWindowDone(shellwm, actor), }); } else { */ @@ -228,10 +331,50 @@ const WindowManagerCommon = { scale_y: 1, x: xDest, y: yDest, - duration: WindowManager.MINIMIZE_WINDOW_ANIMATION_TIME, - mode: WindowManager.MINIMIZE_WINDOW_ANIMATION_MODE, + duration: MINIMIZE_WINDOW_ANIMATION_TIME, + mode: MINIMIZE_WINDOW_ANIMATION_MODE, onStopped: () => this._unminimizeWindowDone(shellwm, actor), }); // } }, }; + +const WorkspaceAnimationController = { + _prepareWorkspaceSwitch(workspaceIndices) { + if (this._switchData) + return; + + const workspaceManager = global.workspace_manager; + const nWorkspaces = workspaceManager.get_n_workspaces(); + + const switchData = {}; + + this._switchData = switchData; + switchData.monitors = []; + + switchData.gestureActivated = false; + switchData.inProgress = false; + + if (!workspaceIndices) + workspaceIndices = [...Array(nWorkspaces).keys()]; + + let monitors = opt.WS_SWITCHER_CURRENT_MONITOR + ? [Main.layoutManager.currentMonitor] : Main.layoutManager.monitors; + monitors = Meta.prefs_get_workspaces_only_on_primary() + ? [Main.layoutManager.primaryMonitor] : monitors; + + for (const monitor of monitors) { + if (Meta.prefs_get_workspaces_only_on_primary() && + monitor.index !== Main.layoutManager.primaryIndex) + continue; + + const group = new WorkspaceAnimation.MonitorGroup(monitor, workspaceIndices, this.movingWindow); + + Main.uiGroup.insert_child_above(group, global.window_group); + + switchData.monitors.push(group); + } + + Meta.disable_unredirect_for_display(global.display); + }, +}; diff --git a/extensions/45/vertical-workspaces/lib/windowPreview.js b/extensions/45/vertical-workspaces/lib/windowPreview.js index c775d37..3253aa5 100644 --- a/extensions/45/vertical-workspaces/lib/windowPreview.js +++ b/extensions/45/vertical-workspaces/lib/windowPreview.js @@ -3,7 +3,7 @@ * windowPreview.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -173,9 +173,9 @@ const WindowPreviewCommon = { } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 2) { this._searchAppWindowsAction(); return Clutter.EVENT_STOP; - } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 3 && opt.WINDOW_THUMBNAIL_ENABLED) { + } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 3 && global.windowThumbnails) { this._removeLaters(); - Me.Modules.winTmbModule.createThumbnail(metaWindow); + global.windowThumbnails?.createThumbnail(metaWindow); return Clutter.EVENT_STOP; } } else if (button === Clutter.BUTTON_MIDDLE) { @@ -185,9 +185,9 @@ const WindowPreviewCommon = { } else if (opt.WIN_PREVIEW_MID_BTN_ACTION === 2) { this._searchAppWindowsAction(); return Clutter.EVENT_STOP; - } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 3 && opt.WINDOW_THUMBNAIL_ENABLED) { + } else if (opt.WIN_PREVIEW_SEC_BTN_ACTION === 3 && global.windowThumbnails) { this._removeLaters(); - Me.Modules.winTmbModule.createThumbnail(metaWindow); + global.windowThumbnails?.createThumbnail(metaWindow); return Clutter.EVENT_STOP; } } @@ -262,9 +262,9 @@ const WindowPreviewCommon = { if (opt.WINDOW_ICON_CLICK_ACTION === 1) { this._searchAppWindowsAction(); return Clutter.EVENT_STOP; - } else if (opt.WINDOW_ICON_CLICK_ACTION === 2 && opt.WINDOW_THUMBNAIL_ENABLED) { + } else if (opt.WINDOW_ICON_CLICK_ACTION === 2 && global.windowThumbnails) { this._removeLaters(); - Me.Modules.winTmbModule.createThumbnail(metaWindow); + global.windowThumbnails?.createThumbnail(metaWindow); return Clutter.EVENT_STOP; } } /* else if (act.get_button() === Clutter.BUTTON_SECONDARY) { @@ -458,12 +458,12 @@ const WindowPreviewCommon = { // 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)) + scale = this._workspace._background._stateAdjustment.value; + else if ((finalState === 1 && !opt.WORKSPACE_MODE) || (finalState === 0 && !opt.WORKSPACE_MODE)) return; } - if (!opt.WS_ANIMATION && (Main.overview._overview.controls._searchController.searchActive || + if (!opt.WS_ANIMATION && (Main.overview.searchController.searchActive || ((initialState === ControlsState.WINDOW_PICKER && finalState === ControlsState.APP_GRID) || (initialState === ControlsState.APP_GRID && finalState === ControlsState.WINDOW_PICKER))) ) diff --git a/extensions/45/vertical-workspaces/lib/windowSearchProvider.js b/extensions/45/vertical-workspaces/lib/windowSearchProvider.js deleted file mode 100644 index 7deddb6..0000000 --- a/extensions/45/vertical-workspaces/lib/windowSearchProvider.js +++ /dev/null @@ -1,331 +0,0 @@ -/** - * V-Shell (Vertical Workspaces) - * windowSearchProvider.js - * - * @author GdH <G-dH@github.com> - * @copyright 2022 -2023 - * @license GPL-3.0 - */ - -'use strict'; - -import Gio from 'gi://Gio'; -import GLib from 'gi://GLib'; -import Meta from 'gi://Meta'; -import Shell from 'gi://Shell'; -import St from 'gi://St'; - -import * as Main from 'resource:///org/gnome/shell/ui/main.js'; - -let Me; -let opt; -// gettext -let _; - -// prefix helps to eliminate results from other search providers -// so it needs to be something less common -// needs to be accessible from vw module -export const PREFIX = 'wq//'; - -const Action = { - NONE: 0, - CLOSE: 1, - CLOSE_ALL: 2, - MOVE_TO_WS: 3, - MOVE_ALL_TO_WS: 4, -}; - -export const WindowSearchProviderModule = class { - // export for other modules - static _PREFIX = PREFIX; - constructor(me) { - Me = me; - opt = Me.opt; - _ = Me.gettext; - - this._firstActivation = true; - this.moduleEnabled = false; - - this._windowSearchProvider = null; - this._enableTimeoutId = 0; - } - - cleanGlobals() { - Me = null; - opt = null; - _ = null; - } - - update(reset) { - this.moduleEnabled = opt.get('windowSearchProviderModule'); - - reset = reset || !this.moduleEnabled; - - if (reset && !this._firstActivation) { - this._disableModule(); - } else if (!reset) { - this._firstActivation = false; - this._activateModule(); - } - if (reset && this._firstActivation) - console.debug(' WindowSearchProviderModule - Keeping untouched'); - } - - _activateModule() { - // delay because Fedora had problem to register a new provider soon after Shell restarts - this._enableTimeoutId = GLib.timeout_add( - GLib.PRIORITY_DEFAULT, - 2000, - () => { - if (!this._windowSearchProvider) { - this._windowSearchProvider = new WindowSearchProvider(opt); - this._getOverviewSearchResult()._registerProvider(this._windowSearchProvider); - } - this._enableTimeoutId = 0; - return GLib.SOURCE_REMOVE; - } - ); - console.debug(' WindowSearchProviderModule - Activated'); - } - - _disableModule() { - if (this._windowSearchProvider) { - this._getOverviewSearchResult()._unregisterProvider(this._windowSearchProvider); - this._windowSearchProvider = null; - } - if (this._enableTimeoutId) { - GLib.source_remove(this._enableTimeoutId); - this._enableTimeoutId = 0; - } - - console.debug(' WindowSearchProviderModule - Disabled'); - } - - _getOverviewSearchResult() { - return Main.overview._overview.controls._searchController._searchResults; - } -}; - -/* const closeSelectedRegex = /^\/x!$/; -const closeAllResultsRegex = /^\/xa!$/; -const moveToWsRegex = /^\/m[0-9]+$/; -const moveAllToWsRegex = /^\/ma[0-9]+$/;*/ - -class WindowSearchProvider { - constructor() { - this.id = 'open-windows'; - // use arbitrary app to get complete appInfo object - // Gio.AppInfo.create_from_commandline lacks something that causes error with parental content / malcontent - const appSystem = Shell.AppSystem.get_default(); - let appInfo = appSystem.lookup_app('com.matjakeman.ExtensionManager.desktop')?.get_app_info(); - if (!appInfo) - appInfo = appSystem.lookup_app('org.gnome.Extensions.desktop')?.get_app_info(); - if (!appInfo) - appInfo = Gio.AppInfo.create_from_commandline('true', _('Open Windows'), null); - appInfo.get_description = () => _('Search open windows'); - appInfo.get_name = () => _('Open Windows'); - appInfo.get_id = () => this.id; - appInfo.get_icon = () => Gio.icon_new_for_string('focus-windows-symbolic'); - appInfo.should_show = () => true; - - this.appInfo = appInfo; - this.canLaunchSearch = false; - 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 = Me.Util.fuzzyMatch(term, candidates[key].name); - else - m = Me.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 - switch (opt.WINDOW_SEARCH_ORDER) { - case 1: // MRU - current ws first - results.sort((a, b) => (this.windows[a.id].window.get_workspace().index() !== currentWs) && (this.windows[b.id].window.get_workspace().index() === currentWs)); - break; - case 2: // MRU - by workspace - results.sort((a, b) => this.windows[a.id].window.get_workspace().index() > this.windows[b.id].window.get_workspace().index()); - break; - case 3: // Stable sequence - by workspace - results.sort((a, b) => this.windows[a.id].window.get_stable_sequence() > this.windows[b.id].window.get_stable_sequence()); - results.sort((a, b) => this.windows[a.id].window.get_workspace().index() > this.windows[b.id].window.get_workspace().index()); - break; - } - - 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)); - return new Promise(resolve => resolve(metas)); - } - - 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 }); - }, - }; - } - - 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, - }; - } - - launchSearch(/* terms, timeStamp*/) { - - } - - activateResult(resultId/* , terms, timeStamp*/) { - const isCtrlPressed = Me.Util.isCtrlPressed(); - const isShiftPressed = Me.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*/) { - 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()}`] = this.makeResult(v, `${i}-${v.get_id()}`); - return windows[`${i}-${v.get_id()}`]; - } - ); - - return new Promise(resolve => resolve(this._getResultSet(terms))); - } - - filterResults(results /* , maxResults*/) { - // return results.slice(0, maxResults); - return results; - } - - getSubsearchResultSet(previousResults, terms/* , callback*/) { - return this.getInitialResultSet(terms); - } - - getSubsearchResultSet42(terms, callback) { - callback(this._getResultSet(terms)); - } -} diff --git a/extensions/45/vertical-workspaces/lib/workspace.js b/extensions/45/vertical-workspaces/lib/workspace.js index 1ff81f1..679a1ab 100644 --- a/extensions/45/vertical-workspaces/lib/workspace.js +++ b/extensions/45/vertical-workspaces/lib/workspace.js @@ -3,7 +3,7 @@ * workspace.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/workspaceAnimation.js b/extensions/45/vertical-workspaces/lib/workspaceAnimation.js index 32c7df1..e29e3ef 100644 --- a/extensions/45/vertical-workspaces/lib/workspaceAnimation.js +++ b/extensions/45/vertical-workspaces/lib/workspaceAnimation.js @@ -3,7 +3,7 @@ * workspacesAnimation.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ diff --git a/extensions/45/vertical-workspaces/lib/workspaceSwitcherPopup.js b/extensions/45/vertical-workspaces/lib/workspaceSwitcherPopup.js index 358bb1f..cf3d4c1 100644 --- a/extensions/45/vertical-workspaces/lib/workspaceSwitcherPopup.js +++ b/extensions/45/vertical-workspaces/lib/workspaceSwitcherPopup.js @@ -3,7 +3,7 @@ * workspacesSwitcherPopup.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -73,6 +73,7 @@ const WorkspaceSwitcherPopupCommon = { after__init() { if (opt.ORIENTATION) { // 1-VERTICAL, 0-HORIZONTAL this._list.vertical = true; + this._list.add_style_class_name('ws-switcher-vertical'); } this._list.set_style('margin: 0;'); if (this.get_constraints()[0]) @@ -89,13 +90,11 @@ const WorkspaceSwitcherPopupCommon = { _setPopupPosition() { let workArea; - if (opt.WS_SW_POPUP_MODE === 1) { - // workArea = Main.layoutManager.getWorkAreaForMonitor(Main.layoutManager.primaryIndex);*/ + if (opt.WS_SW_POPUP_MODE === 1) workArea = global.display.get_monitor_geometry(Main.layoutManager.primaryIndex); - } else { - // workArea = Main.layoutManager.getWorkAreaForMonitor(global.display.get_current_monitor()); + else workArea = global.display.get_monitor_geometry(global.display.get_current_monitor()); - } + let [, natHeight] = this.get_preferred_height(global.screen_width); let [, natWidth] = this.get_preferred_width(natHeight); diff --git a/extensions/45/vertical-workspaces/lib/workspaceThumbnail.js b/extensions/45/vertical-workspaces/lib/workspaceThumbnail.js index 75e5250..d64fda2 100644 --- a/extensions/45/vertical-workspaces/lib/workspaceThumbnail.js +++ b/extensions/45/vertical-workspaces/lib/workspaceThumbnail.js @@ -3,7 +3,7 @@ * workspaceThumbnail.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -335,7 +335,7 @@ const WorkspaceThumbnailCommon = { // 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); + Main.overview.searchController._setSearchActive(false); opt.WORKSPACE_MODE = 1; // setting value to 0 would reset WORKSPACE_MODE stateAdjustment.value = 0.01; diff --git a/extensions/45/vertical-workspaces/lib/workspacesView.js b/extensions/45/vertical-workspaces/lib/workspacesView.js index 98b3062..8e20db3 100644 --- a/extensions/45/vertical-workspaces/lib/workspacesView.js +++ b/extensions/45/vertical-workspaces/lib/workspacesView.js @@ -3,7 +3,7 @@ * workspacesView.js * * @author GdH <G-dH@github.com> - * @copyright 2022 - 2023 + * @copyright 2022 - 2024 * @license GPL-3.0 * */ @@ -263,6 +263,7 @@ const WorkspacesViewCommon = { adjustments.push(this._workspaces[workspaceIndex]._background._stateAdjustment); } + opt.WORKSPACE_MODE = 1; adjustments.forEach(adj => { if (adj.value === 0) { adj.value = 0; @@ -270,7 +271,6 @@ const WorkspacesViewCommon = { duration: 200, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { - opt.WORKSPACE_MODE = 1; if (callback) callback(); }, @@ -333,12 +333,13 @@ const SecondaryMonitorDisplayVertical = { Math.round(scaledWidth)); }, - _getWorkspacesBoxForState(state, box, padding, thumbnailsWidth, spacing) { + _getWorkspacesBoxForState(state, box, thumbnailsWidth, spacing, startY, panelHeight) { // const { ControlsState } = OverviewControls; const workspaceBox = box.copy(); - const [width, height] = workspaceBox.get_size(); + let [width, height] = workspaceBox.get_size(); + height -= panelHeight; - let wWidth, wHeight, wsbX, wsbY, offset, yShift; + let wWidth, wHeight, wsbX, wsbY, offset; switch (state) { case ControlsState.HIDDEN: break; @@ -347,16 +348,8 @@ const SecondaryMonitorDisplayVertical = { 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); + wHeight = Math.min(wWidth / (width / height), height - 4 * spacing); wWidth = Math.round(wWidth * opt.SEC_WS_PREVIEW_SCALE); wHeight = Math.round(wHeight * opt.SEC_WS_PREVIEW_SCALE); @@ -366,7 +359,7 @@ const SecondaryMonitorDisplayVertical = { else wsbX = offset; - wsbY = Math.round((height - wHeight - Math.abs(yShift)) / 2 + yShift); + wsbY = Math.round((startY + height - wHeight) / 2); workspaceBox.set_origin(wsbX, wsbY); workspaceBox.set_size(wWidth, wHeight); @@ -381,24 +374,31 @@ const SecondaryMonitorDisplayVertical = { const themeNode = this.get_theme_node(); const contentBox = themeNode.get_content_box(box); - const [width, height] = contentBox.get_size(); + let [width, height] = contentBox.get_size(); + let [, startY] = contentBox.get_origin(); + // Save some resources + if (this._startY === undefined) { + this._panelHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0; + startY += opt.SEC_WS_PREVIEW_SHIFT && opt.PANEL_POSITION_TOP ? this._panelHeight : 0; + this._startY = startY; + } + + startY = this._startY; + height -= this._panelHeight; const { expandFraction } = this._thumbnails; const spacing = themeNode.get_length('spacing') * expandFraction; - const padding = Math.round(0.1 * height); let thumbnailsWidth = 0; let thumbnailsHeight = 0; this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN; if (this._thumbnails.visible) { - const reduceBoxHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0; - - thumbnailsWidth = width * opt.SEC_MAX_THUMBNAIL_SCALE; + thumbnailsWidth = Math.round(width * opt.SEC_MAX_THUMBNAIL_SCALE); let totalTmbSpacing; [totalTmbSpacing, thumbnailsHeight] = this._thumbnails.get_preferred_height(thumbnailsWidth); thumbnailsHeight = Math.round(thumbnailsHeight + totalTmbSpacing); - const thumbnailsHeightMax = height - spacing - reduceBoxHeight; + const thumbnailsHeightMax = height - spacing; if (thumbnailsHeight > thumbnailsHeightMax) { thumbnailsHeight = thumbnailsHeightMax; @@ -406,11 +406,11 @@ const SecondaryMonitorDisplayVertical = { } let wsTmbX; - if (opt.SEC_WS_TMB_LEFT) { // left - wsTmbX = spacing / 2; + if (opt.SEC_WS_TMB_LEFT) { + wsTmbX = 0; this._thumbnails._positionLeft = true; } else { - wsTmbX = width - spacing / 2 - thumbnailsWidth; + wsTmbX = width - thumbnailsWidth; this._thumbnails._positionLeft = false; } @@ -418,8 +418,9 @@ const SecondaryMonitorDisplayVertical = { const availSpace = height - thumbnailsHeight; let wsTmbY = availSpace / 2; - wsTmbY -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * wsTmbY; - wsTmbY += opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0; + + wsTmbY -= opt.SEC_WS_TMB_POSITION_ADJUSTMENT * (wsTmbY - spacing / 2); + wsTmbY += startY; childBox.set_origin(Math.round(wsTmbX), Math.round(wsTmbY)); childBox.set_size(thumbnailsWidth, thumbnailsHeight); @@ -431,7 +432,7 @@ const SecondaryMonitorDisplayVertical = { } = this._overviewAdjustment.getStateTransitionParams(); let workspacesBox; - const workspaceParams = [contentBox, padding, thumbnailsWidth, spacing]; + const workspaceParams = [contentBox, thumbnailsWidth, spacing, startY, this._panelHeight]; if (!transitioning) { workspacesBox = this._getWorkspacesBoxForState(currentState, ...workspaceParams); @@ -561,12 +562,13 @@ const SecondaryMonitorDisplayHorizontal = { return { opacity, scale, translationY }; }, - _getWorkspacesBoxForState(state, box, padding, thumbnailsHeight, spacing) { + _getWorkspacesBoxForState(state, box, thumbnailsHeight, spacing, startY, panelHeight) { // const { ControlsState } = OverviewControls; const workspaceBox = box.copy(); - const [width, height] = workspaceBox.get_size(); + let [width, height] = workspaceBox.get_size(); + height -= panelHeight; - let wWidth, wHeight, wsbX, wsbY, offset, yShift; + let wWidth, wHeight, wsbX, wsbY, offset; switch (state) { case ControlsState.HIDDEN: break; @@ -575,26 +577,18 @@ const SecondaryMonitorDisplayHorizontal = { 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); + wHeight = height - (thumbnailsHeight ? thumbnailsHeight + 4 * spacing : 4 * spacing); wWidth = Math.min(wHeight * (width / height), width - 5 * spacing); wWidth = Math.round(wWidth * opt.SEC_WS_PREVIEW_SCALE); wHeight = Math.round(wHeight * opt.SEC_WS_PREVIEW_SCALE); - offset = Math.round((height - thumbnailsHeight - wHeight - Math.abs(yShift)) / 2); + offset = Math.round((height - thumbnailsHeight - wHeight) / 2); if (opt.SEC_WS_TMB_TOP) wsbY = thumbnailsHeight + offset; else wsbY = offset; - wsbY += yShift; + wsbY += startY; wsbX = Math.round((width - wWidth) / 2); workspaceBox.set_origin(wsbX, wsbY); @@ -610,17 +604,24 @@ const SecondaryMonitorDisplayHorizontal = { const themeNode = this.get_theme_node(); const contentBox = themeNode.get_content_box(box); - const [width, height] = contentBox.get_size(); + let [width, height] = contentBox.get_size(); + let [, startY] = contentBox.get_origin(); + // Save some resources + if (this._startY === undefined) { + this._panelHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0; + startY += opt.SEC_WS_PREVIEW_SHIFT && opt.PANEL_POSITION_TOP ? this._panelHeight : 0; + this._startY = startY; + } + startY = this._startY; + height -= this._panelHeight; + const { expandFraction } = this._thumbnails; const spacing = themeNode.get_length('spacing') * expandFraction; - const padding = Math.round(0.1 * height); let thumbnailsWidth = 0; let thumbnailsHeight = 0; this._thumbnails.visible = !opt.SEC_WS_TMB_HIDDEN; if (this._thumbnails.visible) { - const reservedHeight = opt.SEC_WS_PREVIEW_SHIFT && Main.panel.visible ? Main.panel.height : 0; - thumbnailsHeight = height * opt.SEC_MAX_THUMBNAIL_SCALE; let totalTmbSpacing; @@ -636,9 +637,9 @@ const SecondaryMonitorDisplayHorizontal = { let wsTmbY; if (opt.SEC_WS_TMB_TOP) - wsTmbY = spacing / 2 + reservedHeight; + wsTmbY = spacing / 2 + startY; else - wsTmbY = height - spacing / 2 - thumbnailsHeight; + wsTmbY = height - spacing / 2 - thumbnailsHeight + startY; const childBox = new Clutter.ActorBox(); const availSpace = width - thumbnailsWidth; @@ -656,7 +657,7 @@ const SecondaryMonitorDisplayHorizontal = { } = this._overviewAdjustment.getStateTransitionParams(); let workspacesBox; - const workspaceParams = [contentBox, padding, thumbnailsHeight, spacing]; + const workspaceParams = [contentBox, thumbnailsHeight, spacing, startY, this._panelHeight]; if (!transitioning) { workspacesBox = this._getWorkspacesBoxForState(currentState, ...workspaceParams); @@ -759,14 +760,12 @@ const ExtraWorkspaceViewCommon = { exposeWindows() { const adjustment = this._workspace._background._stateAdjustment; + opt.WORKSPACE_MODE = 1; if (adjustment.value === 0) { adjustment.value = 0; adjustment.ease(1, { duration: 200, mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - opt.WORKSPACE_MODE = 1; - }, }); } }, @@ -805,7 +804,7 @@ const WorkspacesDisplayCommon = { upper: 0, // FitMode.SINGLE, }), this._overviewAdjustment); - Main.layoutManager.overviewGroup.add_actor(view); + Main.layoutManager.overviewGroup.add_child(view); } this._workspacesViews.push(view); @@ -906,15 +905,15 @@ const WorkspacesDisplayCommon = { break; case Clutter.KEY_space: if (Me.Util.isCtrlPressed() && Me.Util.isShiftPressed()) { - Me.Util.activateSearchProvider(Me.ESP_PREFIX); + Me.Util.openPreferences(); } else if (Me.Util.isAltPressed()) { Main.ctrlAltTabManager._items.forEach(i => { if (i.sortGroup === 1 && i.name === 'Dash') Main.ctrlAltTabManager.focusGroup(i); }); - } else if (opt.get('recentFilesSearchProviderModule') && Me.Util.isCtrlPressed()) { - Me.Util.activateSearchProvider(Me.RFSP_PREFIX); - } else if (opt.get('windowSearchProviderModule')) { + } else if (Me.Util.getEnabledExtensions('extensions-search-provider').length && Me.Util.isCtrlPressed()) { + Me.Util.activateSearchProvider(Me.ESP_PREFIX); + } else if (Me.Util.getEnabledExtensions('windows-search-provider').length) { Me.Util.activateSearchProvider(Me.WSP_PREFIX); } @@ -924,7 +923,7 @@ const WorkspacesDisplayCommon = { case Clutter.KEY_Right: case Clutter.KEY_Up: case Clutter.KEY_Tab: - if (Main.overview._overview._controls._searchController.searchActive) { + if (Main.overview.searchController.searchActive) { Main.overview.searchEntry.grab_key_focus(); } else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && state === 1) { // expose windows by "clicking" on ws thumbnail |