diff --git a/.eslintrc.yml b/.eslintrc.yml index 8e73f8f2b..2b904e3a9 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -23,3 +23,6 @@ overrides: - code: 110 ignoreUrls: true ignoreTemplateLiterals: true + +parserOptions: + sourceType: module diff --git a/Makefile b/Makefile index e31e3d203..ebf85072b 100644 --- a/Makefile +++ b/Makefile @@ -14,6 +14,7 @@ EXTRA_MODULES = \ appIcons.js \ appIconIndicators.js \ fileManager1API.js \ + imports.js \ launcherAPI.js \ locations.js \ locationsWorker.js \ @@ -126,6 +127,7 @@ _build: all -rm -fR ./_build mkdir -p _build cp $(BASE_MODULES) $(EXTRA_MODULES) _build + cp -a dependencies _build cp stylesheet.css _build mkdir -p _build/media cd media ; cp $(EXTRA_MEDIA) ../_build/media/ diff --git a/appIconIndicators.js b/appIconIndicators.js index 558571987..b3ee5d2cc 100644 --- a/appIconIndicators.js +++ b/appIconIndicators.js @@ -1,22 +1,20 @@ -/* exported AppIconIndicator */ - -const { cairo: Cairo } = imports; -const { main: Main } = imports.ui; - -const { +import { Clutter, GdkPixbuf, Gio, GObject, Pango, - St, -} = imports.gi; + St +} from './dependencies/gi.js'; + +import {Main} from './dependencies/shell/ui.js'; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { - docking: Docking, - utils: Utils, -} = Me.imports; +import { + Docking, + Utils +} from './imports.js'; + +const {cairo: Cairo} = imports; const RunningIndicatorStyle = Object.freeze({ DEFAULT: 0, @@ -38,7 +36,7 @@ const MAX_WINDOWS_CLASSES = 4; * obtained by composing the desired classes below based on the settings. * */ -var AppIconIndicator = class DashToDockAppIconIndicator { +export class AppIconIndicator { constructor(source) { this._indicators = []; @@ -46,11 +44,11 @@ var AppIconIndicator = class DashToDockAppIconIndicator { let runningIndicator = null; let runningIndicatorStyle; - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; if (settings.applyCustomTheme) runningIndicatorStyle = RunningIndicatorStyle.DOTS; else - ({ runningIndicatorStyle } = settings); + ({runningIndicatorStyle} = settings); if (settings.showIconsEmblems && !Docking.DockManager.getDefault().notificationsMonitor.dndMode) { @@ -114,12 +112,12 @@ var AppIconIndicator = class DashToDockAppIconIndicator { indicator.destroy(); } } -}; +} /* * Base class to be inherited by all indicators of any kind */ -var IndicatorBase = class DashToDockIndicatorBase { +class IndicatorBase { constructor(source) { this._source = source; this._signalsHandler = new Utils.GlobalSignalsHandler(this._source); @@ -133,14 +131,14 @@ var IndicatorBase = class DashToDockIndicatorBase { this._signalsHandler.destroy(); this._signalsHandler = null; } -}; +} /* * A base indicator class for running style, from which all other EunningIndicators should derive, * providing some basic methods, variables definitions and their update, css style classes handling. * */ -var RunningIndicatorBase = class DashToDockRunningIndicatorBase extends IndicatorBase { +class RunningIndicatorBase extends IndicatorBase { constructor(source) { super(source); @@ -224,11 +222,11 @@ var RunningIndicatorBase = class DashToDockRunningIndicatorBase extends Indicato super.destroy(); } -}; +} // We add a css class so third parties themes can limit their indicaor customization // to the case we do nothing -var RunningIndicatorDefault = class DashToDockRunningIndicatorDefault extends RunningIndicatorBase { +class RunningIndicatorDefault extends RunningIndicatorBase { constructor(source) { super(source); this._source.add_style_class_name('default'); @@ -238,9 +236,9 @@ var RunningIndicatorDefault = class DashToDockRunningIndicatorDefault extends Ru this._source.remove_style_class_name('default'); super.destroy(); } -}; +} -var IndicatorDrawingArea = GObject.registerClass( +const IndicatorDrawingArea = GObject.registerClass( class IndicatorDrawingArea extends St.DrawingArea { vfunc_allocate(box) { if (box.x1 !== 0 || box.y1 !== 0) @@ -256,7 +254,7 @@ class IndicatorDrawingArea extends St.DrawingArea { } }); -var RunningIndicatorDots = class DashToDockRunningIndicatorDots extends RunningIndicatorBase { +class RunningIndicatorDots extends RunningIndicatorBase { constructor(source) { super(source); @@ -311,7 +309,8 @@ var RunningIndicatorDots = class DashToDockRunningIndicatorDots extends RunningI // Apply glossy background // TODO: move to enable/disableBacklit to apply itonly to the running apps? // TODO: move to css class for theming support - this._glossyBackgroundStyle = `background-image: url('${Me.path}/media/glossy.svg');` + + const {extension} = Docking.DockManager; + this._glossyBackgroundStyle = `background-image: url('${extension.path}/media/glossy.svg');` + 'background-size: contain;'; } @@ -350,7 +349,7 @@ var RunningIndicatorDots = class DashToDockRunningIndicatorDots extends RunningI this._borderWidth = themeNode.get_border_width(this._side); this._bodyColor = themeNode.get_background_color(); - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; if (!settings.applyCustomTheme) { // Adjust for the backlit case if (settings.unityBacklitItems) { @@ -431,11 +430,11 @@ var RunningIndicatorDots = class DashToDockRunningIndicatorDots extends RunningI this._area.destroy(); super.destroy(); } -}; +} // Adapted from dash-to-panel by Jason DeRose // https://github.com/jderose9/dash-to-panel -var RunningIndicatorCiliora = class DashToDockRunningIndicatorCiliora extends RunningIndicatorDots { +class RunningIndicatorCiliora extends RunningIndicatorDots { _drawIndicator(cr) { if (this._source.running) { const size = Math.max(this._width / 20, this._borderWidth); @@ -464,11 +463,11 @@ var RunningIndicatorCiliora = class DashToDockRunningIndicatorCiliora extends Ru cr.fill(); } } -}; +} // Adapted from dash-to-panel by Jason DeRose // https://github.com/jderose9/dash-to-panel -var RunningIndicatorSegmented = class DashToDockRunningIndicatorSegmented extends RunningIndicatorDots { +class RunningIndicatorSegmented extends RunningIndicatorDots { _drawIndicator(cr) { if (this._source.running) { const size = Math.max(this._width / 20, this._borderWidth); @@ -495,11 +494,11 @@ var RunningIndicatorSegmented = class DashToDockRunningIndicatorSegmented extend cr.fill(); } } -}; +} // Adapted from dash-to-panel by Jason DeRose // https://github.com/jderose9/dash-to-panel -var RunningIndicatorSolid = class DashToDockRunningIndicatorSolid extends RunningIndicatorDots { +class RunningIndicatorSolid extends RunningIndicatorDots { _drawIndicator(cr) { if (this._source.running) { const size = Math.max(this._width / 20, this._borderWidth); @@ -522,11 +521,11 @@ var RunningIndicatorSolid = class DashToDockRunningIndicatorSolid extends Runnin cr.fill(); } } -}; +} // Adapted from dash-to-panel by Jason DeRose // https://github.com/jderose9/dash-to-panel -var RunningIndicatorSquares = class DashToDockRunningIndicatorSquares extends RunningIndicatorDots { +class RunningIndicatorSquares extends RunningIndicatorDots { _drawIndicator(cr) { if (this._source.running) { const size = Math.max(this._width / 11, this._borderWidth); @@ -550,11 +549,11 @@ var RunningIndicatorSquares = class DashToDockRunningIndicatorSquares extends Ru cr.fill(); } } -}; +} // Adapted from dash-to-panel by Jason DeRose // https://github.com/jderose9/dash-to-panel -var RunningIndicatorDashes = class DashToDockRunningIndicatorDashes extends RunningIndicatorDots { +class RunningIndicatorDashes extends RunningIndicatorDots { _drawIndicator(cr) { if (this._source.running) { const size = Math.max(this._width / 20, this._borderWidth); @@ -580,11 +579,11 @@ var RunningIndicatorDashes = class DashToDockRunningIndicatorDashes extends Runn cr.fill(); } } -}; +} // Adapted from dash-to-panel by Jason DeRose // https://github.com/jderose9/dash-to-panel -var RunningIndicatorMetro = class DashToDockRunningIndicatorMetro extends RunningIndicatorDots { +class RunningIndicatorMetro extends RunningIndicatorDots { constructor(source) { super(source); this._source.add_style_class_name('metro'); @@ -637,9 +636,9 @@ var RunningIndicatorMetro = class DashToDockRunningIndicatorMetro extends Runnin } } } -}; +} -var RunningIndicatorBinary = class DashToDockRunningIndicatorBinary extends RunningIndicatorDots { +class RunningIndicatorBinary extends RunningIndicatorDots { _drawIndicator(cr) { // Draw the required numbers of dots const n = Math.min(15, this._source.windowsCount); @@ -672,12 +671,12 @@ var RunningIndicatorBinary = class DashToDockRunningIndicatorBinary extends Runn cr.fill(); } } -}; +} /* * Unity like notification and progress indicators */ -var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { +class UnityIndicator extends IndicatorBase { constructor(source) { super(source); @@ -695,7 +694,7 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { this._source._iconContainer.add_child(this._notificationBadgeBin); this.updateNotificationBadgeStyle(); - const { remoteModel, notificationsMonitor } = Docking.DockManager.getDefault(); + const {remoteModel, notificationsMonitor} = Docking.DockManager.getDefault(); const remoteEntry = remoteModel.lookupById(this._source.app.id); this._remoteEntry = remoteEntry; @@ -706,12 +705,12 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { ], [ remoteEntry, ['progress-changed', 'progress-visible-changed'], - (sender, { progress, progress_visible: progressVisible }) => + (sender, {progress, progress_visible: progressVisible}) => this.setProgress(progressVisible ? progress : -1), ], [ remoteEntry, 'urgent-changed', - (sender, { urgent }) => this.setUrgent(urgent), + (sender, {urgent}) => this.setUrgent(urgent), ], [ notificationsMonitor, 'changed', @@ -742,7 +741,7 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { const fontDesc = themeContext.get_font(); const defaultFontSize = fontDesc.get_size() / 1024; let fontSize = defaultFontSize * 0.9; - const { iconSize } = Main.overview.dash; + const {iconSize} = Main.overview.dash; const defaultIconSize = Docking.DockManager.settings.get_default_value( 'dash-max-icon-size').unpack(); @@ -799,7 +798,7 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { return; } - const { notificationsMonitor } = Docking.DockManager.getDefault(); + const {notificationsMonitor} = Docking.DockManager.getDefault(); const notificationsCount = notificationsMonitor.getAppNotificationsCount( this._source.app.id); @@ -822,7 +821,7 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { return; } - this._progressOverlayArea = new St.DrawingArea({ x_expand: true, y_expand: true }); + this._progressOverlayArea = new St.DrawingArea({x_expand: true, y_expand: true}); this._progressOverlayArea.add_style_class_name('progress-bar'); this._progressOverlayArea.connect('repaint', () => { this._drawProgressOverlay(this._progressOverlayArea); @@ -842,7 +841,7 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { } _drawProgressOverlay(area) { - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); const [surfaceWidth, surfaceHeight] = area.get_surface_size(); const cr = area.get_context(); @@ -894,11 +893,11 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { [hasColor, bg] = node.lookup_color('-progress-bar-background', false); if (!hasColor) - bg = new Clutter.Color({ red: 204, green: 204, blue: 204, alpha: 255 }); + bg = new Clutter.Color({red: 204, green: 204, blue: 204, alpha: 255}); [hasColor, bd] = node.lookup_color('-progress-bar-border', false); if (!hasColor) - bd = new Clutter.Color({ red: 230, green: 230, blue: 230, alpha: 255 }); + bd = new Clutter.Color({red: 230, green: 230, blue: 230, alpha: 255}); stroke = Cairo.SolidPattern.createRGBA( bd.red / 255, bd.green / 255, bd.blue / 255, bd.alpha / 255); @@ -935,7 +934,7 @@ var UnityIndicator = class DashToDockUnityIndicator extends IndicatorBase { else delete this._isUrgent; } -}; +} // Global icon cache. Used for Unity7 styling. @@ -951,7 +950,7 @@ const DOMINANT_COLOR_ICON_SIZE = 64; // Compute dominant color frim the app icon. // The color is cached for efficiency. -var DominantColorExtractor = class DashToDockDominantColorExtractor { +class DominantColorExtractor { constructor(app) { this._app = app; } @@ -982,11 +981,10 @@ var DominantColorExtractor = class DashToDockDominantColorExtractor { const iconNames = iconTexture.get_names(); const iconInfo = themeLoader.choose_icon(iconNames, DOMINANT_COLOR_ICON_SIZE, 0); - if (iconInfo) { + if (iconInfo) return iconInfo.load_icon(); - } else { + else return null; - } } // Use GdkPixBuf to load the pixel buffer from memory @@ -1124,4 +1122,4 @@ var DominantColorExtractor = class DashToDockDominantColorExtractor { return resampledPixels; } -}; +} diff --git a/appIcons.js b/appIcons.js index e488d7c77..3fc920d95 100644 --- a/appIcons.js +++ b/appIcons.js @@ -1,49 +1,47 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported DockShowAppsIcon, makeAppIcon, itemShowLabel, getInterestingWindows */ - -const { +import { Clutter, Gio, GLib, GObject, Meta, Shell, - St, -} = imports.gi; + St +} from './dependencies/gi.js'; + +import { + AppDisplay, + AppFavorites, + BoxPointer, + Dash, + Main, + PopupMenu +} from './dependencies/shell/ui.js'; + +import { + ParentalControlsManager +} from './dependencies/shell/misc.js'; + +import {Config} from './dependencies/shell/misc.js'; + +import { + AppIconIndicators, + DBusMenuUtils, + Docking, + Locations, + Theming, + Utils, + WindowPreview +} from './imports.js'; + +import {Extension} from './dependencies/shell/extensions/extension.js'; // Use __ () and N__() for the extension gettext domain, and reuse // the shell domain with the default _() and N_() -const Gettext = imports.gettext.domain('dashtodock'); -const __ = Gettext.gettext; -const N__ = e => e; - -const Config = imports.misc.config; - -const { - appDisplay: AppDisplay, - appFavorites: AppFavorites, - boxpointer: BoxPointer, - dash: Dash, - main: Main, - popupMenu: PopupMenu, -} = imports.ui; - -const { - parentalControlsManager: ParentalControlsManager, -} = imports.misc; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const { - appIconIndicators: AppIconIndicators, - dbusmenuUtils: DbusmenuUtils, - docking: Docking, - locations: Locations, - theming: Theming, - utils: Utils, - windowPreview: WindowPreview, -} = Me.imports; +const {gettext: __} = Extension; + +const DBusMenu = await DBusMenuUtils.haveDBusMenu(); const tracker = Shell.WindowTracker.get_default(); @@ -92,7 +90,7 @@ let recentlyClickedAppMonitor = -1; * - Update minimization animation target * - Update menu if open on windows change */ -var DockAbstractAppIcon = GObject.registerClass({ +const DockAbstractAppIcon = GObject.registerClass({ GTypeFlags: GObject.TypeFlags.ABSTRACT, Properties: { 'focused': GObject.ParamSpec.boolean( @@ -164,7 +162,7 @@ var DockAbstractAppIcon = GObject.registerClass({ this.remove_style_class_name('focused'); }); - const { notificationsMonitor } = Docking.DockManager.getDefault(); + const {notificationsMonitor} = Docking.DockManager.getDefault(); this.connect('notify::urgent', () => { const icon = this.icon._iconBin; @@ -240,7 +238,7 @@ var DockAbstractAppIcon = GObject.registerClass({ } vfunc_scroll_event(scrollEvent) { - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; const isEnabled = settings.scrollAction === scrollAction.CYCLE_WINDOWS; if (!isEnabled) return Clutter.EVENT_PROPAGATE; @@ -395,7 +393,7 @@ var DockAbstractAppIcon = GObject.registerClass({ let windows = this.getWindows(); if (Docking.DockManager.settings.multiMonitor) { - const { monitorIndex } = this; + const {monitorIndex} = this; windows = windows.filter(w => w.get_monitor() === monitorIndex); } windows.forEach(w => w.set_icon_geometry(rect)); @@ -431,10 +429,10 @@ var DockAbstractAppIcon = GObject.registerClass({ const monitorIndex = Main.layoutManager.findIndexForActor(this); const workArea = Main.layoutManager.getWorkAreaForMonitor(monitorIndex); const position = Utils.getPosition(); - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); const isHorizontal = position === St.Side.TOP || position === St.Side.BOTTOM; // If horizontal also remove the height of the dash - const { dockFixed: fixedDock } = Docking.DockManager.settings; + const {dockFixed: fixedDock} = Docking.DockManager.settings; const additionalMargin = isHorizontal && !fixedDock ? Main.overview.dash.height : 0; const verticalMargins = this._menu.actor.margin_top + this._menu.actor.margin_bottom; const maxMenuHeight = workArea.height - additionalMargin - verticalMargins; @@ -484,7 +482,7 @@ var DockAbstractAppIcon = GObject.registerClass({ // being used. We then define what buttonAction should be for this // event. let buttonAction = 0; - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; if (button && button === 2) { if (modifiers & Clutter.ModifierType.SHIFT_MASK) buttonAction = settings.shiftMiddleClickAction; @@ -914,7 +912,7 @@ var DockAbstractAppIcon = GObject.registerClass({ } }); -var DockAppIcon = GObject.registerClass({ +const DockAppIcon = GObject.registerClass({ }, class DockAppIcon extends DockAbstractAppIcon { _init(app, monitorIndex, iconAnimator) { super._init(app, monitorIndex, iconAnimator); @@ -923,7 +921,7 @@ var DockAppIcon = GObject.registerClass({ } }); -var DockLocationAppIcon = GObject.registerClass({ +const DockLocationAppIcon = GObject.registerClass({ }, class DockLocationAppIcon extends DockAbstractAppIcon { _init(app, monitorIndex, iconAnimator) { if (!(app.appInfo instanceof Locations.LocationAppInfo)) @@ -960,7 +958,7 @@ var DockLocationAppIcon = GObject.registerClass({ * @param monitorIndex * @param iconAnimator */ -function makeAppIcon(app, monitorIndex, iconAnimator) { +export function makeAppIcon(app, monitorIndex, iconAnimator) { if (app.appInfo instanceof Locations.LocationAppInfo) return new DockLocationAppIcon(app, monitorIndex, iconAnimator); @@ -1000,16 +998,16 @@ const DockAppIconMenu = class DockAppIconMenu extends PopupMenu.PopupMenu { Main.uiGroup.add_actor(this.actor); - const { remoteModel } = Docking.DockManager.getDefault(); + const {remoteModel} = Docking.DockManager.getDefault(); const remoteModelApp = remoteModel?.lookupById(this._source?.app?.id); - if (remoteModelApp && DbusmenuUtils.haveDBusMenu()) { + if (remoteModelApp && DBusMenu) { const [onQuicklist, onDynamicSection] = Utils.splitHandler((sender, - { quicklist }, dynamicSection) => { + {quicklist}, dynamicSection) => { dynamicSection.removeAll(); if (quicklist) { quicklist.get_children().forEach(remoteItem => dynamicSection.addMenuItem( - DbusmenuUtils.makePopupMenuItem(remoteItem, false))); + DBusMenuUtils.makePopupMenuItem(remoteItem, false))); } }); @@ -1296,8 +1294,8 @@ function isWindowUrgent(w) { * @param windows * @param monitorIndex */ -function getInterestingWindows(windows, monitorIndex) { - const { settings } = Docking.DockManager; +export function getInterestingWindows(windows, monitorIndex) { + const {settings} = Docking.DockManager; // When using workspace isolation, we filter out windows // that are neither in the current workspace nor marked urgent @@ -1329,9 +1327,9 @@ function getInterestingWindows(windows, monitorIndex) { * */ -var DockShowAppsIcon = GObject.registerClass({ +export const DockShowAppsIcon = GObject.registerClass({ Signals: { - 'menu-state-changed': { param_types: [GObject.TYPE_BOOLEAN] }, + 'menu-state-changed': {param_types: [GObject.TYPE_BOOLEAN]}, 'sync-tooltip': {}, }, } @@ -1340,7 +1338,7 @@ var DockShowAppsIcon = GObject.registerClass({ super._init(); // Re-use appIcon methods - const { prototype: appIconPrototype } = AppDisplay.AppIcon; + const {prototype: appIconPrototype} = AppDisplay.AppIcon; this.toggleButton.y_expand = false; this.toggleButton.connect('popup-menu', () => appIconPrototype._onKeyboardPopupMenu.call(this)); @@ -1442,16 +1440,16 @@ class DockShowAppsIconMenu extends DockAppIconMenu { const name = __('Dash to Dock %s').format(_('Settings')); const item = this._appendMenuItem(name); - item.connect('activate', () => { - ExtensionUtils.openPrefs(); - }); + item.connect('activate', () => + Docking.DockManager.extension.openPreferences()); } } /** * This function is used for both DockShowAppsIcon and DockDashItemContainer */ -function itemShowLabel() { +export function itemShowLabel() { + /* eslint-disable no-invalid-this */ // Check if the label is still present at all. When switching workpaces, the // item might have been destroyed in between. if (!this._labelText || !this.label.get_stage()) @@ -1519,4 +1517,5 @@ function itemShowLabel() { duration: Dash.DASH_ITEM_LABEL_SHOW_TIME, mode: Clutter.AnimationMode.EASE_OUT_QUAD, }); + /* eslint-enable no-invalid-this */ } diff --git a/appSpread.js b/appSpread.js index 248b81489..adea3cc0d 100644 --- a/appSpread.js +++ b/appSpread.js @@ -1,16 +1,15 @@ -/* exported AppSpread */ +import {Atk, Clutter} from './dependencies/gi.js'; -const { Atk, Clutter } = imports.gi; +import { + Main, + SearchController, + Workspace, + WorkspaceThumbnail +} from './dependencies/shell/ui.js'; -const Main = imports.ui.main; -const SearchController = imports.ui.searchController; -const Workspace = imports.ui.workspace; -const WorkspaceThumbnail = imports.ui.workspaceThumbnail; +import {Utils} from './imports.js'; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { utils: Utils } = Me.imports; - -var AppSpread = class AppSpread { +export class AppSpread { constructor() { this.app = null; this.supported = true; @@ -58,7 +57,7 @@ var AppSpread = class AppSpread { } _restoreDefaultWindows() { - const { workspaceManager } = global; + const {workspaceManager} = global; for (let i = 0; i < workspaceManager.nWorkspaces; i++) { const metaWorkspace = workspaceManager.get_workspace_by_index(i); @@ -67,7 +66,7 @@ var AppSpread = class AppSpread { } _filterWindows() { - const { workspaceManager } = global; + const {workspaceManager} = global; for (let i = 0; i < workspaceManager.nWorkspaces; i++) { const metaWorkspace = workspaceManager.get_workspace_by_index(i); @@ -140,7 +139,7 @@ var AppSpread = class AppSpread { activitiesButton.constructor.prototype, 'key_release_event', function (keyEvent) { - const { keyval } = keyEvent; + const {keyval} = keyEvent; if (keyval === Clutter.KEY_Return || keyval === Clutter.KEY_space) { if (Main.overview.shouldToggleByCornerOrButton()) appSpread._restoreDefaultOverview(); @@ -208,4 +207,4 @@ var AppSpread = class AppSpread { if (Main.overview.searchEntry) Main.overview.searchEntry.opacity = 255; } -}; +} diff --git a/dash.js b/dash.js index b4bbcc436..96b9dafff 100644 --- a/dash.js +++ b/dash.js @@ -1,36 +1,33 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported DockDash */ - -const { +import { Clutter, Gio, GLib, GObject, Shell, - St, -} = imports.gi; - -const { - appFavorites: AppFavorites, - dash: Dash, - dnd: DND, - main: Main, -} = imports.ui; - -const { - util: Util, -} = imports.misc; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { - appIcons: AppIcons, - docking: Docking, - theming: Theming, - utils: Utils, -} = Me.imports; - -const { DASH_ANIMATION_TIME } = Dash; + St +} from './dependencies/gi.js'; + +import { + AppFavorites, + Dash, + DND, + Main +} from './dependencies/shell/ui.js'; + +import { + Util +} from './dependencies/shell/misc.js'; + +import { + AppIcons, + Docking, + Theming, + Utils +} from './imports.js'; + +const {DASH_ANIMATION_TIME} = Dash; const DASH_VISIBILITY_TIMEOUT = 3; const Labels = Object.freeze({ @@ -44,7 +41,7 @@ const Labels = Object.freeze({ * - set label position based on dash orientation * */ -var DockDashItemContainer = GObject.registerClass( +const DockDashItemContainer = GObject.registerClass( class DockDashItemContainer extends Dash.DashItemContainer { _init(position) { super._init(); @@ -91,7 +88,7 @@ const baseIconSizes = [16, 22, 24, 32, 48, 64, 96, 128]; * - sync minimization application target position. * - keep running apps ordered. */ -var DockDash = GObject.registerClass({ +export const DockDash = GObject.registerClass({ Properties: { 'requires-visibility': GObject.ParamSpec.boolean( 'requires-visibility', 'requires-visibility', 'requires-visibility', @@ -164,7 +161,7 @@ var DockDash = GObject.registerClass({ this._box = new St.BoxLayout({ vertical: !this._isHorizontal, clip_to_allocation: false, - ...!this._isHorizontal ? { layout_manager: new DockDashIconsVerticalLayout() } : {}, + ...!this._isHorizontal ? {layout_manager: new DockDashIconsVerticalLayout()} : {}, x_align: rtl ? Clutter.ActorAlign.END : Clutter.ActorAlign.START, y_align: this._isHorizontal ? Clutter.ActorAlign.CENTER : Clutter.ActorAlign.START, y_expand: !this._isHorizontal, @@ -536,7 +533,7 @@ var DockDash = GObject.registerClass({ }); appIcon.connect('notify::focused', () => { - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; if (appIcon.focused && settings.scrollToFocusedApplication) ensureActorVisibleInScrollView(this._scrollView, item); }); @@ -648,8 +645,8 @@ var DockDash = GObject.registerClass({ const spacing = themeNode.get_length('spacing'); - const [{ child: firstButton }] = iconChildren; - const { child: firstIcon } = firstButton?.icon ?? { child: null }; + const [{child: firstButton}] = iconChildren; + const {child: firstIcon} = firstButton?.icon ?? {child: null}; // if no icons there's nothing to adjust if (!firstIcon) @@ -681,7 +678,7 @@ var DockDash = GObject.registerClass({ } const maxIconSize = availSpace / iconChildren.length; - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); const iconSizes = this._availableIconSizes.map(s => s * scaleFactor); let [newIconSize] = this._availableIconSizes; @@ -699,7 +696,7 @@ var DockDash = GObject.registerClass({ const scale = oldIconSize / newIconSize; for (let i = 0; i < iconChildren.length; i++) { - const { icon } = iconChildren[i].child._delegate; + const {icon} = iconChildren[i].child._delegate; // Set the new size immediately, to keep the icons' sizes // in sync with this.iconSize @@ -729,7 +726,7 @@ var DockDash = GObject.registerClass({ if (this._separator) { const animateProperties = this._isHorizontal - ? { height: this.iconSize } : { width: this.iconSize }; + ? {height: this.iconSize} : {width: this.iconSize}; this._separator.ease({ ...animateProperties, @@ -744,7 +741,7 @@ var DockDash = GObject.registerClass({ let running = this._appSystem.get_running(); const dockManager = Docking.DockManager.getDefault(); - const { settings } = dockManager; + const {settings} = dockManager; this._scrollView.set({ xAlign: Clutter.ActorAlign.FILL, @@ -779,7 +776,7 @@ var DockDash = GObject.registerClass({ // Apps supposed to be in the dash const newApps = []; - const { showFavorites } = settings; + const {showFavorites} = settings; if (showFavorites) newApps.push(...Object.values(favorites)); @@ -959,7 +956,7 @@ var DockDash = GObject.registerClass({ if (!this._shownInitially) this._shownInitially = true; - addedItems.forEach(({ item }) => item.show(animate)); + addedItems.forEach(({item}) => item.show(animate)); // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=692744 // Without it, StBoxLayout may use a stale size cache @@ -1066,7 +1063,7 @@ var DockDash = GObject.registerClass({ if (this._showAppsIcon.get_parent() && !this._showAppsIcon.visible) return; - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; const notifiedProperties = []; const showAppsContainer = settings.showAppsAlwaysInTheEdge || !settings.dockExtended ? this._dashContainer : this._boxContainer; @@ -1112,10 +1109,10 @@ var DockDash = GObject.registerClass({ * @param actor */ function ensureActorVisibleInScrollView(scrollView, actor) { - const { adjustment: vAdjustment } = scrollView.vscroll; - const { adjustment: hAdjustment } = scrollView.hscroll; - const { value: vValue0, pageSize: vPageSize, upper: vUpper } = vAdjustment; - const { value: hValue0, pageSize: hPageSize, upper: hUpper } = hAdjustment; + const {adjustment: vAdjustment} = scrollView.vscroll; + const {adjustment: hAdjustment} = scrollView.hscroll; + const {value: vValue0, pageSize: vPageSize, upper: vUpper} = vAdjustment; + const {value: hValue0, pageSize: hPageSize, upper: hUpper} = hAdjustment; let [hValue, vValue] = [hValue0, vValue0]; let vOffset = 0; let hOffset = 0; @@ -1126,7 +1123,7 @@ function ensureActorVisibleInScrollView(scrollView, actor) { } const box = actor.get_allocation_box(); - let { y1 } = box, { y2 } = box, { x1 } = box, { x2 } = box; + let {y1} = box, {y2} = box, {x1} = box, {x2} = box; let parent = actor.get_parent(); while (parent !== scrollView) { diff --git a/dbusmenuUtils.js b/dbusmenuUtils.js index eca37edf1..1476ebdb8 100644 --- a/dbusmenuUtils.js +++ b/dbusmenuUtils.js @@ -1,21 +1,16 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported haveDBusMenu, makePopupMenuItem */ - -const { +import { Atk, Clutter, Gio, GLib, - St, -} = imports.gi; - -let Dbusmenu = null; /* Dynamically imported */ + St +} from './dependencies/gi.js'; -const { popupMenu: PopupMenu } = imports.ui; +import {PopupMenu} from './dependencies/shell/ui.js'; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { utils: Utils } = Me.imports; +import {Utils} from './imports.js'; // Dbusmenu features not (yet) supported: // @@ -43,39 +38,37 @@ const { utils: Utils } = Me.imports; /** * */ -function haveDBusMenu() { - if (Dbusmenu) - return Dbusmenu; - +export async function haveDBusMenu() { try { - ({ Dbusmenu } = imports.gi); - return Dbusmenu; + const {default: DBusMenu} = await import('gi://Dbusmenu'); + return DBusMenu; } catch (e) { - log(`Failed to import DBusMenu, quicklists are not avaialble: ${e}`); + log(`Failed to import DBusMenu, quicklists are not available: ${e}`); return null; } } +const DBusMenu = await haveDBusMenu(); /** * @param dbusmenuItem * @param deep */ -function makePopupMenuItem(dbusmenuItem, deep) { +export function makePopupMenuItem(dbusmenuItem, deep) { // These are the only properties guaranteed to be available when the root // item is first announced. Other properties might be loaded already, but // be sure to connect to Dbusmenu.MENUITEM_SIGNAL_PROPERTY_CHANGED to get // the most up-to-date values in case they aren't. - const itemType = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_TYPE); - const label = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_LABEL); - const visible = dbusmenuItem.property_get_bool(Dbusmenu.MENUITEM_PROP_VISIBLE); - const enabled = dbusmenuItem.property_get_bool(Dbusmenu.MENUITEM_PROP_ENABLED); - const accessibleDesc = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_ACCESSIBLE_DESC); + const itemType = dbusmenuItem.property_get(DBusMenu.MENUITEM_PROP_TYPE); + const label = dbusmenuItem.property_get(DBusMenu.MENUITEM_PROP_LABEL); + const visible = dbusmenuItem.property_get_bool(DBusMenu.MENUITEM_PROP_VISIBLE); + const enabled = dbusmenuItem.property_get_bool(DBusMenu.MENUITEM_PROP_ENABLED); + const accessibleDesc = dbusmenuItem.property_get(DBusMenu.MENUITEM_PROP_ACCESSIBLE_DESC); // const childDisplay = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_CHILD_DISPLAY); let item; const signalsHandler = new Utils.GlobalSignalsHandler(); - const wantIcon = itemType === Dbusmenu.CLIENT_TYPES_IMAGE; + const wantIcon = itemType === DBusMenu.CLIENT_TYPES_IMAGE; // If the basic type of the menu item needs to change, call this. const recreateItem = () => { @@ -95,14 +88,14 @@ function makePopupMenuItem(dbusmenuItem, deep) { }; const updateDisposition = () => { - const disposition = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_DISPOSITION); + const disposition = dbusmenuItem.property_get(DBusMenu.MENUITEM_PROP_DISPOSITION); let iconName = null; switch (disposition) { - case Dbusmenu.MENUITEM_DISPOSITION_ALERT: - case Dbusmenu.MENUITEM_DISPOSITION_WARNING: + case DBusMenu.MENUITEM_DISPOSITION_ALERT: + case DBusMenu.MENUITEM_DISPOSITION_WARNING: iconName = 'dialog-warning-symbolic'; break; - case Dbusmenu.MENUITEM_DISPOSITION_INFORMATIVE: + case DBusMenu.MENUITEM_DISPOSITION_INFORMATIVE: iconName = 'dialog-information-symbolic'; break; } @@ -139,8 +132,8 @@ function makePopupMenuItem(dbusmenuItem, deep) { if (!wantIcon) return; - const iconData = dbusmenuItem.property_get_byte_array(Dbusmenu.MENUITEM_PROP_ICON_DATA); - const iconName = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_ICON_NAME); + const iconData = dbusmenuItem.property_get_byte_array(DBusMenu.MENUITEM_PROP_ICON_DATA); + const iconName = dbusmenuItem.property_get(DBusMenu.MENUITEM_PROP_ICON_NAME); if (iconName) item.icon.icon_name = iconName; else if (iconData.length) @@ -148,20 +141,20 @@ function makePopupMenuItem(dbusmenuItem, deep) { }; const updateOrnament = () => { - const toggleType = dbusmenuItem.property_get(Dbusmenu.MENUITEM_PROP_TOGGLE_TYPE); + const toggleType = dbusmenuItem.property_get(DBusMenu.MENUITEM_PROP_TOGGLE_TYPE); switch (toggleType) { - case Dbusmenu.MENUITEM_TOGGLE_CHECK: + case DBusMenu.MENUITEM_TOGGLE_CHECK: item.actor.accessible_role = Atk.Role.CHECK_MENU_ITEM; break; - case Dbusmenu.MENUITEM_TOGGLE_RADIO: + case DBusMenu.MENUITEM_TOGGLE_RADIO: item.actor.accessible_role = Atk.Role.RADIO_MENU_ITEM; break; default: item.actor.accessible_role = Atk.Role.MENU_ITEM; } let ornament = PopupMenu.Ornament.NONE; - const state = dbusmenuItem.property_get_int(Dbusmenu.MENUITEM_PROP_TOGGLE_STATE); - if (state === Dbusmenu.MENUITEM_TOGGLE_STATE_UNKNOWN) { + const state = dbusmenuItem.property_get_int(DBusMenu.MENUITEM_PROP_TOGGLE_STATE); + if (state === DBusMenu.MENUITEM_TOGGLE_STATE_UNKNOWN) { // PopupMenu doesn't natively support an "unknown" ornament, but we // can hack one in: item.setOrnament(ornament); @@ -170,10 +163,10 @@ function makePopupMenuItem(dbusmenuItem, deep) { item.actor.remove_style_pseudo_class('checked'); } else { item.actor.remove_accessible_state(Atk.StateType.INDETERMINATE); - if (state === Dbusmenu.MENUITEM_TOGGLE_STATE_CHECKED) { - if (toggleType === Dbusmenu.MENUITEM_TOGGLE_CHECK) + if (state === DBusMenu.MENUITEM_TOGGLE_STATE_CHECKED) { + if (toggleType === DBusMenu.MENUITEM_TOGGLE_CHECK) ornament = PopupMenu.Ornament.CHECK; - else if (toggleType === Dbusmenu.MENUITEM_TOGGLE_RADIO) + else if (toggleType === DBusMenu.MENUITEM_TOGGLE_RADIO) ornament = PopupMenu.Ornament.DOT; item.actor.add_style_pseudo_class('checked'); @@ -188,30 +181,30 @@ function makePopupMenuItem(dbusmenuItem, deep) { // `value` is null when a property is cleared, so handle those cases // with sensible defaults. switch (name) { - case Dbusmenu.MENUITEM_PROP_TYPE: + case DBusMenu.MENUITEM_PROP_TYPE: recreateItem(); break; - case Dbusmenu.MENUITEM_PROP_ENABLED: + case DBusMenu.MENUITEM_PROP_ENABLED: item.setSensitive(value ? value.unpack() : false); break; - case Dbusmenu.MENUITEM_PROP_LABEL: + case DBusMenu.MENUITEM_PROP_LABEL: item.label.text = value ? value.unpack() : ''; break; - case Dbusmenu.MENUITEM_PROP_VISIBLE: + case DBusMenu.MENUITEM_PROP_VISIBLE: item.actor.visible = value ? value.unpack() : false; break; - case Dbusmenu.MENUITEM_PROP_DISPOSITION: + case DBusMenu.MENUITEM_PROP_DISPOSITION: updateDisposition(); break; - case Dbusmenu.MENUITEM_PROP_ACCESSIBLE_DESC: + case DBusMenu.MENUITEM_PROP_ACCESSIBLE_DESC: item.actor.get_accessible().accessible_description = value && value.unpack() || ''; break; - case Dbusmenu.MENUITEM_PROP_ICON_DATA: - case Dbusmenu.MENUITEM_PROP_ICON_NAME: + case DBusMenu.MENUITEM_PROP_ICON_DATA: + case DBusMenu.MENUITEM_PROP_ICON_NAME: updateIcon(); break; - case Dbusmenu.MENUITEM_PROP_TOGGLE_TYPE: - case Dbusmenu.MENUITEM_PROP_TOGGLE_STATE: + case DBusMenu.MENUITEM_PROP_TOGGLE_TYPE: + case DBusMenu.MENUITEM_PROP_TOGGLE_STATE: updateOrnament(); break; } @@ -236,20 +229,20 @@ function makePopupMenuItem(dbusmenuItem, deep) { }; updateChildren(); signalsHandler.add( - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_ADDED, updateChildren], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_MOVED, updateChildren], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_REMOVED, updateChildren]); + [dbusmenuItem, DBusMenu.MENUITEM_SIGNAL_CHILD_ADDED, updateChildren], + [dbusmenuItem, DBusMenu.MENUITEM_SIGNAL_CHILD_MOVED, updateChildren], + [dbusmenuItem, DBusMenu.MENUITEM_SIGNAL_CHILD_REMOVED, updateChildren]); } else { // Don't make a submenu. if (!deep) { // We only have the potential to get a submenu if we aren't deep. signalsHandler.add( - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_ADDED, recreateItem], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_MOVED, recreateItem], - [dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_CHILD_REMOVED, recreateItem]); + [dbusmenuItem, DBusMenu.MENUITEM_SIGNAL_CHILD_ADDED, recreateItem], + [dbusmenuItem, DBusMenu.MENUITEM_SIGNAL_CHILD_MOVED, recreateItem], + [dbusmenuItem, DBusMenu.MENUITEM_SIGNAL_CHILD_REMOVED, recreateItem]); } - if (itemType === Dbusmenu.CLIENT_TYPES_SEPARATOR) { + if (itemType === DBusMenu.CLIENT_TYPES_SEPARATOR) { item = new PopupMenu.PopupSeparatorMenuItem(); } else if (wantIcon) { item = new PopupMenu.PopupImageMenuItem(label, null); @@ -274,12 +267,12 @@ function makePopupMenuItem(dbusmenuItem, deep) { item.icon.icon_size = 16; - signalsHandler.add(dbusmenuItem, Dbusmenu.MENUITEM_SIGNAL_PROPERTY_CHANGED, onPropertyChanged); + signalsHandler.add(dbusmenuItem, DBusMenu.MENUITEM_SIGNAL_PROPERTY_CHANGED, onPropertyChanged); // Connections on item will be lost when item is disposed; there's no need // to add them to signalsHandler. item.connect('activate', () => - dbusmenuItem.handle_event(Dbusmenu.MENUITEM_EVENT_ACTIVATED, + dbusmenuItem.handle_event(DBusMenu.MENUITEM_EVENT_ACTIVATED, new GLib.Variant('i', 0), Math.floor(Date.now() / 1000))); item.connect('destroy', () => signalsHandler.destroy()); diff --git a/dependencies/gi.js b/dependencies/gi.js new file mode 100644 index 000000000..36a568196 --- /dev/null +++ b/dependencies/gi.js @@ -0,0 +1,27 @@ +import Atk from 'gi://Atk'; +import Clutter from 'gi://Clutter'; +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gdk from 'gi://Gdk?version=4.0'; +import GdkPixbuf from 'gi://GdkPixbuf'; +import Gio from 'gi://Gio'; +import Gtk from 'gi://Gtk?version=4.0'; +import Meta from 'gi://Meta'; +import Pango from 'gi://Pango'; +import Shell from 'gi://Shell'; +import St from 'gi://St'; + +export { + Atk, + Clutter, + GLib, + GObject, + Gdk, + GdkPixbuf, + Gio, + Gtk, + Meta, + Pango, + Shell, + St +}; diff --git a/dependencies/shell/extensions/extension.js b/dependencies/shell/extensions/extension.js new file mode 100644 index 000000000..bd9db9819 --- /dev/null +++ b/dependencies/shell/extensions/extension.js @@ -0,0 +1 @@ +export * as Extension from 'resource:///org/gnome/shell/extensions/extension.js'; diff --git a/dependencies/shell/misc.js b/dependencies/shell/misc.js new file mode 100644 index 000000000..cfd4b959e --- /dev/null +++ b/dependencies/shell/misc.js @@ -0,0 +1,5 @@ +export * as AnimationUtils from 'resource:///org/gnome/shell/misc/animationUtils.js'; +export * as Config from 'resource:///org/gnome/shell/misc/config.js'; +export * as ExtensionUtils from 'resource:///org/gnome/shell/misc/extensionUtils.js'; +export * as ParentalControlsManager from 'resource:///org/gnome/shell/misc/parentalControlsManager.js'; +export * as Util from 'resource:///org/gnome/shell/misc/util.js'; diff --git a/dependencies/shell/ui.js b/dependencies/shell/ui.js new file mode 100644 index 000000000..40fa4ca39 --- /dev/null +++ b/dependencies/shell/ui.js @@ -0,0 +1,17 @@ +export * as AppDisplay from 'resource:///org/gnome/shell/ui/appDisplay.js'; +export * as AppFavorites from 'resource:///org/gnome/shell/ui/appFavorites.js'; +export * as BoxPointer from 'resource:///org/gnome/shell/ui/boxpointer.js'; +export * as DND from 'resource:///org/gnome/shell/ui/dnd.js'; +export * as Dash from 'resource:///org/gnome/shell/ui/dash.js'; +export * as Layout from 'resource:///org/gnome/shell/ui/layout.js'; +export * as Main from 'resource:///org/gnome/shell/ui/main.js'; +export * as Overview from 'resource:///org/gnome/shell/ui/overview.js'; +export * as OverviewControls from 'resource:///org/gnome/shell/ui/overviewControls.js'; +export * as PointerWatcher from 'resource:///org/gnome/shell/ui/pointerWatcher.js'; +export * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js'; +export * as SearchController from 'resource:///org/gnome/shell/ui/searchController.js'; +export * as ShellMountOperation from 'resource:///org/gnome/shell/ui/shellMountOperation.js'; +export * as Workspace from 'resource:///org/gnome/shell/ui/workspace.js'; +export * as WorkspaceSwitcherPopup from 'resource:///org/gnome/shell/ui/workspaceSwitcherPopup.js'; +export * as WorkspaceThumbnail from 'resource:///org/gnome/shell/ui/workspaceThumbnail.js'; +export * as WorkspacesView from 'resource:///org/gnome/shell/ui/workspacesView.js'; diff --git a/desktopIconsIntegration.js b/desktopIconsIntegration.js index d002c2d3f..f797d060f 100644 --- a/desktopIconsIntegration.js +++ b/desktopIconsIntegration.js @@ -55,17 +55,15 @@ * *******************************************************************************/ -/* exported DesktopIconsUsableAreaClass */ +import {GLib} from './dependencies/gi.js'; +import {Main} from './dependencies/shell/ui.js'; +import {ExtensionUtils} from './dependencies/shell/misc.js'; -const { GLib } = imports.gi; -const { main: Main } = imports.ui; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); +import {DockManager} from './docking.js'; const IDENTIFIER_UUID = '130cbc66-235c-4bd6-8571-98d2d8bba5e2'; -var DesktopIconsUsableAreaClass = class { +export class DesktopIconsUsableAreaClass { constructor() { this._extensionManager = Main.extensionManager; this._timedMarginsID = 0; @@ -158,7 +156,9 @@ var DesktopIconsUsableAreaClass = class { return; const usableArea = extension?.stateObj?.DesktopIconsUsableArea; - if (usableArea?.uuid === IDENTIFIER_UUID) - usableArea.setMarginsForExtension(Me.uuid, this._margins); + if (usableArea?.uuid === IDENTIFIER_UUID) { + usableArea.setMarginsForExtension( + DockManager.extension.uuid, this._margins); + } } -}; +} diff --git a/docking.js b/docking.js index 09dbf99b7..869a9a24c 100644 --- a/docking.js +++ b/docking.js @@ -1,53 +1,50 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported DockManager, IconAnimator, State */ - -const { +import { Clutter, GLib, Gio, GObject, Meta, Shell, - St, -} = imports.gi; - -const { signals: Signals } = imports; - -const { - appDisplay: AppDisplay, - environment: Environment, - layout: Layout, - main: Main, - overview: Overview, - overviewControls: OverviewControls, - pointerWatcher: PointerWatcher, - workspace: Workspace, - workspacesView: WorkspacesView, - workspaceSwitcherPopup: WorkspaceSwitcherPopup, -} = imports.ui; - - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const { - appSpread: AppSpread, - dash: DockDash, - desktopIconsIntegration: DesktopIconsIntegration, - fileManager1API: FileManager1API, - intellihide: Intellihide, - launcherAPI: LauncherAPI, - locations: Locations, - notificationsMonitor: NotificationsMonitor, - theming: Theming, - utils: Utils, -} = Me.imports; + St +} from './dependencies/gi.js'; + +import { + AppDisplay, + Layout, + Main, + Overview, + OverviewControls, + PointerWatcher, + Workspace, + WorkspacesView, + WorkspaceSwitcherPopup +} from './dependencies/shell/ui.js'; + +import { + AnimationUtils +} from './dependencies/shell/misc.js'; + +import { + AppSpread, + DockDash, + DesktopIconsIntegration, + FileManager1API, + Intellihide, + LauncherAPI, + Locations, + NotificationsMonitor, + Theming, + Utils +} from './imports.js'; + +const {signals: Signals} = imports; const DOCK_DWELL_CHECK_INTERVAL = 100; const ICON_ANIMATOR_DURATION = 3000; -var State = Object.freeze({ +export const State = Object.freeze({ HIDDEN: 0, SHOWING: 1, SHOWN: 2, @@ -235,7 +232,7 @@ const DockedDash = GObject.registerClass({ this._rtl = Clutter.get_default_text_direction() === Clutter.TextDirection.RTL; // Load settings - const { settings } = DockManager; + const {settings} = DockManager; this._isHorizontal = (this._position === St.Side.TOP) || (this._position === St.Side.BOTTOM); // Temporary ignore hover events linked to autohide for whatever reason @@ -514,7 +511,7 @@ const DockedDash = GObject.registerClass({ } _bindSettingsChanges() { - const { settings } = DockManager; + const {settings} = DockManager; this._signalsHandler.add([ settings, 'changed::scroll-action', @@ -669,7 +666,7 @@ const DockedDash = GObject.registerClass({ * This is call when visibility settings change */ _updateVisibilityMode() { - const { settings } = DockManager; + const {settings} = DockManager; if (DockManager.settings.dockFixed || DockManager.settings.manualhide) { this._autohideIsEnabled = false; this._intellihideIsEnabled = false; @@ -710,7 +707,7 @@ const DockedDash = GObject.registerClass({ if (Main.overview.visibleTarget) return; - const { settings } = DockManager; + const {settings} = DockManager; if (DockManager.settings.dockFixed) { this._removeAnimations(); @@ -800,7 +797,7 @@ const DockedDash = GObject.registerClass({ _hide() { // If no hiding animation is running or queued if ((this._dockState === State.SHOWN) || (this._dockState === State.SHOWING)) { - const { settings } = DockManager; + const {settings} = DockManager; const delay = settings.hideDelay; if (this._dockState === State.SHOWING) { @@ -956,9 +953,9 @@ const DockedDash = GObject.registerClass({ } _updatePressureBarrier() { - const { settings } = DockManager; + const {settings} = DockManager; this._canUsePressure = global.display.supports_extended_barriers(); - const { pressureThreshold } = settings; + const {pressureThreshold} = settings; // Remove existing pressure barrier if (this._pressureBarrier) { @@ -1138,7 +1135,7 @@ const DockedDash = GObject.registerClass({ // Ensure variables linked to settings are updated. this._updateVisibilityMode(); - const { dockFixed: fixedIsEnabled, dockExtended: extendHeight } = DockManager.settings; + const {dockFixed: fixedIsEnabled, dockExtended: extendHeight} = DockManager.settings; if (fixedIsEnabled) this.add_style_class_name('fixed'); @@ -1197,7 +1194,7 @@ const DockedDash = GObject.registerClass({ if (!this._intellihideIsEnabled) return; - const { desktopIconsUsableArea } = DockManager.getDefault(); + const {desktopIconsUsableArea} = DockManager.getDefault(); if (this._position === St.Side.BOTTOM) desktopIconsUsableArea.setMargins(this.monitorIndex, 0, this._box.height, 0, 0); else if (this._position === St.Side.TOP) @@ -1250,7 +1247,7 @@ const DockedDash = GObject.registerClass({ // Restore dash accessibility Main.ctrlAltTabManager.addGroup( this.dash, _('Dash'), 'user-bookmarks-symbolic', - { focusCallback: this._onAccessibilityFocus.bind(this) }); + {focusCallback: this._onAccessibilityFocus.bind(this)}); } /** @@ -1440,7 +1437,7 @@ const KeyboardShortcuts = class DashToDockKeyboardShortcuts { // Setup keyboard bindings for dash elements const keys = ['app-hotkey-', 'app-shift-hotkey-', 'app-ctrl-hotkey-']; - const { mainDock } = DockManager.getDefault(); + const {mainDock} = DockManager.getDefault(); keys.forEach(function (key) { for (let i = 0; i < NUM_HOTKEYS; i++) { const appNum = i; @@ -1471,7 +1468,7 @@ const KeyboardShortcuts = class DashToDockKeyboardShortcuts { } _optionalNumberOverlay() { - const { settings } = DockManager; + const {settings} = DockManager; this._shortcutIsSet = false; // Enable extra shortcut if either 'overlay' or 'show-dock' are true if (settings.hotKeys && @@ -1494,7 +1491,7 @@ const KeyboardShortcuts = class DashToDockKeyboardShortcuts { } _checkHotkeysOptions() { - const { settings } = DockManager; + const {settings} = DockManager; if (settings.hotKeys && (settings.hotkeysOverlay || settings.hotkeysShowDock)) @@ -1559,7 +1556,7 @@ const KeyboardShortcuts = class DashToDockKeyboardShortcuts { */ const WorkspaceIsolation = class DashToDockWorkspaceIsolation { constructor() { - const { settings } = DockManager; + const {settings} = DockManager; this._signalsHandler = new Utils.GlobalSignalsHandler(); this._injectionsHandler = new Utils.InjectionsHandler(); @@ -1641,19 +1638,19 @@ const WorkspaceIsolation = class DashToDockWorkspaceIsolation { }; -var DockManager = class DashToDockDockManager { - constructor() { - if (Me.imports.extension.dockManager) +export class DockManager { + constructor(extension) { + if (DockManager._singleton) throw new Error('DashToDock has been already initialized'); - - Me.imports.extension.dockManager = this; - + DockManager._singleton = this; + this._extension = extension; this._signalsHandler = new Utils.GlobalSignalsHandler(this); this._methodInjections = new Utils.InjectionsHandler(this); this._vfuncInjections = new Utils.VFuncInjectionsHandler(this); this._propertyInjections = new Utils.PropertyInjectionsHandler(this); - this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock'); - this._appSwitcherSettings = new Gio.Settings({ schema_id: 'org.gnome.shell.app-switcher' }); + this._settings = this._extension.getSettings( + 'org.gnome.shell.extensions.dash-to-dock'); + this._appSwitcherSettings = new Gio.Settings({schema_id: 'org.gnome.shell.app-switcher'}); this._mapSettingsValues(); this._iconTheme = new Utils.IconTheme(); @@ -1711,17 +1708,25 @@ var DockManager = class DashToDockDockManager { } static getDefault() { - return Me.imports.extension.dockManager; + return DockManager._singleton; } static get allDocks() { return DockManager.getDefault()._allDocks; } + static get extension() { + return DockManager.getDefault().extension; + } + static get settings() { return DockManager.getDefault().settings; } + get extension() { + return this._extension; + } + get settings() { return this._settings; } @@ -1779,7 +1784,7 @@ var DockManager = class DashToDockDockManager { } _ensureLocations() { - const { showMounts, showTrash } = this.settings; + const {showMounts, showTrash} = this.settings; if (showTrash || showMounts) { if (!this._fm1Client) @@ -1849,7 +1854,7 @@ var DockManager = class DashToDockDockManager { }, ]); - const { get: defaultFocusAppGetter } = Object.getOwnPropertyDescriptor( + const {get: defaultFocusAppGetter} = Object.getOwnPropertyDescriptor( Shell.WindowTracker.prototype, 'focus_app'); this._propertyInjections.addWithLabel(Labels.LOCATIONS, Shell.WindowTracker.prototype, 'focus_app', { @@ -1915,11 +1920,11 @@ var DockManager = class DashToDockDockManager { `changed::${key}`, updateSetting); if (key !== camelKey) { Object.defineProperty(this.settings, key, - { get: () => this.settings[camelKey] }); + {get: () => this.settings[camelKey]}); } }); Object.defineProperties(this.settings, { - dockExtended: { get: () => this.settings.extendHeight }, + dockExtended: {get: () => this.settings.extendHeight}, }); } @@ -2043,7 +2048,7 @@ var DockManager = class DashToDockDockManager { for (let iMon = 0; iMon < nMon; iMon++) { if (iMon === this._preferredMonitorIndex) continue; - dock = new DockedDash({ monitorIndex: iMon }); + dock = new DockedDash({monitorIndex: iMon}); this._allDocks.push(dock); // connect app icon into the view selector dock.dash.showAppsButton.connect('notify::checked', @@ -2061,7 +2066,7 @@ var DockManager = class DashToDockDockManager { _prepareStartupAnimation(callback) { DockManager.allDocks.forEach(dock => { - const { dash } = dock; + const {dash} = dock; dock.opacity = 255; dash.set({ @@ -2098,10 +2103,10 @@ var DockManager = class DashToDockDockManager { } _runStartupAnimation(callback) { - const { STARTUP_ANIMATION_TIME } = Layout; + const {STARTUP_ANIMATION_TIME} = Layout; DockManager.allDocks.forEach(dock => { - const { dash } = dock; + const {dash} = dock; switch (dock.position) { case St.Side.LEFT: @@ -2194,7 +2199,10 @@ var DockManager = class DashToDockDockManager { return [0, 0]; }); - const { ControlsManager, ControlsManagerLayout } = OverviewControls; + const {ControlsManager} = OverviewControls; + // FIXME: https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2890 + // const { ControlsManagerLayout } = OverviewControls; + const ControlsManagerLayout = this.overviewControls.layout_manager.constructor; this._methodInjections.removeWithLabel(Labels.STARTUP_ANIMATION); this._methodInjections.addWithLabel(Labels.STARTUP_ANIMATION, @@ -2256,7 +2264,7 @@ var DockManager = class DashToDockDockManager { dockManager._signalsHandler.addWithLabel(Labels.STARTUP_ANIMATION, Utils.getMonitorManager(), 'monitors-changed', () => { - const { x, y, width, height } = this.primaryMonitor; + const {x, y, width, height} = this.primaryMonitor; global.window_group.set_clip(x, y, width, height); this._coverPane?.set({ width: global.screen_width, @@ -2300,7 +2308,7 @@ var DockManager = class DashToDockDockManager { const maybeAdjustBoxSize = (state, box, spacing) => { if (state === OverviewControls.ControlsState.WINDOW_PICKER) { const searchBox = this.overviewControls._searchEntry.get_allocation_box(); - const { shouldShow: wsThumbnails } = this.overviewControls._thumbnailsBox; + const {shouldShow: wsThumbnails} = this.overviewControls._thumbnailsBox; if (!wsThumbnails) { box.y1 += spacing; @@ -2349,7 +2357,7 @@ var DockManager = class DashToDockDockManager { const oldStartY = workAreaBox.y1; const propertyInjections = new Utils.PropertyInjectionsHandler(); - propertyInjections.add(Main.layoutManager.panelBox, 'height', { value: startY }); + propertyInjections.add(Main.layoutManager.panelBox, 'height', {value: startY}); if (Main.layoutManager.panelBox.y === Main.layoutManager.primaryMonitor.y) workAreaBox.y1 -= oldStartY; @@ -2498,7 +2506,7 @@ var DockManager = class DashToDockDockManager { const monitor = Main.layoutManager.primaryMonitor; const x = monitor.x + monitor.width / 2.0; const y = monitor.y + monitor.height / 2.0; - const { STARTUP_ANIMATION_TIME } = Layout; + const {STARTUP_ANIMATION_TIME} = Layout; this._prepareStartupAnimation(callback); Main.uiGroup.set_pivot_point( @@ -2566,8 +2574,8 @@ var DockManager = class DashToDockDockManager { } _onShowAppsButtonToggled(button) { - const { checked } = button; - const { overviewControls } = this; + const {checked} = button; + const {overviewControls} = this; if (!Main.overview.visible) { this.mainDock.dash.showAppsButton._fromDesktop = true; @@ -2648,7 +2656,8 @@ var DockManager = class DashToDockDockManager { this._desktopIconsUsableArea.destroy(); this._desktopIconsUsableArea = null; - Me.imports.extension.dockManager = null; + this._extension = null; + DockManager._singleton = null; } /** @@ -2682,12 +2691,12 @@ var DockManager = class DashToDockDockManager { _hasPanelCorners() { return !!Main.panel?._rightCorner && !!Main.panel?._leftCorner; } -}; +} Signals.addSignalMethods(DockManager.prototype); // This class drives long-running icon animations, to keep them running in sync // with each other, and to save CPU by pausing them when the dock is hidden. -var IconAnimator = class DashToDockIconAnimator { +export class IconAnimator { constructor(actor) { this._count = 0; this._started = false; @@ -2695,7 +2704,7 @@ var IconAnimator = class DashToDockIconAnimator { wiggle: [], }; this._timeline = new Clutter.Timeline({ - duration: Environment.adjustAnimationTime(ICON_ANIMATOR_DURATION) || 1, + duration: AnimationUtils.adjustAnimationTime(ICON_ANIMATOR_DURATION) || 1, repeat_count: -1, actor, }); @@ -2715,7 +2724,7 @@ var IconAnimator = class DashToDockIconAnimator { _updateSettings() { this._timeline.set_duration( - Environment.adjustAnimationTime(ICON_ANIMATOR_DURATION) || 1); + AnimationUtils.adjustAnimationTime(ICON_ANIMATOR_DURATION) || 1); } destroy() { @@ -2748,7 +2757,7 @@ var IconAnimator = class DashToDockIconAnimator { addAnimation(target, name) { const targetDestroyId = target.connect('destroy', () => this.removeAnimation(target, name)); - this._animations[name].push({ target, targetDestroyId }); + this._animations[name].push({target, targetDestroyId}); if (this._started && this._count === 0) this._timeline.start(); @@ -2770,4 +2779,4 @@ var IconAnimator = class DashToDockIconAnimator { } } } -}; +} diff --git a/extension.js b/extension.js index 6e4225508..68de2acb0 100644 --- a/extension.js +++ b/extension.js @@ -1,32 +1,18 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported init, enable, disable */ +import {DockManager} from './docking.js'; +import {Extension} from './dependencies/shell/extensions/extension.js'; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); -const { docking: Docking } = Me.imports; +// We export this so it can be accessed by other extensions +export let dockManager; -// We declare this with var so it can be accessed by other extensions in -// GNOME Shell 3.26+ (mozjs52+). -var dockManager; +export default class DashToDockExtension extends Extension.Extension { + enable() { + dockManager = new DockManager(this); + } -/** - * - */ -function init() { - ExtensionUtils.initTranslations('dashtodock'); -} - -/** - * - */ -function enable() { - new Docking.DockManager(); -} - -/** - * - */ -function disable() { - dockManager.destroy(); + disable() { + dockManager?.destroy(); + dockManager = null; + } } diff --git a/fileManager1API.js b/fileManager1API.js index 0ce43fd66..192214a9d 100644 --- a/fileManager1API.js +++ b/fileManager1API.js @@ -1,10 +1,9 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -const { GLib, Gio } = imports.gi; -const { signals: Signals } = imports; +import {GLib, Gio} from './dependencies/gi.js'; +const {signals: Signals} = imports; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { utils: Utils } = Me.imports; +import {Utils} from './imports.js'; const FileManager1Iface = '\ \ @@ -24,7 +23,7 @@ const Labels = Object.freeze({ * The property is a map from window identifiers to a list of locations open in * the window. */ -var FileManager1Client = class DashToDockFileManager1Client { +export class FileManager1Client { constructor() { this._signalsHandler = new Utils.GlobalSignalsHandler(); this._cancellable = new Gio.Cancellable(); @@ -198,5 +197,5 @@ var FileManager1Client = class DashToDockFileManager1Client { this.emit('windows-changed'); } } -}; +} Signals.addSignalMethods(FileManager1Client.prototype); diff --git a/imports.js b/imports.js new file mode 100644 index 000000000..b94461119 --- /dev/null +++ b/imports.js @@ -0,0 +1,35 @@ +import * as AppIconIndicators from './appIconIndicators.js'; +import * as AppIcons from './appIcons.js'; +import * as AppSpread from './appSpread.js'; +import * as DockDash from './dash.js'; +import * as DBusMenuUtils from './dbusmenuUtils.js'; +import * as DesktopIconsIntegration from './desktopIconsIntegration.js'; +import * as Docking from './docking.js'; +import * as Extension from './extension.js'; +import * as FileManager1API from './fileManager1API.js'; +import * as Intellihide from './intellihide.js'; +import * as LauncherAPI from './launcherAPI.js'; +import * as Locations from './locations.js'; +import * as NotificationsMonitor from './notificationsMonitor.js'; +import * as Theming from './theming.js'; +import * as Utils from './utils.js'; +import * as WindowPreview from './windowPreview.js'; + +export { + AppIconIndicators, + AppIcons, + AppSpread, + DockDash, + DBusMenuUtils, + DesktopIconsIntegration, + Docking, + Extension, + FileManager1API, + Intellihide, + LauncherAPI, + Locations, + NotificationsMonitor, + Theming, + Utils, + WindowPreview +}; diff --git a/intellihide.js b/intellihide.js index f41318e56..63beade05 100644 --- a/intellihide.js +++ b/intellihide.js @@ -1,18 +1,17 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -const { +import { GLib, Meta, - Shell, -} = imports.gi; + Shell +} from './dependencies/gi.js'; -const { signals: Signals } = imports; +import { + Docking, + Utils +} from './imports.js'; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { - docking: Docking, - utils: Utils, -} = Me.imports; +const {signals: Signals} = imports; // A good compromise between reactivity and efficiency; to be tuned. const INTELLIHIDE_CHECK_INTERVAL = 100; @@ -52,7 +51,7 @@ const ignoreApps = ['com.rastersoft.ding', 'com.desktop.ding']; * Intallihide object: emit 'status-changed' signal when the overlap of windows * with the provided targetBoxClutter.ActorBox changes; */ -var Intellihide = class DashToDockIntellihide { +export class Intellihide { constructor(monitorIndex) { // Load settings this._monitorIndex = monitorIndex; @@ -291,7 +290,7 @@ var Intellihide = class DashToDockIntellihide { case IntellihideMode.ALWAYS_ON_TOP: // Always on top, except for fullscreen windows if (this._focusApp) { - const { focusWindow } = global.display; + const {focusWindow} = global.display; if (!focusWindow?.fullscreen) return false; } @@ -325,7 +324,7 @@ var Intellihide = class DashToDockIntellihide { const wtype = metaWindow.get_window_type(); for (let i = 0; i < handledWindowTypes.length; i++) { - var hwtype = handledWindowTypes[i]; + const hwtype = handledWindowTypes[i]; if (hwtype === wtype) return true; else if (hwtype > wtype) @@ -333,6 +332,6 @@ var Intellihide = class DashToDockIntellihide { } return false; } -}; +} Signals.addSignalMethods(Intellihide.prototype); diff --git a/launcherAPI.js b/launcherAPI.js index ad24cf7f3..cf08c38a3 100644 --- a/launcherAPI.js +++ b/launcherAPI.js @@ -1,15 +1,11 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported LauncherEntryRemoteModel */ +import {Gio} from './dependencies/gi.js'; +import {DBusMenuUtils} from './imports.js'; -const { Gio } = imports.gi; +const DBusMenu = await DBusMenuUtils.haveDBusMenu(); -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { dbusmenuUtils: DbusmenuUtils } = Me.imports; - -const Dbusmenu = DbusmenuUtils.haveDBusMenu(); - -var LauncherEntryRemoteModel = class DashToDockLauncherEntryRemoteModel { +export class LauncherEntryRemoteModel { constructor() { this._entrySourceStacks = new Map(); this._remoteMaps = new Map(); @@ -119,7 +115,7 @@ var LauncherEntryRemoteModel = class DashToDockLauncherEntryRemoteModel { remoteMap.set(appId, remote = Object.assign({}, launcherEntryDefaults)); for (const name in properties) { - if (name === 'quicklist' && Dbusmenu) { + if (name === 'quicklist' && DBusMenu) { const quicklistPath = properties[name].unpack(); if (quicklistPath && (!remote._quicklistMenuClient || @@ -132,7 +128,7 @@ var LauncherEntryRemoteModel = class DashToDockLauncherEntryRemoteModel { // This property should not be enumerable Object.defineProperty(remote, '_quicklistMenuClient', { writable: true, - value: menuClient = new Dbusmenu.Client({ + value: menuClient = new DBusMenu.Client({ dbus_name: senderName, dbus_object: quicklistPath, }), @@ -148,7 +144,7 @@ var LauncherEntryRemoteModel = class DashToDockLauncherEntryRemoteModel { } } }; - menuClient.connect(Dbusmenu.CLIENT_SIGNAL_ROOT_CHANGED, handler); + menuClient.connect(DBusMenu.CLIENT_SIGNAL_ROOT_CHANGED, handler); } } else { remote[name] = properties[name].unpack(); @@ -158,7 +154,7 @@ var LauncherEntryRemoteModel = class DashToDockLauncherEntryRemoteModel { const sourceStack = this._lookupStackById(appId); sourceStack.target._emitChangedEvents(sourceStack.update(remote)); } -}; +} const launcherEntryDefaults = Object.freeze({ count: 0, @@ -182,7 +178,7 @@ const LauncherEntry = class DashToDockLauncherEntry { callback(this, this); const id = this._nextId++; - const handler = { id, callback }; + const handler = {id, callback}; eventNames.forEach(name => { let handlerList = this._handlers.get(name); if (!handlerList) diff --git a/lint/eslintrc-gjs.yml b/lint/eslintrc-gjs.yml index 466b7e200..9dfc3bcf0 100644 --- a/lint/eslintrc-gjs.yml +++ b/lint/eslintrc-gjs.yml @@ -2,8 +2,7 @@ # SPDX-License-Identifier: MIT OR LGPL-2.0-or-later # SPDX-FileCopyrightText: 2018 Claudio André env: - es6: true - es2020: true + es2021: true extends: 'eslint:recommended' rules: array-bracket-newline: @@ -73,7 +72,10 @@ rules: linebreak-style: - error - unix - lines-between-class-members: error + lines-between-class-members: + - error + - always + - exceptAfterSingleLine: true max-nested-callbacks: error max-statements-per-line: error new-parens: error @@ -112,12 +114,6 @@ rules: no-restricted-globals: [error, window] no-restricted-properties: - error - - object: imports - property: format - message: Use template strings - - object: pkg - property: initFormat - message: Use template strings - object: Lang property: copyProperties message: Use Object.assign() @@ -176,6 +172,7 @@ rules: object-curly-newline: - error - consistent: true + multiline: true object-curly-spacing: error object-shorthand: error operator-assignment: error @@ -240,5 +237,12 @@ globals: print: readonly printerr: readonly window: readonly + TextEncoder: readonly + TextDecoder: readonly + console: readonly + setTimeout: readonly + setInterval: readonly + clearTimeout: readonly + clearInterval: readonly parserOptions: - ecmaVersion: 2020 + ecmaVersion: 2022 diff --git a/lint/eslintrc-shell.yml b/lint/eslintrc-shell.yml index bb0636f02..0ba645218 100644 --- a/lint/eslintrc-shell.yml +++ b/lint/eslintrc-shell.yml @@ -4,20 +4,23 @@ rules: - properties: never allow: [^vfunc_, ^on_] consistent-return: error + eqeqeq: + - error + - smart key-spacing: - error - mode: minimum beforeColon: false afterColon: true - object-curly-spacing: - - error - - always prefer-arrow-callback: error overrides: - - files: js/** + - files: + - js/** + - tests/shell/** excludedFiles: - js/portalHelper/* + - js/extensions/* globals: global: readonly _: readonly diff --git a/locations.js b/locations.js index 3e5ecc0ed..3a4e752b5 100644 --- a/locations.js +++ b/locations.js @@ -1,30 +1,27 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported LocationAppInfo, Trash, wrapFileManagerApp, - unWrapFileManagerApp, getStartingApps */ - -const { +import { Gio, GLib, GObject, Shell, - St, -} = imports.gi; + St +} from './dependencies/gi.js'; + +import {ShellMountOperation} from './dependencies/shell/ui.js'; -const { shellMountOperation: ShellMountOperation } = imports.ui; -const { signals: Signals } = imports; +import { + Docking, + Utils +} from './imports.js'; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { - docking: Docking, - utils: Utils, -} = Me.imports; +import {Extension} from './dependencies/shell/extensions/extension.js'; // Use __ () and N__() for the extension gettext domain, and reuse // the shell domain with the default _() and N_() -const Gettext = imports.gettext.domain('dashtodock'); -const __ = Gettext.gettext; -const N__ = e => e; +const {gettext: __} = Extension; + +const {signals: Signals} = imports; const FALLBACK_REMOVABLE_MEDIA_ICON = 'drive-removable-media'; const FALLBACK_TRASH_ICON = 'user-trash'; @@ -78,7 +75,7 @@ function makeNautilusFileOperationsProxy() { timestamp: global.get_current_time(), windowPosition: 'center', }; - const { parentHandle, timestamp, windowPosition } = { + const {parentHandle, timestamp, windowPosition} = { ...defaultParams, ...params, }; @@ -93,7 +90,7 @@ function makeNautilusFileOperationsProxy() { return proxy; } -var LocationAppInfo = GObject.registerClass({ +export const LocationAppInfo = GObject.registerClass({ Implements: [Gio.AppInfo], Properties: { 'location': GObject.ParamSpec.object( @@ -252,7 +249,7 @@ var LocationAppInfo = GObject.registerClass({ } async _queryLocationIcons(params) { - const icons = { standard: null, custom: null }; + const icons = {standard: null, custom: null}; if (!this.location) return icons; @@ -301,14 +298,14 @@ var LocationAppInfo = GObject.registerClass({ return icons; } - async _updateLocationIcon(params = { standard: true, custom: true }) { + async _updateLocationIcon(params = {standard: true, custom: true}) { const cancellable = new Utils.CancellableChild(this.cancellable); try { this._updateIconCancellable?.cancel(); this._updateIconCancellable = cancellable; - const icons = await this._queryLocationIcons({ cancellable, ...params }); + const icons = await this._queryLocationIcons({cancellable, ...params}); const icon = icons.custom ?? icons.standard; if (icon && !icon.equal(this.icon)) @@ -350,9 +347,11 @@ var LocationAppInfo = GObject.registerClass({ } _getHandlerAppFromWorker(cancellable) { - const locationsWorker = GLib.build_filenamev([Me.path, - 'locationsWorker.js']); - const locationsWorkerArgs = [LocationAppInfo.GJS_BINARY_PATH, + const locationsWorker = GLib.build_filenamev([ + Docking.DockManager.extension.path, + 'locationsWorker.js', + ]); + const locationsWorkerArgs = [LocationAppInfo.GJS_BINARY_PATH, '-m', locationsWorker, 'handler', this.location.get_uri(), '--timeout', `${LAUNCH_HANDLER_MAX_WAIT}`]; const subProcess = Gio.Subprocess.new(locationsWorkerArgs, @@ -504,7 +503,7 @@ class MountableVolumeAppInfo extends LocationAppInfo { list_actions() { const actions = []; - const { mount } = this; + const {mount} = this; if (mount) { if (this.mount.can_unmount()) @@ -554,7 +553,7 @@ class MountableVolumeAppInfo extends LocationAppInfo { this.location = this.mount?.get_default_location() ?? this.volume.get_activation_root(); - this._updateLocationIcon({ custom: true }); + this._updateLocationIcon({custom: true}); } _monitorChanges() { @@ -805,7 +804,7 @@ class TrashAppInfo extends LocationAppInfo { const nautilus = makeNautilusFileOperationsProxy(); const askConfirmation = true; nautilus.EmptyTrashRemote(askConfirmation, - nautilus.platformData({ timestamp }), (_p, error) => { + nautilus.platformData({timestamp}), (_p, error) => { if (error) logError(error, 'Empty trash failed'); }, this.cancellable); @@ -839,7 +838,7 @@ function wrapWindowsBackedApp(shellApp) { set: v => (this[p] = v), configurable: true, enumerable: !!o.enumerable, - }, o.readOnly ? { set: undefined } : {})); + }, o.readOnly ? {set: undefined} : {})); if (o.value) this[p] = o.value; this.proxyProperties.push(publicProp); @@ -860,9 +859,9 @@ function wrapWindowsBackedApp(shellApp) { windows: {}, state: {}, startingWorkspace: {}, - isFocused: { public: true }, - signalConnections: { readOnly: true }, - sources: { readOnly: true }, + isFocused: {public: true}, + signalConnections: {readOnly: true}, + sources: {readOnly: true}, checkFocused: {}, setDtdData: {}, }); @@ -871,9 +870,9 @@ function wrapWindowsBackedApp(shellApp) { for (const [name, value] of Object.entries(data)) { if (params.readOnly && name in this._dtdData) throw new Error('Property %s is already defined'.format(name)); - const defaultParams = { public: true, readOnly: true }; + const defaultParams = {public: true, readOnly: true}; this._dtdData.addProxyProperties(this, { - [name]: { ...defaultParams, ...params, value }, + [name]: {...defaultParams, ...params, value}, }); } }; @@ -882,10 +881,10 @@ function wrapWindowsBackedApp(shellApp) { const p = (...args) => shellApp._dtdData.propertyInjections.add(shellApp, ...args); // mi is Method injector, pi is Property injector - shellApp._setDtdData({ mi: m, pi: p }, { public: false }); + shellApp._setDtdData({mi: m, pi: p}, {public: false}); m('get_state', () => shellApp._state ?? shellApp._getStateByWindows()); - p('state', { get: () => shellApp.get_state() }); + p('state', {get: () => shellApp.get_state()}); m('get_windows', () => shellApp._windows); m('get_n_windows', () => shellApp._windows.length); @@ -926,7 +925,7 @@ function wrapWindowsBackedApp(shellApp) { _setWindows(windows) { const oldState = this.state; const oldWindows = this._windows.slice(); - const result = { windowsChanged: false, stateChanged: false }; + const result = {windowsChanged: false, stateChanged: false}; this._state = undefined; if (windows.length !== oldWindows.length || @@ -944,7 +943,7 @@ function wrapWindowsBackedApp(shellApp) { return result; }, - }, { readOnly: false }); + }, {readOnly: false}); shellApp._sources.add(GLib.idle_add(GLib.DEFAULT_PRIORITY, () => { shellApp._updateWindows(); @@ -969,6 +968,7 @@ function wrapWindowsBackedApp(shellApp) { // Re-implements shell_app_activate_window for generic activation and alt-tab support m('activate_window', function (_om, window, timestamp) { + /* eslint-disable no-invalid-this */ if (!window) [window] = this.get_windows(); else if (!this._windows.includes(window)) @@ -984,10 +984,12 @@ function wrapWindowsBackedApp(shellApp) { workspace.activate_with_focus(window, timestamp); else window.activate(timestamp); + /* eslint-enable no-invalid-this */ }); // Re-implements shell_app_activate_full for generic activation and dash support m('activate_full', function (_om, workspace, timestamp) { + /* eslint-disable no-invalid-this */ if (!timestamp) timestamp = global.get_current_time(); @@ -1008,20 +1010,23 @@ function wrapWindowsBackedApp(shellApp) { this.activate_window(null, timestamp); break; } + /* eslint-enable no-invalid-this */ }); m('activate', () => shellApp.activate_full(-1, 0)); m('compare', (_om, other) => Utils.shellAppCompare(shellApp, other)); - const { destroy: defaultDestroy } = shellApp; + const {destroy: defaultDestroy} = shellApp; shellApp.destroy = function () { + /* eslint-disable no-invalid-this */ this._dtdData.proxyProperties.forEach(prop => delete this[prop]); this._dtdData.destroy(); this._dtdData = undefined; this.appInfo.destroy?.(); this.destroy = defaultDestroy; defaultDestroy?.call(this); + /* eslint-enable no-invalid-this */ }; return shellApp; @@ -1036,7 +1041,7 @@ function makeLocationApp(params) { if (!(params?.appInfo instanceof LocationAppInfo)) throw new TypeError('Invalid location'); - const { fallbackIconName } = params; + const {fallbackIconName} = params; delete params.fallbackIconName; const shellApp = new Shell.App(params); @@ -1045,7 +1050,7 @@ function makeLocationApp(params) { shellApp._setDtdData({ location: () => shellApp.appInfo.location, isTrash: shellApp.appInfo instanceof TrashAppInfo, - }, { getter: true, enumerable: true }); + }, {getter: true, enumerable: true}); shellApp._mi('toString', defaultToString => '[LocationApp "%s" - %s]'.format(shellApp.get_id(), @@ -1092,6 +1097,7 @@ function makeLocationApp(params) { }); shellApp._mi('open_new_window', function (_om, workspace) { + /* eslint-disable no-invalid-this */ const context = global.create_app_launch_context(0, workspace); if (!this.get_n_windows()) { this.appInfo.launch([], context); @@ -1103,26 +1109,31 @@ function makeLocationApp(params) { ? Gio.AppInfoCreateFlags.SUPPORTS_STARTUP_NOTIFICATION : Gio.AppInfoCreateFlags.NONE).launch_uris( [this.appInfo.location.get_uri()], context); + /* eslint-enable no-invalid-this */ }); if (shellApp.appInfo instanceof MountableVolumeAppInfo) { shellApp._mi('get_busy', function (parentGetBusy) { + /* eslint-disable no-invalid-this */ if (this.appInfo.busy) return true; return parentGetBusy.call(this); + /* eslint-enable no-invalid-this */ }); - shellApp._pi('busy', { get: () => shellApp.get_busy() }); + shellApp._pi('busy', {get: () => shellApp.get_busy()}); shellApp._signalConnections.add(shellApp.appInfo, 'notify::busy', _ => shellApp.notify('busy')); } shellApp._mi('get_windows', function () { + /* eslint-disable no-invalid-this */ if (this._needsResort) this._sortWindows(); return this._windows; + /* eslint-enable no-invalid-this */ }); - const { fm1Client } = Docking.DockManager.getDefault(); + const {fm1Client} = Docking.DockManager.getDefault(); shellApp._setDtdData({ _needsResort: true, @@ -1139,7 +1150,7 @@ function makeLocationApp(params) { _updateWindows() { const windows = fm1Client.getWindows(this.location?.get_uri()).sort( Utils.shellWindowsCompare); - const { windowsChanged } = this._setWindows(windows); + const {windowsChanged} = this._setWindows(windows); if (!windowsChanged) return; @@ -1152,7 +1163,7 @@ function makeLocationApp(params) { this._windowsOrderChanged(); })); }, - }, { readOnly: false }); + }, {readOnly: false}); shellApp._signalConnections.add(fm1Client, 'windows-changed', () => shellApp._updateWindows()); @@ -1174,7 +1185,7 @@ function getFileManagerApp() { /** * */ -function wrapFileManagerApp() { +export function wrapFileManagerApp() { const fileManagerApp = getFileManagerApp(); if (!fileManagerApp) return null; @@ -1185,7 +1196,7 @@ function wrapFileManagerApp() { const originalGetWindows = fileManagerApp.get_windows; wrapWindowsBackedApp(fileManagerApp); - const { removables, trash } = Docking.DockManager.getDefault(); + const {removables, trash} = Docking.DockManager.getDefault(); fileManagerApp._signalConnections.addWithLabel(Labels.WINDOWS_CHANGED, fileManagerApp, 'windows-changed', () => { fileManagerApp.stop_emission_by_name('windows-changed'); @@ -1237,7 +1248,7 @@ function wrapFileManagerApp() { /** * */ -function unWrapFileManagerApp() { +export function unWrapFileManagerApp() { const fileManagerApp = getFileManagerApp(); if (!fileManagerApp || !fileManagerApp._dtdData) return; @@ -1249,7 +1260,7 @@ function unWrapFileManagerApp() { * This class maintains a Shell.App representing the Trash and keeps it * up-to-date as the trash fills and is emptied over time. */ -var Trash = class DashToDockTrash { +export class Trash { destroy() { this._trashApp?.destroy(); } @@ -1268,14 +1279,14 @@ var Trash = class DashToDockTrash { this._ensureApp(); return this._trashApp; } -}; +} /** * This class maintains Shell.App representations for removable devices * plugged into the system, and keeps the list of Apps up-to-date as * devices come and go and are mounted and unmounted. */ -var Removables = class DashToDockRemovables { +export class Removables { static initVolumePromises(object) { // TODO: This can be simplified using actual interface type when we // can depend on gjs 1.72 @@ -1391,7 +1402,7 @@ var Removables = class DashToDockRemovables { } _onVolumeRemoved(volume) { - const volumeIndex = this._volumeApps.findIndex(({ appInfo }) => + const volumeIndex = this._volumeApps.findIndex(({appInfo}) => appInfo.volume === volume); if (volumeIndex !== -1) { const [volumeApp] = this._volumeApps.splice(volumeIndex, 1); @@ -1406,7 +1417,7 @@ var Removables = class DashToDockRemovables { if (!Docking.DockManager.settings.showMountsOnlyMounted) return; - if (!this._volumeApps.find(({ appInfo }) => appInfo.mount === mount)) { + if (!this._volumeApps.find(({appInfo}) => appInfo.mount === mount)) { // In some Gio.Mount implementations the volume may be set after // mount is emitted, so we could just ignore it as we'll get it // later via volume-added @@ -1419,7 +1430,7 @@ var Removables = class DashToDockRemovables { getApps() { return this._volumeApps; } -}; +} Signals.addSignalMethods(Removables.prototype); /** @@ -1441,13 +1452,13 @@ function getApps() { /** * */ -function getRunningApps() { +export function getRunningApps() { return getApps().filter(a => a.state === Shell.AppState.RUNNING); } /** * */ -function getStartingApps() { +export function getStartingApps() { return getApps().filter(a => a.state === Shell.AppState.STARTING); } diff --git a/locationsWorker.js b/locationsWorker.js index e7180b3c5..efb9587e4 100644 --- a/locationsWorker.js +++ b/locationsWorker.js @@ -1,9 +1,7 @@ #!/usr/bin/env gjs -const { GLib, Gio } = imports.gi; - -const currentPath = GLib.path_get_dirname(new Error().fileName); -imports.searchPath.unshift(currentPath); +import GLib from 'gi://GLib'; +import Gio from 'gi://Gio'; const GJS_SUPPORTS_FILE_IFACE_PROMISES = imports.system.version >= 17101; diff --git a/metadata.json b/metadata.json index b24c11ac3..9d23d9560 100644 --- a/metadata.json +++ b/metadata.json @@ -1,10 +1,6 @@ { "shell-version": [ - "40", - "41", - "42", - "43", - "44" + "45" ], "uuid": "dash-to-dock@micxgx.gmail.com", "name": "Dash to Dock", diff --git a/notificationsMonitor.js b/notificationsMonitor.js index cfbe2a769..7059916b5 100644 --- a/notificationsMonitor.js +++ b/notificationsMonitor.js @@ -1,29 +1,20 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported NotificationsMonitor */ +import {Gio} from './dependencies/gi.js'; +import {Main} from './dependencies/shell/ui.js'; -const { signals: Signals } = imports; +import { + Docking, + Utils +} from './imports.js'; -const { - Gio, -} = imports.gi; +const {signals: Signals} = imports; -const { - main: Main, -} = imports.ui; - -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); - -const { - docking: Docking, - utils: Utils, -} = Me.imports; const Labels = Object.freeze({ SOURCES: Symbol('sources'), NOTIFICATIONS: Symbol('notifications'), }); -var NotificationsMonitor = class NotificationsManagerImpl { +export class NotificationsMonitor { constructor() { this._settings = new Gio.Settings({ schema_id: 'org.gnome.desktop.notifications', @@ -124,6 +115,6 @@ var NotificationsMonitor = class NotificationsManagerImpl { this.emit('changed'); } -}; +} Signals.addSignalMethods(NotificationsMonitor.prototype); diff --git a/prefs.js b/prefs.js index c7d8ee0bb..e3ca598aa 100644 --- a/prefs.js +++ b/prefs.js @@ -1,41 +1,23 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported init, buildPrefsWidget */ +import GLib from 'gi://GLib'; +import GObject from 'gi://GObject'; +import Gdk from 'gi://Gdk?version=4.0'; +import Gio from 'gi://Gio'; +import Gtk from 'gi://Gtk?version=4.0'; -imports.gi.versions.Gtk = '4.0'; -imports.gi.versions.Gdk = '4.0'; +import { + ExtensionPreferences, -const { Gio } = imports.gi; -const { GLib } = imports.gi; -const { GObject } = imports.gi; -const { Gtk } = imports.gi; -const { Gdk } = imports.gi; -const Signals = imports.signals; - -// Use __ () and N__() for the extension gettext domain, and reuse -// the shell domain with the default _() and N_() -const Gettext = imports.gettext.domain('dashtodock'); -const __ = Gettext.gettext; -const N__ = e => e; - -try { - // eslint-disable-next-line no-unused-expressions - imports.misc.extensionUtils; -} catch (e) { - const resource = Gio.Resource.load( - `${GLib.getenv('JHBUILD_PREFIX') || '/usr' - }/share/gnome-shell/org.gnome.Extensions.src.gresource`); - resource._register(); - imports.searchPath.push('resource:///org/gnome/Extensions/js'); -} + // Use __ () and N__() for the extension gettext domain, and reuse + // the shell domain with the default _() and N_() + gettext as __ +} from 'resource:///org/gnome/Shell/Extensions/js/extensions/prefs.js'; -const Config = imports.misc.config; -const ExtensionUtils = imports.misc.extensionUtils; -const Me = ExtensionUtils.getCurrentExtension(); +const Signals = imports.signals; const SCALE_UPDATE_TIMEOUT = 500; const DEFAULT_ICONS_SIZES = [128, 96, 64, 48, 32, 24, 16]; -const [SHELL_VERSION] = Config?.PACKAGE_VERSION?.split('.') ?? [undefined]; const TransparencyMode = Object.freeze({ DEFAULT: 0, @@ -149,9 +131,9 @@ class MonitorsConfig { // for monitors, it can be removed when we don't care about breaking // old user configurations or external apps configuring this extension // such as ubuntu's gnome-control-center. - const { index: primaryMonitorIndex } = this._primaryMonitor; + const {index: primaryMonitorIndex} = this._primaryMonitor; for (const monitor of this._monitors) { - let { index } = monitor; + let {index} = monitor; // The The dock uses the Gdk index for monitors, where the primary monitor // always has index 0, so let's follow what dash-to-dock does in docking.js // (as part of _createDocks), but using inverted math @@ -189,40 +171,25 @@ function setShortcut(settings) { } } -var Settings = GObject.registerClass({ +const DockSettings = GObject.registerClass({ Implements: [Gtk.BuilderScope], }, class DashToDockSettings extends GObject.Object { - _init() { + _init(extensionPreferences) { super._init(); - if (Me) - this._settings = ExtensionUtils.getSettings('org.gnome.shell.extensions.dash-to-dock'); - else - this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.extensions.dash-to-dock' }); - - this._appSwitcherSettings = new Gio.Settings({ schema_id: 'org.gnome.shell.app-switcher' }); + this._extensionPreferences = extensionPreferences; + this._settings = extensionPreferences.getSettings( + 'org.gnome.shell.extensions.dash-to-dock'); + this._appSwitcherSettings = new Gio.Settings({schema_id: 'org.gnome.shell.app-switcher'}); this._rtl = Gtk.Widget.get_default_direction() === Gtk.TextDirection.RTL; this._builder = new Gtk.Builder(); this._builder.set_scope(this); - if (Me) { - this._builder.set_translation_domain(Me.metadata['gettext-domain']); - this._builder.add_from_file(`${Me.path}/Settings.ui`); - } else { - this._builder.add_from_file('./Settings.ui'); - } + this._builder.set_translation_domain( + extensionPreferences.metadata['gettext-domain']); + this._builder.add_from_file(`${extensionPreferences.path}/Settings.ui`); - this._notebook = this._builder.get_object('settings_notebook'); - - if (SHELL_VERSION >= 42) { - this.widget = this._notebook; - } else { - this.widget = new Gtk.ScrolledWindow({ - hscrollbar_policy: Gtk.PolicyType.NEVER, - vscrollbar_policy: Gtk.PolicyType.AUTOMATIC, - }); - this.widget.set_child(this._notebook); - } + this.widget = this._builder.get_object('settings_notebook'); // Set a reasonable initial window height this.widget.connect('realize', () => { @@ -236,12 +203,6 @@ var Settings = GObject.registerClass({ this._icon_size_timeout = 0; this._opacity_timeout = 0; - if (SHELL_VERSION < 42) { - // Remove this when we won't support earlier versions - this._builder.get_object('shrink_dash_label1').label = - __('Show favorite applications'); - } - this._monitorsConfig = new MonitorsConfig(); this._bindSettings(); } @@ -1195,38 +1156,15 @@ var Settings = GObject.registerClass({ // About Panel - if (Me) - this._builder.get_object('extension_version').set_label(Me.metadata.version.toString()); - else - this._builder.get_object('extension_version').set_label('Unknown'); + this._builder.get_object('extension_version').set_label( + `${this._extensionPreferences.metadata.version}`); } }); -/** - * - */ -function init() { - ExtensionUtils.initTranslations(); -} - -/** - * - */ -function buildPrefsWidget() { - const settings = new Settings(); - const { widget } = settings; - return widget; -} - -if (!Me) { - GLib.setenv('GSETTINGS_SCHEMA_DIR', './schemas', true); - Gtk.init(); - - const loop = GLib.MainLoop.new(null, false); - const win = new Gtk.Window(); - win.set_child(buildPrefsWidget()); - win.connect('close-request', () => loop.quit()); - win.present(); - - loop.run(); +export default class DockPreferences extends ExtensionPreferences { + getPreferencesWidget() { + const settings = new DockSettings(this); + const {widget} = settings; + return widget; + } } diff --git a/theming.js b/theming.js index 1da233c75..35e0fdc49 100644 --- a/theming.js +++ b/theming.js @@ -1,22 +1,19 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported PositionStyleClass */ - -const { signals: Signals } = imports; - -const { +import { Clutter, Meta, - St, -} = imports.gi; + St +} from './dependencies/gi.js'; + +import {Main} from './dependencies/shell/ui.js'; -const { main: Main } = imports.ui; +import { + Docking, + Utils +} from './imports.js'; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { - docking: Docking, - utils: Utils, -} = Me.imports; +const {signals: Signals} = imports; /* * DEFAULT: transparency given by theme @@ -33,7 +30,7 @@ const Labels = Object.freeze({ TRANSPARENCY: Symbol('transparency'), }); -var PositionStyleClass = Object.freeze([ +export const PositionStyleClass = Object.freeze([ 'top', 'right', 'bottom', @@ -43,7 +40,7 @@ var PositionStyleClass = Object.freeze([ /** * Manage theme customization and custom theme support */ -var ThemeManager = class DashToDockThemeManager { +export class ThemeManager { constructor(dock) { this._signalsHandler = new Utils.GlobalSignalsHandler(this); this._bindSettingsChanges(); @@ -51,8 +48,8 @@ var ThemeManager = class DashToDockThemeManager { this._dash = dock.dash; // initialize colors with generic values - this._customizedBackground = { red: 0, green: 0, blue: 0, alpha: 0 }; - this._customizedBorder = { red: 0, green: 0, blue: 0, alpha: 0 }; + this._customizedBackground = {red: 0, green: 0, blue: 0, alpha: 0}; + this._customizedBorder = {red: 0, green: 0, blue: 0, alpha: 0}; this._transparency = new Transparency(dock); this._signalsHandler.add([ @@ -159,7 +156,7 @@ var ThemeManager = class DashToDockThemeManager { if (!backgroundColor) return; - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; if (settings.customBackgroundColor) { // When applying a custom color, we need to check the alpha value, @@ -168,7 +165,7 @@ var ThemeManager = class DashToDockThemeManager { // the opacity will be set by the opaque/transparent styles anyway. let newAlpha = Math.round(backgroundColor.alpha / 2.55) / 100; - ({ backgroundColor } = settings); + ({backgroundColor} = settings); // backgroundColor is a string like rgb(0,0,0) const [ret, color] = Clutter.Color.from_string(backgroundColor); if (!ret) { @@ -195,7 +192,7 @@ var ThemeManager = class DashToDockThemeManager { } _updateCustomStyleClasses() { - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; if (settings.applyCustomTheme) this._actor.add_style_class_name('dashtodock'); @@ -242,7 +239,7 @@ var ThemeManager = class DashToDockThemeManager { if (!this._dash._background.get_stage()) return; - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; // Remove prior style edits this._dash._background.set_style(null); @@ -313,7 +310,7 @@ var ThemeManager = class DashToDockThemeManager { () => this.updateCustomTheme(), ])); } -}; +} Signals.addSignalMethods(ThemeManager.prototype); /** @@ -321,7 +318,7 @@ Signals.addSignalMethods(ThemeManager.prototype); * https://git.gnome.org/browse/gnome-shell/commit/?id=447bf55e45b00426ed908b1b1035f472c2466956 * Transparency when free-floating */ -var Transparency = class DashToDockTransparency { +class Transparency { constructor(dock) { this._dash = dock.dash; this._actor = this._dash._container; @@ -550,7 +547,7 @@ var Transparency = class DashToDockTransparency { Main.uiGroup.remove_child(dummyObject); - const { settings } = Docking.DockManager; + const {settings} = Docking.DockManager; if (settings.customizeAlphas) { this._opaqueAlpha = settings.maxAlpha; @@ -559,5 +556,5 @@ var Transparency = class DashToDockTransparency { this._transparentAlphaBorder = this._transparentAlpha / 2; } } -}; +} Signals.addSignalMethods(Transparency.prototype); diff --git a/utils.js b/utils.js index 96fb1e705..3305b924e 100644 --- a/utils.js +++ b/utils.js @@ -1,10 +1,4 @@ -/* exported GlobalSignalsHandler, InjectionsHandler, VFuncInjectionsHandler, - PropertyInjectionsHandler, SignalHandlersFlags, IconTheme, - CancellableChild, getPosition, drawRoundedLine, - getWindowsByObjectPath, shellAppCompare, shellWindowsCompare, - splitHandler, getMonitorManager, laterAdd, laterRemove */ - -const { +import { Clutter, GLib, Gio, @@ -12,15 +6,16 @@ const { Gtk, Meta, Shell, - St, -} = imports.gi; + St +} from './dependencies/gi.js'; -const { _gi: Gi } = imports; +import { + Docking +} from './imports.js'; -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { docking: Docking } = Me.imports; +const {_gi: Gi} = imports; -var SignalsHandlerFlags = Object.freeze({ +export const SignalsHandlerFlags = Object.freeze({ NONE: 0, CONNECT_AFTER: 1, }); @@ -160,7 +155,7 @@ const BasicHandler = class DashToDockBasicHandler { /** * Manage global signals */ -var GlobalSignalsHandler = class DashToDockGlobalSignalHandler extends BasicHandler { +export class GlobalSignalsHandler extends BasicHandler { _create(object, event, callback, flags = SignalsHandlerFlags.NONE) { if (!object) throw new Error('Impossible to connect to an invalid object'); @@ -203,12 +198,12 @@ var GlobalSignalsHandler = class DashToDockGlobalSignalHandler extends BasicHand if (object instanceof GObject.Object) GObject.Object.prototype.unblock_signal_handler.call(object, id); } -}; +} /** * Color manipulation utilities */ -var ColorUtils = class DashToDockColorUtils { +export class ColorUtils { // Darken or brigthen color by a fraction dlum // Each rgb value is modified by the same fraction. // Return "#rrggbb" string @@ -237,7 +232,7 @@ var ColorUtils = class DashToDockColorUtils { // Return {r:r, g:g, b:b} object. static HSVtoRGB(h, s, v) { if (arguments.length === 1) - ({ s, v, h } = h); + ({s, v, h} = h); let r, g, b; const c = v * s; @@ -285,7 +280,7 @@ var ColorUtils = class DashToDockColorUtils { // Return {h:h, s:s, v:v} object. static RGBtoHSV(r, g, b) { if (arguments.length === 1) - ({ r, g, b } = r); + ({r, g, b} = r); let h, s; @@ -315,13 +310,13 @@ var ColorUtils = class DashToDockColorUtils { v, }; } -}; +} /** * Manage function injection: both instances and prototype can be overridden * and restored */ -var InjectionsHandler = class DashToDockInjectionsHandler extends BasicHandler { +export class InjectionsHandler extends BasicHandler { _create(object, name, injectedFunction) { const original = object[name]; @@ -338,13 +333,13 @@ var InjectionsHandler = class DashToDockInjectionsHandler extends BasicHandler { const [object, name, original] = item; object[name] = original; } -}; +} /** * Manage vfunction injection: both instances and prototype can be overridden * and restored */ -var VFuncInjectionsHandler = class DashToDockVFuncInjectionsHandler extends BasicHandler { +export class VFuncInjectionsHandler extends BasicHandler { _create(prototype, name, injectedFunction) { const original = prototype[`vfunc_${name}`]; if (!(original instanceof Function)) @@ -379,25 +374,25 @@ var VFuncInjectionsHandler = class DashToDockVFuncInjectionsHandler extends Basi return prototype[Gi.hook_up_vfunc_symbol](name, func); } -}; +} /** * Manage properties injection: both instances and prototype can be overridden * and restored */ -var PropertyInjectionsHandler = class DashToDockPropertyInjectionsHandler extends BasicHandler { +export class PropertyInjectionsHandler extends BasicHandler { _create(instance, name, injectedPropertyDescriptor) { if (!(name in instance)) throw new Error(`Object ${instance} has no '${name}' property`); - const { prototype } = instance.constructor; + const {prototype} = instance.constructor; const originalPropertyDescriptor = Object.getOwnPropertyDescriptor(prototype, name) ?? Object.getOwnPropertyDescriptor(instance, name); Object.defineProperty(instance, name, { ...originalPropertyDescriptor, ...injectedPropertyDescriptor, - ...{ configurable: true }, + ...{configurable: true}, }); return [instance, name, originalPropertyDescriptor]; } @@ -409,12 +404,12 @@ var PropertyInjectionsHandler = class DashToDockPropertyInjectionsHandler extend else delete instance[name]; } -}; +} /** * Return the actual position reverseing left and right in rtl */ -function getPosition() { +export function getPosition() { const position = Docking.DockManager.settings.dockPosition; if (Clutter.get_default_text_direction() === Clutter.TextDirection.RTL) { if (position === St.Side.LEFT) @@ -436,7 +431,7 @@ function getPosition() { * @param stroke * @param fill */ -function drawRoundedLine(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) { +export function drawRoundedLine(cr, x, y, width, height, isRoundLeft, isRoundRight, stroke, fill) { if (height > width) { y += Math.floor((height - width) / 2.0); height = width; @@ -444,8 +439,8 @@ function drawRoundedLine(cr, x, y, width, height, isRoundLeft, isRoundRight, str height = 2.0 * Math.floor(height / 2.0); - var leftRadius = isRoundLeft ? height / 2.0 : 0.0; - var rightRadius = isRoundRight ? height / 2.0 : 0.0; + const leftRadius = isRoundLeft ? height / 2.0 : 0.0; + const rightRadius = isRoundRight ? height / 2.0 : 0.0; cr.moveTo(x + width - rightRadius, y); cr.lineTo(x + leftRadius, y); @@ -477,13 +472,13 @@ function drawRoundedLine(cr, x, y, width, height, isRoundLeft, isRoundRight, str * * @param handler */ -function splitHandler(handler) { +export function splitHandler(handler) { if (handler.length > 30) throw new Error('too many parameters'); const count = handler.length - 1; let missingValueBits = (1 << count) - 1; - const values = Array.from({ length: count }); + const values = Array.from({length: count}); return values.map((_ignored, i) => { const mask = ~(1 << i); return (obj, value) => { @@ -495,7 +490,7 @@ function splitHandler(handler) { }); } -var IconTheme = class DashToDockIconTheme { +export class IconTheme { constructor() { if (St.IconTheme) { this._iconTheme = new St.IconTheme(); @@ -520,14 +515,14 @@ var IconTheme = class DashToDockIconTheme { this._iconTheme = null; } -}; +} /** * Construct a map of gtk application window object paths to MetaWindows. */ -function getWindowsByObjectPath() { +export function getWindowsByObjectPath() { const windowsByObjectPath = new Map(); - const { workspaceManager } = global; + const {workspaceManager} = global; const workspaces = [...new Array(workspaceManager.nWorkspaces)].map( (_c, i) => workspaceManager.get_workspace_by_index(i)); @@ -548,7 +543,7 @@ function getWindowsByObjectPath() { * @param appA * @param appB */ -function shellAppCompare(appA, appB) { +export function shellAppCompare(appA, appB) { if (appA.state !== appB.state) { if (appA.state === Shell.AppState.RUNNING) return -1; @@ -586,7 +581,7 @@ function shellAppCompare(appA, appB) { * @param winA * @param winB */ -function shellWindowsCompare(winA, winB) { +export function shellWindowsCompare(winA, winB) { const activeWorkspace = global.workspaceManager.get_active_workspace(); const wsA = winA.get_workspace() === activeWorkspace; const wsB = winB.get_workspace() === activeWorkspace; @@ -607,7 +602,7 @@ function shellWindowsCompare(winA, winB) { return winB.get_user_time() - winA.get_user_time(); } -var CancellableChild = GObject.registerClass({ +export const CancellableChild = GObject.registerClass({ Properties: { 'parent': GObject.ParamSpec.object( 'parent', 'parent', 'parent', @@ -620,7 +615,7 @@ class CancellableChild extends Gio.Cancellable { if (parent && !(parent instanceof Gio.Cancellable)) throw TypeError('Not a valid cancellable'); - super._init({ parent }); + super._init({parent}); if (parent?.is_cancelled()) { this.cancel(); @@ -665,7 +660,7 @@ class CancellableChild extends Gio.Cancellable { /** * */ -function getMonitorManager() { +export function getMonitorManager() { return global.backend.get_monitor_manager?.() ?? Meta.MonitorManager.get(); } @@ -673,7 +668,7 @@ function getMonitorManager() { * @param laterType * @param callback */ -function laterAdd(laterType, callback) { +export function laterAdd(laterType, callback) { return global.compositor?.get_laters?.().add(laterType, callback) ?? Meta.later_add(laterType, callback); } @@ -681,7 +676,7 @@ function laterAdd(laterType, callback) { /** * @param id */ -function laterRemove(id) { +export function laterRemove(id) { if (global.compositor?.get_laters) global.compositor?.get_laters().remove(id); else diff --git a/windowPreview.js b/windowPreview.js index 14517b539..6ffa0d767 100644 --- a/windowPreview.js +++ b/windowPreview.js @@ -5,29 +5,26 @@ * Some code was also adapted from the upstream Gnome Shell source code. */ -/* exported WindowPreviewMenu */ - -const { +import { Clutter, GLib, GObject, Meta, - St, -} = imports.gi; - -const { - boxpointer: BoxPointer, - main: Main, - popupMenu: PopupMenu, - workspace: Workspace, -} = imports.ui; - -const Me = imports.misc.extensionUtils.getCurrentExtension(); -const { - docking: Docking, - theming: Theming, - utils: Utils, -} = Me.imports; + St +} from './dependencies/gi.js'; + +import { + BoxPointer, + Main, + PopupMenu, + Workspace +} from './dependencies/shell/ui.js'; + +import { + Docking, + Theming, + Utils +} from './imports.js'; const PREVIEW_MAX_WIDTH = 250; const PREVIEW_MAX_HEIGHT = 150; @@ -37,7 +34,7 @@ const MAX_PREVIEW_GENERATION_ATTEMPTS = 15; const MENU_MARGINS = 10; -var WindowPreviewMenu = class DashToDockWindowPreviewMenu extends PopupMenu.PopupMenu { +export class WindowPreviewMenu extends PopupMenu.PopupMenu { constructor(source) { super(source, 0.5, Utils.getPosition()); @@ -48,7 +45,7 @@ var WindowPreviewMenu = class DashToDockWindowPreviewMenu extends PopupMenu.Popu this._app = this._source.app; const workArea = Main.layoutManager.getWorkAreaForMonitor( this._source.monitorIndex); - const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); + const {scaleFactor} = St.ThemeContext.get_for_stage(global.stage); this.actor.add_style_class_name('app-menu'); this.actor.set_style( @@ -93,9 +90,9 @@ var WindowPreviewMenu = class DashToDockWindowPreviewMenu extends PopupMenu.Popu if (this._destroyId) this._source.disconnect(this._destroyId); } -}; +} -var WindowPreviewList = class DashToDockWindowPreviewList extends PopupMenu.PopupMenuSection { +class WindowPreviewList extends PopupMenu.PopupMenuSection { constructor(source) { super(); this.actor = new St.ScrollView({ @@ -323,9 +320,9 @@ var WindowPreviewList = class DashToDockWindowPreviewList extends PopupMenu.Popu return result || actor.animatingOut; }, false); } -}; +} -var WindowPreviewMenuItem = GObject.registerClass( +export const WindowPreviewMenuItem = GObject.registerClass( class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { _init(window, position, params) { super._init(params); @@ -335,7 +332,7 @@ class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { this._windowAddedId = 0; // We don't want this: it adds spacing on the left of the item. - this.remove_child(this._ornamentLabel); + this.remove_child(this._ornamentIcon); this.add_style_class_name('dashtodock-app-well-preview-menu-item'); this.add_style_class_name(Theming.PositionStyleClass[position]); if (Docking.DockManager.settings.customThemeShrink) @@ -362,7 +359,7 @@ class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { ? Clutter.ActorAlign.START : Clutter.ActorAlign.END, y_align: Clutter.ActorAlign.START, }); - this.closeButton.add_actor(new St.Icon({ icon_name: 'window-close-symbolic' })); + this.closeButton.add_actor(new St.Icon({icon_name: 'window-close-symbolic'})); this.closeButton.connect('clicked', () => this._closeWindow()); const overlayGroup = new Clutter.Actor({ @@ -373,18 +370,22 @@ class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { overlayGroup.add_actor(this._cloneBin); overlayGroup.add_actor(this.closeButton); - const label = new St.Label({ text: window.get_title() }); + const label = new St.Label({text: window.get_title()}); label.set_style(`max-width: ${PREVIEW_MAX_WIDTH}px`); - const labelBin = new St.Bin({ child: label, - x_align: Clutter.ActorAlign.CENTER }); + const labelBin = new St.Bin({ + child: label, + x_align: Clutter.ActorAlign.CENTER, + }); this._windowTitleId = this._window.connect('notify::title', () => { label.set_text(this._window.get_title()); }); - const box = new St.BoxLayout({ vertical: true, + const box = new St.BoxLayout({ + vertical: true, reactive: true, - x_expand: true }); + x_expand: true, + }); box.add(overlayGroup); box.add(labelBin); this._box = box; @@ -406,7 +407,7 @@ class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { let [minHeight, naturalHeight] = this._box.get_preferred_height(naturalWidth); [minWidth, naturalWidth] = themeNode.adjust_preferred_width(minWidth, naturalWidth); [minHeight, naturalHeight] = themeNode.adjust_preferred_height(minHeight, naturalHeight); - this.set({ minWidth, naturalWidth, minHeight, naturalHeight }); + this.set({minWidth, naturalWidth, minHeight, naturalHeight}); } _getWindowPreviewSize() { @@ -420,7 +421,7 @@ class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { if (!width || !height) return emptySize; - let { previewSizeScale: scale } = Docking.DockManager.settings; + let {previewSizeScale: scale} = Docking.DockManager.settings; if (!scale) { // a simple example with 1680x1050: // * 250/1680 = 0,1488 @@ -464,10 +465,12 @@ class WindowPreviewMenuItem extends PopupMenu.PopupBaseMenuItem { } const mutterWindow = metaWin.get_compositor_private(); - const clone = new Clutter.Clone({ source: mutterWindow, + const clone = new Clutter.Clone({ + source: mutterWindow, reactive: true, width: this._width * this._scale, - height: this._height * this._scale }); + height: this._height * this._scale, + }); // when the source actor is destroyed, i.e. the window closed, first destroy the clone // and then destroy the menu item (do this animating out)