summaryrefslogtreecommitdiffstats
path: root/extensions/44/vertical-workspaces/lib/appDisplay.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 16:02:53 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-08 16:02:53 +0000
commit4d8b071804d73b7a733f2b7696fde40caf8800bb (patch)
tree86aefc1c0ea9c596bab0ecbc0c054a2378d6cd13 /extensions/44/vertical-workspaces/lib/appDisplay.js
parentUpdating 44/no-overview to version 44 [68db01d]. (diff)
downloadgnome-shell-extensions-extra-4d8b071804d73b7a733f2b7696fde40caf8800bb.tar.xz
gnome-shell-extensions-extra-4d8b071804d73b7a733f2b7696fde40caf8800bb.zip
Updating 44/vertical-workspaces to version 37+20231208 [0d82192].
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'extensions/44/vertical-workspaces/lib/appDisplay.js')
-rw-r--r--extensions/44/vertical-workspaces/lib/appDisplay.js1243
1 files changed, 760 insertions, 483 deletions
diff --git a/extensions/44/vertical-workspaces/lib/appDisplay.js b/extensions/44/vertical-workspaces/lib/appDisplay.js
index 2ac70b1..aeb2808 100644
--- a/extensions/44/vertical-workspaces/lib/appDisplay.js
+++ b/extensions/44/vertical-workspaces/lib/appDisplay.js
@@ -10,246 +10,501 @@
'use strict';
-const { Clutter, GLib, GObject, Meta, Shell, St, Graphene, Pango } = imports.gi;
+const Clutter = imports.gi.Clutter;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Graphene = imports.gi.Graphene;
+const Meta = imports.gi.Meta;
+const Pango = imports.gi.Pango;
+const Shell = imports.gi.Shell;
+const St = imports.gi.St;
-const DND = imports.ui.dnd;
-const Main = imports.ui.main;
const AppDisplay = imports.ui.appDisplay;
+const DND = imports.ui.dnd;
const IconGrid = imports.ui.iconGrid;
+const Main = imports.ui.main;
-const ExtensionUtils = imports.misc.extensionUtils;
-const Me = ExtensionUtils.getCurrentExtension();
-const IconGridOverride = Me.imports.lib.iconGrid;
-const _Util = Me.imports.lib.util;
+let Me;
+let opt;
-const DIALOG_SHADE_NORMAL = Clutter.Color.from_pixel(0x00000022);
-const DIALOG_SHADE_HIGHLIGHT = Clutter.Color.from_pixel(0x00000000);
+let _timeouts;
-// gettext
-const _ = Me.imports.lib.settings._;
+// DIALOG_SHADE_NORMAL = Clutter.Color.from_pixel(0x00000022);
+// DIALOG_SHADE_HIGHLIGHT = Clutter.Color.from_pixel(0x00000000);
-let _overrides;
+var AppDisplayModule = class {
+ constructor(me) {
+ Me = me;
+ opt = Me.opt;
-let _appGridLayoutSettings;
-let _appDisplayScrollConId;
-let _appSystemStateConId;
-let _appGridLayoutConId;
-let _origAppViewItemAcceptDrop;
-let _updateFolderIcons;
+ this._firstActivation = true;
+ this.moduleEnabled = false;
+ this._overrides = null;
-let opt;
-let shellVersion = _Util.shellVersion;
-let _firstRun = true;
+ this._appGridLayoutSettings = null;
+ this._appDisplayScrollConId = 0;
+ this._appSystemStateConId = 0;
+ this._appGridLayoutConId = 0;
+ this._origAppViewItemAcceptDrop = null;
+ this._updateFolderIcons = 0;
+ }
-function update(reset = false) {
- opt = Me.imports.lib.settings.opt;
- const moduleEnabled = opt.get('appDisplayModule', true);
- reset = reset || !moduleEnabled;
+ cleanGlobals() {
+ Me = null;
+ opt = null;
+ }
- // don't even touch this module if disabled
- if (_firstRun && reset)
- return;
+ update(reset) {
+ this._removeTimeouts();
+ this.moduleEnabled = opt.get('appDisplayModule');
+ const conflict = false;
- _firstRun = false;
+ reset = reset || !this.moduleEnabled || conflict;
- if (_overrides)
- _overrides.removeAll();
+ // don't touch the original code if module disabled
+ if (reset && !this._firstActivation) {
+ this._disableModule();
+ this.moduleEnabled = false;
+ } else if (!reset) {
+ this._firstActivation = false;
+ this._activateModule();
+ }
+ if (reset && this._firstActivation) {
+ this.moduleEnabled = false;
+ console.debug(' AppDisplayModule - Keeping untouched');
+ }
+ }
- if (reset) {
- _setAppDisplayOrientation(false);
- _updateAppGridProperties(reset);
- _updateAppGridDND(reset);
- _restoreOverviewGroup();
- _overrides = null;
- opt = null;
- return;
+ _activateModule() {
+ Me.Modules.iconGridModule.update();
+
+ if (!this._overrides)
+ this._overrides = new Me.Util.Overrides();
+
+ _timeouts = {};
+
+ // Common
+ this._overrides.addOverride('FolderView', AppDisplay.FolderView.prototype, FolderView);
+ this._overrides.addOverride('FolderIcon', AppDisplay.FolderIcon.prototype, FolderIcon);
+ if (opt.APP_GRID_ACTIVE_PREVIEW)
+ this._overrides.addOverride('ActiveFolderIcon', AppDisplay.FolderIcon, ActiveFolderIcon);
+ this._overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIcon);
+ this._overrides.addOverride('AppDisplay', AppDisplay.AppDisplay.prototype, AppDisplayCommon);
+ this._overrides.addOverride('AppViewItem', AppDisplay.AppViewItem.prototype, AppViewItemCommon);
+ this._overrides.addOverride('BaseAppViewCommon', AppDisplay.BaseAppView.prototype, BaseAppViewCommon);
+
+ if (opt.ORIENTATION === Clutter.Orientation.VERTICAL) {
+ this._overrides.addOverride('AppDisplayVertical', AppDisplay.AppDisplay.prototype, AppDisplayVertical);
+ this._overrides.addOverride('BaseAppViewVertical', AppDisplay.BaseAppView.prototype, BaseAppViewVertical);
+ }
+
+ // Custom App Grid
+ this._overrides.addOverride('AppFolderDialog', AppDisplay.AppFolderDialog.prototype, AppFolderDialog);
+ if (Me.shellVersion >= 43) {
+ // const defined class needs to be touched before real access
+ this._dummy = AppDisplay.AppGrid;
+ delete this._dummy;
+ // BaseAppViewGridLayout is not exported, we can only access current instance
+ this._overrides.addOverride('BaseAppViewGridLayout', Main.overview._overview.controls._appDisplay._appGridLayout, BaseAppViewGridLayout);
+ this._overrides.addOverride('FolderGrid', AppDisplay.FolderGrid.prototype, FolderGrid);
+ } else {
+ this._overrides.addOverride('FolderGrid', AppDisplay.FolderGrid.prototype, FolderGridLegacy);
+ }
+
+ this._setAppDisplayOrientation(opt.ORIENTATION === Clutter.Orientation.VERTICAL);
+ this._updateDND();
+ if (!Main.sessionMode.isGreeter)
+ this._updateAppDisplayProperties();
+
+ console.debug(' AppDisplayModule - Activated');
}
- _overrides = new _Util.Overrides();
+ _disableModule() {
+ Me.Modules.iconGridModule.update(true);
+
+ if (this._overrides)
+ this._overrides.removeAll();
+ this._overrides = null;
- if (opt.ORIENTATION === Clutter.Orientation.VERTICAL) {
- _overrides.addOverride('AppDisplayVertical', AppDisplay.AppDisplay.prototype, AppDisplayVertical);
- _overrides.addOverride('BaseAppViewVertical', AppDisplay.BaseAppView.prototype, BaseAppViewVertical);
+ const reset = true;
+ this._setAppDisplayOrientation(false);
+ this._updateAppDisplayProperties(reset);
+ this._updateDND(reset);
+ this._restoreOverviewGroup();
+ this._removeStatusMessage();
+
+ console.debug(' AppDisplayModule - Disabled');
}
- // Custom App Grid
- _overrides.addOverride('AppFolderDialog', AppDisplay.AppFolderDialog.prototype, AppFolderDialog);
- if (shellVersion >= 43) {
- // const defined class needs to be touched before real access
- AppDisplay.BaseAppViewGridLayout;
- _overrides.addOverride('BaseAppViewGridLayout', AppDisplay.BaseAppViewGridLayout.prototype, BaseAppViewGridLayout);
+ _removeTimeouts() {
+ if (_timeouts) {
+ Object.values(_timeouts).forEach(t => {
+ if (t)
+ GLib.source_remove(t);
+ });
+ _timeouts = null;
+ }
}
- _overrides.addOverride('FolderView', AppDisplay.FolderView.prototype, FolderView);
- _overrides.addOverride('FolderIcon', AppDisplay.FolderIcon.prototype, FolderIcon);
- _overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIcon);
- _overrides.addOverride('AppDisplay', AppDisplay.AppDisplay.prototype, AppDisplayCommon);
- _overrides.addOverride('AppViewItem', AppDisplay.AppViewItem.prototype, AppViewItemCommon);
- _overrides.addOverride('BaseAppViewCommon', AppDisplay.BaseAppView.prototype, BaseAppViewCommon);
-
- _setAppDisplayOrientation(opt.ORIENTATION === Clutter.Orientation.VERTICAL);
- _updateAppGridProperties();
- _updateAppGridDND();
- opt._appGridNeedsRedisplay = true;
-}
-
-function _setAppDisplayOrientation(vertical = false) {
- const CLUTTER_ORIENTATION = vertical ? Clutter.Orientation.VERTICAL : Clutter.Orientation.HORIZONTAL;
- const scroll = vertical ? 'vscroll' : 'hscroll';
- // app display to vertical has issues - page indicator not working
- // global appDisplay orientation switch is not built-in
- let appDisplay = Main.overview._overview._controls._appDisplay;
- // following line itself only changes in which axis will operate overshoot detection which switches appDisplay pages while dragging app icon to vertical
- appDisplay._orientation = CLUTTER_ORIENTATION;
- appDisplay._grid.layoutManager._orientation = CLUTTER_ORIENTATION;
- appDisplay._swipeTracker.orientation = CLUTTER_ORIENTATION;
- appDisplay._swipeTracker._reset();
- if (vertical) {
- appDisplay._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL);
-
- // move and change orientation of page indicators
- // needs corrections in appgrid page calculations, e.g. appDisplay.adaptToSize() fnc,
- // which complicates use of super call inside the function
- const pageIndicators = appDisplay._pageIndicators;
- pageIndicators.vertical = true;
- appDisplay._box.vertical = false;
- pageIndicators.x_expand = false;
- pageIndicators.y_align = Clutter.ActorAlign.CENTER;
- pageIndicators.x_align = Clutter.ActorAlign.START;
-
- const scrollContainer = appDisplay._scrollView.get_parent();
- if (shellVersion < 43) {
- // remove touch friendly side navigation bars / arrows
- if (appDisplay._hintContainer && appDisplay._hintContainer.get_parent())
- scrollContainer.remove_child(appDisplay._hintContainer);
+
+ _setAppDisplayOrientation(vertical = false) {
+ const CLUTTER_ORIENTATION = vertical ? Clutter.Orientation.VERTICAL : Clutter.Orientation.HORIZONTAL;
+ const scroll = vertical ? 'vscroll' : 'hscroll';
+ // app display to vertical has issues - page indicator not working
+ // global appDisplay orientation switch is not built-in
+ let appDisplay = Main.overview._overview._controls._appDisplay;
+ // following line itself only changes in which axis will operate overshoot detection which switches appDisplay pages while dragging app icon to vertical
+ appDisplay._orientation = CLUTTER_ORIENTATION;
+ appDisplay._grid.layoutManager._orientation = CLUTTER_ORIENTATION;
+ appDisplay._swipeTracker.orientation = CLUTTER_ORIENTATION;
+ appDisplay._swipeTracker._reset();
+ if (vertical) {
+ appDisplay._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL);
+
+ // move and change orientation of page indicators
+ const pageIndicators = appDisplay._pageIndicators;
+ pageIndicators.vertical = true;
+ appDisplay._box.vertical = false;
+ pageIndicators.x_expand = false;
+ pageIndicators.y_align = Clutter.ActorAlign.CENTER;
+ pageIndicators.x_align = Clutter.ActorAlign.START;
+
+ const scrollContainer = appDisplay._scrollView.get_parent();
+ if (Me.shellVersion < 43) {
+ // remove touch friendly side navigation bars / arrows
+ if (appDisplay._hintContainer && appDisplay._hintContainer.get_parent())
+ scrollContainer.remove_child(appDisplay._hintContainer);
+ } else {
+ // moving these bars needs more patching of the appDisplay's code
+ // for now we just change bars style to be more like vertically oriented arrows indicating direction to prev/next page
+ appDisplay._nextPageIndicator.add_style_class_name('nextPageIndicator');
+ appDisplay._prevPageIndicator.add_style_class_name('prevPageIndicator');
+ }
+
+ // setting their x_scale to 0 removes the arrows and avoid allocation issues compared to .hide() them
+ appDisplay._nextPageArrow.scale_x = 0;
+ appDisplay._prevPageArrow.scale_x = 0;
} else {
- // moving these bars needs more patching of the appDisplay's code
- // for now we just change bars style to be more like vertically oriented arrows indicating direction to prev/next page
- appDisplay._nextPageIndicator.add_style_class_name('nextPageIndicator');
- appDisplay._prevPageIndicator.add_style_class_name('prevPageIndicator');
- }
+ appDisplay._scrollView.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.NEVER);
+ if (this._appDisplayScrollConId) {
+ appDisplay._adjustment.disconnect(this._appDisplayScrollConId);
+ this._appDisplayScrollConId = 0;
+ }
- // setting their x_scale to 0 removes the arrows and avoid allocation issues compared to .hide() them
- appDisplay._nextPageArrow.scale_x = 0;
- appDisplay._prevPageArrow.scale_x = 0;
- } else {
- appDisplay._scrollView.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.NEVER);
- if (_appDisplayScrollConId) {
- appDisplay._adjustment.disconnect(_appDisplayScrollConId);
- _appDisplayScrollConId = 0;
+ // restore original page indicators
+ const pageIndicators = appDisplay._pageIndicators;
+ pageIndicators.vertical = false;
+ appDisplay._box.vertical = true;
+ pageIndicators.x_expand = true;
+ pageIndicators.y_align = Clutter.ActorAlign.END;
+ pageIndicators.x_align = Clutter.ActorAlign.CENTER;
+
+ // put back touch friendly navigation bars/buttons
+ const scrollContainer = appDisplay._scrollView.get_parent();
+ if (appDisplay._hintContainer && !appDisplay._hintContainer.get_parent()) {
+ scrollContainer.add_child(appDisplay._hintContainer);
+ // the hit container covers the entire app grid and added at the top of the stack blocks DND drops
+ // so it needs to be pushed below
+ scrollContainer.set_child_below_sibling(appDisplay._hintContainer, null);
+ }
+
+ appDisplay._nextPageArrow.scale_x = 1;
+ appDisplay._prevPageArrow.scale_x = 1;
+
+ appDisplay._nextPageIndicator.remove_style_class_name('nextPageIndicator');
+ appDisplay._prevPageIndicator.remove_style_class_name('prevPageIndicator');
}
- // restore original page indicators
- const pageIndicators = appDisplay._pageIndicators;
- pageIndicators.vertical = false;
- appDisplay._box.vertical = true;
- pageIndicators.x_expand = true;
- pageIndicators.y_align = Clutter.ActorAlign.END;
- pageIndicators.x_align = Clutter.ActorAlign.CENTER;
-
- // put back touch friendly navigation bars/buttons
- const scrollContainer = appDisplay._scrollView.get_parent();
- if (appDisplay._hintContainer && !appDisplay._hintContainer.get_parent()) {
- scrollContainer.add_child(appDisplay._hintContainer);
- // the hit container covers the entire app grid and added at the top of the stack blocks DND drops
- // so it needs to be pushed below
- scrollContainer.set_child_below_sibling(appDisplay._hintContainer, null);
+ // value for page indicator is calculated from scroll adjustment, horizontal needs to be replaced by vertical
+ appDisplay._adjustment = appDisplay._scrollView[scroll].adjustment;
+
+ // no need to connect already connected signal (wasn't removed the original one before)
+ if (!vertical) {
+ // reset used appDisplay properties
+ Main.overview._overview._controls._appDisplay.scale_y = 1;
+ Main.overview._overview._controls._appDisplay.scale_x = 1;
+ Main.overview._overview._controls._appDisplay.opacity = 255;
+ return;
}
- appDisplay._nextPageArrow.scale_x = 1;
- appDisplay._prevPageArrow.scale_x = 1;
+ // update appGrid dot pages indicators
+ this._appDisplayScrollConId = appDisplay._adjustment.connect('notify::value', adj => {
+ const value = adj.value / adj.page_size;
+ appDisplay._pageIndicators.setCurrentPosition(value);
+ });
+ }
+
+ // Set App Grid columns, rows, icon size, incomplete pages
+ _updateAppDisplayProperties(reset = false) {
+ opt._appGridNeedsRedisplay = false;
+ // columns, rows, icon size
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ appDisplay.visible = true;
+ if (reset) {
+ appDisplay._grid.layoutManager.fixedIconSize = -1;
+ appDisplay._grid.layoutManager.allow_incomplete_pages = true;
+ appDisplay._grid._currentMode = -1;
+ appDisplay._grid.setGridModes();
+ if (this._appGridLayoutSettings) {
+ this._appGridLayoutSettings.disconnect(this._appGridLayoutConId);
+ this._appGridLayoutConId = 0;
+ this._appGridLayoutSettings = null;
+ }
+ appDisplay._redisplay();
- appDisplay._nextPageIndicator.remove_style_class_name('nextPageIndicator');
- appDisplay._prevPageIndicator.remove_style_class_name('prevPageIndicator');
+ appDisplay._grid.set_style('');
+ this._updateAppGrid(reset);
+ } else {
+ // update grid on layout reset
+ if (!this._appGridLayoutSettings) {
+ this._appGridLayoutSettings = new Gio.Settings({ schema_id: 'org.gnome.shell' });
+ this._appGridLayoutConId = this._appGridLayoutSettings.connect('changed::app-picker-layout', this._updateLayout);
+ }
+
+ appDisplay._grid.layoutManager.allow_incomplete_pages = opt.APP_GRID_ALLOW_INCOMPLETE_PAGES;
+ // appDisplay._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`);
+ // APP_GRID_SPACING constant is used for grid dimensions calculation
+ // but sometimes the actual grid spacing properties affect/change the calculated size, therefore we set it lower to avoid this problem
+ // main app grid always use available space and the spacing is optimized for the grid dimensions
+ appDisplay._grid.set_style('column-spacing: 5px; row-spacing: 5px;');
+
+ // force redisplay
+ appDisplay._grid._currentMode = -1;
+ appDisplay._grid.setGridModes();
+ appDisplay._grid.layoutManager.fixedIconSize = opt.APP_GRID_ICON_SIZE;
+ // avoid resetting appDisplay before startup animation
+ // x11 shell restart skips startup animation
+ if (!Main.layoutManager._startingUp) {
+ this._updateAppGrid();
+ } else if (Main.layoutManager._startingUp && (Meta.is_restart() || Me.Util.dashIsDashToDock())) {
+ _timeouts.three = GLib.idle_add(GLib.PRIORITY_LOW, () => {
+ this._updateAppGrid();
+ _timeouts.three = 0;
+ return GLib.SOURCE_REMOVE;
+ });
+ }
+ }
}
- // value for page indicator is calculated from scroll adjustment, horizontal needs to be replaced by vertical
- appDisplay._adjustment = appDisplay._scrollView[scroll].adjustment;
+ _updateDND(reset) {
+ if (!reset) {
+ if (!this._appSystemStateConId && opt.APP_GRID_INCLUDE_DASH >= 3) {
+ this._appSystemStateConId = Shell.AppSystem.get_default().connect(
+ 'app-state-changed',
+ () => {
+ this._updateFolderIcons = true;
+ Main.overview._overview.controls._appDisplay._redisplay();
+ }
+ );
+ }
+ } else if (this._appSystemStateConId) {
+ Shell.AppSystem.get_default().disconnect(this._appSystemStateConId);
+ this._appSystemStateConId = 0;
+ }
+ }
- // no need to connect already connected signal (wasn't removed the original one before)
- if (!vertical) {
- // reset used appDisplay properties
- Main.overview._overview._controls._appDisplay.scale_y = 1;
- Main.overview._overview._controls._appDisplay.scale_x = 1;
+ _restoreOverviewGroup() {
+ Main.overview.dash.showAppsButton.checked = false;
+ Main.layoutManager.overviewGroup.opacity = 255;
+ Main.layoutManager.overviewGroup.scale_x = 1;
+ Main.layoutManager.overviewGroup.scale_y = 1;
+ Main.layoutManager.overviewGroup.hide();
+ Main.overview._overview._controls._appDisplay.translation_x = 0;
+ Main.overview._overview._controls._appDisplay.translation_y = 0;
+ Main.overview._overview._controls._appDisplay.visible = true;
Main.overview._overview._controls._appDisplay.opacity = 255;
- return;
}
- // update appGrid dot pages indicators
- _appDisplayScrollConId = appDisplay._adjustment.connect('notify::value', adj => {
- const value = adj.value / adj.page_size;
- appDisplay._pageIndicators.setCurrentPosition(value);
- });
-}
-
-// Set App Grid columns, rows, icon size, incomplete pages
-function _updateAppGridProperties(reset = false) {
- opt._appGridNeedsRedisplay = false;
- // columns, rows, icon size
- const appDisplay = Main.overview._overview._controls._appDisplay;
- appDisplay.visible = true;
-
- if (reset) {
- appDisplay._grid.layoutManager.fixedIconSize = -1;
- appDisplay._grid.layoutManager.allow_incomplete_pages = true;
- appDisplay._grid.setGridModes();
- if (_appGridLayoutSettings) {
- _appGridLayoutSettings.disconnect(_appGridLayoutConId);
- _appGridLayoutConId = 0;
- _appGridLayoutSettings = null;
+ // update all invalid positions that may be result of grid/icon size change
+ _updateIconPositions() {
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ const layout = JSON.stringify(global.settings.get_value('app-picker-layout').recursiveUnpack());
+ // if app grid layout is empty, sort source alphabetically to avoid misplacing
+ if (layout === JSON.stringify([]) && appDisplay._sortOrderedItemsAlphabetically)
+ appDisplay._sortOrderedItemsAlphabetically();
+ const icons = [...appDisplay._orderedItems];
+ for (let i = 0; i < icons.length; i++)
+ appDisplay._moveItem(icons[i], -1, -1);
+ }
+
+ _removeIcons() {
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ const icons = [...appDisplay._orderedItems];
+ for (let i = 0; i < icons.length; i++) {
+ const icon = icons[i];
+ if (icon._dialog)
+ Main.layoutManager.overviewGroup.remove_child(icon._dialog);
+ appDisplay._removeItem(icon);
+ icon.destroy();
}
- appDisplay._redisplay();
+ appDisplay._folderIcons = [];
+ }
+
+ _removeStatusMessage() {
+ if (Me._vShellStatusMessage) {
+ if (Me._vShellMessageTimeoutId) {
+ GLib.source_remove(Me._vShellMessageTimeoutId);
+ Me._vShellMessageTimeoutId = 0;
+ }
+ Me._vShellStatusMessage.destroy();
+ Me._vShellStatusMessage = null;
+ }
+ }
- appDisplay._grid.set_style('');
- _resetAppGrid();
- } else {
- // update grid on layout reset
- if (!_appGridLayoutSettings) {
- _appGridLayoutSettings = ExtensionUtils.getSettings('org.gnome.shell');
- _appGridLayoutConId = _appGridLayoutSettings.connect('changed::app-picker-layout', _resetAppGrid);
+ _updateLayout(settings, key) {
+ const currentValue = JSON.stringify(settings.get_value(key).deep_unpack());
+ const emptyValue = JSON.stringify([]);
+ const customLayout = currentValue !== emptyValue;
+ if (!customLayout) {
+ this._updateAppGrid();
+ }
+ }
+
+ _updateAppGrid(reset = false, callback) {
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ // reset the grid only if called directly without args or if all folders where removed by using reset button in Settings window
+ // otherwise this function is called every time a user moves icon to another position as a settings callback
+
+ // force update icon size using adaptToSize(), the page size cannot be the same as the current one
+ appDisplay._grid.layoutManager._pageWidth += 1;
+ appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight);
+
+ // don't delay the first screen lock on GS < 44, removing icons takes a time and with other 15 enabled extensions it can be multiplied by 15
+ if (!Main.sessionMode.isLocked)
+ this._removeIcons();
+
+ appDisplay._redisplay();
+ // don't realize appDisplay on disable, or at startup if disabled
+ // always realize appDisplay otherwise to avoid errors while opening folders (that I was unable to trace)
+ if (reset || (!opt.APP_GRID_PERFORMANCE && callback)) {
+ this._removeStatusMessage();
+ if (callback)
+ callback();
+ return;
}
- appDisplay._grid.layoutManager.allow_incomplete_pages = opt.APP_GRID_ALLOW_INCOMPLETE_PAGES;
- appDisplay._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`);
+ // workaround - silently realize appDisplay
+ // appDisplay and its content must be "visible" (opacity > 0) on the screen (within monitor geometry)
+ // to realize its objects
+ // this action takes some time and affects animations during the first use
+ // if we do it invisibly before user needs it, it can improve the user's experience
+
+ this._exposeAppGrid();
+
+ // let the main loop process our changes before continuing
+ _timeouts.one = GLib.idle_add(GLib.PRIORITY_LOW, () => {
+ this._updateIconPositions();
+ if (appDisplay._sortOrderedItemsAlphabetically) {
+ appDisplay._sortOrderedItemsAlphabetically();
+ appDisplay._grid.layoutManager._pageWidth += 1;
+ appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight);
+ appDisplay._setLinearPositions(appDisplay._orderedItems);
+ }
- // force redisplay
- appDisplay._grid._currentMode = -1;
- appDisplay._grid.setGridModes();
- appDisplay._grid.layoutManager.fixedIconSize = opt.APP_GRID_ICON_SIZE;
- // appDisplay._folderIcons.forEach(folder => folder._dialog?._updateFolderSize());
- _resetAppGrid();
+ appDisplay._redisplay();
+ // realize also all app folders (by opening them) so the first popup is as smooth as the second one
+ // let the main loop process our changes before continuing
+ _timeouts.two = GLib.idle_add(GLib.PRIORITY_LOW, () => {
+ this._restoreAppGrid();
+ Me._resetInProgress = false;
+ this._removeStatusMessage();
+
+ if (callback)
+ callback();
+
+ _timeouts.two = 0;
+ return GLib.SOURCE_REMOVE;
+ });
+ _timeouts.one = 0;
+ return GLib.SOURCE_REMOVE;
+ });
}
-}
-function _updateAppGridDND(reset) {
- if (!reset) {
- if (!_appSystemStateConId && opt.APP_GRID_INCLUDE_DASH >= 3) {
- _appSystemStateConId = Shell.AppSystem.get_default().connect(
- 'app-state-changed',
- () => {
- _updateFolderIcons = true;
- Main.overview._overview._controls._appDisplay._redisplay();
- }
- );
+ _exposeAppGrid() {
+ const overviewGroup = Main.layoutManager.overviewGroup;
+ if (!overviewGroup.visible) {
+ // scale down the overviewGroup so it don't cover uiGroup
+ overviewGroup.scale_y = 0.001;
+ // make it invisible to the eye, but visible for the renderer
+ overviewGroup.opacity = 1;
+ // if overview is hidden, show it
+ overviewGroup.visible = true;
}
- } else if (_appSystemStateConId) {
- Shell.AppSystem.get_default().disconnect(_appSystemStateConId);
- _appSystemStateConId = 0;
+
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ appDisplay.opacity = 1;
+
+ // find usable value, sometimes it's one, sometime the other...
+ let [x, y] = appDisplay.get_position();
+ let { x1, y1 } = appDisplay.allocation;
+ x = x === Infinity ? 0 : x;
+ y = y === Infinity ? 0 : y;
+ x1 = x1 === Infinity ? 0 : x1;
+ y1 = y1 === Infinity ? 0 : y1;
+ appDisplay.translation_x = -(x ? x : x1);
+ appDisplay.translation_y = -(y ? y : y1);
+ this._exposeAppFolders();
+ }
+
+ _exposeAppFolders() {
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ appDisplay._folderIcons.forEach(d => {
+ d._ensureFolderDialog();
+ d._dialog._updateFolderSize();
+ d._dialog.scale_y = 0.0001;
+ d._dialog.show();
+ });
+ }
+
+ _restoreAppGrid() {
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ appDisplay.translation_x = 0;
+ appDisplay.translation_y = 0;
+ // appDisplay.opacity = 0;
+ this._hideAppFolders();
+
+ const overviewGroup = Main.layoutManager.overviewGroup;
+ if (!Main.overview._shown)
+ overviewGroup.hide();
+ overviewGroup.scale_y = 1;
+ overviewGroup.opacity = 255;
+
+ this._removeStatusMessage();
+ }
+
+ _hideAppFolders() {
+ const appDisplay = Main.overview._overview._controls._appDisplay;
+ appDisplay._folderIcons.forEach(d => {
+ if (d._dialog) {
+ d._dialog._updateFolderSize();
+ d._dialog.hide();
+ d._dialog.scale_y = 1;
+ }
+ });
+ }
+
+ _getWindowApp(metaWin) {
+ const tracker = Shell.WindowTracker.get_default();
+ return tracker.get_window_app(metaWin);
}
- if (opt.APP_GRID_ORDER && !reset) {
- if (!_origAppViewItemAcceptDrop)
- _origAppViewItemAcceptDrop = AppDisplay.AppViewItem.prototype.acceptDrop;
- AppDisplay.AppViewItem.prototype.acceptDrop = () => false;
- } else if (_origAppViewItemAcceptDrop) {
- AppDisplay.AppViewItem.prototype.acceptDrop = _origAppViewItemAcceptDrop;
+
+ _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;
}
-}
-function _restoreOverviewGroup() {
- Main.overview.dash.showAppsButton.checked = false;
- Main.layoutManager.overviewGroup.opacity = 255;
- Main.layoutManager.overviewGroup.scale_x = 1;
- Main.layoutManager.overviewGroup.hide();
-}
+ _getAppRecentWorkspace(app) {
+ const recentWin = this._getAppLastUsedWindow(app);
+ if (recentWin)
+ return recentWin.get_workspace();
+
+ return null;
+ }
+};
const AppDisplayVertical = {
// correction of the appGrid size when page indicators were moved from the bottom to the right
@@ -302,7 +557,7 @@ const AppDisplayCommon = {
const appsInsideFolders = new Set();
this._folderIcons = [];
- if (!opt.APP_GRID_ORDER) {
+ if (!opt.APP_GRID_USAGE) {
let folders = this._folderSettings.get_strv('folder-children');
folders.forEach(id => {
let path = `${this._folderSettings.path}folders/${id}/`;
@@ -317,8 +572,8 @@ const AppDisplayCommon = {
if (icon.pressed)
this.updateDragFocus(icon);
});
- } else if (_updateFolderIcons && opt.APP_GRID_EXCLUDE_RUNNING) {
- // if any app changed its running state, update folder icon
+ } else if (this._updateFolderIcons && opt.APP_GRID_EXCLUDE_RUNNING) {
+ // if any app changed its running state, update folder icon
icon.icon.update();
}
@@ -334,8 +589,9 @@ const AppDisplayCommon = {
icon.getAppIds().forEach(appId => appsInsideFolders.add(appId));
});
}
+
// reset request to update active icon
- _updateFolderIcons = false;
+ this._updateFolderIcons = false;
// Allow dragging of the icon only if the Dash would accept a drop to
// change favorite-apps. There are no other possible drop targets from
@@ -348,7 +604,7 @@ const AppDisplayCommon = {
global.settings.is_writable('app-picker-layout');
apps.forEach(appId => {
- if (!opt.APP_GRID_ORDER && appsInsideFolders.has(appId))
+ if (!opt.APP_GRID_USAGE && appsInsideFolders.has(appId))
return;
let icon = this._items.get(appId);
@@ -380,7 +636,7 @@ const AppDisplayCommon = {
dragMotion: this._onDragMotion.bind(this),
};
DND.addDragMonitor(this._dragMonitor);
- if (shellVersion < 43)
+ if (Me.shellVersion < 43)
this._slideSidePages(AppDisplay.SidePages.PREVIOUS | AppDisplay.SidePages.NEXT | AppDisplay.SidePages.DND);
else
this._appGridLayout.showPageIndicators();
@@ -419,50 +675,16 @@ const AppDisplayCommon = {
this._redisplay();
},
- // accept source from active preview
+ // accept source from active folder preview
acceptDrop(source) {
- if (opt.APP_GRID_ORDER)
+ if (opt.APP_GRID_USAGE)
return false;
if (source._sourceItem)
source = source._sourceItem;
- let dropTarget = null;
- if (shellVersion >= 43) {
- dropTarget = this._dropTarget;
- delete this._dropTarget;
- }
-
- if (!this._canAccept(source))
+ if (!BaseAppViewCommon.acceptDrop.bind(this)(source))
return false;
- if ((shellVersion < 43 && this._dropPage) ||
- (shellVersion >= 43 && (dropTarget === this._prevPageIndicator ||
- dropTarget === this._nextPageIndicator))) {
- let increment;
-
- if (shellVersion < 43)
- increment = this._dropPage === AppDisplay.SidePages.NEXT ? 1 : -1;
- else
- increment = dropTarget === this._prevPageIndicator ? -1 : 1;
-
- const { currentPage, nPages } = this._grid;
- const page = Math.min(currentPage + increment, nPages);
- const position = page < nPages ? -1 : 0;
-
- this._moveItem(source, page, position);
- this.goToPage(page);
- } else if (this._delayedMoveData) {
- // Dropped before the icon was moved
- const { page, position } = this._delayedMoveData;
-
- try {
- this._moveItem(source, page, position);
- } catch (e) {
- log(`Warning:${e}`);
- }
- this._removeDelayedMove();
- }
-
this._savePages();
let view = AppDisplay._getViewFromIcon(source);
@@ -493,7 +715,7 @@ const BaseAppViewVertical = {
this._pageIndicators.x_align = Clutter.ActorAlign.START;
this._pageIndicators.set_style('margin-right: 10px;');
const scrollContainer = this._scrollView.get_parent();
- if (shellVersion < 43) {
+ if (Me.shellVersion < 43) {
// remove touch friendly side navigation bars / arrows
if (this._hintContainer && this._hintContainer.get_parent())
scrollContainer.remove_child(this._hintContainer);
@@ -536,7 +758,7 @@ const BaseAppViewCommon = {
try {
this._moveItem(icon, page, position);
} catch (e) {
- log(`Warning:${e}`);
+ console.warn(`Warning:${e}`);
}
});
},
@@ -570,14 +792,19 @@ const BaseAppViewCommon = {
}
});
- // sort all alphabetically
- if (opt.APP_GRID_ORDER > 0) {
+ // different options for root app grid and app folders
+ const thisIsFolder = this instanceof AppDisplay.FolderView;
+ const thisIsAppDisplay = !thisIsFolder;
+ if ((opt.APP_GRID_ORDER && thisIsAppDisplay) ||
+ (opt.APP_FOLDER_ORDER && thisIsFolder)) {
// const { itemsPerPage } = this._grid;
let appIcons = this._orderedItems;
+ // sort all alphabetically
this._sortOrderedItemsAlphabetically(appIcons);
// appIcons.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
// then sort used apps by usage
- if (opt.APP_GRID_ORDER === 2)
+ if ((opt.APP_GRID_USAGE && thisIsAppDisplay) ||
+ (opt.APP_FOLDER_USAGE && thisIsFolder))
appIcons.sort((a, b) => Shell.AppUsage.get_default().compare(a.app.id, b.app.id));
// sort favorites first
@@ -595,9 +822,14 @@ const BaseAppViewCommon = {
}
// sort running first
- if (opt.APP_GRID_DASH_FIRST)
+ if (opt.APP_GRID_DASH_FIRST && thisIsAppDisplay)
appIcons.sort((a, b) => a.app.get_state() !== Shell.AppState.RUNNING && b.app.get_state() === Shell.AppState.RUNNING);
+ if (opt.APP_GRID_FOLDERS_FIRST)
+ appIcons.sort((a, b) => b._folder && !a._folder);
+ else if (opt.APP_GRID_FOLDERS_LAST)
+ appIcons.sort((a, b) => a._folder && !b._folder);
+
this._setLinearPositions(appIcons);
this._orderedItems = appIcons;
@@ -611,7 +843,7 @@ const BaseAppViewCommon = {
},
_canAccept(source) {
- return opt.APP_GRID_ORDER ? false : source instanceof AppDisplay.AppViewItem;
+ return source instanceof AppDisplay.AppViewItem;
},
// support active preview icons
@@ -619,12 +851,25 @@ const BaseAppViewCommon = {
if (!this._canAccept(source))
return false;
- if (source._sourceItem)
- source = source._sourceItem;
+ let dropTarget = null;
+ if (Me.shellVersion >= 43) {
+ dropTarget = this._dropTarget;
+ delete this._dropTarget;
+ }
+
+ if (!this._canAccept(source))
+ return false;
+ if ((Me.shellVersion < 43 && this._dropPage) ||
+ (Me.shellVersion >= 43 && (dropTarget === this._prevPageIndicator ||
+ dropTarget === this._nextPageIndicator))) {
+ let increment;
+
+ if (Me.shellVersion < 43)
+ increment = this._dropPage === AppDisplay.SidePages.NEXT ? 1 : -1;
+ else
+ increment = dropTarget === this._prevPageIndicator ? -1 : 1;
- if (this._dropPage) {
- const increment = this._dropPage === AppDisplay.SidePages.NEXT ? 1 : -1;
const { currentPage, nPages } = this._grid;
const page = Math.min(currentPage + increment, nPages);
const position = page < nPages ? -1 : 0;
@@ -635,7 +880,11 @@ const BaseAppViewCommon = {
// Dropped before the icon was moved
const { page, position } = this._delayedMoveData;
- this._moveItem(source, page, position);
+ try {
+ this._moveItem(source, page, position);
+ } catch (e) {
+ console.warn(`Warning:${e}`);
+ }
this._removeDelayedMove();
}
@@ -652,7 +901,7 @@ const BaseAppViewCommon = {
const appIcon = dragEvent.source;
- if (shellVersion < 43) {
+ if (Me.shellVersion < 43) {
this._dropPage = this._pageForCoords(dragEvent.x, dragEvent.y);
if (this._dropPage &&
this._dropPage === AppDisplay.SidePages.PREVIOUS &&
@@ -663,7 +912,7 @@ const BaseAppViewCommon = {
}
if (appIcon instanceof AppDisplay.AppViewItem) {
- if (shellVersion < 44) {
+ if (Me.shellVersion < 44) {
// Handle the drag overshoot. When dragging to above the
// icon grid, move to the page above; when dragging below,
// move to the page below.
@@ -685,7 +934,10 @@ const BaseAppViewCommon = {
}
}
- this._maybeMoveItem(dragEvent);
+ const thisIsFolder = this instanceof AppDisplay.FolderView;
+ const thisIsAppDisplay = !thisIsFolder;
+ if ((!opt.APP_GRID_ORDER && thisIsAppDisplay) || (!opt.APP_FOLDER_ORDER && thisIsFolder))
+ this._maybeMoveItem(dragEvent);
return DND.DragMotionResult.CONTINUE;
},
@@ -771,16 +1023,12 @@ const FolderIcon = {
: St.ButtonMask.ONE | St.ButtonMask.TWO;
this.button_mask = buttonMask;*/
this.button_mask = St.ButtonMask.ONE | St.ButtonMask.TWO;
-
- // build the folders now to avoid node errors when dragging active folder preview icons
- if (this.visible && opt.APP_GRID_ACTIVE_PREVIEW)
- this._ensureFolderDialog();
},
open() {
this._ensureFolderDialog();
- if (this._dialog._designCapacity !== this.view._orderedItems.length)
- this._dialog._updateFolderSize();
+ // if (this._dialog._designCapacity !== this.view._orderedItems.length)
+ this._dialog._updateFolderSize();
this.view._scrollView.vscroll.adjustment.value = 0;
this._dialog.popup();
@@ -789,15 +1037,7 @@ const FolderIcon = {
const FolderView = {
_createGrid() {
- let grid;
- if (shellVersion < 43)
- grid = new FolderGrid();
- else
- grid = new FolderGrid43();
-
- // IconGrid algorithm for adaptive icon size
- // counts with different default(max) size for folders
- grid.layoutManager._isFolder = true;
+ let grid = new AppDisplay.FolderGrid();
return grid;
},
@@ -832,11 +1072,15 @@ const FolderView = {
bin.child = this._orderedItems[i].app.create_icon_texture(subSize);
} else {
const app = this._orderedItems[i].app;
- const child = new ActiveFolderIcon(app);
+ const child = new AppDisplay.AppIcon(app, {
+ setSizeManually: true,
+ showLabel: false,
+ });
child._sourceItem = this._orderedItems[i];
child._sourceFolder = this;
child.icon.style_class = '';
child.icon.set_style('margin: 0; padding: 0;');
+ child._dot.set_style('margin-bottom: 1px;');
child.icon.setIconSize(subSize);
bin.child = child;
@@ -863,9 +1107,9 @@ const FolderView = {
layout.attach(bin, rtl ? (i + 1) % gridSize : i % gridSize, Math.floor(i / gridSize), 1, 1);
}
- // if folder content changed, update folder size
- if (this._dialog && this._dialog._designCapacity !== this._orderedItems.length)
- this._dialog._updateFolderSize();
+ // if folder content changed, update folder size, but not if it's empty
+ /* if (this._dialog && this._dialog._designCapacity !== this._orderedItems.length && this._orderedItems.length)
+ this._dialog._updateFolderSize();*/
return icon;
},
@@ -927,6 +1171,13 @@ const FolderView = {
items.push(icon);
});
+
+ if (opt.APP_FOLDER_ORDER)
+ Main.overview._overview.controls._appDisplay._sortOrderedItemsAlphabetically(items);
+
+ if (opt.APP_FOLDER_USAGE)
+ items.sort((a, b) => Shell.AppUsage.get_default().compare(a.app.id, b.app.id));
+
this._appIds = this._apps.map(app => app.get_id());
return items;
},
@@ -942,10 +1193,9 @@ const FolderView = {
};
// folder columns and rows
-const FolderGrid = GObject.registerClass(
-class FolderGrid extends IconGrid.IconGrid {
+const FolderGridLegacy = {
_init() {
- super._init({
+ IconGrid.IconGrid.prototype._init.bind(this)({
allow_incomplete_pages: false,
// For adaptive size (0), set the numbers high enough to fit all the icons
// to avoid splitting the icons to pages
@@ -954,56 +1204,52 @@ class FolderGrid extends IconGrid.IconGrid {
page_halign: Clutter.ActorAlign.CENTER,
page_valign: Clutter.ActorAlign.CENTER,
});
-
+ this.layout_manager._isFolder = true;
// if (!opt.APP_GRID_FOLDER_DEFAULT)
const spacing = opt.APP_GRID_SPACING;
this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`);
- this.layout_manager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
- }
+ this.layoutManager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
+ },
adaptToSize(width, height) {
this.layout_manager.adaptToSize(width, height);
- }
-});
-
-
-let FolderGrid43;
-// first reference to constant defined using const in other module returns undefined, the AppGrid const will remain empty and unused
-const AppGrid = AppDisplay.AppGrid;
-if (AppDisplay.AppGrid) {
- FolderGrid43 = GObject.registerClass(
- class FolderGrid43 extends AppDisplay.AppGrid {
- _init() {
- super._init({
- allow_incomplete_pages: false,
- columns_per_page: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 20,
- rows_per_page: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 20,
- page_halign: Clutter.ActorAlign.CENTER,
- page_valign: Clutter.ActorAlign.CENTER,
- });
+ },
+};
+
+const FolderGrid = {
+ _init() {
+ AppDisplay.AppGrid.prototype._init.bind(this)({
+ allow_incomplete_pages: false,
+ columns_per_page: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 20,
+ rows_per_page: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 20,
+ page_halign: Clutter.ActorAlign.CENTER,
+ page_valign: Clutter.ActorAlign.CENTER,
+ });
+ this.layout_manager._isFolder = true;
+ const spacing = opt.APP_GRID_SPACING;
+ this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`);
+ this.layoutManager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
- const spacing = opt.APP_GRID_SPACING;
- this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`);
- this.layout_manager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
+ this.setGridModes([
+ {
+ columns: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 3,
+ rows: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 3,
+ },
+ ]);
+ },
- this.setGridModes([
- {
- columns: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 3,
- rows: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 3,
- },
- ]);
- }
+ adaptToSize(width, height) {
+ this.layout_manager.adaptToSize(width, height);
+ },
+};
- adaptToSize(width, height) {
- this.layout_manager.adaptToSize(width, height);
- }
- });
-}
const FOLDER_DIALOG_ANIMATION_TIME = 200; // AppDisplay.FOLDER_DIALOG_ANIMATION_TIME
const AppFolderDialog = {
// injection to _init()
after__init() {
+ this._viewBox.add_style_class_name('app-folder-dialog-vshell');
+
// delegate this dialog to the FolderIcon._view
// so its _createFolderIcon function can update the dialog if folder content changed
this._view._dialog = this;
@@ -1023,18 +1269,65 @@ const AppFolderDialog = {
});
this.child.add_action(clickAction);
+
+ // Adjust empty actor to center the title
+ this._entryBox.get_first_child().width = 82;
+ },
+
+ after__addFolderNameEntry() {
+ // Edit button
+ this._removeButton = new St.Button({
+ style_class: 'edit-folder-button',
+ button_mask: St.ButtonMask.ONE,
+ toggle_mode: false,
+ reactive: true,
+ can_focus: true,
+ x_align: Clutter.ActorAlign.END,
+ y_align: Clutter.ActorAlign.CENTER,
+ child: new St.Icon({
+ icon_name: 'user-trash-symbolic',
+ icon_size: 16,
+ }),
+ });
+
+ this._removeButton.connect('clicked', () => {
+ if (Date.now() - this._removeButton._lastClick < Clutter.Settings.get_default().double_click_time) {
+ this._grabHelper.ungrab({ actor: this });
+ // without hiding the dialog, Shell crashes (at least on X11)
+ this.hide();
+ this._view._deletingFolder = true;
+
+ // Resetting all keys deletes the relocatable schema
+ let keys = this._folder.settings_schema.list_keys();
+ for (const key of keys)
+ this._folder.reset(key);
+
+ let settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.app-folders' });
+ let folders = settings.get_strv('folder-children');
+ folders.splice(folders.indexOf(this._view._id), 1);
+
+ // remove all abandoned folders (usually my own garbage and unwanted default folders...)
+ /* const appFolders = this._appDisplay._folderIcons.map(icon => icon._id);
+ folders.forEach(folder => {
+ if (!appFolders.includes(folder)) {
+ folders.splice(folders.indexOf(folder._id), 1);
+ }
+ });*/
+ settings.set_strv('folder-children', folders);
+
+ this._view._deletingFolder = false;
+ return;
+ }
+ this._removeButton._lastClick = Date.now();
+ });
+
+ this._entryBox.add_child(this._removeButton);
},
popup() {
if (this._isOpen)
return;
- /* if (!this._correctSize) {
- // update folder with the precise app item size when the dialog is realized
- GLib.idle_add(0, () => this._updateFolderSize(true));
- this._correctSize = true;
- }*/
-
this._isOpen = this._grabHelper.grab({
actor: this,
onUngrab: () => this.popdown(),
@@ -1046,26 +1339,48 @@ const AppFolderDialog = {
this.get_parent().set_child_above_sibling(this, null);
this._needsZoomAndFade = true;
- this.show();
+ // the first folder dialog realization needs size correction
+ // so set the folder size, let it realize and then update the folder content
+ if (!this.realized) {
+ this._updateFolderSize();
+ GLib.idle_add(
+ GLib.PRIORITY_DEFAULT,
+ () => {
+ this._updateFolderSize();
+ }
+ );
+ }
+
+ this.show();
this.emit('open-state-changed', true);
},
_updateFolderSize() {
- // adapt folder size according to the settings and number of icons
const view = this._view;
+ const [firstItem] = view._grid.layoutManager._container;
+ if (!firstItem)
+ return;
+ // adapt folder size according to the settings and number of icons
+ const appDisplay = this._source._parentView;
+ if (!appDisplay.width || appDisplay.allocation.x2 === Infinity || appDisplay.allocation.x2 === -Infinity) {
+ return;
+ }
+
view._grid.layoutManager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
view._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`);
const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
- const dialogMargin = 30;
+ const itemPadding = 55; // default icon item padding on Fedora 44
+ // const dialogMargin = 30;
const nItems = view._orderedItems.length;
let columns = opt.APP_GRID_FOLDER_COLUMNS;
let rows = opt.APP_GRID_FOLDER_ROWS;
+ const fullAdaptiveGrid = !columns && !rows;
let spacing = opt.APP_GRID_SPACING;
- const monitor = global.display.get_monitor_geometry(global.display.get_primary_monitor());
+ const minItemSize = 48 + itemPadding;
- if (!columns && !rows) {
+ if (fullAdaptiveGrid) {
columns = Math.ceil(Math.sqrt(nItems));
rows = columns;
if (columns * (columns - 1) >= nItems) {
@@ -1081,38 +1396,67 @@ const AppFolderDialog = {
}
const iconSize = opt.APP_GRID_FOLDER_ICON_SIZE < 0 ? opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT : opt.APP_GRID_FOLDER_ICON_SIZE;
- let itemSize = iconSize + 53; // icon padding
+ view._grid.layoutManager.fixedIconSize = iconSize;
+
+ let itemSize = iconSize + 55; // icon padding
// first run sets the grid before we can read the real icon size
// so we estimate the size from default properties
// and correct it in the second run
- if (this._notFirstRun) {
- const [firstItem] = view._grid.layoutManager._container;
+ if (this.realized) {
firstItem.icon.setIconSize(iconSize);
const [firstItemWidth] = firstItem.get_preferred_size();
const realSize = firstItemWidth / scaleFactor;
- if (realSize > iconSize)
+ // if the preferred item size is smaller than icon plus some padding, ignore it
+ // (icons that are not yet realized are returning sizes like 45 or 53)
+ if (realSize > (iconSize + 24))
itemSize = realSize;
- } else {
- this._needsUpdateSize = true;
- this._notFirstRun = true;
}
-
let width = columns * (itemSize + spacing) + /* padding for nav arrows*/64;
- width = Math.round(width + (opt.ORIENTATION || !opt.APP_GRID_FOLDER_COLUMNS ? 100 : 160/* space for navigation arrows*/));
- let height = rows * (itemSize + spacing) + /* header*/75 + /* padding*/100;
+ width = Math.round(width + (opt.ORIENTATION ? 100 : 160/* space for navigation arrows*/));
+ let height = rows * (itemSize + spacing) + /* header*/75 + /* padding*/ 2 * 30 + /* padding + ?page indicator*/(!opt.ORIENTATION || !opt.APP_GRID_FOLDER_COLUMNS ? 100 : 70);
+
+ // allocation is more reliable than appDisplay width/height properties
+ const appDisplayWidth = appDisplay.allocation.x2 - appDisplay.allocation.x1;
+ const appDisplayHeight = appDisplay.allocation.y2 - appDisplay.allocation.y1 + (opt.SHOW_SEARCH_ENTRY ? Main.overview._overview.controls._searchEntryBin.height : 0);
- // folder must fit the primary monitor
+ // folder must fit the appDisplay area
// reduce columns/rows if needed and count with the scaled values
- while (width * scaleFactor > monitor.width - 2 * dialogMargin) {
- width -= itemSize + spacing;
- columns -= 1;
+ if (!opt.APP_GRID_FOLDER_ROWS) {
+ while ((height * scaleFactor) > appDisplayHeight) {
+ height -= itemSize + spacing;
+ rows -= 1;
+ }
+ }
+
+ if (!opt.APP_GRID_FOLDER_COLUMNS) {
+ while ((width * scaleFactor) > appDisplayWidth) {
+ width -= itemSize + spacing;
+ columns -= 1;
+ }
}
- while (height * scaleFactor > monitor.height - 2 * dialogMargin) {
- height -= itemSize + spacing;
- rows -= 1;
+ // try to compensate for the previous reduction if there is a space
+ if (!opt.APP_GRID_FOLDER_COLUMNS) {
+ while ((nItems > columns * rows) && ((width * scaleFactor + itemSize + spacing) <= appDisplayWidth)) {
+ width += itemSize + spacing;
+ columns += 1;
+ }
+ // remove columns that cannot be displayed
+ if ((columns * minItemSize + (columns - 1) * spacing) > appDisplayWidth)
+ columns = Math.floor(appDisplayWidth / (minItemSize + spacing));
}
- width = Math.max(540, width);
+ if (!opt.APP_GRID_FOLDER_ROWS) {
+ while ((nItems > columns * rows) && ((height * scaleFactor + itemSize + spacing) <= appDisplayHeight)) {
+ height += itemSize + spacing;
+ rows += 1;
+ }
+ // remove rows that cannot be displayed
+ if ((rows * minItemSize + (rows - 1) * spacing) > appDisplayHeight)
+ rows = Math.floor(appDisplayWidth / (minItemSize + spacing));
+ }
+
+ width = Math.clamp(width, 640, appDisplayWidth);
+ height = Math.min(height, appDisplayHeight);
const layoutManager = view._grid.layoutManager;
layoutManager.rows_per_page = rows;
@@ -1127,6 +1471,8 @@ const AppFolderDialog = {
padding: 30px;
`);
+ view._grid.layoutManager._pageWidth += 1;
+ view._grid.layoutManager.adaptToSize(view._grid.layoutManager._pageWidth - 1, view._grid.layoutManager._pageHeight);
view._redisplay();
// store original item count
@@ -1145,40 +1491,34 @@ const AppFolderDialog = {
// this. covers the whole screen
let dialogTargetX = dialogX;
let dialogTargetY = dialogY;
- if (!opt.APP_GRID_FOLDER_CENTER) {
- const appDisplay = this._source._parentView;
- dialogTargetX = Math.round(sourceCenterX - this.child.width / 2);
- dialogTargetY = Math.round(sourceCenterY - this.child.height / 2);
+ const appDisplay = this._source._parentView;
+ const [appDisplayX, appDisplayY] = this._source._parentView.get_transformed_position();
- // keep the dialog in appDisplay area if possible
- dialogTargetX = Math.clamp(
- dialogTargetX,
- this.x + appDisplay.x,
- this.x + appDisplay.x + appDisplay.width - this.child.width
- );
+ if (!opt.APP_GRID_FOLDER_CENTER) {
+ dialogTargetX = sourceCenterX - this.child.width / 2;
+ dialogTargetY = sourceCenterY - this.child.height / 2;
- dialogTargetY = Math.clamp(
- dialogTargetY,
- this.y + appDisplay.y,
- this.y + appDisplay.y + appDisplay.height - this.child.height
- );
- // or at least in the monitor area
- const monitor = global.display.get_monitor_geometry(global.display.get_primary_monitor());
+ // keep the dialog in appDisplay area if possible
dialogTargetX = Math.clamp(
dialogTargetX,
- this.x + monitor.x,
- this.x + monitor.x + monitor.width - this.child.width
+ appDisplayX,
+ appDisplayX + appDisplay.width - this.child.width
);
dialogTargetY = Math.clamp(
dialogTargetY,
- this.y + monitor.y,
- this.y + monitor.y + monitor.height - this.child.height
+ appDisplayY,
+ appDisplayY + appDisplay.height - this.child.height
);
+ } else {
+ const searchEntryHeight = opt.SHOW_SEARCH_ENTRY ? Main.overview._overview.controls._searchEntryBin.height : 0;
+ dialogTargetX = appDisplayX + appDisplay.width / 2 - this.child.width / 2;
+ dialogTargetY = appDisplayY - searchEntryHeight + ((appDisplay.height + searchEntryHeight) / 2 - this.child.height / 2) / 2;
}
- const dialogOffsetX = -dialogX + dialogTargetX;
- const dialogOffsetY = -dialogY + dialogTargetY;
+
+ const dialogOffsetX = Math.round(dialogTargetX - dialogX);
+ const dialogOffsetY = Math.round(dialogTargetY - dialogY);
this.child.set({
translation_x: sourceX - dialogX,
@@ -1188,12 +1528,6 @@ const AppFolderDialog = {
opacity: 0,
});
- this.ease({
- background_color: DIALOG_SHADE_NORMAL,
- duration: FOLDER_DIALOG_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
-
this.child.ease({
translation_x: dialogOffsetX,
translation_y: dialogOffsetY,
@@ -1202,17 +1536,22 @@ const AppFolderDialog = {
opacity: 255,
duration: FOLDER_DIALOG_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- onComplete: () => {
- // if the folder grid was build with the estimated icon item size because the real size wasn't available
- // rebuild it with the real size now, after the folder was realized
- if (this._needsUpdateSize) {
- this._updateFolderSize();
- this._view._redisplay();
- this._needsUpdateSize = false;
- }
- },
});
+ appDisplay.ease({
+ opacity: 0,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+
+ if (opt.SHOW_SEARCH_ENTRY) {
+ Main.overview.searchEntry.ease({
+ opacity: 0,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+ }
+
this._needsZoomAndFade = false;
if (this._sourceMappedId === 0) {
@@ -1230,17 +1569,20 @@ const AppFolderDialog = {
return;
}
+ // if the dialog was shown silently, skip animation
+ if (this.scale_y < 1) {
+ this._needsZoomAndFade = false;
+ this.hide();
+ this._popdownCallbacks.forEach(func => func());
+ this._popdownCallbacks = [];
+ return;
+ }
+
let [sourceX, sourceY] =
this._source.get_transformed_position();
let [dialogX, dialogY] =
this.child.get_transformed_position();
- this.ease({
- background_color: Clutter.Color.from_pixel(0x00000000),
- duration: FOLDER_DIALOG_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
-
this.child.ease({
translation_x: sourceX - dialogX + this.child.translation_x,
translation_y: sourceY - dialogY + this.child.translation_y,
@@ -1264,11 +1606,35 @@ const AppFolderDialog = {
},
});
+ const appDisplay = this._source._parentView;
+ appDisplay.ease({
+ opacity: 255,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+
+ if (opt.SHOW_SEARCH_ENTRY) {
+ Main.overview.searchEntry.ease({
+ opacity: 255,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+ }
+
this._needsZoomAndFade = false;
},
_setLighterBackground(lighter) {
- const backgroundColor = lighter
+ if (this._isOpen) {
+ const appDisplay = this._source._parentView;
+ appDisplay.ease({
+ opacity: lighter ? 20 : 0,
+ duration: FOLDER_DIALOG_ANIMATION_TIME,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ });
+ }
+
+ /* const backgroundColor = lighter
? DIALOG_SHADE_HIGHLIGHT
: DIALOG_SHADE_NORMAL;
@@ -1276,91 +1642,10 @@ const AppFolderDialog = {
backgroundColor,
duration: FOLDER_DIALOG_ANIMATION_TIME,
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
+ }); */
},
};
-// just make app grid to update all invalid positions that may be result of grid/icon size change
-function _updateIconPositions() {
- const appDisplay = Main.overview._overview._controls._appDisplay;
- const icons = [...appDisplay._orderedItems];
- for (let i = 0; i < icons.length; i++)
- appDisplay._moveItem(icons[i], -1, -1);
-}
-
-function _removeIcons() {
- const appDisplay = Main.overview._overview._controls._appDisplay;
- const icons = [...appDisplay._orderedItems];
- for (let i = 0; i < icons.length; i++) {
- const icon = icons[i];
- if (icon._dialog)
- Main.layoutManager.overviewGroup.remove_child(icon._dialog);
- appDisplay._removeItem(icon);
- icon.destroy();
- }
- appDisplay._folderIcons = [];
-}
-
-function _resetAppGrid(settings) {
- const appDisplay = Main.overview._overview._controls._appDisplay;
- // reset the grid only if called directly without args or if all folders where removed by using reset button in Settings window
- // otherwise this function is called every time a user moves icon to another position as a settings callback
- if (settings) {
- const currentValue = JSON.stringify(global.settings.get_value('app-picker-layout').deep_unpack());
- const emptyValue = JSON.stringify([]);
- const customLayout = currentValue !== emptyValue;
- // appDisplay._customLayout = customLayout;
- if (customLayout)
- return;
- else
- opt._appGridNeedsRedisplay = true;
- }
-
- // force update icon size using adaptToSize(). the page size cannot be the same as the current one
- appDisplay._grid.layoutManager._pageWidth += 1;
- appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight);
- _removeIcons();
- appDisplay._redisplay();
- // force appDisplay to move all icons to proper positions and update all properties
- GLib.idle_add(0, () => {
- _updateIconPositions();
- if (appDisplay._sortOrderedItemsAlphabetically) {
- appDisplay._sortOrderedItemsAlphabetically();
- appDisplay._grid.layoutManager._pageWidth += 1;
- appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight);
- appDisplay._setLinearPositions(appDisplay._orderedItems);
- } else {
- appDisplay._removeItem(appDisplay._orderedItems[0]);
- appDisplay._redisplay();
- }
-
- appDisplay._redisplay();
- });
-}
-
-function _getWindowApp(metaWin) {
- const tracker = Shell.WindowTracker.get_default();
- return tracker.get_window_app(metaWin);
-}
-
-function _getAppLastUsedWindow(app) {
- let recentWin;
- global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => {
- const winApp = _getWindowApp(metaWin);
- if (!recentWin && winApp === app)
- recentWin = metaWin;
- });
- return recentWin;
-}
-
-function _getAppRecentWorkspace(app) {
- const recentWin = _getAppLastUsedWindow(app);
- if (recentWin)
- return recentWin.get_workspace();
-
- return null;
-}
-
const AppIcon = {
after__init() {
// update the app label behavior
@@ -1377,7 +1662,7 @@ const AppIcon = {
return source !== this &&
(source instanceof this.constructor) &&
(view instanceof AppDisplay.AppDisplay &&
- !opt.APP_GRID_ORDER);
+ !opt.APP_GRID_USAGE);
},
};
@@ -1427,7 +1712,7 @@ const AppViewItemCommon = {
// support active preview icons
acceptDrop(source, _actor, x) {
- if (opt.APP_GRID_ORDER)
+ if (opt.APP_GRID_USAGE)
return DND.DragMotionResult.NO_DROP;
this._setHoveringByDnd(false);
@@ -1449,26 +1734,18 @@ const AppViewItemCommon = {
};
-const ActiveFolderIcon = GObject.registerClass(
-class ActiveFolderIcon extends AppDisplay.AppIcon {
- _init(app) {
- super._init(app, {
- setSizeManually: true,
- showLabel: false,
- });
- }
-
+const ActiveFolderIcon = {
handleDragOver() {
return DND.DragMotionResult.CONTINUE;
- }
+ },
acceptDrop() {
return false;
- }
+ },
_onDragEnd() {
this._dragging = false;
this.undoScaleAndFade();
Main.overview.endItemDrag(this._sourceItem.icon);
- }
-});
+ },
+};