summaryrefslogtreecommitdiffstats
path: root/extensions/vertical-workspaces/lib/appDisplay.js
diff options
context:
space:
mode:
Diffstat (limited to 'extensions/vertical-workspaces/lib/appDisplay.js')
-rw-r--r--extensions/vertical-workspaces/lib/appDisplay.js1474
1 files changed, 0 insertions, 1474 deletions
diff --git a/extensions/vertical-workspaces/lib/appDisplay.js b/extensions/vertical-workspaces/lib/appDisplay.js
deleted file mode 100644
index 2ac70b1..0000000
--- a/extensions/vertical-workspaces/lib/appDisplay.js
+++ /dev/null
@@ -1,1474 +0,0 @@
-/**
- * V-Shell (Vertical Workspaces)
- * appDisplay.js
- *
- * @author GdH <G-dH@github.com>
- * @copyright 2022 - 2023
- * @license GPL-3.0
- *
- */
-
-'use strict';
-
-const { Clutter, GLib, GObject, Meta, Shell, St, Graphene, Pango } = imports.gi;
-
-const DND = imports.ui.dnd;
-const Main = imports.ui.main;
-const AppDisplay = imports.ui.appDisplay;
-const IconGrid = imports.ui.iconGrid;
-
-const ExtensionUtils = imports.misc.extensionUtils;
-const Me = ExtensionUtils.getCurrentExtension();
-const IconGridOverride = Me.imports.lib.iconGrid;
-const _Util = Me.imports.lib.util;
-
-const DIALOG_SHADE_NORMAL = Clutter.Color.from_pixel(0x00000022);
-const DIALOG_SHADE_HIGHLIGHT = Clutter.Color.from_pixel(0x00000000);
-
-// gettext
-const _ = Me.imports.lib.settings._;
-
-let _overrides;
-
-let _appGridLayoutSettings;
-let _appDisplayScrollConId;
-let _appSystemStateConId;
-let _appGridLayoutConId;
-let _origAppViewItemAcceptDrop;
-let _updateFolderIcons;
-
-let opt;
-let shellVersion = _Util.shellVersion;
-let _firstRun = true;
-
-function update(reset = false) {
- opt = Me.imports.lib.settings.opt;
- const moduleEnabled = opt.get('appDisplayModule', true);
- reset = reset || !moduleEnabled;
-
- // don't even touch this module if disabled
- if (_firstRun && reset)
- return;
-
- _firstRun = false;
-
- if (_overrides)
- _overrides.removeAll();
-
- if (reset) {
- _setAppDisplayOrientation(false);
- _updateAppGridProperties(reset);
- _updateAppGridDND(reset);
- _restoreOverviewGroup();
- _overrides = null;
- opt = null;
- return;
- }
-
- _overrides = new _Util.Overrides();
-
- if (opt.ORIENTATION === Clutter.Orientation.VERTICAL) {
- _overrides.addOverride('AppDisplayVertical', AppDisplay.AppDisplay.prototype, AppDisplayVertical);
- _overrides.addOverride('BaseAppViewVertical', AppDisplay.BaseAppView.prototype, BaseAppViewVertical);
- }
-
- // Custom App Grid
- _overrides.addOverride('AppFolderDialog', AppDisplay.AppFolderDialog.prototype, AppFolderDialog);
- if (shellVersion >= 43) {
- // const defined class needs to be touched before real access
- AppDisplay.BaseAppViewGridLayout;
- _overrides.addOverride('BaseAppViewGridLayout', AppDisplay.BaseAppViewGridLayout.prototype, BaseAppViewGridLayout);
- }
- _overrides.addOverride('FolderView', AppDisplay.FolderView.prototype, FolderView);
- _overrides.addOverride('FolderIcon', AppDisplay.FolderIcon.prototype, FolderIcon);
- _overrides.addOverride('AppIcon', AppDisplay.AppIcon.prototype, AppIcon);
- _overrides.addOverride('AppDisplay', AppDisplay.AppDisplay.prototype, AppDisplayCommon);
- _overrides.addOverride('AppViewItem', AppDisplay.AppViewItem.prototype, AppViewItemCommon);
- _overrides.addOverride('BaseAppViewCommon', AppDisplay.BaseAppView.prototype, BaseAppViewCommon);
-
- _setAppDisplayOrientation(opt.ORIENTATION === Clutter.Orientation.VERTICAL);
- _updateAppGridProperties();
- _updateAppGridDND();
- opt._appGridNeedsRedisplay = true;
-}
-
-function _setAppDisplayOrientation(vertical = false) {
- const CLUTTER_ORIENTATION = vertical ? Clutter.Orientation.VERTICAL : Clutter.Orientation.HORIZONTAL;
- const scroll = vertical ? 'vscroll' : 'hscroll';
- // app display to vertical has issues - page indicator not working
- // global appDisplay orientation switch is not built-in
- let appDisplay = Main.overview._overview._controls._appDisplay;
- // following line itself only changes in which axis will operate overshoot detection which switches appDisplay pages while dragging app icon to vertical
- appDisplay._orientation = CLUTTER_ORIENTATION;
- appDisplay._grid.layoutManager._orientation = CLUTTER_ORIENTATION;
- appDisplay._swipeTracker.orientation = CLUTTER_ORIENTATION;
- appDisplay._swipeTracker._reset();
- if (vertical) {
- appDisplay._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL);
-
- // move and change orientation of page indicators
- // needs corrections in appgrid page calculations, e.g. appDisplay.adaptToSize() fnc,
- // which complicates use of super call inside the function
- const pageIndicators = appDisplay._pageIndicators;
- pageIndicators.vertical = true;
- appDisplay._box.vertical = false;
- pageIndicators.x_expand = false;
- pageIndicators.y_align = Clutter.ActorAlign.CENTER;
- pageIndicators.x_align = Clutter.ActorAlign.START;
-
- const scrollContainer = appDisplay._scrollView.get_parent();
- if (shellVersion < 43) {
- // remove touch friendly side navigation bars / arrows
- if (appDisplay._hintContainer && appDisplay._hintContainer.get_parent())
- scrollContainer.remove_child(appDisplay._hintContainer);
- } else {
- // moving these bars needs more patching of the appDisplay's code
- // for now we just change bars style to be more like vertically oriented arrows indicating direction to prev/next page
- appDisplay._nextPageIndicator.add_style_class_name('nextPageIndicator');
- appDisplay._prevPageIndicator.add_style_class_name('prevPageIndicator');
- }
-
- // setting their x_scale to 0 removes the arrows and avoid allocation issues compared to .hide() them
- appDisplay._nextPageArrow.scale_x = 0;
- appDisplay._prevPageArrow.scale_x = 0;
- } else {
- appDisplay._scrollView.set_policy(St.PolicyType.EXTERNAL, St.PolicyType.NEVER);
- if (_appDisplayScrollConId) {
- appDisplay._adjustment.disconnect(_appDisplayScrollConId);
- _appDisplayScrollConId = 0;
- }
-
- // restore original page indicators
- const pageIndicators = appDisplay._pageIndicators;
- pageIndicators.vertical = false;
- appDisplay._box.vertical = true;
- pageIndicators.x_expand = true;
- pageIndicators.y_align = Clutter.ActorAlign.END;
- pageIndicators.x_align = Clutter.ActorAlign.CENTER;
-
- // put back touch friendly navigation bars/buttons
- const scrollContainer = appDisplay._scrollView.get_parent();
- if (appDisplay._hintContainer && !appDisplay._hintContainer.get_parent()) {
- scrollContainer.add_child(appDisplay._hintContainer);
- // the hit container covers the entire app grid and added at the top of the stack blocks DND drops
- // so it needs to be pushed below
- scrollContainer.set_child_below_sibling(appDisplay._hintContainer, null);
- }
-
- appDisplay._nextPageArrow.scale_x = 1;
- appDisplay._prevPageArrow.scale_x = 1;
-
- appDisplay._nextPageIndicator.remove_style_class_name('nextPageIndicator');
- appDisplay._prevPageIndicator.remove_style_class_name('prevPageIndicator');
- }
-
- // value for page indicator is calculated from scroll adjustment, horizontal needs to be replaced by vertical
- appDisplay._adjustment = appDisplay._scrollView[scroll].adjustment;
-
- // no need to connect already connected signal (wasn't removed the original one before)
- if (!vertical) {
- // reset used appDisplay properties
- Main.overview._overview._controls._appDisplay.scale_y = 1;
- Main.overview._overview._controls._appDisplay.scale_x = 1;
- Main.overview._overview._controls._appDisplay.opacity = 255;
- return;
- }
-
- // update appGrid dot pages indicators
- _appDisplayScrollConId = appDisplay._adjustment.connect('notify::value', adj => {
- const value = adj.value / adj.page_size;
- appDisplay._pageIndicators.setCurrentPosition(value);
- });
-}
-
-// Set App Grid columns, rows, icon size, incomplete pages
-function _updateAppGridProperties(reset = false) {
- opt._appGridNeedsRedisplay = false;
- // columns, rows, icon size
- const appDisplay = Main.overview._overview._controls._appDisplay;
- appDisplay.visible = true;
-
- if (reset) {
- appDisplay._grid.layoutManager.fixedIconSize = -1;
- appDisplay._grid.layoutManager.allow_incomplete_pages = true;
- appDisplay._grid.setGridModes();
- if (_appGridLayoutSettings) {
- _appGridLayoutSettings.disconnect(_appGridLayoutConId);
- _appGridLayoutConId = 0;
- _appGridLayoutSettings = null;
- }
- appDisplay._redisplay();
-
- appDisplay._grid.set_style('');
- _resetAppGrid();
- } else {
- // update grid on layout reset
- if (!_appGridLayoutSettings) {
- _appGridLayoutSettings = ExtensionUtils.getSettings('org.gnome.shell');
- _appGridLayoutConId = _appGridLayoutSettings.connect('changed::app-picker-layout', _resetAppGrid);
- }
-
- appDisplay._grid.layoutManager.allow_incomplete_pages = opt.APP_GRID_ALLOW_INCOMPLETE_PAGES;
- appDisplay._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`);
-
- // force redisplay
- appDisplay._grid._currentMode = -1;
- appDisplay._grid.setGridModes();
- appDisplay._grid.layoutManager.fixedIconSize = opt.APP_GRID_ICON_SIZE;
- // appDisplay._folderIcons.forEach(folder => folder._dialog?._updateFolderSize());
- _resetAppGrid();
- }
-}
-
-function _updateAppGridDND(reset) {
- if (!reset) {
- if (!_appSystemStateConId && opt.APP_GRID_INCLUDE_DASH >= 3) {
- _appSystemStateConId = Shell.AppSystem.get_default().connect(
- 'app-state-changed',
- () => {
- _updateFolderIcons = true;
- Main.overview._overview._controls._appDisplay._redisplay();
- }
- );
- }
- } else if (_appSystemStateConId) {
- Shell.AppSystem.get_default().disconnect(_appSystemStateConId);
- _appSystemStateConId = 0;
- }
- if (opt.APP_GRID_ORDER && !reset) {
- if (!_origAppViewItemAcceptDrop)
- _origAppViewItemAcceptDrop = AppDisplay.AppViewItem.prototype.acceptDrop;
- AppDisplay.AppViewItem.prototype.acceptDrop = () => false;
- } else if (_origAppViewItemAcceptDrop) {
- AppDisplay.AppViewItem.prototype.acceptDrop = _origAppViewItemAcceptDrop;
- }
-}
-
-function _restoreOverviewGroup() {
- Main.overview.dash.showAppsButton.checked = false;
- Main.layoutManager.overviewGroup.opacity = 255;
- Main.layoutManager.overviewGroup.scale_x = 1;
- Main.layoutManager.overviewGroup.hide();
-}
-
-const AppDisplayVertical = {
- // correction of the appGrid size when page indicators were moved from the bottom to the right
- adaptToSize(width, height) {
- const [, indicatorWidth] = this._pageIndicators.get_preferred_width(-1);
- width -= indicatorWidth;
-
- this._grid.findBestModeForSize(width, height);
-
- const adaptToSize = AppDisplay.BaseAppView.prototype.adaptToSize.bind(this);
- adaptToSize(width, height);
- },
-};
-
-const AppDisplayCommon = {
- _ensureDefaultFolders() {
- // disable creation of default folders if user deleted them
- },
-
- _redisplay() {
- this._folderIcons.forEach(icon => {
- icon.view._redisplay();
- });
-
- BaseAppViewCommon._redisplay.bind(this)();
- },
-
- // apps load adapted for custom sorting and including dash items
- _loadApps() {
- let appIcons = [];
- const runningApps = Shell.AppSystem.get_default().get_running().map(a => a.id);
-
- this._appInfoList = Shell.AppSystem.get_default().get_installed().filter(appInfo => {
- try {
- appInfo.get_id(); // catch invalid file encodings
- } catch (e) {
- return false;
- }
-
- const appIsRunning = runningApps.includes(appInfo.get_id());
- const appIsFavorite = this._appFavorites.isFavorite(appInfo.get_id());
- const excludeApp = (opt.APP_GRID_EXCLUDE_RUNNING && appIsRunning) || (opt.APP_GRID_EXCLUDE_FAVORITES && appIsFavorite);
-
- return this._parentalControlsManager.shouldShowApp(appInfo) && !excludeApp;
- });
-
- let apps = this._appInfoList.map(app => app.get_id());
-
- let appSys = Shell.AppSystem.get_default();
-
- const appsInsideFolders = new Set();
- this._folderIcons = [];
- if (!opt.APP_GRID_ORDER) {
- let folders = this._folderSettings.get_strv('folder-children');
- folders.forEach(id => {
- let path = `${this._folderSettings.path}folders/${id}/`;
- let icon = this._items.get(id);
- if (!icon) {
- icon = new AppDisplay.FolderIcon(id, path, this);
- icon.connect('apps-changed', () => {
- this._redisplay();
- this._savePages();
- });
- icon.connect('notify::pressed', () => {
- if (icon.pressed)
- this.updateDragFocus(icon);
- });
- } else if (_updateFolderIcons && opt.APP_GRID_EXCLUDE_RUNNING) {
- // if any app changed its running state, update folder icon
- icon.icon.update();
- }
-
- // remove empty folder icons
- if (!icon.visible) {
- icon.destroy();
- return;
- }
-
- appIcons.push(icon);
- this._folderIcons.push(icon);
-
- icon.getAppIds().forEach(appId => appsInsideFolders.add(appId));
- });
- }
- // reset request to update active icon
- _updateFolderIcons = false;
-
- // Allow dragging of the icon only if the Dash would accept a drop to
- // change favorite-apps. There are no other possible drop targets from
- // the app picker, so there's no other need for a drag to start,
- // at least on single-monitor setups.
- // This also disables drag-to-launch on multi-monitor setups,
- // but we hope that is not used much.
- const isDraggable =
- global.settings.is_writable('favorite-apps') ||
- global.settings.is_writable('app-picker-layout');
-
- apps.forEach(appId => {
- if (!opt.APP_GRID_ORDER && appsInsideFolders.has(appId))
- return;
-
- let icon = this._items.get(appId);
- if (!icon) {
- let app = appSys.lookup_app(appId);
- icon = new AppDisplay.AppIcon(app, { isDraggable });
- icon.connect('notify::pressed', () => {
- if (icon.pressed)
- this.updateDragFocus(icon);
- });
- }
-
- appIcons.push(icon);
- });
-
- // At last, if there's a placeholder available, add it
- if (this._placeholder)
- appIcons.push(this._placeholder);
-
- return appIcons;
- },
-
- // support active preview icons
- _onDragBegin(overview, source) {
- if (source._sourceItem)
- source = source._sourceItem;
-
- this._dragMonitor = {
- dragMotion: this._onDragMotion.bind(this),
- };
- DND.addDragMonitor(this._dragMonitor);
- if (shellVersion < 43)
- this._slideSidePages(AppDisplay.SidePages.PREVIOUS | AppDisplay.SidePages.NEXT | AppDisplay.SidePages.DND);
- else
- this._appGridLayout.showPageIndicators();
- this._dragFocus = null;
- this._swipeTracker.enabled = false;
-
- // When dragging from a folder dialog, the dragged app icon doesn't
- // exist in AppDisplay. We work around that by adding a placeholder
- // icon that is either destroyed on cancel, or becomes the effective
- // new icon when dropped.
- if (AppDisplay._getViewFromIcon(source) instanceof AppDisplay.FolderView ||
- (opt.APP_GRID_EXCLUDE_FAVORITES && this._appFavorites.isFavorite(source.id)))
- this._ensurePlaceholder(source);
- },
-
- _ensurePlaceholder(source) {
- if (this._placeholder)
- return;
-
- if (source._sourceItem)
- source = source._sourceItem;
-
- const appSys = Shell.AppSystem.get_default();
- const app = appSys.lookup_app(source.id);
-
- const isDraggable =
- global.settings.is_writable('favorite-apps') ||
- global.settings.is_writable('app-picker-layout');
-
- this._placeholder = new AppDisplay.AppIcon(app, { isDraggable });
- this._placeholder.connect('notify::pressed', () => {
- if (this._placeholder?.pressed)
- this.updateDragFocus(this._placeholder);
- });
- this._placeholder.scaleAndFade();
- this._redisplay();
- },
-
- // accept source from active preview
- acceptDrop(source) {
- if (opt.APP_GRID_ORDER)
- return false;
- if (source._sourceItem)
- source = source._sourceItem;
-
- let dropTarget = null;
- if (shellVersion >= 43) {
- dropTarget = this._dropTarget;
- delete this._dropTarget;
- }
-
- if (!this._canAccept(source))
- return false;
-
- if ((shellVersion < 43 && this._dropPage) ||
- (shellVersion >= 43 && (dropTarget === this._prevPageIndicator ||
- dropTarget === this._nextPageIndicator))) {
- let increment;
-
- if (shellVersion < 43)
- increment = this._dropPage === AppDisplay.SidePages.NEXT ? 1 : -1;
- else
- increment = dropTarget === this._prevPageIndicator ? -1 : 1;
-
- const { currentPage, nPages } = this._grid;
- const page = Math.min(currentPage + increment, nPages);
- const position = page < nPages ? -1 : 0;
-
- this._moveItem(source, page, position);
- this.goToPage(page);
- } else if (this._delayedMoveData) {
- // Dropped before the icon was moved
- const { page, position } = this._delayedMoveData;
-
- try {
- this._moveItem(source, page, position);
- } catch (e) {
- log(`Warning:${e}`);
- }
- this._removeDelayedMove();
- }
-
- this._savePages();
-
- let view = AppDisplay._getViewFromIcon(source);
- if (view instanceof AppDisplay.FolderView)
- view.removeApp(source.app);
-
- if (this._currentDialog)
- this._currentDialog.popdown();
-
- if (opt.APP_GRID_EXCLUDE_FAVORITES && this._appFavorites.isFavorite(source.id))
- this._appFavorites.removeFavorite(source.id);
-
- return true;
- },
-};
-
-const BaseAppViewVertical = {
- after__init() {
- this._grid.layoutManager._orientation = Clutter.Orientation.VERTICAL;
- this._scrollView.set_policy(St.PolicyType.NEVER, St.PolicyType.EXTERNAL);
- this._orientation = Clutter.Orientation.VERTICAL;
- this._swipeTracker.orientation = Clutter.Orientation.VERTICAL;
- this._swipeTracker._reset();
- this._pageIndicators.vertical = true;
- this._box.vertical = false;
- this._pageIndicators.x_expand = false;
- this._pageIndicators.y_align = Clutter.ActorAlign.CENTER;
- this._pageIndicators.x_align = Clutter.ActorAlign.START;
- this._pageIndicators.set_style('margin-right: 10px;');
- const scrollContainer = this._scrollView.get_parent();
- if (shellVersion < 43) {
- // remove touch friendly side navigation bars / arrows
- if (this._hintContainer && this._hintContainer.get_parent())
- scrollContainer.remove_child(this._hintContainer);
- } else {
- // moving these bars needs more patching of the this's code
- // for now we just change bars style to be more like vertically oriented arrows indicating direction to prev/next page
- this._nextPageIndicator.add_style_class_name('nextPageIndicator');
- this._prevPageIndicator.add_style_class_name('prevPageIndicator');
- }
-
- // setting their x_scale to 0 removes the arrows and avoid allocation issues compared to .hide() them
- this._nextPageArrow.scale_x = 0;
- this._prevPageArrow.scale_x = 0;
-
- this._adjustment = this._scrollView.vscroll.adjustment;
-
- this._adjustment.connect('notify::value', adj => {
- const value = adj.value / adj.page_size;
- this._pageIndicators.setCurrentPosition(value);
- });
- },
- // <= 42 only, this fixes dnd from appDisplay to the workspace thumbnail on the left if appDisplay is on page 1 because of appgrid left overshoot
- _pageForCoords() {
- return AppDisplay.SidePages.NONE;
- },
-};
-
-const BaseAppViewCommon = {
- _sortOrderedItemsAlphabetically(icons = null) {
- if (!icons)
- icons = this._orderedItems;
- icons.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
- },
-
- _setLinearPositions(icons) {
- const { itemsPerPage } = this._grid;
- icons.forEach((icon, i) => {
- const page = Math.floor(i / itemsPerPage);
- const position = i % itemsPerPage;
- try {
- this._moveItem(icon, page, position);
- } catch (e) {
- log(`Warning:${e}`);
- }
- });
- },
-
- // adds sorting options and option to add favorites and running apps
- _redisplay() {
- let oldApps = this._orderedItems.slice();
- let oldAppIds = oldApps.map(icon => icon.id);
-
- let newApps = this._loadApps().sort(this._compareItems.bind(this));
- let newAppIds = newApps.map(icon => icon.id);
-
- let addedApps = newApps.filter(icon => !oldAppIds.includes(icon.id));
- let removedApps = oldApps.filter(icon => !newAppIds.includes(icon.id));
-
- // Remove old app icons
- removedApps.forEach(icon => {
- this._removeItem(icon);
- icon.destroy();
- });
-
- // Add new app icons, or move existing ones
- newApps.forEach(icon => {
- const [page, position] = this._getItemPosition(icon);
- if (addedApps.includes(icon)) {
- this._addItem(icon, page, position);
- } else if (page !== -1 && position !== -1) {
- this._moveItem(icon, page, position);
- } else {
- // App is part of a folder
- }
- });
-
- // sort all alphabetically
- if (opt.APP_GRID_ORDER > 0) {
- // const { itemsPerPage } = this._grid;
- let appIcons = this._orderedItems;
- this._sortOrderedItemsAlphabetically(appIcons);
- // appIcons.sort((a, b) => a.name.toLowerCase().localeCompare(b.name.toLowerCase()));
- // then sort used apps by usage
- if (opt.APP_GRID_ORDER === 2)
- appIcons.sort((a, b) => Shell.AppUsage.get_default().compare(a.app.id, b.app.id));
-
- // sort favorites first
- if (opt.APP_GRID_DASH_FIRST) {
- const fav = Object.keys(this._appFavorites._favorites);
- appIcons.sort((a, b) => {
- let aFav = fav.indexOf(a.id);
- if (aFav < 0)
- aFav = 999;
- let bFav = fav.indexOf(b.id);
- if (bFav < 0)
- bFav = 999;
- return bFav < aFav;
- });
- }
-
- // sort running first
- if (opt.APP_GRID_DASH_FIRST)
- appIcons.sort((a, b) => a.app.get_state() !== Shell.AppState.RUNNING && b.app.get_state() === Shell.AppState.RUNNING);
-
- this._setLinearPositions(appIcons);
-
- this._orderedItems = appIcons;
- }
-
- this.emit('view-loaded');
- if (!opt.APP_GRID_ALLOW_INCOMPLETE_PAGES) {
- for (let i = 0; i < this._grid.nPages; i++)
- this._grid.layoutManager._fillItemVacancies(i);
- }
- },
-
- _canAccept(source) {
- return opt.APP_GRID_ORDER ? false : source instanceof AppDisplay.AppViewItem;
- },
-
- // support active preview icons
- acceptDrop(source) {
- if (!this._canAccept(source))
- return false;
-
- if (source._sourceItem)
- source = source._sourceItem;
-
-
- if (this._dropPage) {
- const increment = this._dropPage === AppDisplay.SidePages.NEXT ? 1 : -1;
- const { currentPage, nPages } = this._grid;
- const page = Math.min(currentPage + increment, nPages);
- const position = page < nPages ? -1 : 0;
-
- this._moveItem(source, page, position);
- this.goToPage(page);
- } else if (this._delayedMoveData) {
- // Dropped before the icon was moved
- const { page, position } = this._delayedMoveData;
-
- this._moveItem(source, page, position);
- this._removeDelayedMove();
- }
-
- return true;
- },
-
- // support active preview icons
- _onDragMotion(dragEvent) {
- if (!(dragEvent.source instanceof AppDisplay.AppViewItem))
- return DND.DragMotionResult.CONTINUE;
-
- if (dragEvent.source._sourceItem)
- dragEvent.source = dragEvent.source._sourceItem;
-
- const appIcon = dragEvent.source;
-
- if (shellVersion < 43) {
- this._dropPage = this._pageForCoords(dragEvent.x, dragEvent.y);
- if (this._dropPage &&
- this._dropPage === AppDisplay.SidePages.PREVIOUS &&
- this._grid.currentPage === 0) {
- delete this._dropPage;
- return DND.DragMotionResult.NO_DROP;
- }
- }
-
- if (appIcon instanceof AppDisplay.AppViewItem) {
- if (shellVersion < 44) {
- // Handle the drag overshoot. When dragging to above the
- // icon grid, move to the page above; when dragging below,
- // move to the page below.
- this._handleDragOvershoot(dragEvent);
- } else if (!this._dragMaybeSwitchPageImmediately(dragEvent)) {
- // Two ways of switching pages during DND:
- // 1) When "bumping" the cursor against the monitor edge, we switch
- // page immediately.
- // 2) When hovering over the next-page indicator for a certain time,
- // we also switch page.
-
- const { targetActor } = dragEvent;
-
- if (targetActor === this._prevPageIndicator ||
- targetActor === this._nextPageIndicator)
- this._maybeSetupDragPageSwitchInitialTimeout(dragEvent);
- else
- this._resetDragPageSwitch();
- }
- }
-
- this._maybeMoveItem(dragEvent);
-
- return DND.DragMotionResult.CONTINUE;
- },
-
- // adjustable page width for GS <= 42
- adaptToSize(width, height, isFolder = false) {
- let box = new Clutter.ActorBox({
- x2: width,
- y2: height,
- });
- box = this.get_theme_node().get_content_box(box);
- box = this._scrollView.get_theme_node().get_content_box(box);
- box = this._grid.get_theme_node().get_content_box(box);
-
- const availWidth = box.get_width();
- const availHeight = box.get_height();
-
- let pageWidth, pageHeight;
-
- pageHeight = availHeight;
- pageWidth = Math.ceil(availWidth * (isFolder ? 1 : opt.APP_GRID_PAGE_WIDTH_SCALE));
- // subtract space for navigation arrows in horizontal mode
- pageWidth -= opt.ORIENTATION ? 0 : 128;
-
- this._grid.layout_manager.pagePadding.left =
- Math.floor(availWidth * 0.02);
- this._grid.layout_manager.pagePadding.right =
- Math.ceil(availWidth * 0.02);
-
- this._grid.adaptToSize(pageWidth, pageHeight);
-
- const leftPadding = Math.floor(
- (availWidth - this._grid.layout_manager.pageWidth) / 2);
- const rightPadding = Math.ceil(
- (availWidth - this._grid.layout_manager.pageWidth) / 2);
- const topPadding = Math.floor(
- (availHeight - this._grid.layout_manager.pageHeight) / 2);
- const bottomPadding = Math.ceil(
- (availHeight - this._grid.layout_manager.pageHeight) / 2);
-
- this._scrollView.content_padding = new Clutter.Margin({
- left: leftPadding,
- right: rightPadding,
- top: topPadding,
- bottom: bottomPadding,
- });
-
- this._availWidth = availWidth;
- this._availHeight = availHeight;
-
- this._pageIndicatorOffset = leftPadding;
- this._pageArrowOffset = Math.max(
- leftPadding - 80, 0); // 80 is AppDisplay.PAGE_PREVIEW_MAX_ARROW_OFFSET
- },
-};
-
-const BaseAppViewGridLayout = {
- _getIndicatorsWidth(box) {
- const [width, height] = box.get_size();
- const arrows = [
- this._nextPageArrow,
- this._previousPageArrow,
- ];
-
- const minArrowsWidth = arrows.reduce(
- (previousWidth, accessory) => {
- const [min] = accessory.get_preferred_width(height);
- return Math.max(previousWidth, min);
- }, 0);
-
- const idealIndicatorWidth = (width * 0.1/* PAGE_PREVIEW_RATIO*/) / 2;
-
- return Math.max(idealIndicatorWidth, minArrowsWidth);
- },
-};
-
-const FolderIcon = {
- after__init() {
- /* // If folder preview icons are clickable,
- // disable opening the folder with primary mouse button and enable the secondary one
- const buttonMask = opt.APP_GRID_ACTIVE_PREVIEW
- ? St.ButtonMask.TWO | St.ButtonMask.THREE
- : St.ButtonMask.ONE | St.ButtonMask.TWO;
- this.button_mask = buttonMask;*/
- this.button_mask = St.ButtonMask.ONE | St.ButtonMask.TWO;
-
- // build the folders now to avoid node errors when dragging active folder preview icons
- if (this.visible && opt.APP_GRID_ACTIVE_PREVIEW)
- this._ensureFolderDialog();
- },
-
- open() {
- this._ensureFolderDialog();
- if (this._dialog._designCapacity !== this.view._orderedItems.length)
- this._dialog._updateFolderSize();
-
- this.view._scrollView.vscroll.adjustment.value = 0;
- this._dialog.popup();
- },
-};
-
-const FolderView = {
- _createGrid() {
- let grid;
- if (shellVersion < 43)
- grid = new FolderGrid();
- else
- grid = new FolderGrid43();
-
- // IconGrid algorithm for adaptive icon size
- // counts with different default(max) size for folders
- grid.layoutManager._isFolder = true;
- return grid;
- },
-
- createFolderIcon(size) {
- const layout = new Clutter.GridLayout({
- row_homogeneous: true,
- column_homogeneous: true,
- });
-
- let icon = new St.Widget({
- layout_manager: layout,
- x_align: Clutter.ActorAlign.CENTER,
- style: `width: ${size}px; height: ${size}px;`,
- });
-
- const numItems = this._orderedItems.length;
- // decide what number of icons switch to 3x3 grid
- // APP_GRID_FOLDER_ICON_GRID: 3 -> more than 4
- // : 4 -> more than 8
- const threshold = opt.APP_GRID_FOLDER_ICON_GRID % 3 ? 8 : 4;
- const gridSize = opt.APP_GRID_FOLDER_ICON_GRID > 2 && numItems > threshold ? 3 : 2;
- const FOLDER_SUBICON_FRACTION = gridSize === 2 ? 0.4 : 0.27;
-
- let subSize = Math.floor(FOLDER_SUBICON_FRACTION * size);
- let rtl = icon.get_text_direction() === Clutter.TextDirection.RTL;
- for (let i = 0; i < gridSize * gridSize; i++) {
- const style = `width: ${subSize}px; height: ${subSize}px;`;
- let bin = new St.Bin({ style, reactive: true });
- bin.pivot_point = new Graphene.Point({ x: 0.5, y: 0.5 });
- if (i < numItems) {
- if (!opt.APP_GRID_ACTIVE_PREVIEW) {
- bin.child = this._orderedItems[i].app.create_icon_texture(subSize);
- } else {
- const app = this._orderedItems[i].app;
- const child = new ActiveFolderIcon(app);
- child._sourceItem = this._orderedItems[i];
- child._sourceFolder = this;
- child.icon.style_class = '';
- child.icon.set_style('margin: 0; padding: 0;');
- child.icon.setIconSize(subSize);
-
- bin.child = child;
-
- bin.connect('enter-event', () => {
- bin.ease({
- duration: 100,
- scale_x: 1.14,
- scale_y: 1.14,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
- });
- bin.connect('leave-event', () => {
- bin.ease({
- duration: 100,
- scale_x: 1,
- scale_y: 1,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
- });
- }
- }
-
- layout.attach(bin, rtl ? (i + 1) % gridSize : i % gridSize, Math.floor(i / gridSize), 1, 1);
- }
-
- // if folder content changed, update folder size
- if (this._dialog && this._dialog._designCapacity !== this._orderedItems.length)
- this._dialog._updateFolderSize();
-
- return icon;
- },
-
- // this just overrides _redisplay() for GS < 44
- _redisplay() {
- // super._redisplay(); - super doesn't work in my overrides
- AppDisplay.BaseAppView.prototype._redisplay.bind(this)();
- },
-
- _loadApps() {
- this._apps = [];
- const excludedApps = this._folder.get_strv('excluded-apps');
- const appSys = Shell.AppSystem.get_default();
- const addAppId = appId => {
- if (excludedApps.includes(appId))
- return;
-
- if (opt.APP_GRID_EXCLUDE_FAVORITES && this._appFavorites.isFavorite(appId))
- return;
-
- const app = appSys.lookup_app(appId);
- if (!app)
- return;
-
- if (opt.APP_GRID_EXCLUDE_RUNNING) {
- const runningApps = Shell.AppSystem.get_default().get_running().map(a => a.id);
- if (runningApps.includes(appId))
- return;
- }
-
- if (!this._parentalControlsManager.shouldShowApp(app.get_app_info()))
- return;
-
- if (this._apps.indexOf(app) !== -1)
- return;
-
- this._apps.push(app);
- };
-
- const folderApps = this._folder.get_strv('apps');
- folderApps.forEach(addAppId);
-
- const folderCategories = this._folder.get_strv('categories');
- const appInfos = this._parentView.getAppInfos();
- appInfos.forEach(appInfo => {
- let appCategories = AppDisplay._getCategories(appInfo);
- if (!AppDisplay._listsIntersect(folderCategories, appCategories))
- return;
-
- addAppId(appInfo.get_id());
- });
-
- let items = [];
- this._apps.forEach(app => {
- let icon = this._items.get(app.get_id());
- if (!icon)
- icon = new AppDisplay.AppIcon(app);
-
- items.push(icon);
- });
- this._appIds = this._apps.map(app => app.get_id());
- return items;
- },
-
- // 42 only - don't apply appGrid scale on folders
- adaptToSize(width, height) {
- if (!opt.ORIENTATION) {
- const [, indicatorHeight] = this._pageIndicators.get_preferred_height(-1);
- height -= indicatorHeight;
- }
- BaseAppViewCommon.adaptToSize.bind(this)(width, height, true);
- },
-};
-
-// folder columns and rows
-const FolderGrid = GObject.registerClass(
-class FolderGrid extends IconGrid.IconGrid {
- _init() {
- super._init({
- allow_incomplete_pages: false,
- // For adaptive size (0), set the numbers high enough to fit all the icons
- // to avoid splitting the icons to pages
- columns_per_page: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 20,
- rows_per_page: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 20,
- page_halign: Clutter.ActorAlign.CENTER,
- page_valign: Clutter.ActorAlign.CENTER,
- });
-
- // if (!opt.APP_GRID_FOLDER_DEFAULT)
- const spacing = opt.APP_GRID_SPACING;
- this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`);
- this.layout_manager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
- }
-
- adaptToSize(width, height) {
- this.layout_manager.adaptToSize(width, height);
- }
-});
-
-
-let FolderGrid43;
-// first reference to constant defined using const in other module returns undefined, the AppGrid const will remain empty and unused
-const AppGrid = AppDisplay.AppGrid;
-if (AppDisplay.AppGrid) {
- FolderGrid43 = GObject.registerClass(
- class FolderGrid43 extends AppDisplay.AppGrid {
- _init() {
- super._init({
- allow_incomplete_pages: false,
- columns_per_page: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 20,
- rows_per_page: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 20,
- page_halign: Clutter.ActorAlign.CENTER,
- page_valign: Clutter.ActorAlign.CENTER,
- });
-
- const spacing = opt.APP_GRID_SPACING;
- this.set_style(`column-spacing: ${spacing}px; row-spacing: ${spacing}px;`);
- this.layout_manager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
-
- this.setGridModes([
- {
- columns: opt.APP_GRID_FOLDER_COLUMNS ? opt.APP_GRID_FOLDER_COLUMNS : 3,
- rows: opt.APP_GRID_FOLDER_ROWS ? opt.APP_GRID_FOLDER_ROWS : 3,
- },
- ]);
- }
-
- adaptToSize(width, height) {
- this.layout_manager.adaptToSize(width, height);
- }
- });
-}
-
-const FOLDER_DIALOG_ANIMATION_TIME = 200; // AppDisplay.FOLDER_DIALOG_ANIMATION_TIME
-const AppFolderDialog = {
- // injection to _init()
- after__init() {
- // delegate this dialog to the FolderIcon._view
- // so its _createFolderIcon function can update the dialog if folder content changed
- this._view._dialog = this;
-
- // right click into the folder popup should close it
- this.child.reactive = true;
- const clickAction = new Clutter.ClickAction();
- clickAction.connect('clicked', act => {
- if (act.get_button() === Clutter.BUTTON_PRIMARY)
- return Clutter.EVENT_STOP;
- const [x, y] = clickAction.get_coords();
- const actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
- // if it's not entry for editing folder title
- if (actor !== this._entry)
- this.popdown();
- return Clutter.EVENT_STOP;
- });
-
- this.child.add_action(clickAction);
- },
-
- popup() {
- if (this._isOpen)
- return;
-
- /* if (!this._correctSize) {
- // update folder with the precise app item size when the dialog is realized
- GLib.idle_add(0, () => this._updateFolderSize(true));
- this._correctSize = true;
- }*/
-
- this._isOpen = this._grabHelper.grab({
- actor: this,
- onUngrab: () => this.popdown(),
- });
-
- if (!this._isOpen)
- return;
-
- this.get_parent().set_child_above_sibling(this, null);
-
- this._needsZoomAndFade = true;
- this.show();
-
- this.emit('open-state-changed', true);
- },
-
- _updateFolderSize() {
- // adapt folder size according to the settings and number of icons
- const view = this._view;
- view._grid.layoutManager.fixedIconSize = opt.APP_GRID_FOLDER_ICON_SIZE;
- view._grid.set_style(`column-spacing: ${opt.APP_GRID_SPACING}px; row-spacing: ${opt.APP_GRID_SPACING}px;`);
-
- const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage);
- const dialogMargin = 30;
- const nItems = view._orderedItems.length;
- let columns = opt.APP_GRID_FOLDER_COLUMNS;
- let rows = opt.APP_GRID_FOLDER_ROWS;
- let spacing = opt.APP_GRID_SPACING;
- const monitor = global.display.get_monitor_geometry(global.display.get_primary_monitor());
-
- if (!columns && !rows) {
- columns = Math.ceil(Math.sqrt(nItems));
- rows = columns;
- if (columns * (columns - 1) >= nItems) {
- rows = columns - 1;
- } else if ((columns + 1) * (columns - 1) >= nItems) {
- rows = columns - 1;
- columns += 1;
- }
- } else if (!columns && rows) {
- columns = Math.ceil(nItems / rows);
- } else if (columns && !rows) {
- rows = Math.ceil(nItems / columns);
- }
-
- const iconSize = opt.APP_GRID_FOLDER_ICON_SIZE < 0 ? opt.APP_GRID_FOLDER_ICON_SIZE_DEFAULT : opt.APP_GRID_FOLDER_ICON_SIZE;
- let itemSize = iconSize + 53; // icon padding
- // first run sets the grid before we can read the real icon size
- // so we estimate the size from default properties
- // and correct it in the second run
- if (this._notFirstRun) {
- const [firstItem] = view._grid.layoutManager._container;
- firstItem.icon.setIconSize(iconSize);
- const [firstItemWidth] = firstItem.get_preferred_size();
- const realSize = firstItemWidth / scaleFactor;
- if (realSize > iconSize)
- itemSize = realSize;
- } else {
- this._needsUpdateSize = true;
- this._notFirstRun = true;
- }
-
-
- let width = columns * (itemSize + spacing) + /* padding for nav arrows*/64;
- width = Math.round(width + (opt.ORIENTATION || !opt.APP_GRID_FOLDER_COLUMNS ? 100 : 160/* space for navigation arrows*/));
- let height = rows * (itemSize + spacing) + /* header*/75 + /* padding*/100;
-
- // folder must fit the primary monitor
- // reduce columns/rows if needed and count with the scaled values
- while (width * scaleFactor > monitor.width - 2 * dialogMargin) {
- width -= itemSize + spacing;
- columns -= 1;
- }
- while (height * scaleFactor > monitor.height - 2 * dialogMargin) {
- height -= itemSize + spacing;
- rows -= 1;
- }
- width = Math.max(540, width);
-
- const layoutManager = view._grid.layoutManager;
- layoutManager.rows_per_page = rows;
- layoutManager.columns_per_page = columns;
-
- // this line is required by GS 43
- view._grid.setGridModes([{ columns, rows }]);
-
- this.child.set_style(`
- width: ${width}px;
- height: ${height}px;
- padding: 30px;
- `);
-
- view._redisplay();
-
- // store original item count
- this._designCapacity = nItems;
- },
-
- _zoomAndFadeIn() {
- let [sourceX, sourceY] =
- this._source.get_transformed_position();
- let [dialogX, dialogY] =
- this.child.get_transformed_position();
-
- const sourceCenterX = sourceX + this._source.width / 2;
- const sourceCenterY = sourceY + this._source.height / 2;
-
- // this. covers the whole screen
- let dialogTargetX = dialogX;
- let dialogTargetY = dialogY;
- if (!opt.APP_GRID_FOLDER_CENTER) {
- const appDisplay = this._source._parentView;
-
- dialogTargetX = Math.round(sourceCenterX - this.child.width / 2);
- dialogTargetY = Math.round(sourceCenterY - this.child.height / 2);
-
- // keep the dialog in appDisplay area if possible
- dialogTargetX = Math.clamp(
- dialogTargetX,
- this.x + appDisplay.x,
- this.x + appDisplay.x + appDisplay.width - this.child.width
- );
-
- dialogTargetY = Math.clamp(
- dialogTargetY,
- this.y + appDisplay.y,
- this.y + appDisplay.y + appDisplay.height - this.child.height
- );
- // or at least in the monitor area
- const monitor = global.display.get_monitor_geometry(global.display.get_primary_monitor());
- dialogTargetX = Math.clamp(
- dialogTargetX,
- this.x + monitor.x,
- this.x + monitor.x + monitor.width - this.child.width
- );
-
- dialogTargetY = Math.clamp(
- dialogTargetY,
- this.y + monitor.y,
- this.y + monitor.y + monitor.height - this.child.height
- );
- }
- const dialogOffsetX = -dialogX + dialogTargetX;
- const dialogOffsetY = -dialogY + dialogTargetY;
-
- this.child.set({
- translation_x: sourceX - dialogX,
- translation_y: sourceY - dialogY,
- scale_x: this._source.width / this.child.width,
- scale_y: this._source.height / this.child.height,
- opacity: 0,
- });
-
- this.ease({
- background_color: DIALOG_SHADE_NORMAL,
- duration: FOLDER_DIALOG_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
-
- this.child.ease({
- translation_x: dialogOffsetX,
- translation_y: dialogOffsetY,
- scale_x: 1,
- scale_y: 1,
- opacity: 255,
- duration: FOLDER_DIALOG_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- onComplete: () => {
- // if the folder grid was build with the estimated icon item size because the real size wasn't available
- // rebuild it with the real size now, after the folder was realized
- if (this._needsUpdateSize) {
- this._updateFolderSize();
- this._view._redisplay();
- this._needsUpdateSize = false;
- }
- },
- });
-
- this._needsZoomAndFade = false;
-
- if (this._sourceMappedId === 0) {
- this._sourceMappedId = this._source.connect(
- 'notify::mapped', this._zoomAndFadeOut.bind(this));
- }
- },
-
- _zoomAndFadeOut() {
- if (!this._isOpen)
- return;
-
- if (!this._source.mapped) {
- this.hide();
- return;
- }
-
- let [sourceX, sourceY] =
- this._source.get_transformed_position();
- let [dialogX, dialogY] =
- this.child.get_transformed_position();
-
- this.ease({
- background_color: Clutter.Color.from_pixel(0x00000000),
- duration: FOLDER_DIALOG_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
-
- this.child.ease({
- translation_x: sourceX - dialogX + this.child.translation_x,
- translation_y: sourceY - dialogY + this.child.translation_y,
- scale_x: this._source.width / this.child.width,
- scale_y: this._source.height / this.child.height,
- opacity: 0,
- duration: FOLDER_DIALOG_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- onComplete: () => {
- this.child.set({
- translation_x: 0,
- translation_y: 0,
- scale_x: 1,
- scale_y: 1,
- opacity: 255,
- });
- this.hide();
-
- this._popdownCallbacks.forEach(func => func());
- this._popdownCallbacks = [];
- },
- });
-
- this._needsZoomAndFade = false;
- },
-
- _setLighterBackground(lighter) {
- const backgroundColor = lighter
- ? DIALOG_SHADE_HIGHLIGHT
- : DIALOG_SHADE_NORMAL;
-
- this.ease({
- backgroundColor,
- duration: FOLDER_DIALOG_ANIMATION_TIME,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- });
- },
-};
-
-// just make app grid to update all invalid positions that may be result of grid/icon size change
-function _updateIconPositions() {
- const appDisplay = Main.overview._overview._controls._appDisplay;
- const icons = [...appDisplay._orderedItems];
- for (let i = 0; i < icons.length; i++)
- appDisplay._moveItem(icons[i], -1, -1);
-}
-
-function _removeIcons() {
- const appDisplay = Main.overview._overview._controls._appDisplay;
- const icons = [...appDisplay._orderedItems];
- for (let i = 0; i < icons.length; i++) {
- const icon = icons[i];
- if (icon._dialog)
- Main.layoutManager.overviewGroup.remove_child(icon._dialog);
- appDisplay._removeItem(icon);
- icon.destroy();
- }
- appDisplay._folderIcons = [];
-}
-
-function _resetAppGrid(settings) {
- const appDisplay = Main.overview._overview._controls._appDisplay;
- // reset the grid only if called directly without args or if all folders where removed by using reset button in Settings window
- // otherwise this function is called every time a user moves icon to another position as a settings callback
- if (settings) {
- const currentValue = JSON.stringify(global.settings.get_value('app-picker-layout').deep_unpack());
- const emptyValue = JSON.stringify([]);
- const customLayout = currentValue !== emptyValue;
- // appDisplay._customLayout = customLayout;
- if (customLayout)
- return;
- else
- opt._appGridNeedsRedisplay = true;
- }
-
- // force update icon size using adaptToSize(). the page size cannot be the same as the current one
- appDisplay._grid.layoutManager._pageWidth += 1;
- appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight);
- _removeIcons();
- appDisplay._redisplay();
- // force appDisplay to move all icons to proper positions and update all properties
- GLib.idle_add(0, () => {
- _updateIconPositions();
- if (appDisplay._sortOrderedItemsAlphabetically) {
- appDisplay._sortOrderedItemsAlphabetically();
- appDisplay._grid.layoutManager._pageWidth += 1;
- appDisplay._grid.layoutManager.adaptToSize(appDisplay._grid.layoutManager._pageWidth - 1, appDisplay._grid.layoutManager._pageHeight);
- appDisplay._setLinearPositions(appDisplay._orderedItems);
- } else {
- appDisplay._removeItem(appDisplay._orderedItems[0]);
- appDisplay._redisplay();
- }
-
- appDisplay._redisplay();
- });
-}
-
-function _getWindowApp(metaWin) {
- const tracker = Shell.WindowTracker.get_default();
- return tracker.get_window_app(metaWin);
-}
-
-function _getAppLastUsedWindow(app) {
- let recentWin;
- global.display.get_tab_list(Meta.TabList.NORMAL_ALL, null).forEach(metaWin => {
- const winApp = _getWindowApp(metaWin);
- if (!recentWin && winApp === app)
- recentWin = metaWin;
- });
- return recentWin;
-}
-
-function _getAppRecentWorkspace(app) {
- const recentWin = _getAppLastUsedWindow(app);
- if (recentWin)
- return recentWin.get_workspace();
-
- return null;
-}
-
-const AppIcon = {
- after__init() {
- // update the app label behavior
- this._updateMultiline();
- },
-
- // avoid accepting by placeholder when dragging active preview
- // and also by icon if alphabet or usage sorting are used
- _canAccept(source) {
- if (source._sourceItem)
- source = source._sourceItem;
- let view = AppDisplay._getViewFromIcon(source);
-
- return source !== this &&
- (source instanceof this.constructor) &&
- (view instanceof AppDisplay.AppDisplay &&
- !opt.APP_GRID_ORDER);
- },
-};
-
-const AppViewItemCommon = {
- _updateMultiline() {
- const { label } = this.icon;
- if (label)
- label.opacity = 255;
- if (!this._expandTitleOnHover || !this.icon.label)
- return;
-
- const { clutterText } = label;
-
- const isHighlighted = this.has_key_focus() || this.hover || this._forcedHighlight;
-
- if (opt.APP_GRID_NAMES_MODE === 2 && this._expandTitleOnHover) { // !_expandTitleOnHover indicates search result icon
- label.opacity = isHighlighted || !this.app ? 255 : 0;
- }
- if (isHighlighted)
- this.get_parent()?.set_child_above_sibling(this, null);
-
- if (!opt.APP_GRID_NAMES_MODE) {
- const layout = clutterText.get_layout();
- if (!layout.is_wrapped() && !layout.is_ellipsized())
- return;
- }
-
- label.remove_transition('allocation');
-
- const id = label.connect('notify::allocation', () => {
- label.restore_easing_state();
- label.disconnect(id);
- });
-
- const expand = opt.APP_GRID_NAMES_MODE === 1 || this._forcedHighlight || this.hover || this.has_key_focus();
-
- label.save_easing_state();
- label.set_easing_duration(expand
- ? AppDisplay.APP_ICON_TITLE_EXPAND_TIME
- : AppDisplay.APP_ICON_TITLE_COLLAPSE_TIME);
- clutterText.set({
- line_wrap: expand,
- line_wrap_mode: expand ? Pango.WrapMode.WORD_CHAR : Pango.WrapMode.NONE,
- ellipsize: expand ? Pango.EllipsizeMode.NONE : Pango.EllipsizeMode.END,
- });
- },
-
- // support active preview icons
- acceptDrop(source, _actor, x) {
- if (opt.APP_GRID_ORDER)
- return DND.DragMotionResult.NO_DROP;
-
- this._setHoveringByDnd(false);
-
- if (!this._canAccept(source))
- return false;
-
- if (this._withinLeeways(x))
- return false;
-
- // added - remove app from the source folder after dnd to other folder
- if (source._sourceItem) {
- const app = source._sourceItem.app;
- source._sourceFolder.removeApp(app);
- }
-
- return true;
- },
-
-};
-
-const ActiveFolderIcon = GObject.registerClass(
-class ActiveFolderIcon extends AppDisplay.AppIcon {
- _init(app) {
- super._init(app, {
- setSizeManually: true,
- showLabel: false,
- });
- }
-
- handleDragOver() {
- return DND.DragMotionResult.CONTINUE;
- }
-
- acceptDrop() {
- return false;
- }
-
- _onDragEnd() {
- this._dragging = false;
- this.undoScaleAndFade();
- Main.overview.endItemDrag(this._sourceItem.icon);
- }
-});