1
0
Fork 0

Adding 45/vertical-workspaces version 37+20240412 [9b05a79].

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-03-24 19:43:11 +01:00
parent 155878f41e
commit 9a6f4265d9
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
37 changed files with 3192 additions and 3142 deletions

View file

@ -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,

View file

@ -3,7 +3,7 @@
* appFavorites.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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,6 +865,220 @@ const DashIconCommon = {
else
this._dot.hide();
},
/* after__init() {
if (this._updateRunningDotStyle)
this._updateRunningDotStyle();
},*/
_updateRunningDotStyle() {
if (opt.RUNNING_DOT_STYLE)
this._dot.add_style_class_name('app-well-app-running-dot-custom');
else
this._dot.remove_style_class_name('app-well-app-running-dot-custom');
if (!this.label && shellVersion46) {
if (opt.DASH_VERTICAL) {
this._dot.translation_y = 0;
this._dot.translation_x = 0; // opt.DASH_LEFT ? -4 : 4;
} else {
this._dot.translation_y = 8;
this._dot.translation_x = 0;
}
}
},
activate(button) {
const event = Clutter.get_current_event();
const state = event ? event.get_state() : 0;
const isMiddleButton = button && button === Clutter.BUTTON_MIDDLE;
const isCtrlPressed = Me.Util.isCtrlPressed(state);
const isShiftPressed = Me.Util.isShiftPressed(state);
const currentWS = global.workspace_manager.get_active_workspace();
const appRecentWorkspace = this._getAppRecentWorkspace(this.app);
// this feature shouldn't affect search results, dash icons don't have labels, so we use them as a condition
const showWidowsBeforeActivation = opt.DASH_CLICK_ACTION === 1 && !this.icon.label;
let targetWindowOnCurrentWs = false;
if (opt.DASH_FOLLOW_RECENT_WIN) {
targetWindowOnCurrentWs = appRecentWorkspace === currentWS;
} else {
this.app.get_windows().forEach(
w => {
targetWindowOnCurrentWs = targetWindowOnCurrentWs || (w.get_workspace() === currentWS);
}
);
}
const openNewWindow = this.app.can_open_new_window() &&
this.app.state === Shell.AppState.RUNNING &&
(((isCtrlPressed || isMiddleButton) && !opt.DASH_CLICK_OPEN_NEW_WIN) ||
(opt.DASH_CLICK_OPEN_NEW_WIN && !this._selectedMetaWin && !isMiddleButton) ||
((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !targetWindowOnCurrentWs));
if ((this.app.state === Shell.AppState.STOPPED || openNewWindow) && !isShiftPressed)
this.animateLaunch();
if (openNewWindow) {
this.app.open_new_window(-1);
// if DASH_CLICK_ACTION == "SHOW_WINS_BEFORE", the app has more than one window and has no window on the current workspace,
// don't activate the app immediately, only move the overview to the workspace with the app's recent window
} else if (showWidowsBeforeActivation && !isShiftPressed && this.app.get_n_windows() > 1 && !targetWindowOnCurrentWs/* && !(opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE)*/) {
Main.wm.actionMoveWorkspace(appRecentWorkspace);
Main.overview.dash.showAppsButton.checked = false;
return;
} else if (this._selectedMetaWin) {
this._selectedMetaWin.activate(global.get_current_time());
} else if (showWidowsBeforeActivation && opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && !isShiftPressed && this.app.get_n_windows() > 1) {
// expose windows
Main.overview._overview._controls._thumbnailsBox._activateThumbnailAtPoint(0, 0, global.get_current_time(), true);
return;
} else if (((opt.DASH_SHIFT_CLICK_MV && isShiftPressed) || ((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !openNewWindow)) && this.app.get_windows().length) {
this._moveAppToCurrentWorkspace();
if (opt.DASH_ISOLATE_WS) {
this.app.activate();
// hide the overview after the window is re-created
GLib.idle_add(GLib.PRIORITY_LOW, () => Main.overview.hide());
}
return;
} else if (isShiftPressed) {
return;
} else {
this.app.activate();
}
Main.overview.hide();
},
_moveAppToCurrentWorkspace() {
this.app.get_windows().forEach(w => w.change_workspace(global.workspace_manager.get_active_workspace()));
},
popupMenu(side = St.Side.LEFT) {
side = opt.DASH_VERTICAL ? St.Side.LEFT : St.Side.BOTTOM;
// AppIconCommon.popupMenu.bind(this)(side);
this.setForcedHighlight(true);
this._removeMenuTimeout();
this.fake_release();
if (!this._getWindowsOnCurrentWs) {
this._getWindowsOnCurrentWs = function () {
const winList = [];
this.app.get_windows().forEach(w => {
if (w.get_workspace() === global.workspace_manager.get_active_workspace())
winList.push(w);
});
return winList;
};
this._windowsOnOtherWs = function () {
return (this.app.get_windows().length - this._getWindowsOnCurrentWs().length) > 0;
};
}
if (!this._menu) {
this._menu = new AppMenu.AppMenu(this, side, {
favoritesSection: true,
showSingleWindows: true,
});
this._menu.setApp(this.app);
this._openSigId = this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
if (!isPoppedUp)
this._onMenuPoppedDown();
});
// Main.overview.connectObject('hiding',
this._hidingSigId = Main.overview.connect('hiding',
() => this._menu.close(), this);
Main.uiGroup.add_child(this._menu.actor);
this._menuManager.addMenu(this._menu);
}
// once the menu is created, it stays unchanged and we need to modify our items based on current situation
if (this._addedMenuItems && this._addedMenuItems.length)
this._addedMenuItems.forEach(i => i.destroy());
const popupItems = [];
const separator = new PopupMenu.PopupSeparatorMenuItem();
this._menu.addMenuItem(separator);
if (this.app.get_n_windows()) {
// if (/* opt.APP_MENU_FORCE_QUIT*/true) {}
popupItems.push([_('Force Quit'), () => {
this.app.get_windows()[0].kill();
}]);
// if (opt.APP_MENU_CLOSE_WS) {}
const nWin = this._getWindowsOnCurrentWs().length;
if (nWin) {
popupItems.push([_(`Close ${nWin} Windows on Current Workspace`), () => {
const windows = this._getWindowsOnCurrentWs();
let time = global.get_current_time();
for (let win of windows) {
// increase time by 1 ms for each window to avoid errors from GS
win.delete(time++);
}
}]);
}
popupItems.push([_('Move App to Current Workspace ( Shift + Click )'), this._moveAppToCurrentWorkspace]);
// WTMB (Windows Thumbnails) extension required
if (global.windowThumbnails) {
popupItems.push([_('Create Window Thumbnail/PiP'), () => {
global.windowThumbnails?.createThumbnail(this.app.get_windows()[0]);
}]);
}
}
this._addedMenuItems = [];
this._addedMenuItems.push(separator);
popupItems.forEach(i => {
let item = new PopupMenu.PopupMenuItem(i[0]);
this._menu.addMenuItem(item);
item.connect('activate', i[1].bind(this));
if (i[1] === this._moveAppToCurrentWorkspace && !this._windowsOnOtherWs())
item.setSensitive(false);
this._addedMenuItems.push(item);
});
this.emit('menu-state-changed', true);
this._menu.open(BoxPointer.PopupAnimation.FULL);
this._menuManager.ignoreRelease();
this.emit('sync-tooltip');
return false;
},
_getWindowApp(metaWin) {
const tracker = Shell.WindowTracker.get_default();
return tracker.get_window_app(metaWin);
},
_getAppLastUsedWindow(app) {
let recentWin;
global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => {
const winApp = this._getWindowApp(metaWin);
if (!recentWin && winApp === app)
recentWin = metaWin;
});
return recentWin;
},
_getAppRecentWorkspace(app) {
const recentWin = this._getAppLastUsedWindow(app);
if (recentWin)
return recentWin.get_workspace();
return null;
},
};
const DashExtensions = {
@ -1173,305 +1267,6 @@ const AppIconCommon = {
else
this._dot.remove_style_class_name('app-well-app-running-dot-custom');
},
activate(button) {
const event = Clutter.get_current_event();
const state = event ? event.get_state() : 0;
const isMiddleButton = button && button === Clutter.BUTTON_MIDDLE;
const isCtrlPressed = Me.Util.isCtrlPressed(state);
const isShiftPressed = Me.Util.isShiftPressed(state);
const currentWS = global.workspace_manager.get_active_workspace();
const appRecentWorkspace = this._getAppRecentWorkspace(this.app);
// this feature shouldn't affect search results, dash icons don't have labels, so we use them as a condition
const showWidowsBeforeActivation = opt.DASH_CLICK_ACTION === 1 && !this.icon.label;
let targetWindowOnCurrentWs = false;
if (opt.DASH_FOLLOW_RECENT_WIN) {
targetWindowOnCurrentWs = appRecentWorkspace === currentWS;
} else {
this.app.get_windows().forEach(
w => {
targetWindowOnCurrentWs = targetWindowOnCurrentWs || (w.get_workspace() === currentWS);
}
);
}
const openNewWindow = this.app.can_open_new_window() &&
this.app.state === Shell.AppState.RUNNING &&
(((isCtrlPressed || isMiddleButton) && !opt.DASH_CLICK_OPEN_NEW_WIN) ||
(opt.DASH_CLICK_OPEN_NEW_WIN && !this._selectedMetaWin && !isMiddleButton) ||
((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !targetWindowOnCurrentWs));
if ((this.app.state === Shell.AppState.STOPPED || openNewWindow) && !isShiftPressed)
this.animateLaunch();
if (openNewWindow) {
this.app.open_new_window(-1);
// if DASH_CLICK_ACTION == "SHOW_WINS_BEFORE", the app has more than one window and has no window on the current workspace,
// don't activate the app immediately, only move the overview to the workspace with the app's recent window
} else if (showWidowsBeforeActivation && !isShiftPressed && this.app.get_n_windows() > 1 && !targetWindowOnCurrentWs/* && !(opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE)*/) {
Main.wm.actionMoveWorkspace(appRecentWorkspace);
Main.overview.dash.showAppsButton.checked = false;
return;
} else if (this._selectedMetaWin) {
this._selectedMetaWin.activate(global.get_current_time());
} else if (showWidowsBeforeActivation && opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && !isShiftPressed && this.app.get_n_windows() > 1) {
// expose windows
Main.overview._overview._controls._thumbnailsBox._activateThumbnailAtPoint(0, 0, global.get_current_time(), true);
return;
} else if (((opt.DASH_SHIFT_CLICK_MV && isShiftPressed) || ((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !openNewWindow)) && this.app.get_windows().length) {
this._moveAppToCurrentWorkspace();
if (opt.DASH_ISOLATE_WS) {
this.app.activate();
// hide the overview after the window is re-created
GLib.idle_add(GLib.PRIORITY_LOW, () => Main.overview.hide());
}
return;
} else if (isShiftPressed) {
return;
} else {
this.app.activate();
}
Main.overview.hide();
},
_moveAppToCurrentWorkspace() {
this.app.get_windows().forEach(w => w.change_workspace(global.workspace_manager.get_active_workspace()));
},
popupMenu(side = St.Side.LEFT) {
this.setForcedHighlight(true);
this._removeMenuTimeout();
this.fake_release();
if (!this._getWindowsOnCurrentWs) {
this._getWindowsOnCurrentWs = function () {
const winList = [];
this.app.get_windows().forEach(w => {
if (w.get_workspace() === global.workspace_manager.get_active_workspace())
winList.push(w);
});
return winList;
};
this._windowsOnOtherWs = function () {
return (this.app.get_windows().length - this._getWindowsOnCurrentWs().length) > 0;
};
}
if (!this._menu) {
this._menu = new AppMenu.AppMenu(this, side, {
favoritesSection: true,
showSingleWindows: true,
});
this._menu.setApp(this.app);
this._openSigId = this._menu.connect('open-state-changed', (menu, isPoppedUp) => {
if (!isPoppedUp)
this._onMenuPoppedDown();
});
// Main.overview.connectObject('hiding',
this._hidingSigId = Main.overview.connect('hiding',
() => this._menu.close(), this);
Main.uiGroup.add_actor(this._menu.actor);
this._menuManager.addMenu(this._menu);
}
// once the menu is created, it stays unchanged and we need to modify our items based on current situation
if (this._addedMenuItems && this._addedMenuItems.length)
this._addedMenuItems.forEach(i => i.destroy());
const popupItems = [];
const separator = new PopupMenu.PopupSeparatorMenuItem();
this._menu.addMenuItem(separator);
if (this.app.get_n_windows()) {
// if (/* opt.APP_MENU_FORCE_QUIT*/true) {}
popupItems.push([_('Force Quit'), () => {
this.app.get_windows()[0].kill();
}]);
// if (opt.APP_MENU_CLOSE_WS) {}
const nWin = this._getWindowsOnCurrentWs().length;
if (nWin) {
popupItems.push([_(`Close ${nWin} Windows on Current Workspace`), () => {
const windows = this._getWindowsOnCurrentWs();
let time = global.get_current_time();
for (let win of windows) {
// increase time by 1 ms for each window to avoid errors from GS
win.delete(time++);
}
}]);
}
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]);
}]);
}
}
this._addedMenuItems = [];
this._addedMenuItems.push(separator);
popupItems.forEach(i => {
let item = new PopupMenu.PopupMenuItem(i[0]);
this._menu.addMenuItem(item);
item.connect('activate', i[1].bind(this));
if (i[1] === this._moveAppToCurrentWorkspace && !this._windowsOnOtherWs())
item.setSensitive(false);
this._addedMenuItems.push(item);
});
this.emit('menu-state-changed', true);
this._menu.open(BoxPointer.PopupAnimation.FULL);
this._menuManager.ignoreRelease();
this.emit('sync-tooltip');
return false;
},
_getWindowApp(metaWin) {
const tracker = Shell.WindowTracker.get_default();
return tracker.get_window_app(metaWin);
},
_getAppLastUsedWindow(app) {
let recentWin;
global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => {
const winApp = this._getWindowApp(metaWin);
if (!recentWin && winApp === app)
recentWin = metaWin;
});
return recentWin;
},
_getAppRecentWorkspace(app) {
const recentWin = this._getAppLastUsedWindow(app);
if (recentWin)
return recentWin.get_workspace();
return null;
},
};
const 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,
});
this._iconActor = null;
this.icon = new IconGrid.BaseIcon(this.labelText, {
setSizeManually: true,
showLabel: false,
createIcon: this._createIcon.bind(this),
});
this.icon.y_align = Clutter.ActorAlign.CENTER;
this.toggleButton.add_actor(this.icon);
this.toggleButton._delegate = this;
this.setChild(this.toggleButton);
if (opt.SEARCH_WINDOWS_ICON_SCROLL) {
this.reactive = true;
this._scrollConId = this.connect('scroll-event', DashExtensions.onScrollEvent.bind(this));
this._leaveConId = this.connect('leave-event', DashExtensions.onLeaveEvent.bind(this));
}
},
_createIcon(size) {
this._iconActor = new St.Icon({
icon_name: 'focus-windows-symbolic',
icon_size: size,
style_class: 'show-apps-icon',
track_hover: true,
});
return this._iconActor;
},
};
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;
this.toggleButton.add_actor(this.icon);
this.toggleButton._delegate = this;
this.setChild(this.toggleButton);
},
_createIcon(size) {
this._iconActor = new St.Icon({
icon_name: 'document-open-recent-symbolic',
icon_size: size,
style_class: 'show-apps-icon',
track_hover: true,
});
return this._iconActor;
},
};
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,
});
this._iconActor = null;
this.icon = new IconGrid.BaseIcon(this.labelText, {
setSizeManually: true,
showLabel: false,
createIcon: this._createIcon.bind(this),
});
this.icon.y_align = Clutter.ActorAlign.CENTER;
this.toggleButton.add_actor(this.icon);
this.toggleButton._delegate = this;
this.setChild(this.toggleButton);
},
_createIcon(size) {
this._iconActor = new St.Icon({
icon_name: 'application-x-addon-symbolic',
icon_size: size,
style_class: 'show-apps-icon',
track_hover: true,
});
return this._iconActor;
},
};
const AppMenuCommon = {

View file

@ -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();
}
});

View file

@ -3,7 +3,7 @@
* iconGrid.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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;

View file

@ -3,7 +3,7 @@
* messageTray.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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;
}

View file

@ -3,7 +3,7 @@
* osdWindow.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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

View file

@ -3,7 +3,7 @@
* overview.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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();

View file

@ -3,7 +3,7 @@
* panel.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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.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.appInfo = appInfo;
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 {

View file

@ -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('');
},
};

View file

@ -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');

View file

@ -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() {

View file

@ -3,7 +3,7 @@
* swipeTracker.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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));
}

View file

@ -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;
},
});
}
}
});

View file

@ -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);

View file

@ -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);
},
};

View file

@ -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)))
)

View file

@ -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));
}
}

View file

@ -3,7 +3,7 @@
* workspace.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -3,7 +3,7 @@
* workspacesAnimation.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2023
* @copyright 2022 - 2024
* @license GPL-3.0
*
*/

View file

@ -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);

View file

@ -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;

View file

@ -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