1
0
Fork 0

Updating 47/vertical-workspaces to version 47.5+20250210 [b14ba3cf].

Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
Daniel Baumann 2025-03-24 19:45:01 +01:00
parent 297ae772ab
commit 6b0458069f
Signed by: daniel
GPG key ID: FBB4F0E80A80222F
26 changed files with 5479 additions and 3202 deletions

View file

@ -71,6 +71,12 @@ export const AppDisplayModule = class {
this._appGridLayoutConId = 0;
this._origAppViewItemAcceptDrop = null;
this._updateFolderIcons = 0;
// By default appDisplay.name (which can be used to address styling) is not set
// In GS 46+ we need to adapt the appDisplay style even if the appDisplay module is disabled,
// to allow the use of wallpaper in the overview
if (shellVersion46)
Main.overview._overview.controls._appDisplay.name = 'app-display';
}
cleanGlobals() {
@ -78,6 +84,7 @@ export const AppDisplayModule = class {
opt = null;
_ = null;
_appDisplay = null;
Main.overview._overview.controls._appDisplay.name = null;
}
update(reset) {
@ -111,7 +118,6 @@ export const AppDisplayModule = class {
this._applyOverrides();
this._updateAppDisplay();
_appDisplay.add_style_class_name('app-display-46');
console.debug(' AppDisplayModule - Activated');
}
@ -127,8 +133,6 @@ export const AppDisplayModule = class {
this._updateAppDisplay(reset);
this._restoreOverviewGroup();
_appDisplay.remove_style_class_name('app-display-46');
console.debug(' AppDisplayModule - Disabled');
}
@ -363,7 +367,7 @@ const AppDisplayCommon = {
},
// apps load adapted for custom sorting and including dash items
_loadApps() {
_loadApps(results) {
let appIcons = [];
const runningApps = Shell.AppSystem.get_default().get_running().map(a => a.id);
@ -387,7 +391,7 @@ const AppDisplayCommon = {
const appsInsideFolders = new Set();
this._folderIcons = [];
if (!opt.APP_GRID_USAGE) {
if (!(opt.APP_GRID_USAGE || results)) {
let folders = this._folderSettings.get_strv('folder-children');
folders.forEach(id => {
let path = `${this._folderSettings.path}folders/${id}/`;
@ -589,9 +593,15 @@ const BaseAppViewCommon = {
this._swipeTracker.orientation = orientation;
this._swipeTracker._reset();
this._adjustment = vertical
? this._scrollView.get_vscroll_bar().adjustment
: this._scrollView.get_hscroll_bar().adjustment;
if (this._scrollView.get_vadjustment) {
this._adjustment = vertical
? this._scrollView.get_vadjustment()
: this._scrollView.get_hadjustment();
} else {
this._adjustment = vertical
? this._scrollView.get_vscroll_bar().adjustment
: this._scrollView.get_hscroll_bar().adjustment;
}
this._prevPageArrow.pivot_point = new Graphene.Point({ x: 0.5, y: 0.5 });
this._prevPageArrow.rotation_angle_z = vertical ? 90 : 0;
@ -680,8 +690,8 @@ const BaseAppViewCommon = {
this._grid.layoutManager._shouldEaseItems = false;
},
// Adds sorting options
_redisplay() {
// Adds sorting options / support app search provider
_redisplay(results) {
// different options for main app grid and app folders
const thisIsFolder = this instanceof AppDisplay.FolderView;
const thisIsAppDisplay = !thisIsFolder;
@ -699,7 +709,7 @@ const BaseAppViewCommon = {
const oldApps = this._orderedItems.slice();
const oldAppIds = oldApps.map(icon => icon.id);
const newApps = this._loadApps();
const newApps = this._loadApps(results);
const newAppIds = newApps.map(icon => icon.id);
const addedApps = newApps.filter(icon => !oldAppIds.includes(icon.id));
@ -719,7 +729,10 @@ const BaseAppViewCommon = {
let allowIncompletePages = thisIsAppDisplay && opt.APP_GRID_ALLOW_INCOMPLETE_PAGES;
const customOrder = !((opt.APP_GRID_ORDER && thisIsAppDisplay) || (opt.APP_FOLDER_ORDER && thisIsFolder));
if (!customOrder) {
if (results) {
newApps.sort((a, b) => results.indexOf(a.app?.id) - results.indexOf(b.app?.id));
} else if (!customOrder) {
allowIncompletePages = false;
// Sort by name
@ -770,7 +783,7 @@ const BaseAppViewCommon = {
});
// When a placeholder icon was added to the custom sorted grid during DND from a folder
// update its initial position on the page
if (customOrder)
if (customOrder && !results)
newApps.sort(this._compareItems.bind(this));
this._orderedItems = newApps;
@ -1086,11 +1099,7 @@ const AppGridCommon = {
const FolderIcon = {
after__init() {
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');
this.button_mask = St.ButtonMask.ONE | St.ButtonMask.TWO | St.ButtonMask.THREE;
},
open() {
@ -1368,6 +1377,9 @@ const AppFolderDialog = {
});
this.child.add_action(clickAction);
// Redundant, added just because of extensions.gnome.org rules
this.connect('destroy', this._removePopdownTimeout.bind(this));
this._viewBox.add_style_class_name('app-folder-dialog-translucent');
},
after__addFolderNameEntry() {
@ -1496,6 +1508,14 @@ const AppFolderDialog = {
});
},
_removePopdownTimeout() {
if (this._popdownTimeoutId === 0)
return;
GLib.source_remove(this._popdownTimeoutId);
this._popdownTimeoutId = 0;
},
vfunc_allocate(box) {
this._updateFolderSize();
@ -1788,7 +1808,11 @@ const AppFolderDialog = {
opacity: 0,
});
// Add a short delay to account for the dialog update time
// and prevent incomplete animation that disrupts the user experience
const delay = 20;
this.child.ease({
delay,
translation_x: dialogOffsetX,
translation_y: dialogOffsetY,
scale_x: 1,
@ -1799,6 +1823,7 @@ const AppFolderDialog = {
});
appDisplay.ease({
delay,
opacity: 0,
duration: FOLDER_DIALOG_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,

View file

@ -362,13 +362,13 @@ const DashItemContainerCommon = {
y = stageY - this.label.height - yOffset;
} else if (opt.DASH_RIGHT) {
const yOffset = Math.floor((itemHeight - labelHeight) / 2);
xOffset = shellVersion46 ? 8 : 4;
xOffset = shellVersion46 && opt.DASH_BG_GS3_STYLE ? 12 : 0;
x = stageX - xOffset - this.label.width;
y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight);
} else if (opt.DASH_LEFT) {
const yOffset = Math.floor((itemHeight - labelHeight) / 2);
xOffset = shellVersion46 ? 8 : 4;
xOffset = shellVersion46 && opt.DASH_BG_GS3_STYLE ? 12 : 0;
x = stageX + this.width + xOffset;
y = Math.clamp(stageY + yOffset, 0, global.stage.height - labelHeight);
@ -864,60 +864,53 @@ const AppIconCommon = {
activate(button) {
const event = Clutter.get_current_event();
const state = event ? event.get_state() : 0;
const isMiddleButton = button && button === Clutter.BUTTON_MIDDLE;
const isCtrlPressed = Me.Util.isCtrlPressed(state);
const isShiftPressed = Me.Util.isShiftPressed(state);
const currentWS = global.workspace_manager.get_active_workspace();
const isCtrlPressed = Me.Util.isCtrlPressed(state);
const appIsRunning = this.app.state === Shell.AppState.RUNNING;
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;
const targetWindowOnCurrentWs = this._isTargetWindowOnCurrentWs(appRecentWorkspace);
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._shouldOpenNewWindow(appIsRunning, button, isShiftPressed, isCtrlPressed, targetWindowOnCurrentWs);
const staticWorkspace = !opt.WORKSPACE_MODE;
const nWindows = appIsRunning ? this.app.get_n_windows() : 0;
// This feature shouldn't affect search results. Dash icons lack labels, so their absence is used as a condition
const showWidowsBeforeActivation =
opt.DASH_CLICK_ACTION === 1 && !this.icon.label &&
!isShiftPressed && nWindows > 1;/* &&
!(opt.DASH_ISOLATE_WS || opt.DASH_CLICK_OPEN_NEW_WIN || opt.DASH_CLICK_PREFER_WORKSPACE);*/
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)
if ((!appIsRunning || 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) {
// 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) {
if (!targetWindowOnCurrentWs) {
Main.wm.actionMoveWorkspace(appRecentWorkspace);
Main.overview.dash.showAppsButton.checked = false;
// Activate the app to ensure it appears above all other apps in static workspace mode
this.app.activate();
return;
} else if (staticWorkspace) {
// spread windows
Me.Util.exposeWindows();
return;
} else {
this.app.activate();
}
} else if (this._shouldMoveToCurrentWorkspace(isShiftPressed, openNewWindow, targetWindowOnCurrentWs, nWindows)) {
this._moveAppToCurrentWorkspace();
if (opt.DASH_ISOLATE_WS) {
if ((opt.DASH_ISOLATE_WS || opt.DASH_CLICK_PREFER_WORKSPACE) && !isShiftPressed) {
this.app.activate();
// hide the overview after the window is re-created
GLib.idle_add(GLib.PRIORITY_LOW, () => Main.overview.hide());
return;
}
return;
} else if (isShiftPressed) {
return;
} else {
this.app.activate();
}
@ -925,6 +918,35 @@ const AppIconCommon = {
Main.overview.hide();
},
_shouldOpenNewWindow(appIsRunning, button, isShiftPressed, isCtrlPressed, targetWindowOnCurrentWs) {
const isMiddleButton = button && button === Clutter.BUTTON_MIDDLE;
return this.app.can_open_new_window() &&
appIsRunning && !isShiftPressed &&
(((isCtrlPressed || isMiddleButton) && !opt.DASH_CLICK_OPEN_NEW_WIN) ||
(opt.DASH_CLICK_OPEN_NEW_WIN && !isMiddleButton) ||
((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !targetWindowOnCurrentWs));
},
_isTargetWindowOnCurrentWs(appRecentWorkspace) {
const currentWS = global.workspace_manager.get_active_workspace();
if (opt.DASH_FOLLOW_RECENT_WIN)
return appRecentWorkspace === currentWS;
let targetWindowOnCurrentWs = false;
this.app.get_windows().forEach(
w => {
targetWindowOnCurrentWs = targetWindowOnCurrentWs || (w.get_workspace() === currentWS);
}
);
return targetWindowOnCurrentWs;
},
_shouldMoveToCurrentWorkspace(isShiftPressed, openNewWindow, targetWindowOnCurrentWs, nWindows) {
return ((opt.DASH_SHIFT_CLICK_MV && isShiftPressed) ||
((opt.DASH_CLICK_PREFER_WORKSPACE || opt.DASH_ISOLATE_WS) && !openNewWindow && !targetWindowOnCurrentWs)) &&
nWindows > 0;
},
_moveAppToCurrentWorkspace() {
this.app.get_windows().forEach(w => w.change_workspace(global.workspace_manager.get_active_workspace()));
},
@ -972,51 +994,55 @@ const AppIconCommon = {
if (this._addedMenuItems && this._addedMenuItems.length)
this._addedMenuItems.forEach(i => i.destroy());
const popupItems = [];
const separator = new PopupMenu.PopupSeparatorMenuItem();
this._menu.addMenuItem(separator);
this._addedMenuItems = [];
if (this.app.get_n_windows()) {
// if (/* opt.APP_MENU_FORCE_QUIT*/true) {}
popupItems.push([_('Force Quit'), () => {
this.app.get_windows()[0].kill();
}]);
// if (opt.APP_MENU_CLOSE_WS) {}
const nWin = this._getWindowsOnCurrentWs().length;
if (nWin) {
popupItems.push([_(`Close ${nWin} Windows on Current Workspace`), () => {
const windows = this._getWindowsOnCurrentWs();
let time = global.get_current_time();
for (let win of windows) {
// increase time by 1 ms for each window to avoid errors from GS
win.delete(time++);
}
}]);
if (opt.APP_MENU_FORCE_QUIT) {
const item = new PopupMenu.PopupMenuItem(_('Force Quit'));
item.connect('activate', () => this.app.get_windows()[0].kill());
this._menu.addMenuItem(item);
this._addedMenuItems.push(item);
}
if (opt.APP_MENU_CLOSE_WINS_WS) {
const nWin = this._getWindowsOnCurrentWs().length;
if (nWin) {
const item = new PopupMenu.PopupMenuItem(_(`Close ${nWin} Windows on Current Workspace`));
item.connect('activate', () => {
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++);
}
});
this._menu.addMenuItem(item);
this._addedMenuItems.push(item);
}
}
const separator = new PopupMenu.PopupSeparatorMenuItem();
this._menu.addMenuItem(separator);
this._addedMenuItems.push(separator);
if (opt.APP_MENU_MOVE_APP) {
const item = new PopupMenu.PopupMenuItem(_('Move App to Current Workspace [Shift + Click]'));
item.connect('activate', this._moveAppToCurrentWorkspace.bind(this));
this._menu.addMenuItem(item);
this._addedMenuItems.push(item);
if (!this._windowsOnOtherWs())
item.setSensitive(false);
}
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]);
}]);
if (opt.APP_MENU_WINDOW_TMB && global.windowThumbnails) {
const item = new PopupMenu.PopupMenuItem(_('Create Window Thumbnail (PiP)'));
item.connect('activate', () => global.windowThumbnails?.createThumbnail(this.app.get_windows()[0]));
this._menu.addMenuItem(item);
this._addedMenuItems.push(item);
}
}
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);

View file

@ -280,7 +280,7 @@ export const ItemFactory = class ItemFactory {
box.is_profile_box = true;
const entry = new Gtk.Entry({
width_chars: 40,
width_chars: 45,
halign: Gtk.Align.END,
valign: Gtk.Align.CENTER,
hexpand: true,

View file

@ -125,16 +125,20 @@ const OverviewCommon = {
}
this._syncGrab();
if (controls._stateAdjustment.value <= 1 && !controls._searchController.searchActive)
Me.Util.activateKeyboardForWorkspaceView();
},
// Workaround - should probably be fixed elsewhere in the upstream code
// If a new window is opened from the overview
// and is realized before the overview animation is complete,
// the new window will not get focus
after__hideDone() {
this.resetOverviewMode();
if (!opt.FIX_NEW_WINDOW_FOCUS)
return;
// Workaround - should probably be fixed elsewhere in the upstream code
// If a new window is opened from the overview
// and is realized before the overview animation is complete,
// the new window will not get focus
const workspace = global.workspace_manager.get_active_workspace();
const recentDesktopWin = global.display.get_tab_list(1, workspace)[0];
let recentNormalWin = null;
@ -160,3 +164,4 @@ const OverviewCommon = {
recentWin.activate(global.get_current_time());
},
};

View file

@ -33,6 +33,7 @@ const FitMode = WorkspacesView.FitMode;
const STARTUP_ANIMATION_TIME = 500;
const ANIMATION_TIME = Overview.ANIMATION_TIME;
const SIDE_CONTROLS_ANIMATION_TIME = 250; // OverviewControls.SIDE_CONTROLS_ANIMATION_TIME = Overview.ANIMATION_TIME = 250
const DASH_MAX_SIZE_RATIO = 0.35;
let _timeouts;
@ -157,9 +158,16 @@ export const OverviewControlsModule = class {
this._clickEmptyConId = 0;
}
if (this._tmbBoxClickConnection) {
Main.overview._overview.controls._thumbnailsBox.disconnect(this._tmbBoxClickConnection);
this._tmbBoxClickConnection = 0;
}
if (reset || !opt.CLICK_EMPTY_CLOSE)
return;
this._tmbBoxClickConnection = Main.overview._overview.controls._thumbnailsBox.connect('button-release-event', () => Clutter.EVENT_STOP);
overview.reactive = true;
this._clickEmptyConId = overview.connect('button-release-event', (actor, event) => {
const button = event.get_button();
@ -181,6 +189,9 @@ const ControlsManagerCommon = {
}*/
prepareToEnterOverview() {
// set
this.set_child_above_sibling(this._workspacesDisplay, null);
this._searchController.prepareToEnterOverview();
this._workspacesDisplay.prepareToEnterOverview();
// Workaround for thumbnailsBox not re-scaling after switching workspace outside of overview using a trackpad
@ -194,8 +205,14 @@ const ControlsManagerCommon = {
else if (this._bgManagers && !(opt.SHOW_BG_IN_OVERVIEW || !opt.SHOW_WS_PREVIEW_BG))
this._setBackground(true);
// Force updating the app grid order
if (opt.APP_GRID_USAGE)
this._appDisplay._redisplay();
// store pointer X coordinate for OVERVIEW_MODE 1 - to prevent immediate switch to WORKSPACE_MODE 1 if the mouse pointer is steady
opt.showingPointerX = global.get_pointer()[0];
this._updateSearchStyle();
},
// this function has duplicate in WorkspaceView so we use one function for both to avoid issues with syncing them
@ -274,10 +291,12 @@ const ControlsManagerCommon = {
const skipDash = Me.Util.dashNotDefault();
// OVERVIEW_MODE 2 should animate dash and wsTmbBox only if WORKSPACE_MODE === 0 (windows not spread)
const animateOverviewMode2 = opt.OVERVIEW_MODE2 && !(finalState === 1 && opt.WORKSPACE_MODE);
const animateOverviewMode2 = opt.OVERVIEW_MODE2 && !(finalState === 1 && opt.WORKSPACE_MODE && !Main.overview.animationInProgress);
if (!Main.layoutManager._startingUp && ((!opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2) || animateOverviewMode2)) {
if (!tmbBox._translationOriginal || Math.abs(tmbBox._translationOriginal[0]) > 500) { // swipe gesture can call this calculation before tmbBox is realized, giving nonsense width
const [dashTranslationX, dashTranslationY, tmbTranslationX, tmbTranslationY, searchTranslationY] = this._getOverviewTranslations(dash, tmbBox, searchEntryBin);
if (!tmbBox._translationOriginal || Math.abs(tmbBox._translationOriginal[0]) > 500) {
// swipe gesture can call this calculation before tmbBox gets its allocation, giving nonsense width
const [dashTranslationX, dashTranslationY, tmbTranslationX, tmbTranslationY, searchTranslationY] =
this._getOverviewTranslations(dash, tmbBox, searchEntryBin);
tmbBox._translationOriginal = [tmbTranslationX, tmbTranslationY];
dash._translationOriginal = [dashTranslationX, dashTranslationY];
searchEntryBin._translationOriginal = searchTranslationY;
@ -322,9 +341,6 @@ const ControlsManagerCommon = {
} else {
this._workspacesDisplay.scale_x = 1;
}
if (opt.LEAVING_SEARCH && currentState <= ControlsState.WINDOW_PICKER) {
opt.LEAVING_SEARCH = false;
}
this._workspacesDisplay.setPrimaryWorkspaceVisible(workspacesDisplayVisible);
@ -361,16 +377,14 @@ const ControlsManagerCommon = {
stateTransitionParams = this._stateAdjustment.getStateTransitionParams();
const { currentState } = stateTransitionParams;
if (this.dash.showAppsButton.checked)
this._searchTransition = false;
// if !APP_GRID_ANIMATION, appGrid needs to be hidden in WINDOW_PICKER mode (1)
// but needs to be visible for transition from HIDDEN (0) to APP_GRID (2)
this._appDisplay.visible =
currentState > ControlsState.HIDDEN &&
!this._searchController.searchActive &&
currentState > ControlsState.HIDDEN && this._appDisplay.opacity > 0 &&
(!this._searchController.searchActive || (opt.SEARCH_APP_GRID_MODE && this.dash.showAppsButton.checked)) &&
!(currentState === ControlsState.WINDOW_PICKER && !opt.APP_GRID_ANIMATION) &&
!this._searchTransition;
!this._searchInProgress;
},
_activateSearchAppGridMode() {
@ -387,7 +401,6 @@ const ControlsManagerCommon = {
opt.APP_GRID_EXCLUDE_FAVORITES = false;
opt.APP_GRID_EXCLUDE_RUNNING = false;
this._appDisplay._grid.layoutManager.allowIncompletePages = false;
this._appDisplay._redisplay();
}
},
@ -405,19 +418,79 @@ const ControlsManagerCommon = {
this._appDisplay._grid.layoutManager.allowIncompletePages = this._origAppGridContent.incompletePages;
this._origAppGridContent = null;
this._appDisplay._redisplay();
this._searchInProgress = false;
}
},
_searchAppGridMode(searchActive) {
const appSearchModeActive = opt.SEARCH_APP_GRID_MODE && this.dash.showAppsButton.checked;
if (searchActive && appSearchModeActive)
this._activateSearchAppGridMode();
else
this._deactivateSearchAppGridMode();
return appSearchModeActive;
},
_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 { finalState } = this._stateAdjustment.getStateTransitionParams();
const { searchActive } = this._searchController;
const SIDE_CONTROLS_ANIMATION_TIME = 250; // OverviewControls.SIDE_CONTROLS_ANIMATION_TIME = Overview.ANIMATION_TIME = 250
this._updateSearchEntryVisibility(searchActive);
// If the user starts typing or activates the search provider during the overview animation,
// this function will be called again after the overview animation finishes
if (opt.SEARCH_VIEW_ANIMATION && Main.overview._animationInProgress && finalState === ControlsState.WINDOW_PICKER)
return;
this._updateSearchStyle();
this._searchInProgress = true;
if (this._searchAppGridMode(searchActive) && searchActive)
return;
if (opt.SHOW_BG_IN_OVERVIEW && this._bgManagers)
this._updateBackground(this._bgManagers[0]);
this._fadeWorkspaces(searchActive);
this._fadeSearchResults(searchActive);
this._fadeAppDisplay(searchActive);
// reuse overview transition, just replace APP_GRID with the search view
this._shiftOverviewStateIfNeeded(searchActive, finalState);
this._animateSearchResultsIfNeeded(searchActive);
},
_shiftOverviewStateIfNeeded(searchActive, finalState) {
if ((opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) ||
Main.overview._animationInProgress ||
finalState === ControlsState.HIDDEN ||
this.dash.showAppsButton.checked)
return;
// Delay to allow the workspace preview to fade out instead of animating
const delay = searchActive && !opt.SEARCH_VIEW_ANIMATION ? opt.SEARCH_DELAY : 0;
// duration: 0 skips the delay for some reason
// Animation needs to be shorter than the search delay to avoid stuttering
const inDuration = 1;
const outDuration = opt.SEARCH_VIEW_ANIMATION ? SIDE_CONTROLS_ANIMATION_TIME : 1;
this._stateAdjustment.ease(searchActive ? ControlsState.APP_GRID : ControlsState.WINDOW_PICKER, {
// shorter animation time when entering search view can avoid stuttering in transition
// collecting search results take some time and the problematic part is the realization of the object on the screen
// if the ws animation ends before this event, the whole transition is smoother
// removing the ws transition (duration: 0) seems like the best solution here
delay,
duration: searchActive ? inDuration : outDuration,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onStopped: () => {
this._searchInProgress = searchActive;
this._workspacesDisplay.setPrimaryWorkspaceVisible(true);
},
});
},
_updateSearchEntryVisibility(searchActive) {
const entry = this._searchEntry;
entry.remove_all_transitions();
if (opt.SHOW_SEARCH_ENTRY) {
entry.visible = true;
entry.opacity = 255;
@ -429,141 +502,121 @@ const ControlsManagerCommon = {
opacity: searchActive ? 255 : 0,
duration: SIDE_CONTROLS_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
onStopped: () => {
entry.visible = searchActive;
entry.opacity = 255;
},
});
}
},
// if user start typing or activated search provider during overview animation, this switcher will be called again after animation ends
if (opt.SEARCH_VIEW_ANIMATION && Main.overview._animationInProgress && finalState !== ControlsState.HIDDEN)
return;
_fadeSearchResults(searchActive) {
this._searchController.opacity = 255;
this._searchController._searchResults.opacity = searchActive ? 0 : 255;
if (searchActive)
this._searchController.visible = searchActive;
else // hide "No search results" during transition
this._searchController.opacity = 1;
if (!searchActive) {
if (!this.dash.showAppsButton.checked)
opt.LEAVING_SEARCH = true;
this._searchController._searchResults.ease({
opacity: searchActive ? 255 : 0,
duration: SIDE_CONTROLS_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onStopped: () => {
this._searchController.visible = searchActive;
if ((opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) || this.dash.showAppsButton.checked)
this._searchInProgress = searchActive;
this._updateAppDisplayVisibility();
},
});
},
if (this._origAppGridContent)
this._deactivateSearchAppGridMode();
this._workspacesDisplay.reactive = true;
this._workspacesDisplay.setPrimaryWorkspaceVisible(true);
_fadeWorkspaces(searchActive) {
if (/* searchActive &&*/ !opt.SEARCH_VIEW_ANIMATION && !(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)) {
this._workspacesDisplay.reactive = false;
this._workspacesDisplay.ease({
opacity: searchActive ? 0 : 255,
// duration needs to be short enough to complete before the search results load, preventing stuttering
duration: searchActive ? opt.SEARCH_DELAY : 150,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
} else {
if (opt.SEARCH_APP_GRID_MODE && this.dash.showAppsButton.checked) {
this._activateSearchAppGridMode();
return;
}
if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)
this._searchController._searchResults._statusText.add_style_class_name('search-statustext-om2');
else
this._searchController._searchResults._statusText.remove_style_class_name('search-statustext-om2');
this._searchController.show();
entry.visible = true;
entry.opacity = 255;
opt.LEAVING_SEARCH = false;
this._workspacesDisplay.setPrimaryWorkspaceVisible(true);
this._workspacesDisplay.opacity = 255;
this._workspacesDisplay.reactive = true;
}
},
if (opt.SHOW_BG_IN_OVERVIEW && this._bgManagers)
this._updateBackground(this._bgManagers[0]);
this._searchTransition = true;
this._searchController._searchResults.translation_x = 0;
this._searchController._searchResults.translation_y = 0;
this._searchController.visible = true;
_fadeAppDisplay(searchActive) {
if (this.dash.showAppsButton.checked) {
this._appDisplay.visible = true;
if (opt.SEARCH_VIEW_ANIMATION && ![4, 8].includes(opt.WS_TMB_POSITION)) {
this._updateAppDisplayVisibility();
this._searchController._searchResults._statusBin.opacity = 1;
let translationX = 0;
let translationY = 0;
const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor());
switch (opt.SEARCH_VIEW_ANIMATION) {
case 1:
// make it longer to cover the delay before results appears
translationX = geometry.width;
translationY = 0;
break;
case 2:
translationX = -geometry.width;
translationY = 0;
break;
case 3:
translationX = 0;
translationY = geometry.height;
break;
case 5:
translationX = 0;
translationY = -geometry.height;
break;
}
if (searchActive) {
this._searchController._searchResults.translation_x = translationX;
this._searchController._searchResults.translation_y = translationY;
} else {
this._searchController._searchResults.translation_x = 0;
this._searchController._searchResults.translation_y = 0;
}
this._searchController._searchResults.ease({
delay: 150, // wait for results
opacity: searchActive ? 255 : 0,
translation_x: searchActive ? 0 : translationX,
translation_y: searchActive ? 0 : translationY,
this._appDisplay.ease({
opacity: searchActive ? 1 : 255,
duration: SIDE_CONTROLS_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._searchController.visible = searchActive;
this._searchTransition = false;
this._searchController._searchResults._statusBin.opacity = 255;
},
});
this._workspacesDisplay.opacity = 255;
} else {
this._appDisplay.ease({
opacity: searchActive || currentState < 2 ? 0 : 255,
duration: SIDE_CONTROLS_ANIMATION_TIME / 2,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._updateAppDisplayVisibility();
},
});
this._workspacesDisplay.setPrimaryWorkspaceVisible(true);
this._searchController._searchResults.ease({
opacity: searchActive ? 255 : 0,
duration: searchActive ? SIDE_CONTROLS_ANIMATION_TIME / 2 : 0,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => (this._searchController.visible = searchActive),
});
}
},
// reuse already tuned overview transition, just replace APP_GRID with the search view
if (!(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) && !Main.overview._animationInProgress && finalState !== ControlsState.HIDDEN && !this.dash.showAppsButton.checked) {
this._searchController._searchResults._content.remove_style_class_name('search-section-content-bg-om2');
this._searchEntry.remove_style_class_name('search-entry-om2');
const duration = opt.SEARCH_VIEW_ANIMATION ? 140 : 0;
this._stateAdjustment.ease(searchActive ? ControlsState.APP_GRID : ControlsState.WINDOW_PICKER, {
// shorter animation time when entering search view can avoid stuttering in transition
// collecting search results take some time and the problematic part is the realization of the object on the screen
// if the ws animation ends before this event, the whole transition is smoother
// removing the ws transition (duration: 0) seems like the best solution here
duration: searchActive ? duration : SIDE_CONTROLS_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._workspacesDisplay.setPrimaryWorkspaceVisible(!searchActive);
// Set the delay before processing a new search entry to 150 on deactivation, so search providers can't make make the workspace animation stuttering
// set it back to 0 after in-animation, so the search can be snappy
opt.SEARCH_DELAY = searchActive || !opt.SEARCH_VIEW_ANIMATION ? 0 : 150;
},
});
} else if (opt.OVERVIEW_MODE2 && !(opt.WORKSPACE_MODE || this.dash.showAppsButton.checked)) {
// add background to search results and make searchEntry border thicker for better visibility
_animateSearchResultsIfNeeded(searchActive) {
if (!opt.SEARCH_VIEW_ANIMATION) {
this._searchController._searchResults.translation_x = 0;
this._searchController._searchResults.translation_y = 0;
return;
}
this._searchController._searchResults._statusBin.opacity = 1;
let translationX = 0;
let translationY = 0;
const geometry = global.display.get_monitor_geometry(global.display.get_primary_monitor());
switch (opt.SEARCH_VIEW_ANIMATION) {
case 1:
// make it longer to cover the delay before results appears
translationX = geometry.width;
translationY = 0;
break;
case 2:
translationX = -geometry.width;
translationY = 0;
break;
case 3:
translationX = 0;
translationY = geometry.height;
break;
case 5:
translationX = 0;
translationY = -geometry.height;
break;
}
if (searchActive) {
this._searchController._searchResults.translation_x = translationX;
this._searchController._searchResults.translation_y = translationY;
} else {
this._searchController._searchResults.translation_x = 0;
this._searchController._searchResults.translation_y = 0;
}
this._searchController._searchResults.ease({
delay: 150, // wait for results
opacity: searchActive ? 255 : 0,
translation_x: searchActive ? 0 : translationX,
translation_y: searchActive ? 0 : translationY,
duration: SIDE_CONTROLS_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
this._searchController.visible = searchActive;
this._searchController._searchResults._statusBin.opacity = 255;
},
});
},
_updateSearchStyle(reset) {
if (!reset && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && !this.dash.showAppsButton.checked)) {
this._searchController._searchResults._content.add_style_class_name('search-section-content-bg-om2');
this._searchEntry.add_style_class_name('search-entry-om2');
} else {
@ -618,9 +671,9 @@ const ControlsManagerCommon = {
const [dashTranslationX, dashTranslationY, tmbTranslationX, tmbTranslationY, searchTranslationY] =
this._getOverviewTranslations(dash, tmbBox, searchEntryBin);
const onComplete = function () {
const onStopped = function () {
// running init callback again causes issues (multiple connections)
if (!Main.overview._startupInitComplete)
if (callback && !Main.overview._startupInitComplete)
callback();
const appDisplayModule = Me.Modules.appDisplayModule;
@ -632,34 +685,6 @@ const ControlsManagerCommon = {
Main.overview._startupInitComplete = true;
}.bind(this);
if (dash.visible && !Me.Util.dashNotDefault()) {
dash.translation_x = dashTranslationX;
dash.translation_y = dashTranslationY;
dash.opacity = 255;
dash.ease({
translation_x: 0,
translation_y: 0,
delay: STARTUP_ANIMATION_TIME / 2,
duration: STARTUP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete,
});
} else {
// set dash opacity to make it visible if user enable it later
dash.opacity = 255;
// if dash is hidden, substitute the ease timeout with GLib.timeout
_timeouts.startupAnim2 = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
// delay + animation time
STARTUP_ANIMATION_TIME * 2 * St.Settings.get().slow_down_factor,
() => {
onComplete();
_timeouts.startupAnim2 = 0;
return GLib.SOURCE_REMOVE;
}
);
}
if (searchEntryBin.visible) {
searchEntryBin.translation_y = searchTranslationY;
searchEntryBin.ease({
@ -710,6 +735,69 @@ const ControlsManagerCommon = {
}
}
}
if (dash.visible && !Me.Util.dashNotDefault()) {
dash.translation_x = dashTranslationX;
dash.translation_y = dashTranslationY;
dash.opacity = 255;
if (!callback) { // GS 47+
return new Promise(resolve => {
dash.ease({
translation_x: 0,
translation_y: 0,
delay: STARTUP_ANIMATION_TIME / 2,
duration: STARTUP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onStopped: () => {
onStopped();
resolve();
},
});
});
}
dash.ease({
translation_x: 0,
translation_y: 0,
delay: STARTUP_ANIMATION_TIME / 2,
duration: STARTUP_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onStopped,
});
} else {
// set dash opacity to make it visible if user enable it later
dash.opacity = 255;
// if dash is hidden, substitute the ease timeout with GLib.timeout
if (!callback) { // GS 47+
return new Promise(resolve => {
_timeouts.startupAnim2 = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
// delay + animation time
STARTUP_ANIMATION_TIME * 2 * St.Settings.get().slow_down_factor,
() => {
onStopped();
resolve();
_timeouts.startupAnim2 = 0;
return GLib.SOURCE_REMOVE;
}
);
});
}
_timeouts.startupAnim2 = GLib.timeout_add(
GLib.PRIORITY_DEFAULT,
// delay + animation time
STARTUP_ANIMATION_TIME * 2 * St.Settings.get().slow_down_factor,
() => {
onStopped();
_timeouts.startupAnim2 = 0;
return GLib.SOURCE_REMOVE;
}
);
}
return null;
},
_realizeAppDisplayAndFinishSequence() {
@ -832,7 +920,7 @@ const ControlsManagerCommon = {
animateToOverview(state, callback) {
this._ignoreShowAppsButtonToggle = true;
this._searchTransition = false;
this._searchInProgress = false;
this._stateAdjustment.value = ControlsState.HIDDEN;
@ -843,7 +931,7 @@ const ControlsManagerCommon = {
// even if it takes little more time, than jumping frames
let delay = 0;
if (opt.DELAY_OVERVIEW_ANIMATION)
delay = global.display.get_tab_list(0, global.workspace_manager.get_active_workspace()).length * 3;
delay = global.display.get_tab_list(0, null).length * opt.DELAY_PER_WINDOW;
this._stateAdjustment.ease(state, {
delay,
@ -900,106 +988,120 @@ const ControlsManagerCommon = {
}
},
_updateBackground(bgManager, stateValue = 2, stateAdjustment = null) {
_updateBackground(bgManager, stateValue = 2/* , stateAdjustment = null*/) {
if (this._checkConflict())
return;
const searchActive = this._searchController.searchActive;
const staticWorkspace = opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && !this.dash.showAppsButton.checked;
if (!opt.SHOW_BG_IN_OVERVIEW && !opt.SHOW_WS_PREVIEW_BG) {
if (!(staticWorkspace && stateValue <= 1))
this._fadeWallpaper(bgManager, stateValue, staticWorkspace);
} else {
this._setBgBrightness(bgManager, stateValue, staticWorkspace, searchActive);
if (opt.OVERVIEW_BG_BLUR_SIGMA || opt.APP_GRID_BG_BLUR_SIGMA)
this._setBlurEffect(bgManager, stateValue, staticWorkspace, searchActive);
}
},
_setBgBrightness(bgManager, stateValue, staticWorkspace, searchActive) {
bgManager.backgroundActor.opacity = 255;
const overviewBrightness = !opt.SHOW_WS_PREVIEW_BG && staticWorkspace ? 1 : opt.OVERVIEW_BG_BRIGHTNESS;
let secBrightness = searchActive ? opt.SEARCH_BG_BRIGHTNESS : opt.OVERVIEW_BG_BRIGHTNESS;
if (staticWorkspace && !this._appDisplay.visible)
secBrightness = overviewBrightness;
const vignette = !opt.SHOW_WS_PREVIEW_BG && staticWorkspace ? 0 : 0.2;
let currentBrightness = 1;
let currentVignette = 0;
if ((opt.SHOW_WS_PREVIEW_BG && stateValue < 1) || (opt.SHOW_WS_PREVIEW_BG && staticWorkspace)) {
// No need to animate transition unless appGrid state is involved, static bg is covered by the ws preview bg
currentBrightness = overviewBrightness;
currentVignette = vignette;
} else if (stateValue === 1 || (stateValue > 1 && !bgManager._primary)) {
currentBrightness = overviewBrightness;
currentVignette = vignette;
} else if (stateValue === 0) {
currentBrightness = 1;
currentVignette = 0;
} else if (stateValue < 1 /* && !searchActive*/) {
currentBrightness = Util.lerp(1, overviewBrightness, stateValue);
currentVignette = Util.lerp(0, vignette, stateValue);
} else if (stateValue > 1 && bgManager._primary) {
currentBrightness = Util.lerp(overviewBrightness, secBrightness, stateValue - 1);
currentVignette = vignette;
}
bgManager.backgroundActor.content.vignette_sharpness = currentVignette;
bgManager.backgroundActor.content.brightness = currentBrightness;
},
_setBlurEffect(bgManager, stateValue, staticWorkspace) {
const blurEffect = this._getBlurEffect(bgManager);
// In GNOME 46 the "sigma" property has been renamed to "radius"
const radiusProperty = blurEffect.sigma === undefined ? 'radius' : 'sigma';
// reduce number of steps of blur transition to improve performance
const step = opt.SMOOTH_BLUR_TRANSITIONS ? 0.05 : 0.2;
const progress = stateValue - (stateValue % step);
const overviewBlurRadius = !opt.SHOW_WS_PREVIEW_BG && staticWorkspace ? 0 : opt.OVERVIEW_BG_BLUR_SIGMA;
const appGridBlurRadius = staticWorkspace && !blurEffect[radiusProperty] && !this._appDisplay.visible ? overviewBlurRadius : opt.APP_GRID_BG_BLUR_SIGMA;
let radius = overviewBlurRadius;
if ((opt.SHOW_WS_PREVIEW_BG && stateValue < 1) || (opt.SHOW_WS_PREVIEW_BG && staticWorkspace)) {
// No need to animate transition unless appGrid state is involved, static bg is covered by the ws preview bg
radius = overviewBlurRadius;
} else if (stateValue === 0) {
radius = 0;
} else if (stateValue === 1 || (stateValue > 1 && !bgManager._primary)) {
radius = overviewBlurRadius;
} else if (stateValue === 2) {
radius = appGridBlurRadius;
} else if (stateValue < 1) {
radius = Math.round(Util.lerp(0, overviewBlurRadius, progress));
} else if (stateValue > 1 && bgManager._primary) {
radius = Math.round(Util.lerp(overviewBlurRadius, appGridBlurRadius, progress - 1));
}
if (blurEffect[radiusProperty] !== radius)
blurEffect[radiusProperty] = radius;
},
_fadeWallpaper(bgManager, stateValue, staticWorkspace) {
// if no bg shown in the overview, fade out the wallpaper
if (bgManager.backgroundActor.get_effect('blur'))
bgManager.backgroundActor.remove_effect_by_name('blur');
let value = stateValue;
if (staticWorkspace && stateValue > 1)
value = stateValue - 1;
bgManager.backgroundActor.opacity = Util.lerp(255, 0, Math.min(value, 1));
},
_getBlurEffect(bgManager) {
let blurEffect = bgManager.backgroundActor.get_effect('blur');
if (!blurEffect) {
blurEffect = new Shell.BlurEffect({
brightness: 1,
mode: Shell.BlurMode.ACTOR,
});
bgManager.backgroundActor.add_effect_with_name('blur', blurEffect);
}
return blurEffect;
},
_checkConflict() {
// Just in case something destroys our background (like older versions of Blur My Shell)
if (this._bgManagers[0] && !Main.layoutManager.overviewGroup.get_children().includes(this._bgManagers[0].backgroundActor)) {
console.error(`[${Me.metadata.name}]`, 'Error: The overview background has been destroyed, possibly by another incompatible extension');
// remove and disconnect our destroyed backgrounds to avoid further errors
this._setBackground(true);
return;
return true;
}
const finalState = stateAdjustment?.getStateTransitionParams().finalState;
if (!opt.SHOW_BG_IN_OVERVIEW && !opt.SHOW_WS_PREVIEW_BG) {
// if no bg shown in the overview, fade out the wallpaper
if (bgManager.backgroundActor.get_effect('blur'))
bgManager.backgroundActor.remove_effect_by_name('blur');
if (!(opt.OVERVIEW_MODE2 && opt.WORKSPACE_MODE && finalState === 1))
bgManager.backgroundActor.opacity = Util.lerp(255, 0, Math.min(stateValue, 1));
} else {
bgManager.backgroundActor.opacity = 255;
let VIGNETTE, BRIGHTNESS, bgValue;
if (opt.OVERVIEW_MODE2 && stateValue <= 1 && !opt.WORKSPACE_MODE) {
VIGNETTE = 0;
BRIGHTNESS = 1;
bgValue = stateValue;
} else {
VIGNETTE = 0.2;
BRIGHTNESS = opt.OVERVIEW_BG_BRIGHTNESS;
if (opt.OVERVIEW_MODE2 && stateValue > 1 && !opt.WORKSPACE_MODE)
bgValue = stateValue - 1;
else
bgValue = stateValue;
}
let blurEffect = bgManager.backgroundActor.get_effect('blur');
if (!blurEffect) {
blurEffect = new Shell.BlurEffect({
brightness: 1,
mode: Shell.BlurMode.ACTOR,
});
bgManager.backgroundActor.add_effect_with_name('blur', blurEffect);
}
// In GNOME 46 the "sigma" property has been renamed to "radius"
const radius = blurEffect.sigma !== undefined ? 'sigma' : 'radius';
const searchActive = this._searchController.searchActive;
if (searchActive)
BRIGHTNESS = opt.SEARCH_BG_BRIGHTNESS;
bgManager.backgroundActor.content.vignette_sharpness = VIGNETTE;
bgManager.backgroundActor.content.brightness = BRIGHTNESS;
let vignetteInit, brightnessInit;// , sigmaInit;
if (opt.SHOW_BG_IN_OVERVIEW && opt.SHOW_WS_PREVIEW_BG) {
vignetteInit = VIGNETTE;
brightnessInit = BRIGHTNESS;
// sigmaInit = opt.OVERVIEW_BG_BLUR_SIGMA;
} else {
vignetteInit = 0;
brightnessInit = 1;
// sigmaInit = 0;
}
if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE) {
bgManager.backgroundActor.content.vignette_sharpness = Util.lerp(vignetteInit, VIGNETTE, bgValue);
bgManager.backgroundActor.content.brightness = Util.lerp(brightnessInit, BRIGHTNESS, bgValue);
} else {
bgManager.backgroundActor.content.vignette_sharpness = Util.lerp(vignetteInit, VIGNETTE, Math.min(stateValue, 1));
bgManager.backgroundActor.content.brightness = Util.lerp(brightnessInit, BRIGHTNESS, Math.min(stateValue, 1));
}
if (opt.OVERVIEW_BG_BLUR_SIGMA || opt.APP_GRID_BG_BLUR_SIGMA) {
// reduce number of steps of blur transition to improve performance
const step = opt.SMOOTH_BLUR_TRANSITIONS ? 0.05 : 0.2;
const progress = stateValue - (stateValue % step);
if (opt.SHOW_WS_PREVIEW_BG && stateValue < 1 && !searchActive) { // no need to animate transition, unless appGrid state is involved, static bg is covered by the ws preview bg
if (blurEffect[radius] !== opt.OVERVIEW_BG_BLUR_SIGMA)
blurEffect[radius] = opt.OVERVIEW_BG_BLUR_SIGMA;
} else if (stateValue < 1 && !searchActive && !(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)) {
const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress));
if (sigma !== blurEffect[radius])
blurEffect[radius] = sigma;
} else if (stateValue < 1 && !searchActive && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && blurEffect[radius])) {
const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress));
if (sigma !== blurEffect[radius])
blurEffect[radius] = sigma;
} else if (stateValue > 1 && !searchActive && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && finalState === 1)) {
const sigma = Math.round(Util.lerp(0, opt.OVERVIEW_BG_BLUR_SIGMA, progress % 1));
if (sigma !== blurEffect[radius])
blurEffect[radius] = sigma;
} else if ((stateValue > 1 && bgManager._primary) || searchActive) {
const sigma = Math.round(Util.lerp(opt.OVERVIEW_BG_BLUR_SIGMA, opt.APP_GRID_BG_BLUR_SIGMA, progress % 1));
if (sigma !== blurEffect[radius])
blurEffect[radius] = sigma;
} else if (stateValue === 1 && !(opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE)) {
blurEffect[radius] = opt.OVERVIEW_BG_BLUR_SIGMA;
} else if (stateValue === 0 || (stateValue === 1 && (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE))) {
blurEffect[radius] = 0;
}
}
}
return false;
},
};
@ -1221,15 +1323,16 @@ const ControlsManagerLayoutVertical = {
let wsTmbHeight = 0;
if (opt.SHOW_WS_TMB) {
const searchActive = this._searchController.searchActive;
let maxWsTmbScale = this._dash.showAppsButton.checked && !(searchActive && !opt.SEARCH_APP_GRID_MODE)
let maxWsTmbScale = this._dash.showAppsButton.checked
? opt.MAX_THUMBNAIL_SCALE_APPGRID
: opt.MAX_THUMBNAIL_SCALE;
if (transitionParams.currentState % 1 && !opt.MAX_THUMBNAIL_SCALE_STABLE && !searchActive && !opt.LEAVING_SEARCH) {
const searchActive = Main.overview._overview.controls._searchInProgress;
if (!opt.MAX_THUMBNAIL_SCALE_STABLE && !searchActive) {
const initState = transitionParams.initialState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE;
const finalState = transitionParams.finalState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE;
maxWsTmbScale = Util.lerp(initState, finalState, transitionParams.progress);
}
wsTmbWidth = Math.round(width * maxWsTmbScale);
let totalTmbSpacing;
@ -1274,28 +1377,29 @@ const ControlsManagerLayoutVertical = {
}
let dashX = opt.DASH_RIGHT ? width - dashWidth : 0;
let dashY = opt.DASH_TOP ? startY : startY + height - dashHeight;
let dashY = opt.DASH_TOP ? 0 : height - dashHeight;
if (!opt.DASH_VERTICAL) {
const dashLeftOffset = (opt.WS_TMB_FULL || opt.CENTER_DASH_WS) && opt.WS_TMB_LEFT ? wsTmbWidth + spacing : 0;
const dashRightOffset = (opt.WS_TMB_FULL || opt.CENTER_DASH_WS) && opt.WS_TMB_RIGHT ? wsTmbWidth + spacing : 0;
let offset = (width - dashWidth - (opt.CENTER_DASH_WS && !this._xAlignCenter ? dashLeftOffset + dashRightOffset : 0)) / 2;
offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - spacing);
dashX = startX + (opt.CENTER_DASH_WS ? dashLeftOffset : 0) + offset;
dashX = (opt.CENTER_DASH_WS ? dashLeftOffset : 0) + offset;
if (opt.WS_TMB_FULL) // Limit the adjustment while keeping the center of adjustment on the screen center
dashX = Math.clamp(startX + dashLeftOffset + spacing, dashX, startX + width - dashRightOffset - spacing - dashWidth);
dashX = Math.clamp(dashLeftOffset + spacing, dashX, width - dashRightOffset - spacing - dashWidth);
} else {
const offset = (height - dashHeight) / 2;
dashY = startY + (offset - opt.DASH_POSITION_ADJUSTMENT * (offset - spacing));
dashY = offset - opt.DASH_POSITION_ADJUSTMENT * (offset - spacing);
}
dashY = Math.round(dashY);
dashX = Math.round(startX + dashX);
dashY = Math.round(startY + dashY);
childBox.set_origin(startX + dashX, dashY);
childBox.set_origin(dashX, dashY);
childBox.set_size(dashWidth, dashHeight);
this._dash.allocate(childBox);
}
// View box offsets
// Main view offsets
const leftBoxOffset = (opt.DASH_LEFT ? dashWidth : spacing) + (opt.WS_TMB_LEFT ? wsTmbWidth + spacing : 0);
const rightBoxOffset = (opt.DASH_RIGHT ? dashWidth : spacing) + (opt.WS_TMB_RIGHT ? wsTmbWidth + spacing : 0);
let topBoxOffset = (opt.DASH_TOP ? dashHeight : spacing) + (opt.WS_TMB_TOP ? wsTmbHeight + spacing : 0);
@ -1338,7 +1442,16 @@ const ControlsManagerLayoutVertical = {
topBoxOffset += opt.SHOW_SEARCH_ENTRY ? searchEntryHeight + spacing : 0;
// workspace
let params = [box, wsTmbWidth, wsTmbHeight, leftBoxOffset, rightBoxOffset, topBoxOffset, bottomBoxOffset, centeredBoxOffset];
let params = [
box,
wsTmbWidth,
wsTmbHeight,
leftBoxOffset,
rightBoxOffset,
topBoxOffset,
bottomBoxOffset,
centeredBoxOffset,
];
// Update cached boxes
for (const state of Object.values(ControlsState)) {
@ -1446,11 +1559,11 @@ const ControlsManagerLayoutHorizontal = {
let wsTmbHeight = 0;
if (opt.SHOW_WS_TMB) {
const searchActive = this._searchController.searchActive;
let maxWsTmbScale = this._dash.showAppsButton.checked && !(searchActive && !opt.SEARCH_APP_GRID_MODE)
let maxWsTmbScale = this._dash.showAppsButton.checked
? opt.MAX_THUMBNAIL_SCALE_APPGRID
: opt.MAX_THUMBNAIL_SCALE;
if (transitionParams.currentState % 1 && !opt.MAX_THUMBNAIL_SCALE_STABLE && !searchActive && !opt.LEAVING_SEARCH) {
const searchActive = Main.overview._overview.controls._searchInProgress;
if (!opt.MAX_THUMBNAIL_SCALE_STABLE && !searchActive) {
const initState = transitionParams.initialState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE;
const finalState = transitionParams.finalState === ControlsState.APP_GRID ? opt.MAX_THUMBNAIL_SCALE_APPGRID : opt.MAX_THUMBNAIL_SCALE;
maxWsTmbScale = Util.lerp(initState, finalState, transitionParams.progress);
@ -1498,23 +1611,24 @@ const ControlsManagerLayoutHorizontal = {
}
let dashX = opt.DASH_RIGHT ? width - dashWidth : 0;
let dashY = opt.DASH_TOP ? startY : startY + height - dashHeight;
let dashY = opt.DASH_TOP ? 0 : height - dashHeight;
if (opt.DASH_VERTICAL) {
const dashTopOffset = (opt.WS_TMB_FULL || opt.CENTER_DASH_WS) && opt.WS_TMB_TOP ? wsTmbHeight + spacing : 0;
const dashBottomOffset = (opt.WS_TMB_FULL || opt.CENTER_DASH_WS) && opt.WS_TMB_BOTTOM ? wsTmbHeight + spacing : 0;
let offset = (height - dashHeight - (opt.CENTER_DASH_WS ? dashTopOffset + dashBottomOffset : 0)) / 2;
offset -= opt.DASH_POSITION_ADJUSTMENT * (offset - spacing);
dashY = startY + (opt.CENTER_DASH_WS ? dashTopOffset : 0) + offset;
dashY = (opt.CENTER_DASH_WS ? dashTopOffset : 0) + offset;
if (opt.WS_TMB_FULL) // Limit the adjustment while keeping the center of adjustment on the screen center
dashY = Math.clamp(startY + dashTopOffset + spacing, dashY, startY + height - dashBottomOffset - spacing - dashHeight);
dashY = Math.clamp(dashTopOffset + spacing, dashY, height - dashBottomOffset - spacing - dashHeight);
} else {
const offset = (width - dashWidth) / 2;
dashX = startX + (offset - opt.DASH_POSITION_ADJUSTMENT * (offset - spacing));
}
dashX = Math.round(dashX);
dashX = Math.round(startX + dashX);
dashY = Math.round(startY + dashY);
childBox.set_origin(startX + dashX, dashY);
childBox.set_origin(dashX, dashY);
childBox.set_size(dashWidth, dashHeight);
this._dash.allocate(childBox);
}

View file

@ -3,7 +3,7 @@
* panel.js
*
* @author GdH <G-dH@github.com>
* @copyright 2022 - 2024
* @copyright 2022 - 2025
* @license GPL-3.0
*
*/
@ -67,6 +67,7 @@ export const PanelModule = class {
this._overrides = new Me.Util.Overrides();
const panelBox = Main.layoutManager.panelBox;
panelBox.scale_y = 1;
this._setPanelPosition();
this._updateStyleChangedConnection();
@ -80,29 +81,23 @@ export const PanelModule = class {
} else if (opt.PANEL_OVERVIEW_ONLY) {
if (opt.SHOW_WS_PREVIEW_BG) {
this._reparentPanel(true);
if (opt.OVERVIEW_MODE2) {
// in OM2 if the panel has been moved to the overviewGroup move panel above all
Main.layoutManager.overviewGroup.set_child_above_sibling(panelBox, null);
this._updateOverviewConnection();
} else {
this._updateOverviewConnection(true);
}
this._showPanel(true);
} else {
// if ws preview bg is disabled, panel can stay in uiGroup
this._reparentPanel(false);
this._showPanel(false);
this._updateOverviewConnection();
}
this._updateOverviewConnection();
// _connectPanel();
} else if (opt.PANEL_DISABLED) {
this._updateOverviewConnection(true);
this._reparentPanel(false);
this._showPanel(false);
panelBox.scale_y = 0;
// _connectPanel();
}
this._setPanelStructs(!opt.PANEL_MODE);
Main.layoutManager._updateHotCorners();
Main.overview._overview.controls.layoutManager._updateWorkAreaBox();
this._overrides.addOverride('ActivitiesButton', Main.panel.statusArea.activities, ActivitiesButton);
@ -118,6 +113,7 @@ export const PanelModule = class {
this._updateStyleChangedConnection(reset);
const panelBox = Main.layoutManager.panelBox;
panelBox.scale_y = 1;
panelBox.translation_y = 0;
Main.panel.opacity = 255;
this._setPanelStructs(true);
@ -147,14 +143,18 @@ export const PanelModule = class {
}
} else if (!this._styleChangedConId) {
this._styleChangedConId = Main.panel.connect('style-changed', () => {
if (opt.PANEL_OVERVIEW_ONLY && !opt.OVERVIEW_MODE2)
Main.panel.add_style_pseudo_class('overview');
else if (opt.OVERVIEW_MODE2)
Main.panel.remove_style_pseudo_class('overview');
this._updateStyle();
});
}
}
_updateStyle() {
if (opt.OVERVIEW_MODE2 || !opt.PANEL_OVERVIEW_STYLE)
Main.panel.remove_style_pseudo_class('overview');
else if (opt.PANEL_OVERVIEW_ONLY && !opt.OVERVIEW_MODE2)
Main.panel.add_style_pseudo_class('overview');
}
_updateOverviewConnection(reset = false) {
if (reset) {
if (this._hidingOverviewConId) {
@ -168,16 +168,15 @@ export const PanelModule = class {
} else {
if (!this._hidingOverviewConId) {
this._hidingOverviewConId = Main.overview.connect('hiding', () => {
if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2)
this._showPanel(false);
this._showPanel(false);
});
}
if (!this._showingOverviewConId) {
this._showingOverviewConId = Main.overview.connect('showing', () => {
if (Main.layoutManager._startingUp)
return;
if (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2 || Main.layoutManager.panelBox.translation_y)
this._showPanel(true);
this._updateStyle();
this._showPanel(true);
});
}
}
@ -211,9 +210,29 @@ export const PanelModule = class {
}
_showPanel(show = true) {
const panelBox = Main.layoutManager.panelBox;
const panelHeight = Main.panel.height;
const overviewGroup = Main.layoutManager.overviewGroup;
if (panelBox.get_parent() === overviewGroup) {
if (opt.OVERVIEW_MODE2)
overviewGroup.set_child_above_sibling(panelBox, null);
else
overviewGroup.set_child_below_sibling(panelBox, Main.overview._overview);
}
if (opt.SHOW_WS_PREVIEW_BG && !opt.OVERVIEW_MODE2 && !Main.layoutManager.panelBox.translation_y)
return;
if (show) {
panelBox.translation_y = opt.PANEL_POSITION_TOP ? -panelHeight : panelHeight;
Main.panel.opacity = 255;
Main.layoutManager.panelBox.ease({
let delay = 0;
// Panel animation needs to wait until overview is visible
if (opt.DELAY_OVERVIEW_ANIMATION)
delay = global.display.get_tab_list(0, null).length * opt.DELAY_PER_WINDOW + 50;
panelBox.ease({
delay,
duration: ANIMATION_TIME,
translation_y: 0,
onComplete: () => {
@ -221,10 +240,10 @@ export const PanelModule = class {
},
});
} else if (!Main.layoutManager._startingUp) {
const panelHeight = Main.panel.height;
Main.layoutManager.panelBox.ease({
panelBox.translation_y = 0;
panelBox.ease({
duration: ANIMATION_TIME,
translation_y: opt.PANEL_POSITION_TOP ? -panelHeight + 1 : panelHeight - 1,
translation_y: opt.PANEL_POSITION_TOP ? -panelHeight : panelHeight,
onComplete: () => {
Main.panel.opacity = 0;
this._setPanelStructs(!opt.PANEL_MODE);

View file

@ -211,7 +211,13 @@ const AppSearchProvider = {
},
_filterAppGrid(results) {
const icons = Main.overview._overview.controls._appDisplay._orderedItems;
const appDisplay = Main.overview._overview.controls._appDisplay;
let icons = appDisplay._orderedItems;
icons.forEach(icon => {
icon.visible = true;
});
appDisplay._redisplay(results);
icons = appDisplay._orderedItems;
icons.forEach(icon => {
icon.visible = results.includes(icon.id);
});
@ -245,8 +251,6 @@ const SystemActionIcon = GObject.registerClass({
}, class SystemActionIcon extends Search.GridSearchResult {
_init(provider, metaInfo, resultsView) {
super._init(provider, metaInfo, resultsView);
if (!Clutter.Container)
this.add_style_class_name('grid-search-result-46');
this.icon._setSizeManually = true;
this.icon.setIconSize(provider._iconSize);
}

View file

@ -113,9 +113,14 @@ export const Options = class Options {
dashShowWindowsBeforeActivation: ['int', 'dash-show-windows-before-activation'],
dashIconScroll: ['int', 'dash-icon-scroll'],
dashIsolateWorkspaces: ['boolean', 'dash-isolate-workspaces'],
appMenuForceQuit: ['boolean', 'app-menu-force-quit'],
appMenuCloseWinsWs: ['boolean', 'app-menu-close-wins-ws'],
appMenuMoveApp: ['boolean', 'app-menu-move-app'],
appMenuWindowTmb: ['boolean', 'app-menu-window-tmb'],
searchWindowsIconScroll: ['int', 'search-windows-icon-scroll'],
panelVisibility: ['int', 'panel-visibility'],
panelPosition: ['int', 'panel-position'],
panelOverviewStyle: ['int', 'panel-overview-style'],
windowAttentionMode: ['int', 'window-attention-mode'],
wsSwPopupHPosition: ['int', 'ws-sw-popup-h-position'],
wsSwPopupVPosition: ['int', 'ws-sw-popup-v-position'],
@ -331,11 +336,15 @@ export const Options = class Options {
this.MAX_ICON_SIZE = this.get('dashMaxIconSize');
this.APP_MENU_FORCE_QUIT = this.get('appMenuForceQuit');
this.APP_MENU_CLOSE_WINS_WS = this.get('appMenuCloseWinsWs');
this.APP_MENU_MOVE_APP = this.get('appMenuMoveApp');
this.APP_MENU_WINDOW_TMB = this.get('appMenuWindowTmb');
this.WS_TMB_POSITION = this.get('workspaceThumbnailsPosition');
this.ORIENTATION = this.WS_TMB_POSITION > 4 ? 0 : 1;
this.WORKSPACE_MAX_SPACING = this.get('wsMaxSpacing');
this.WS_MAX_SPACING_OFF_SCREEN = 350;
this.FORCE_SINGLE_WS_TRANSITION = false;
// ORIENTATION || DASH_LEFT || DASH_RIGHT ? 350 : 80;
this.SHOW_WS_TMB = ![4, 9].includes(this.WS_TMB_POSITION); // 4, 9 - disable
this.WS_TMB_FULL = this.get('wsThumbnailsFull');
@ -362,7 +371,6 @@ export const Options = class Options {
this.MAX_THUMBNAIL_SCALE = this.get('wsThumbnailScale') / 100 + 0.01;
this.MAX_THUMBNAIL_SCALE_APPGRID = this.get('wsThumbnailScaleAppGrid') / 100 + 0.01;
this.SHOW_WS_TMB_APPGRID = true;
this.MAX_THUMBNAIL_SCALE_STABLE = this.MAX_THUMBNAIL_SCALE === this.MAX_THUMBNAIL_SCALE_APPGRID;
this.SEC_MAX_THUMBNAIL_SCALE = this.get('secWsThumbnailScale') / 100 + 0.01;
@ -411,8 +419,8 @@ 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.SEARCH_APP_GRID_MODE = this.get('searchAppGridMode');
this.SEARCH_DELAY = this.SEARCH_VIEW_ANIMATION ? 100 : 0;
this.SEARCH_APP_GRID_MODE = this.get('searchAppGridMode') && this.get('appDisplayModule');
this.APP_GRID_ALLOW_INCOMPLETE_PAGES = this.get('appGridIncompletePages');
this.APP_GRID_ICON_SIZE = this.get('appGridIconSize');
@ -469,6 +477,7 @@ export const Options = class Options {
this.PANEL_MODE = this.get('panelVisibility');
this.PANEL_DISABLED = this.PANEL_MODE === 2;
this.PANEL_OVERVIEW_ONLY = this.PANEL_MODE === 1;
this.PANEL_OVERVIEW_STYLE = this.get('panelOverviewStyle');
this.WINDOW_ATTENTION_MODE = this.get('windowAttentionMode');
this.WINDOW_ATTENTION_DISABLE_NOTIFICATIONS = this.WINDOW_ATTENTION_MODE === 1;
@ -479,6 +488,8 @@ export const Options = class Options {
this.WS_SW_POPUP_MODE = this.get('wsSwPopupMode');
this.WS_ANIMATION = this.get('workspaceAnimation');
this.WS_ANIMATION_SINGLE = this.WS_ANIMATION === 1;
this.WS_ANIMATION_ALL = this.WS_ANIMATION === 2;
this.WS_WRAPAROUND = this.get('wsSwitcherWraparound');
this.WS_IGNORE_LAST = this.get('wsSwitcherIgnoreLast');
this.WS_SWITCHER_CURRENT_MONITOR = this.get('wsSwitcherMode') === 1;
@ -528,6 +539,8 @@ export const Options = class Options {
this.HIGHLIGHT_NONE = this.HIGHLIGHTING_STYLE === 2;
this.DELAY_STARTUP = this.get('delayStartup');
this.DELAY_OVERVIEW_ANIMATION = true;
this.DELAY_PER_WINDOW = 5;
}
_getAnimationDirection() {

View file

@ -131,7 +131,7 @@ export function openPreferences(metadata) {
}
if (!metaWin || (metaWin && !isMe)) {
// delay to avoid errors if previous prefs window has been colsed
// delay to avoid errors if previous prefs window has been closed
GLib.idle_add(GLib.PRIORITY_LOW, () => {
try {
Main.extensionManager.openExtensionPrefs(metadata.uuid, '', {});
@ -144,12 +144,14 @@ export function openPreferences(metadata) {
export function activateSearchProvider(prefix = '') {
const searchEntry = Main.overview.searchEntry;
if (!searchEntry.get_text() || !searchEntry.get_text().startsWith(prefix)) {
const searchEntryText = searchEntry.get_text();
if (!searchEntryText || (searchEntryText && !searchEntry.get_text().startsWith(prefix))) {
prefix = `${prefix} `;
const position = prefix.length;
searchEntry.set_text(prefix);
searchEntry.get_first_child().set_cursor_position(position);
searchEntry.get_first_child().set_selection(position, position);
searchEntry.grab_key_focus();
} else {
searchEntry.set_text('');
}
@ -172,34 +174,51 @@ export function reorderWorkspace(direction = 0) {
global.workspace_manager.reorder_workspace(activeWs, targetIdx);
}
// In WINDOW_PICKER mode, enable keyboard navigation
// by focusing on the active window's preview
export function activateKeyboardForWorkspaceView() {
Main.ctrlAltTabManager._items.forEach(i => {
if (i.sortGroup === 1 && i.name === 'Windows')
Main.ctrlAltTabManager.focusGroup(i);
});
}
const currentWindowActor = global.display.focus_window?.get_compositor_private();
if (!currentWindowActor)
return;
export function exposeWindows(adjustment, activateKeyboard) {
// expose windows for static overview modes
if (!adjustment.value && !Main.overview._animationInProgress) {
if (adjustment.value === 0) {
adjustment.value = 0;
adjustment.ease(1, {
duration: 200,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
if (activateKeyboard) {
Main.ctrlAltTabManager._items.forEach(i => {
if (i.sortGroup === 1 && i.name === 'Windows')
Main.ctrlAltTabManager.focusGroup(i);
});
}
},
});
const activeWorkspace = global.workspace_manager.get_active_workspace().index();
const nMonitors = global.display.get_n_monitors();
for (let monitor = 0; monitor < nMonitors; monitor++) {
// secondary monitor
let windows = Main.overview._overview.controls._workspacesDisplay._workspacesViews[monitor]._workspacesView?._workspaces[activeWorkspace]._windows;
if (!windows) // primary monitor
windows = Main.overview._overview.controls._workspacesDisplay._workspacesViews[monitor]._workspaces[activeWorkspace]._windows;
for (const win of windows) {
if (win._windowActor === currentWindowActor) {
win.grab_key_focus();
break;
}
}
}
}
export function exposeWindows() {
Main.overview._overview.controls._workspacesDisplay._workspacesViews.forEach(
view => {
view.exposeWindows();
}
);
}
export function exposeWindowsWithOverviewTransition() {
// 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
const stateAdjustment = Main.overview._overview.controls._stateAdjustment;
Me.opt.WORKSPACE_MODE = 1;
// setting value to 0 would reset WORKSPACE_MODE
stateAdjustment.value = 0.01;
stateAdjustment.ease(1, {
duration: 200,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => activateKeyboardForWorkspaceView(),
});
}
export function isShiftPressed(state = null) {
if (state === null)
[,, state] = global.get_pointer();

View file

@ -375,6 +375,9 @@ const WorkspaceAnimationController = {
switchData.monitors.push(group);
}
Meta.disable_unredirect_for_display(global.display);
if (Meta.disable_unredirect_for_display)
Meta.disable_unredirect_for_display(global.display);
else // new in GS 48
global.compositor.disable_unredirect();
},
};

View file

@ -112,18 +112,18 @@ const WindowPreviewCommon = {
const ICON_SIZE = opt.WIN_PREVIEW_ICON_SIZE;
const windowContainer = new Clutter.Actor({
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
});
Shell.WindowPreview.prototype._init.bind(this)({
reactive: true,
can_focus: true,
accessible_role: Atk.Role.PUSH_BUTTON,
offscreen_redirect: Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY,
windowContainer,
});
const windowContainer = new Clutter.Actor({
pivot_point: new Graphene.Point({ x: 0.5, y: 0.5 }),
});
this.window_container = windowContainer;
windowContainer.connect('notify::scale-x',
() => this._adjustOverlayOffsets());
// gjs currently can't handle setting an actors layout manager during
@ -186,7 +186,7 @@ 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 && global.windowThumbnails) {
} else if (opt.WIN_PREVIEW_MID_BTN_ACTION === 3 && global.windowThumbnails) {
this._removeLaters();
global.windowThumbnails?.createThumbnail(metaWindow);
return Clutter.EVENT_STOP;
@ -382,13 +382,13 @@ const WindowPreviewCommon = {
if (opt.OVERVIEW_MODE === 1) {
// spread windows on hover
this._wsStateConId = this.connect('enter-event', () => {
// don't spread windows if user don't use pointer device at this moment
// prevent spreading windows immediately after entering overview
if (global.get_pointer()[0] === opt.showingPointerX || Main.overview._overview._controls._stateAdjustment.value < 1)
return;
opt.WORKSPACE_MODE = 1;
const view = this._workspace.get_parent();
view.exposeWindows(this._workspace.metaWorkspace.index());
view.exposeWindows();
this.disconnect(this._wsStateConId);
});
}
@ -500,8 +500,7 @@ const WindowPreviewCommon = {
return;
this._overlayShown = true;
if (opt.WIN_TITLES_POSITION === 2)
this._restack();
this._restack();
// If we're supposed to animate and an animation in our direction
// is already happening, let that one continue
@ -550,11 +549,15 @@ const WindowPreviewCommon = {
return;
this._overlayShown = false;
if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW && Main.overview._overview.controls._stateAdjustment.value < 1)
// When leaving overview, mark the window for activation if needed
// The marked window is activated during _onDestroy()
const leavingOverview = Main.overview._overview.controls._stateAdjustment.value < 1;
if (opt.ALWAYS_ACTIVATE_SELECTED_WINDOW && leavingOverview)
this._activateSelected = true;
if (opt.WIN_TITLES_POSITION === 2)
// Prevent restacking the preview if it should remain on top
// while leaving overview
if (!(opt.ALWAYS_ACTIVATE_SELECTED_WINDOW && leavingOverview))
this._restack();
// If we're supposed to animate and an animation in our direction

View file

@ -78,17 +78,19 @@ export const WorkspaceModule = class {
}
};
// workaround for upstream bug (that is not that invisible in default shell)
// smaller window cannot be scaled below 0.95 (WINDOW_PREVIEW_MAXIMUM_SCALE)
// when its target scale for exposed windows view (workspace state 1) is bigger than the scale needed for ws state 0.
// in workspace state 0 where windows are not spread and window scale should follow workspace scale,
// this window follows proper top left corner position, but doesn't scale with the workspace
// so it looks bad and the window can exceed border of the workspace
// extremely annoying in OVERVIEW_MODE 1 with single smaller window on the workspace, also affects appGrid transition animation
// disadvantage of following workaround - the WINDOW_PREVIEW_MAXIMUM_SCALE value is common for every workspace,
// on multi-monitor system can be visible unwanted scaling of windows on workspace in WORKSPACE_MODE 0 (windows not spread)
// when leaving overview while any other workspace is in the WORKSPACE_MODE 1.
// Workaround for an upstream bug affecting window scaling and positioning:
//
// Issue:
// - Smaller windows cannot scale below 0.95 (WINDOW_PREVIEW_MAXIMUM_SCALE)
// when their target scale for the spread windows view (workspace state 1)
// exceeds the scale needed for workspace state 0.
// - In workspace state 0 (where windows are not spread and scale matches the workspace),
// the window aligns correctly to the top-left corner but does not scale with the workspace,
// causing visual issues and the window may exceed the workspace border.
//
// Effects:
// - Particularly noticeable in OVERVIEW_MODE 1 with a single smaller window on the workspace.
// - Also impacts the appGrid transition animation.
const WorkspaceLayout = {
// injection to _init()
after__init() {
@ -96,14 +98,18 @@ const WorkspaceLayout = {
WINDOW_PREVIEW_MAXIMUM_SCALE = 0.95;
if (opt.OVERVIEW_MODE === 1) {
this._stateAdjustment.connect('notify::value', () => {
// scale 0.1 for window state 0 just needs to be smaller then possible scale of any window in spread view
// When transitioning to workspace state 1 (WINDOW_PICKER),
// replace the constant with the original value.
// Ensure that the scale for workspace state 0 is smaller
// than the minimum possible scale of any window on the workspace,
// so they stay at their real size relative to ws preview
const scale = this._stateAdjustment.value ? 0.95 : 0.1;
if (scale !== WINDOW_PREVIEW_MAXIMUM_SCALE) {
if (scale !== WINDOW_PREVIEW_MAXIMUM_SCALE)
WINDOW_PREVIEW_MAXIMUM_SCALE = scale;
// when transition to ws state 1 (WINDOW_PICKER) begins, replace the constant with the original one
// and force recalculation of the target layout, so the transition will be smooth
// Force recalculation of the target layout
// to ensure that the new WINDOW_PREVIEW_MAXIMUM_SCALE is applied
if (this._stateAdjustment.value < 0.5)
this._needsLayout = true;
}
});
}
},

View file

@ -67,6 +67,7 @@ export const WorkspaceAnimationModule = class {
this._overrides.addOverride('MonitorGroup', WorkspaceAnimation.MonitorGroup.prototype, MonitorGroup);
this._connectWsAnimationSwipeTracker();
this._overrideMonitorGroupProperty();
console.debug(' WorkspaceAnimationModule - Activated');
}
@ -77,6 +78,7 @@ export const WorkspaceAnimationModule = class {
this._overrides = null;
const reset = true;
this._connectWsAnimationSwipeTracker(reset);
this._overrideMonitorGroupProperty(reset);
console.debug(' WorkspaceAnimationModule - Disabled');
}
@ -126,6 +128,30 @@ export const WorkspaceAnimationModule = class {
Main.wm._workspaceSwitcherPopup.display(wsIndex);
}
_overrideMonitorGroupProperty(reset = false) {
if (!this._origBaseDistance)
this._origBaseDistance = Object.getOwnPropertyDescriptor(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance').get;
let getter;
if (reset) {
if (this._origBaseDistance)
getter = { get: this._origBaseDistance };
} else {
getter = {
get() {
const spacing = 0; // 100 * St.ThemeContext.get_for_stage(global.stage).scale_factor;
if (global.workspace_manager.layout_rows === -1)
return this._monitor.height + spacing + (opt.PANEL_MODE ? Main.panel.height : 0); // compensation for hidden panel
else
return this._monitor.width + spacing;
},
};
}
if (getter)
Object.defineProperty(WorkspaceAnimation.MonitorGroup.prototype, 'baseDistance', getter);
}
};
const MonitorGroup = {

View file

@ -10,6 +10,7 @@
'use strict';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import Clutter from 'gi://Clutter';
import St from 'gi://St';
@ -120,7 +121,7 @@ const WorkspaceThumbnailCommon = {
const wsIndex = this.metaWorkspace.index();
let label = `${wsIndex + 1}`;
if (opt.SHOW_WST_LABELS === 2) { // 2 - index + workspace name
const settings = Me.getSettings('org.gnome.desktop.wm.preferences');
const settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.wm.preferences' });
const wsLabels = settings.get_strv('workspace-names');
if (wsLabels.length > wsIndex && wsLabels[wsIndex])
label += `: ${wsLabels[wsIndex]}`;
@ -182,6 +183,9 @@ const WorkspaceThumbnailCommon = {
return GLib.SOURCE_REMOVE;
});
});
if (opt.SHOW_WST_LABELS_ON_HOVER)
this._wsLabel.opacity = 0;
}
if (opt.CLOSE_WS_BUTTON_MODE) {
@ -229,9 +233,6 @@ const WorkspaceThumbnailCommon = {
this._lastCloseClickTime = 0;
}
if (opt.SHOW_WST_LABELS_ON_HOVER)
this._wsLabel.opacity = 0;
this.connect('enter-event', () => {
if (opt.CLOSE_WS_BUTTON_MODE && (!Meta.prefs_get_dynamic_workspaces() || (Meta.prefs_get_dynamic_workspaces() && global.workspace_manager.get_n_workspaces() - 1 !== this.metaWorkspace.index())))
this._closeButton.opacity = 200;
@ -267,7 +268,7 @@ const WorkspaceThumbnailCommon = {
// full brightness of the thumbnail bg draws unnecessary attention
// there is a grey bg under the wallpaper
this._bgManager.backgroundActor.opacity = 220;
// this._bgManager.backgroundActor.opacity = 220;
}
this.connect('destroy', () => {
@ -327,23 +328,12 @@ const WorkspaceThumbnailCommon = {
} else {
this.metaWorkspace.activate(time);
}
} else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && wsIndex < lastWsIndex) {
} else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && wsIndex <= lastWsIndex) {
if (stateAdjustment.value > 1)
stateAdjustment.value = 1;
// spread windows
// in OVERVIEW MODE 2 windows are not spread and workspace is not scaled
// we need to repeat transition to the overview state 1 (window picker), but with spreading windows animation
if (this.metaWorkspace.active) {
Main.overview.searchController._setSearchActive(false);
opt.WORKSPACE_MODE = 1;
// setting value to 0 would reset WORKSPACE_MODE
stateAdjustment.value = 0.01;
stateAdjustment.ease(1, {
duration: 200,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
});
Me.Util.exposeWindowsWithOverviewTransition();
} else {
// switch ws
this.metaWorkspace.activate(time);
@ -422,6 +412,8 @@ const WorkspaceThumbnailCommon = {
const ThumbnailsBoxCommon = {
after__init(scrollAdjustment, monitorIndex, orientation = opt.ORIENTATION) {
this._boxOrientation = orientation;
// Block propagation of the button-release-event
this.connect('button-release-event', () => Clutter.EVENT_STOP);
},
_activateThumbnailAtPoint(stageX, stageY, time, activateCurrent = false) {

View file

@ -159,7 +159,6 @@ const WorkspacesViewCommon = {
// normal view 0, spread windows 1
_getWorkspaceModeForOverviewState(state) {
switch (state) {
case ControlsState.HIDDEN:
return 0;
@ -210,8 +209,8 @@ const WorkspacesViewCommon = {
// if we disable workspaces that we can't or don't need to see, transition animations will be noticeably smoother
// only the current ws needs to be visible during overview transition animations
// and only current and adjacent ws when switching ws
w.visible =
(this._animating && wsScrollProgress && distanceToCurrentWorkspace <= (opt.NUMBER_OF_VISIBLE_NEIGHBORS + 1)) ||
w.visible = opt.WS_ANIMATION_ALL ||
((this._animating && wsScrollProgress && distanceToCurrentWorkspace <= (opt.NUMBER_OF_VISIBLE_NEIGHBORS + 1)) ||
scaleProgress === 1 ||
(opt.WORKSPACE_MAX_SPACING >= opt.WS_MAX_SPACING_OFF_SCREEN &&
distanceToCurrentWorkspace <= opt.NUMBER_OF_VISIBLE_NEIGHBORS &&
@ -222,7 +221,7 @@ const WorkspacesViewCommon = {
(distanceToCurrentWorkspace <= opt.NUMBER_OF_VISIBLE_NEIGHBORS &&
currentState <= ControlsState.WINDOW_PICKER &&
(initialState < ControlsState.APP_GRID && finalState < ControlsState.APP_GRID)
);
));
// after transition from APP_GRID to WINDOW_PICKER state,
// adjacent workspaces are hidden and we need them to show up
@ -263,7 +262,7 @@ const WorkspacesViewCommon = {
});
},
exposeWindows(workspaceIndex = null, callback) {
exposeWindows(workspaceIndex = null) {
let adjustments = [];
if (workspaceIndex === null) {
this._workspaces.forEach(ws => {
@ -276,14 +275,9 @@ const WorkspacesViewCommon = {
opt.WORKSPACE_MODE = 1;
adjustments.forEach(adj => {
if (adj.value === 0) {
adj.value = 0;
adj.ease(1, {
duration: 200,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
onComplete: () => {
if (callback)
callback();
},
});
}
});
@ -298,7 +292,7 @@ const SecondaryMonitorDisplayCommon = {
const SecondaryMonitorDisplayVertical = {
_getThumbnailParamsForState(state) {
const spacing = opt.SPACING;
let opacity, scale, translationX;
switch (state) {
case ControlsState.HIDDEN:
@ -306,7 +300,7 @@ const SecondaryMonitorDisplayVertical = {
scale = 1;
translationX = 0;
if (!Main.layoutManager._startingUp && (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2))
translationX = this._thumbnails.width * (opt.SEC_WS_TMB_LEFT ? -1 : 1);
translationX = (this._thumbnails.width + spacing) * (opt.SEC_WS_TMB_LEFT ? -1 : 1);
break;
case ControlsState.WINDOW_PICKER:
@ -357,11 +351,11 @@ const SecondaryMonitorDisplayVertical = {
let offset = Math.round(width - wsTmbWidth - wsBoxWidth - spacing) / 2;
const wsbX = startX + opt.SEC_WS_TMB_LEFT
const wsbX = startX + (opt.SEC_WS_TMB_LEFT
? wsTmbWidth + spacing + offset
: offset;
: offset);
const wsbY = Math.round((startY + height - wsBoxHeight) / 2);
const wsbY = Math.round(startY + (height - wsBoxHeight) / 2);
workspaceBox.set_origin(wsbX, wsbY);
workspaceBox.set_size(wsBoxWidth, wsBoxHeight);
@ -532,8 +526,7 @@ const SecondaryMonitorDisplayVertical = {
const SecondaryMonitorDisplayHorizontal = {
_getThumbnailParamsForState(state) {
// const { ControlsState } = OverviewControls;
const spacing = opt.SPACING;
let opacity, scale, translationY;
switch (state) {
case ControlsState.HIDDEN:
@ -541,7 +534,7 @@ const SecondaryMonitorDisplayHorizontal = {
scale = 1;
translationY = 0;
if (!Main.layoutManager._startingUp && (!opt.SHOW_WS_PREVIEW_BG || opt.OVERVIEW_MODE2))
translationY = this._thumbnails.height * (opt.SEC_WS_TMB_TOP ? -1 : 1);
translationY = (this._thumbnails.height + spacing) * (opt.SEC_WS_TMB_TOP ? -1 : 1);
break;
case ControlsState.WINDOW_PICKER:
@ -592,11 +585,11 @@ const SecondaryMonitorDisplayHorizontal = {
let offset = Math.round(height - wsTmbHeight - wsBoxHeight - spacing) / 2;
const wsbX = Math.round((startX + width - wsBoxWidth) / 2);
const wsbX = Math.round(startX + (width - wsBoxWidth) / 2);
const wsbY = startY + opt.SEC_WS_TMB_TOP
const wsbY = startY + (opt.SEC_WS_TMB_TOP
? wsTmbHeight + spacing + offset
: offset;
: offset);
workspaceBox.set_origin(wsbX, wsbY);
workspaceBox.set_size(wsBoxWidth, wsBoxHeight);
@ -760,7 +753,6 @@ const ExtraWorkspaceViewCommon = {
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,
@ -934,24 +926,16 @@ const WorkspacesDisplayCommon = {
case Clutter.KEY_Tab:
if (Main.overview.searchController.searchActive) {
Main.overview.searchEntry.grab_key_focus();
} else if (opt.OVERVIEW_MODE2 && !opt.WORKSPACE_MODE && state === 1) {
// expose windows by "clicking" on ws thumbnail
// in this case overview stateAdjustment will be used for transition
Main.overview._overview.controls._thumbnailsBox._activateThumbnailAtPoint(0, 0, global.get_current_time(), true);
Main.ctrlAltTabManager._items.forEach(i => {
if (i.sortGroup === 1 && i.name === 'Windows')
Main.ctrlAltTabManager.focusGroup(i);
});
} else if (opt.OVERVIEW_MODE && !opt.WORKSPACE_MODE && state === 1) {
// expose windows for OVERVIEW_MODE 1
const wsIndex = global.workspace_manager.get_active_workspace().index();
// after expose animation activate keyboard for window selection
const callback = Me.Util.activateKeyboardForWorkspaceView;
this._workspacesViews.forEach(
view => {
view.exposeWindows(wsIndex, callback);
}
);
} else if (!opt.WORKSPACE_MODE && state <= 1) {
if (opt.OVERVIEW_MODE2)
Main.overview._overview.controls._updateSearchStyle(true);
// spread windows in OVERVIEW_MODE
if (state < 1)
opt.WORKSPACE_MODE = 1;
else if (opt.OVERVIEW_MODE2)
Me.Util.exposeWindowsWithOverviewTransition();
else
Me.Util.exposeWindows();
} else {
if (state === 2)
return Clutter.EVENT_PROPAGATE;