diff --git a/SOURCES/0001-dash-to-panel-Stop-messing-with-overview-allocation.patch b/SOURCES/0001-dash-to-panel-Stop-messing-with-overview-allocation.patch new file mode 100644 index 0000000..42859ca --- /dev/null +++ b/SOURCES/0001-dash-to-panel-Stop-messing-with-overview-allocation.patch @@ -0,0 +1,261 @@ +From 21c6b13e951e342e4f1e1178afa28f1303b19f2a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Mon, 5 May 2025 15:31:12 +0200 +Subject: [PATCH] dash-to-panel: Stop messing with overview allocation + +See upstream commits facbdbd437a and e544d2c7a. +--- + extensions/dash-to-panel/overview.js | 225 --------------------------- + 1 file changed, 225 deletions(-) + +diff --git a/extensions/dash-to-panel/overview.js b/extensions/dash-to-panel/overview.js +index 38f04c75..9b0a8e71 100644 +--- a/extensions/dash-to-panel/overview.js ++++ b/extensions/dash-to-panel/overview.js +@@ -70,7 +70,6 @@ var dtpOverview = Utils.defineClass({ + this._optionalNumberOverlay(); + this._optionalClickToExit(); + this._toggleDash(); +- this._hookupAllocation(); + + this._signalsHandler.add([ + Me.settings, +@@ -81,10 +80,6 @@ var dtpOverview = Utils.defineClass({ + }, + + disable: function () { +- Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', Workspace.WorkspaceBackground.prototype.vfunc_allocate); +- Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', OverviewControls.ControlsManagerLayout.prototype.vfunc_allocate); +- OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = this._oldComputeWorkspacesBoxForState; +- + this._signalsHandler.destroy(); + this._injectionsHandler.destroy(); + +@@ -481,224 +476,4 @@ var dtpOverview = Utils.defineClass({ + ]); + return true; + }, +- +- _hookupAllocation: function() { +- Utils.hookVfunc(OverviewControls.ControlsManagerLayout.prototype, 'allocate', function vfunc_allocate(container, box) { +- const childBox = new Clutter.ActorBox(); +- +- const { spacing } = this; +- +- let startY = 0; +- let startX = 0; +- +- if (Me.settings.get_boolean('stockgs-keep-top-panel') && Main.layoutManager.panelBox.y === Main.layoutManager.primaryMonitor.y) { +- startY = Main.layoutManager.panelBox.height; +- box.y1 += startY; +- } +- +- const panel = global.dashToPanel.panels[0]; +- if(panel) { +- switch (panel.getPosition()) { +- case St.Side.TOP: +- startY = panel.panelBox.height; +- box.y1 += startY; +- break; +- case St.Side.LEFT: +- startX = panel.panelBox.width; +- box.x1 += startX; +- break; +- case St.Side.RIGHT: +- box.x2 -= panel.panelBox.width; +- break; +- +- } +- } +- +- +- const [width, height] = box.get_size(); +- let availableHeight = height; +- +- // Search entry +- let [searchHeight] = this._searchEntry.get_preferred_height(width); +- childBox.set_origin(startX, startY); +- childBox.set_size(width, searchHeight); +- this._searchEntry.allocate(childBox); +- +- availableHeight -= searchHeight + spacing; +- +- // Dash +- const maxDashHeight = Math.round(box.get_height() * DASH_MAX_HEIGHT_RATIO); +- this._dash.setMaxSize(width, maxDashHeight); +- +- let [, dashHeight] = this._dash.get_preferred_height(width); +- if (Me.settings.get_boolean('stockgs-keep-dash')) +- dashHeight = Math.min(dashHeight, maxDashHeight); +- else +- dashHeight = spacing*5; // todo: determine proper spacing for window labels on maximized windows on workspace display +- childBox.set_origin(startX, startY + height - dashHeight); +- childBox.set_size(width, dashHeight); +- this._dash.allocate(childBox); +- +- availableHeight -= dashHeight + spacing; +- +- // Workspace Thumbnails +- let thumbnailsHeight = 0; +- if (this._workspacesThumbnails.visible) { +- const { expandFraction } = this._workspacesThumbnails; +- [thumbnailsHeight] = +- this._workspacesThumbnails.get_preferred_height(width); +- thumbnailsHeight = Math.min( +- thumbnailsHeight * expandFraction, +- height * WorkspaceThumbnail.MAX_THUMBNAIL_SCALE); +- childBox.set_origin(startX, startY + searchHeight + spacing); +- childBox.set_size(width, thumbnailsHeight); +- this._workspacesThumbnails.allocate(childBox); +- } +- +- // Workspaces +- let params = [box, startX, startY, searchHeight, dashHeight, thumbnailsHeight]; +- const transitionParams = this._stateAdjustment.getStateTransitionParams(); +- +- // Update cached boxes +- for (const state of Object.values(OverviewControls.ControlsState)) { +- this._cachedWorkspaceBoxes.set( +- state, this._computeWorkspacesBoxForState(state, ...params)); +- } +- +- let workspacesBox; +- if (!transitionParams.transitioning) { +- workspacesBox = this._cachedWorkspaceBoxes.get(transitionParams.currentState); +- } else { +- const initialBox = this._cachedWorkspaceBoxes.get(transitionParams.initialState); +- const finalBox = this._cachedWorkspaceBoxes.get(transitionParams.finalState); +- workspacesBox = initialBox.interpolate(finalBox, transitionParams.progress); +- } +- +- this._workspacesDisplay.allocate(workspacesBox); +- +- // AppDisplay +- if (this._appDisplay.visible) { +- const workspaceAppGridBox = +- this._cachedWorkspaceBoxes.get(OverviewControls.ControlsState.APP_GRID); +- +- const monitor = Main.layoutManager.findMonitorForActor(this._container); +- const workArea = Main.layoutManager.getWorkAreaForMonitor(monitor.index); +- const workAreaBox = new Clutter.ActorBox(); +- +- workAreaBox.set_origin(startX, startY); +- workAreaBox.set_size(workArea.width, workArea.height); +- +- params = [workAreaBox, searchHeight, dashHeight, workspaceAppGridBox] +- +- let appDisplayBox; +- if (!transitionParams.transitioning) { +- appDisplayBox = +- this._getAppDisplayBoxForState(transitionParams.currentState, ...params); +- } else { +- const initialBox = +- this._getAppDisplayBoxForState(transitionParams.initialState, ...params); +- const finalBox = +- this._getAppDisplayBoxForState(transitionParams.finalState, ...params); +- +- appDisplayBox = initialBox.interpolate(finalBox, transitionParams.progress); +- } +- +- this._appDisplay.allocate(appDisplayBox); +- } +- +- // Search +- childBox.set_origin(0, startY + searchHeight + spacing); +- childBox.set_size(width, availableHeight); +- +- this._searchController.allocate(childBox); +- +- this._runPostAllocation(); +- }); +- +- this._oldComputeWorkspacesBoxForState = OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState; +- OverviewControls.ControlsManagerLayout.prototype._computeWorkspacesBoxForState = function _computeWorkspacesBoxForState(state, box, startX, startY, searchHeight, dashHeight, thumbnailsHeight) { +- const workspaceBox = box.copy(); +- const [width, height] = workspaceBox.get_size(); +- const { spacing } = this; +- const { expandFraction } = this._workspacesThumbnails; +- +- switch (state) { +- case OverviewControls.ControlsState.HIDDEN: +- break; +- case OverviewControls.ControlsState.WINDOW_PICKER: +- workspaceBox.set_origin(startX, +- startY + searchHeight + spacing + +- thumbnailsHeight + spacing * expandFraction); +- workspaceBox.set_size(width, +- height - +- dashHeight - spacing - +- searchHeight - spacing - +- thumbnailsHeight - spacing * expandFraction); +- break; +- case OverviewControls.ControlsState.APP_GRID: +- workspaceBox.set_origin(startX, startY + searchHeight + spacing); +- workspaceBox.set_size( +- width, +- Math.round(height * SMALL_WORKSPACE_RATIO)); +- break; +- } +- +- return workspaceBox; +- } +- +- Utils.hookVfunc(Workspace.WorkspaceBackground.prototype, 'allocate', function vfunc_allocate(box) { +- const [width, height] = box.get_size(); +- const { scaleFactor } = St.ThemeContext.get_for_stage(global.stage); +- const scaledHeight = height - (BACKGROUND_MARGIN * 2 * scaleFactor); +- const scaledWidth = (scaledHeight / height) * width; +- +- const scaledBox = box.copy(); +- scaledBox.set_origin( +- box.x1 + (width - scaledWidth) / 2, +- box.y1 + (height - scaledHeight) / 2); +- scaledBox.set_size(scaledWidth, scaledHeight); +- +- const progress = this._stateAdjustment.value; +- +- if (progress === 1) +- box = scaledBox; +- else if (progress !== 0) +- box = box.interpolate(scaledBox, progress); +- +- this.set_allocation(box); +- +- const themeNode = this.get_theme_node(); +- const contentBox = themeNode.get_content_box(box); +- +- this._bin.allocate(contentBox); +- +- +- const [contentWidth, contentHeight] = contentBox.get_size(); +- const monitor = Main.layoutManager.monitors[this._monitorIndex]; +- let xOff = (contentWidth / this._workarea.width) * +- (this._workarea.x - monitor.x); +- let yOff = (contentHeight / this._workarea.height) * +- (this._workarea.y - monitor.y); +- +- let startX = -xOff; +- let startY = -yOff; +- const panel = Utils.find(global.dashToPanel.panels, p => p.monitor.index == this._monitorIndex); +- switch (panel.getPosition()) { +- case St.Side.TOP: +- yOff += panel.panelBox.height; +- startY -= panel.panelBox.height; +- break; +- case St.Side.BOTTOM: +- yOff += panel.panelBox.height; +- break; +- case St.Side.RIGHT: +- xOff += panel.panelBox.width; +- break; +- } +- contentBox.set_origin(startX, startY); +- contentBox.set_size(xOff + contentWidth, yOff + contentHeight); +- this._backgroundGroup.allocate(contentBox); +- }); +- +- } + }); +-- +2.49.0 + diff --git a/SOURCES/improve-workspace-names.patch b/SOURCES/improve-workspace-names.patch new file mode 100644 index 0000000..4a17fc5 --- /dev/null +++ b/SOURCES/improve-workspace-names.patch @@ -0,0 +1,2389 @@ +From 11442f82272a1fba9ed1ff7088e6e2ae68e01787 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Tue, 17 Jun 2025 22:22:29 +0200 +Subject: [PATCH 01/19] Fix signal leak + +--- + extensions/workspace-indicator/workspaceIndicator.js | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index 14359a0e..f70dcaf7 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -431,6 +431,7 @@ const WorkspacePreviews = GObject.registerClass({ + + _onDestroy() { + global.workspace_manager.disconnect(this._nWorkspacesChanged); ++ global.workspace_manager.disconnect(this._workspaceSwitchedId); + } + }); + +-- +2.50.0 + + +From 874ee94d7ead1c1792ce73c5aea0663223c89228 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 11 Oct 2024 12:10:36 +0200 +Subject: [PATCH 02/19] workspace-indicator: Split out workspaces prefs page + +The window-list extension already uses the extension code for +its embedded workspace indicator, this will allow it to do the +same for the preference page. + +Part-of: +--- + extensions/workspace-indicator/meson.build | 2 +- + extensions/workspace-indicator/prefs.js | 238 +---------------- + .../workspace-indicator/workspacePrefs.js | 245 ++++++++++++++++++ + po/POTFILES.in | 2 +- + 4 files changed, 249 insertions(+), 238 deletions(-) + create mode 100644 extensions/workspace-indicator/workspacePrefs.js + +diff --git a/extensions/workspace-indicator/meson.build b/extensions/workspace-indicator/meson.build +index a88db78a..52ab5334 100644 +--- a/extensions/workspace-indicator/meson.build ++++ b/extensions/workspace-indicator/meson.build +@@ -10,4 +10,4 @@ extension_data += files( + ) + extension_schemas += files('schemas/' + metadata_conf.get('gschemaname') + '.gschema.xml') + +-extension_sources += files('prefs.js', 'workspaceIndicator.js') ++extension_sources += files('prefs.js', 'workspaceIndicator.js', 'workspacePrefs.js') +diff --git a/extensions/workspace-indicator/prefs.js b/extensions/workspace-indicator/prefs.js +index 9809b46a..2d90e198 100644 +--- a/extensions/workspace-indicator/prefs.js ++++ b/extensions/workspace-indicator/prefs.js +@@ -1,249 +1,15 @@ + // -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*- + /* exported init buildPrefsWidget */ + +-const { Gio, GLib, GObject, Gtk, Pango } = imports.gi; +- + const ExtensionUtils = imports.misc.extensionUtils; + const Me = ExtensionUtils.getCurrentExtension(); + +-const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); +-const _ = Gettext.gettext; +-const N_ = e => e; +- +-const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; +-const WORKSPACE_KEY = 'workspace-names'; +- +-const GeneralGroup = GObject.registerClass( +-class GeneralGroup extends Gtk.Box { +- _init() { +- super._init({ +- orientation: Gtk.Orientation.VERTICAL, +- }); +- +- const row = new Gtk.Box(); +- this.append(row); +- +- row.append(new Gtk.Label({ +- label: _('Show Previews In Top Bar'), +- })); +- +- const sw = new Gtk.Switch({ +- hexpand: true, +- halign: Gtk.Align.END, +- }); +- row.append(sw); +- +- const settings = ExtensionUtils.getSettings(); +- +- settings.bind('embed-previews', +- sw, 'active', +- Gio.SettingsBindFlags.DEFAULT); +- } +-}); +- +-const WorkspaceSettingsWidget = GObject.registerClass( +-class WorkspaceSettingsWidget extends Gtk.ScrolledWindow { +- _init() { +- super._init({ +- hscrollbar_policy: Gtk.PolicyType.NEVER, +- }); +- +- const box = new Gtk.Box({ +- orientation: Gtk.Orientation.VERTICAL, +- halign: Gtk.Align.CENTER, +- spacing: 12, +- margin_top: 36, +- margin_bottom: 36, +- margin_start: 36, +- margin_end: 36, +- }); +- this.set_child(box); +- +- box.append(new GeneralGroup()); +- +- box.append(new Gtk.Label({ +- label: '%s'.format(_('Workspace Names')), +- use_markup: true, +- halign: Gtk.Align.START, +- })); +- +- this._list = new Gtk.ListBox({ +- selection_mode: Gtk.SelectionMode.NONE, +- valign: Gtk.Align.START, +- show_separators: true, +- }); +- this._list.connect('row-activated', (l, row) => row.edit()); +- box.append(this._list); +- +- const context = this._list.get_style_context(); +- const cssProvider = new Gtk.CssProvider(); +- cssProvider.load_from_data( +- 'list { min-width: 25em; }', -1); +- +- context.add_provider(cssProvider, +- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); +- context.add_class('frame'); +- +- this._list.append(new NewWorkspaceRow()); +- +- this._actionGroup = new Gio.SimpleActionGroup(); +- this._list.insert_action_group('workspaces', this._actionGroup); +- +- let action; +- action = new Gio.SimpleAction({ name: 'add' }); +- action.connect('activate', () => { +- const names = this._settings.get_strv(WORKSPACE_KEY); +- this._settings.set_strv(WORKSPACE_KEY, [ +- ...names, +- _('Workspace %d').format(names.length + 1), +- ]); +- }); +- this._actionGroup.add_action(action); +- +- action = new Gio.SimpleAction({ +- name: 'remove', +- parameter_type: new GLib.VariantType('s'), +- }); +- action.connect('activate', (a, param) => { +- const removed = param.deepUnpack(); +- this._settings.set_strv(WORKSPACE_KEY, +- this._settings.get_strv(WORKSPACE_KEY) +- .filter(name => name !== removed)); +- }); +- this._actionGroup.add_action(action); +- +- action = new Gio.SimpleAction({ name: 'update' }); +- action.connect('activate', () => { +- const names = this._getWorkspaceRows().map(row => row.name); +- this._settings.set_strv(WORKSPACE_KEY, names); +- }); +- this._actionGroup.add_action(action); +- +- this._settings = new Gio.Settings({ +- schema_id: WORKSPACE_SCHEMA, +- }); +- this._settings.connect(`changed::${WORKSPACE_KEY}`, +- this._sync.bind(this)); +- this._sync(); +- } +- +- _getWorkspaceRows() { +- return [...this._list].filter(row => row.name); +- } +- +- _sync() { +- const rows = this._getWorkspaceRows(); +- +- const oldNames = rows.map(row => row.name); +- const newNames = this._settings.get_strv(WORKSPACE_KEY); +- +- const removed = oldNames.filter(n => !newNames.includes(n)); +- const added = newNames.filter(n => !oldNames.includes(n)); +- +- removed.forEach(n => this._list.remove(rows.find(r => r.name === n))); +- added.forEach(n => { +- this._list.insert(new WorkspaceRow(n), newNames.indexOf(n)); +- }); +- } +-}); +- +-const WorkspaceRow = GObject.registerClass( +-class WorkspaceRow extends Gtk.ListBoxRow { +- _init(name) { +- super._init({ name }); +- +- const controller = new Gtk.ShortcutController(); +- controller.add_shortcut(new Gtk.Shortcut({ +- trigger: Gtk.ShortcutTrigger.parse_string('Escape'), +- action: Gtk.CallbackAction.new(this._stopEdit.bind(this)), +- })); +- this.add_controller(controller); +- +- const box = new Gtk.Box({ +- spacing: 12, +- margin_top: 6, +- margin_bottom: 6, +- margin_start: 6, +- margin_end: 6, +- }); +- +- const label = new Gtk.Label({ +- hexpand: true, +- xalign: 0, +- max_width_chars: 25, +- ellipsize: Pango.EllipsizeMode.END, +- }); +- this.bind_property('name', label, 'label', +- GObject.BindingFlags.SYNC_CREATE); +- box.append(label); +- +- const button = new Gtk.Button({ +- action_name: 'workspaces.remove', +- action_target: new GLib.Variant('s', name), +- icon_name: 'edit-delete-symbolic', +- }); +- box.append(button); +- +- this._entry = new Gtk.Entry({ +- max_width_chars: 25, +- }); +- +- this._stack = new Gtk.Stack(); +- this._stack.add_named(box, 'display'); +- this._stack.add_named(this._entry, 'edit'); +- this.child = this._stack; +- +- this._entry.connect('activate', () => { +- this.name = this._entry.text; +- this._stopEdit(); +- }); +- this._entry.connect('notify::has-focus', () => { +- if (this._entry.has_focus) +- return; +- this._stopEdit(); +- }); +- +- this.connect('notify::name', () => { +- button.action_target = new GLib.Variant('s', this.name); +- this.activate_action('workspaces.update', null); +- }); +- } +- +- edit() { +- this._entry.text = this.name; +- this._entry.grab_focus(); +- this._stack.visible_child_name = 'edit'; +- } +- +- _stopEdit() { +- this.grab_focus(); +- this._stack.visible_child_name = 'display'; +- } +-}); +- +-const NewWorkspaceRow = GObject.registerClass( +-class NewWorkspaceRow extends Gtk.ListBoxRow { +- _init() { +- super._init({ +- action_name: 'workspaces.add', +- child: new Gtk.Image({ +- icon_name: 'list-add-symbolic', +- pixel_size: 16, +- margin_top: 12, +- margin_bottom: 12, +- margin_start: 12, +- margin_end: 12, +- }), +- }); +- this.update_property( +- [Gtk.AccessibleProperty.LABEL], [_('Add Workspace')]); +- } +-}); ++const { WorkspacesPage } = Me.imports.workspacePrefs; + + function init() { + ExtensionUtils.initTranslations(); + } + + function buildPrefsWidget() { +- return new WorkspaceSettingsWidget(); ++ return new WorkspacesPage(); + } +diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js +new file mode 100644 +index 00000000..5691996d +--- /dev/null ++++ b/extensions/workspace-indicator/workspacePrefs.js +@@ -0,0 +1,245 @@ ++// SPDX-FileCopyrightText: 2012 Giovanni Campagna ++// SPDX-FileCopyrightText: 2014 Florian Müllner ++// ++// SPDX-License-Identifier: GPL-2.0-or-later ++ ++/* exported WorkspacesPage */ ++const { Gio, GLib, GObject, Gtk, Pango } = imports.gi; ++ ++const ExtensionUtils = imports.misc.extensionUtils; ++const Me = ExtensionUtils.getCurrentExtension(); ++ ++const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); ++const _ = Gettext.gettext; ++const N_ = e => e; ++ ++const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; ++const WORKSPACE_KEY = 'workspace-names'; ++ ++const GeneralGroup = GObject.registerClass( ++class GeneralGroup extends Gtk.Box { ++ _init() { ++ super._init({ ++ orientation: Gtk.Orientation.VERTICAL, ++ }); ++ ++ const row = new Gtk.Box(); ++ this.append(row); ++ ++ row.append(new Gtk.Label({ ++ label: _('Show Previews In Top Bar'), ++ })); ++ ++ const sw = new Gtk.Switch({ ++ hexpand: true, ++ halign: Gtk.Align.END, ++ }); ++ row.append(sw); ++ ++ const settings = ExtensionUtils.getSettings(); ++ ++ settings.bind('embed-previews', ++ sw, 'active', ++ Gio.SettingsBindFlags.DEFAULT); ++ } ++}); ++ ++var WorkspacesPage = GObject.registerClass( ++class WorkspacesPage extends Gtk.ScrolledWindow { ++ _init() { ++ super._init({ ++ hscrollbar_policy: Gtk.PolicyType.NEVER, ++ vexpand: true, ++ }); ++ ++ const box = new Gtk.Box({ ++ orientation: Gtk.Orientation.VERTICAL, ++ halign: Gtk.Align.CENTER, ++ spacing: 12, ++ margin_top: 36, ++ margin_bottom: 36, ++ margin_start: 36, ++ margin_end: 36, ++ }); ++ this.set_child(box); ++ ++ box.append(new GeneralGroup()); ++ ++ box.append(new Gtk.Label({ ++ label: '%s'.format(_('Workspace Names')), ++ use_markup: true, ++ halign: Gtk.Align.START, ++ })); ++ ++ this._list = new Gtk.ListBox({ ++ selection_mode: Gtk.SelectionMode.NONE, ++ valign: Gtk.Align.START, ++ show_separators: true, ++ }); ++ this._list.connect('row-activated', (l, row) => row.edit()); ++ box.append(this._list); ++ ++ const context = this._list.get_style_context(); ++ const cssProvider = new Gtk.CssProvider(); ++ cssProvider.load_from_data( ++ 'list { min-width: 25em; }', -1); ++ ++ context.add_provider(cssProvider, ++ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); ++ context.add_class('frame'); ++ ++ this._list.append(new NewWorkspaceRow()); ++ ++ this._actionGroup = new Gio.SimpleActionGroup(); ++ this._list.insert_action_group('workspaces', this._actionGroup); ++ ++ let action; ++ action = new Gio.SimpleAction({ name: 'add' }); ++ action.connect('activate', () => { ++ const names = this._settings.get_strv(WORKSPACE_KEY); ++ this._settings.set_strv(WORKSPACE_KEY, [ ++ ...names, ++ _('Workspace %d').format(names.length + 1), ++ ]); ++ }); ++ this._actionGroup.add_action(action); ++ ++ action = new Gio.SimpleAction({ ++ name: 'remove', ++ parameter_type: new GLib.VariantType('s'), ++ }); ++ action.connect('activate', (a, param) => { ++ const removed = param.deepUnpack(); ++ this._settings.set_strv(WORKSPACE_KEY, ++ this._settings.get_strv(WORKSPACE_KEY) ++ .filter(name => name !== removed)); ++ }); ++ this._actionGroup.add_action(action); ++ ++ action = new Gio.SimpleAction({ name: 'update' }); ++ action.connect('activate', () => { ++ const names = this._getWorkspaceRows().map(row => row.name); ++ this._settings.set_strv(WORKSPACE_KEY, names); ++ }); ++ this._actionGroup.add_action(action); ++ ++ this._settings = new Gio.Settings({ ++ schema_id: WORKSPACE_SCHEMA, ++ }); ++ this._settings.connect(`changed::${WORKSPACE_KEY}`, ++ this._sync.bind(this)); ++ this._sync(); ++ } ++ ++ _getWorkspaceRows() { ++ return [...this._list].filter(row => row.name); ++ } ++ ++ _sync() { ++ const rows = this._getWorkspaceRows(); ++ ++ const oldNames = rows.map(row => row.name); ++ const newNames = this._settings.get_strv(WORKSPACE_KEY); ++ ++ const removed = oldNames.filter(n => !newNames.includes(n)); ++ const added = newNames.filter(n => !oldNames.includes(n)); ++ ++ removed.forEach(n => this._list.remove(rows.find(r => r.name === n))); ++ added.forEach(n => { ++ this._list.insert(new WorkspaceRow(n), newNames.indexOf(n)); ++ }); ++ } ++}); ++ ++const WorkspaceRow = GObject.registerClass( ++class WorkspaceRow extends Gtk.ListBoxRow { ++ _init(name) { ++ super._init({ name }); ++ ++ const controller = new Gtk.ShortcutController(); ++ controller.add_shortcut(new Gtk.Shortcut({ ++ trigger: Gtk.ShortcutTrigger.parse_string('Escape'), ++ action: Gtk.CallbackAction.new(this._stopEdit.bind(this)), ++ })); ++ this.add_controller(controller); ++ ++ const box = new Gtk.Box({ ++ spacing: 12, ++ margin_top: 6, ++ margin_bottom: 6, ++ margin_start: 6, ++ margin_end: 6, ++ }); ++ ++ const label = new Gtk.Label({ ++ hexpand: true, ++ xalign: 0, ++ max_width_chars: 25, ++ ellipsize: Pango.EllipsizeMode.END, ++ }); ++ this.bind_property('name', label, 'label', ++ GObject.BindingFlags.SYNC_CREATE); ++ box.append(label); ++ ++ const button = new Gtk.Button({ ++ action_name: 'workspaces.remove', ++ action_target: new GLib.Variant('s', name), ++ icon_name: 'edit-delete-symbolic', ++ }); ++ box.append(button); ++ ++ this._entry = new Gtk.Entry({ ++ max_width_chars: 25, ++ }); ++ ++ this._stack = new Gtk.Stack(); ++ this._stack.add_named(box, 'display'); ++ this._stack.add_named(this._entry, 'edit'); ++ this.child = this._stack; ++ ++ this._entry.connect('activate', () => { ++ this.name = this._entry.text; ++ this._stopEdit(); ++ }); ++ this._entry.connect('notify::has-focus', () => { ++ if (this._entry.has_focus) ++ return; ++ this._stopEdit(); ++ }); ++ ++ this.connect('notify::name', () => { ++ button.action_target = new GLib.Variant('s', this.name); ++ this.activate_action('workspaces.update', null); ++ }); ++ } ++ ++ edit() { ++ this._entry.text = this.name; ++ this._entry.grab_focus(); ++ this._stack.visible_child_name = 'edit'; ++ } ++ ++ _stopEdit() { ++ this.grab_focus(); ++ this._stack.visible_child_name = 'display'; ++ } ++}); ++ ++const NewWorkspaceRow = GObject.registerClass( ++class NewWorkspaceRow extends Gtk.ListBoxRow { ++ _init() { ++ super._init({ ++ action_name: 'workspaces.add', ++ child: new Gtk.Image({ ++ icon_name: 'list-add-symbolic', ++ pixel_size: 16, ++ margin_top: 12, ++ margin_bottom: 12, ++ margin_start: 12, ++ margin_end: 12, ++ }), ++ }); ++ this.update_property( ++ [Gtk.AccessibleProperty.LABEL], [_('Add Workspace')]); ++ } ++}); +diff --git a/po/POTFILES.in b/po/POTFILES.in +index 4d551780..1fb8f17a 100644 +--- a/po/POTFILES.in ++++ b/po/POTFILES.in +@@ -17,6 +17,6 @@ extensions/window-list/org.gnome.shell.extensions.window-list.gschema.xml + extensions/window-list/prefs.js + extensions/window-list/workspaceIndicator.js + extensions/windowsNavigator/extension.js +-extensions/workspace-indicator/prefs.js + extensions/workspace-indicator/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml + extensions/workspace-indicator/workspaceIndicator.js ++extensions/workspace-indicator/workspacePrefs.js +-- +2.50.0 + + +From 96c95e0114fa158237d7f16c71b314bea30946a1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 11 Oct 2024 12:13:05 +0200 +Subject: [PATCH 03/19] workspace-indicator: Don't mention "top bar" in prefs + +The preferences will be shared with the window-list extension, +so avoid mentioning a specific placement. + +Part-of: +--- + extensions/workspace-indicator/workspacePrefs.js | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js +index 5691996d..77c333f1 100644 +--- a/extensions/workspace-indicator/workspacePrefs.js ++++ b/extensions/workspace-indicator/workspacePrefs.js +@@ -27,7 +27,7 @@ class GeneralGroup extends Gtk.Box { + this.append(row); + + row.append(new Gtk.Label({ +- label: _('Show Previews In Top Bar'), ++ label: _('Show Previews'), + })); + + const sw = new Gtk.Switch({ +-- +2.50.0 + + +From 5012e5e2b758f389b6ccfdd24a281b00ca900060 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 11 Oct 2024 12:45:54 +0200 +Subject: [PATCH 04/19] window-list: Remove workspace-previews setting from + prefs + +We are about to include the workspace prefs page from the +workspace-indicator extension, which already includes +the setting. + +Part-of: +--- + extensions/window-list/prefs.js | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js +index 79cd1355..e35990ff 100644 +--- a/extensions/window-list/prefs.js ++++ b/extensions/window-list/prefs.js +@@ -102,12 +102,6 @@ class WindowListPrefsWidget extends Gtk.Box { + }); + this._settings.bind('display-all-workspaces', check, 'active', Gio.SettingsBindFlags.DEFAULT); + this.append(check); +- +- check = new Gtk.CheckButton({ +- label: _('Show workspace previews'), +- }); +- this._settings.bind('embed-previews', check, 'active', Gio.SettingsBindFlags.DEFAULT); +- this.append(check); + } + }); + +-- +2.50.0 + + +From fdfd486005be35f4bf43bb37992dea281618edec Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 29 Jun 2025 23:49:15 +0200 +Subject: [PATCH 05/19] window-list: Add workspaces page to prefs + +This brings back the workspace-previews setting, and adds the +ability to change the workspace names. + +Given that those names are used as tooltips or preview titles, +it makes sense to allow editing them from the extension prefs +rather than relying on external tools (like dconf-editor). + +Part-of: +--- + extensions/window-list/meson.build | 1 + + extensions/window-list/prefs.js | 28 ++++++++++++++++++++++++++-- + 2 files changed, 27 insertions(+), 2 deletions(-) + +diff --git a/extensions/window-list/meson.build b/extensions/window-list/meson.build +index 12d2b174..c4485965 100644 +--- a/extensions/window-list/meson.build ++++ b/extensions/window-list/meson.build +@@ -30,6 +30,7 @@ workspaceIndicatorSources = [ + command: transform_stylesheet, + capture: true, + ), ++ files('../workspace-indicator/workspacePrefs.js'), + ] + + extension_sources += files('prefs.js', 'windowPicker.js') + workspaceIndicatorSources +diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js +index e35990ff..f1ce4bb7 100644 +--- a/extensions/window-list/prefs.js ++++ b/extensions/window-list/prefs.js +@@ -9,13 +9,14 @@ const Me = ExtensionUtils.getCurrentExtension(); + const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); + const _ = Gettext.gettext; + ++const { WorkspacesPage } = Me.imports.workspacePrefs; + + function init() { + ExtensionUtils.initTranslations(); + } + +-const WindowListPrefsWidget = GObject.registerClass( +-class WindowListPrefsWidget extends Gtk.Box { ++const WindowListPage = GObject.registerClass( ++class WindowListPage extends Gtk.Box { + _init() { + super._init({ + orientation: Gtk.Orientation.VERTICAL, +@@ -105,6 +106,29 @@ class WindowListPrefsWidget extends Gtk.Box { + } + }); + ++const WindowListPrefsWidget = GObject.registerClass( ++class WindowListPrefsWidget extends Gtk.Box { ++ _init() { ++ super._init({ ++ orientation: Gtk.Orientation.VERTICAL, ++ spacing: 6, ++ }); ++ ++ const stack = new Gtk.Stack(); ++ const stackSwitcher = new Gtk.StackSwitcher({ ++ stack, ++ margin_top: 12, ++ halign: Gtk.Align.CENTER, ++ }); ++ ++ this.append(stackSwitcher); ++ this.append(stack); ++ ++ stack.add_titled(new WindowListPage(), 'window-list', _('Window List')); ++ stack.add_titled(new WorkspacesPage(), 'workspaces', _('Workspaces')); ++ } ++}); ++ + function buildPrefsWidget() { + return new WindowListPrefsWidget(); + } +-- +2.50.0 + + +From cd0b7ee2ca454244f8171e9120c3ea1ff3bfdd51 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 22 May 2025 16:31:57 +0200 +Subject: [PATCH 06/19] workspace-indicator: Remove left-over variable + +Part-of: +--- + extensions/workspace-indicator/workspaceIndicator.js | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index f70dcaf7..5a5dba2f 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -470,8 +470,6 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._thumbnails = new WorkspacePreviews(); + container.add_child(this._thumbnails); + +- this._workspacesItems = []; +- + this._workspaceManagerSignals = [ + workspaceManager.connect_after('workspace-switched', + this._onWorkspaceSwitched.bind(this)), +-- +2.50.0 + + +From cd725aaa4cba84ae3e779307e681a8551106ed19 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 22 May 2025 16:27:57 +0200 +Subject: [PATCH 07/19] workspace-indicator: Split out WorkspacesMenu + +The menu currently only contains the previews without any logic +on its own. This is about to change, so split the menu into a +separate class. + +Part-of: +--- + .../workspace-indicator/workspaceIndicator.js | 21 ++++++++++--------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index 5a5dba2f..7e6b9cce 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -435,6 +435,16 @@ const WorkspacePreviews = GObject.registerClass({ + } + }); + ++class WorkspacesMenu extends PopupMenu.PopupMenu { ++ constructor(sourceActor) { ++ super(sourceActor, 0.5, St.Side.TOP); ++ ++ const previews = new WorkspacePreviews({show_labels: true}); ++ this.box.add_child(previews); ++ this.actor.add_style_class_name(`${baseStyleClassName}-menu`); ++ } ++} ++ + var WorkspaceIndicator = GObject.registerClass( + class WorkspaceIndicator extends PanelMenu.Button { + _init(params = {}) { +@@ -511,7 +521,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._thumbnails.visible = !useMenu; + + this.setMenu(useMenu +- ? this._createPreviewMenu() ++ ? new WorkspacesMenu(this) + : null); + + this._updateTopBarRedirect(); +@@ -538,13 +548,4 @@ class WorkspaceIndicator extends PanelMenu.Button { + const current = this._currentWorkspace + 1; + return `${current} / ${nWorkspaces}`; + } +- +- _createPreviewMenu() { +- const menu = new PopupMenu.PopupMenu(this, 0.5, St.Side.TOP); +- +- const previews = new WorkspacePreviews({show_labels: true}); +- menu.box.add_child(previews); +- menu.actor.add_style_class_name(`${baseStyleClassName}-menu`); +- return menu; +- } + }); +-- +2.50.0 + + +From 8b3ad4561dd1ce86e3575b1184dc8a6f15249c5c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 22 May 2025 18:53:20 +0200 +Subject: [PATCH 08/19] workspace-indicator: Add back plain workspaces menu + +Unlike in the top bar, the previews in the menu were not too +successful. Change back to a regular menu with a list of workspace +names. + +Part-of: +--- + .../workspace-indicator/stylesheet-dark.css | 20 ------ + .../workspace-indicator/workspaceIndicator.js | 72 ++++++++++++++++++- + 2 files changed, 70 insertions(+), 22 deletions(-) + +diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css +index 872c6afc..d9bc65b1 100644 +--- a/extensions/workspace-indicator/stylesheet-dark.css ++++ b/extensions/workspace-indicator/stylesheet-dark.css +@@ -6,19 +6,10 @@ + -st-hfade-offset: 20px; + } + +-.workspace-indicator-menu .workspaces-view { +- max-width: 480px; +-} +- + .workspace-indicator .workspaces-box { + spacing: 3px; + } + +-.workspace-indicator-menu .workspaces-box { +- padding: 5px; +- spacing: 6px; +-} +- + .workspace-indicator .workspace-box { + padding-top: 5px; + padding-bottom: 5px; +@@ -33,11 +24,6 @@ + padding-right: 5px; + } + +-.workspace-indicator-menu .workspace-box { +- spacing: 6px; +-} +- +-.workspace-indicator-menu .workspace, + .workspace-indicator .workspace { + border: 1px solid transparent; + border-radius: 4px; +@@ -48,12 +34,6 @@ + width: 52px; + } + +-.workspace-indicator-menu .workspace { +- height: 80px; +- width: 160px; +-} +- +-.workspace-indicator-menu .workspace.active, + .workspace-indicator .workspace.active { + border-color: #fff; + } +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index 7e6b9cce..ebe92363 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -439,9 +439,77 @@ class WorkspacesMenu extends PopupMenu.PopupMenu { + constructor(sourceActor) { + super(sourceActor, 0.5, St.Side.TOP); + +- const previews = new WorkspacePreviews({show_labels: true}); +- this.box.add_child(previews); + this.actor.add_style_class_name(`${baseStyleClassName}-menu`); ++ this.actor.connect('destroy', () => this._onDestroy()); ++ ++ this._workspacesSection = new PopupMenu.PopupMenuSection(); ++ this.addMenuItem(this._workspacesSection); ++ ++ this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); ++ ++ this.addAction(_('Settings'), () => ExtensionUtils.openPrefs()); ++ ++ this._desktopSettings = ++ new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'}); ++ this._workspaceNamesChangedId = ++ this._desktopSettings.connect('changed::workspace-names', ++ () => this._updateWorkspaceLabels()); ++ ++ const {workspaceManager} = global; ++ this._workspaceManagerSignals = [ ++ workspaceManager.connect('notify::n-workspaces', ++ () => this._updateWorkspaceItems()), ++ workspaceManager.connect('workspace-switched', ++ () => this._updateActiveIndicator()), ++ ]; ++ this._updateWorkspaceItems(); ++ } ++ ++ _updateWorkspaceItems() { ++ const {workspaceManager} = global; ++ const {nWorkspaces} = workspaceManager; ++ ++ const section = this._workspacesSection.actor; ++ while (section.get_n_children() < nWorkspaces) { ++ const item = new PopupMenu.PopupMenuItem(''); ++ item.connect('activate', (o, event) => { ++ const index = [...section].indexOf(item); ++ const workspace = workspaceManager.get_workspace_by_index(index); ++ workspace?.activate(event.get_time()); ++ }); ++ this._workspacesSection.addMenuItem(item); ++ } ++ ++ [...section].splice(nWorkspaces).forEach(item => item.destroy()); ++ ++ this._updateWorkspaceLabels(); ++ this._updateActiveIndicator(); ++ } ++ ++ _updateWorkspaceLabels() { ++ const items = [...this._workspacesSection.actor]; ++ items.forEach( ++ (item, i) => (item.label.text = Meta.prefs_get_workspace_name(i))); ++ } ++ ++ _updateActiveIndicator() { ++ const {workspaceManager} = global; ++ const active = workspaceManager.get_active_workspace_index(); ++ ++ const items = [...this._workspacesSection.actor]; ++ items.forEach((item, i) => { ++ item.setOrnament(i === active ++ ? PopupMenu.Ornament.CHECK ++ : PopupMenu.Ornament.NONE); ++ }); ++ } ++ ++ _onDestroy() { ++ for (const id of this._workspaceManagerSignals) ++ global.workspace_manager.disconnect(id); ++ ++ this._desktopSettings.disconnect(this._workspaceNamesChangedId); ++ this._desktopSettings = null; + } + } + +-- +2.50.0 + + +From 1072bf3d6652b67e311a30c3e3592e2ea9410990 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 22 May 2025 19:00:23 +0200 +Subject: [PATCH 09/19] workspace-indicator: Remove preview labels + +Previews are no longer used in the menu, so they are never +shown with labels. + +Part-of: +--- + .../workspace-indicator/workspaceIndicator.js | 36 ++----------------- + 1 file changed, 2 insertions(+), 34 deletions(-) + +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index ebe92363..54912746 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -122,10 +122,6 @@ const WorkspaceThumbnail = GObject.registerClass({ + 'active', '', '', + GObject.ParamFlags.READWRITE, + false), +- 'show-label': GObject.ParamSpec.boolean( +- 'show-label', '', '', +- GObject.ParamFlags.READWRITE, +- false), + }, + }, class WorkspaceThumbnail extends St.Button { + _init(index) { +@@ -150,32 +146,15 @@ const WorkspaceThumbnail = GObject.registerClass({ + }); + box.add_child(this._preview); + +- this._label = new St.Label({ +- x_align: Clutter.ActorAlign.CENTER, +- text: Meta.prefs_get_workspace_name(index), +- }); +- box.add_child(this._label); +- + this._tooltip = new St.Label({ + style_class: 'dash-label', + visible: false, + }); + Main.uiGroup.add_child(this._tooltip); + +- this.bind_property('show-label', +- this._label, 'visible', +- GObject.BindingFlags.SYNC_CREATE); +- + this.connect('destroy', this._onDestroy.bind(this)); + this.connect('notify::hover', this._syncTooltip.bind(this)); + +- this._desktopSettings = +- new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'}); +- this._namesChangedId = +- this._desktopSettings.connect('changed::workspace-names', () => { +- this._label.text = Meta.prefs_get_workspace_name(index); +- }); +- + this._index = index; + this._delegate = this; // needed for DND + +@@ -273,9 +252,6 @@ const WorkspaceThumbnail = GObject.registerClass({ + } + + _syncTooltip() { +- if (this.showLabel) +- return; +- + if (this.hover) { + this._tooltip.set({ + text: Meta.prefs_get_workspace_name(this._index), +@@ -312,9 +288,6 @@ const WorkspaceThumbnail = GObject.registerClass({ + this._workspace.disconnect(this._windowAddedId); + this._workspace.disconnect(this._windowRemovedId); + global.display.disconnect(this._restackedId); +- +- this._desktopSettings.disconnect(this._namesChangedId); +- this._desktopSettings = null; + } + }); + +@@ -376,13 +349,8 @@ const WorkspacePreviews = GObject.registerClass({ + + this._thumbnailsBox.destroy_all_children(); + +- for (let i = 0; i < nWorkspaces; i++) { +- const thumb = new WorkspaceThumbnail(i); +- this.bind_property('show-labels', +- thumb, 'show-label', +- GObject.BindingFlags.SYNC_CREATE); +- this._thumbnailsBox.add_child(thumb); +- } ++ for (let i = 0; i < nWorkspaces; i++) ++ this._thumbnailsBox.add_child(new WorkspaceThumbnail(i)); + + if (this.mapped) + this._updateScrollPosition(); +-- +2.50.0 + + +From a8aae63fc91f1ac5494f7ac8685d4f0fb39b4658 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 28 May 2025 02:16:33 +0200 +Subject: [PATCH 10/19] workspace-indicator: Include menu with previews + +The menu is currently only used when previews are disabled. But +as we are going to use the menu for changing workspace names, it +should be always available. So add it unconditionally, and show +it on right-click when using previews. + +Part-of: +--- + .../workspace-indicator/stylesheet-dark.css | 5 ++++ + .../workspace-indicator/workspaceIndicator.js | 25 +++++++++++++------ + 2 files changed, 23 insertions(+), 7 deletions(-) + +diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css +index d9bc65b1..1ca929f9 100644 +--- a/extensions/workspace-indicator/stylesheet-dark.css ++++ b/extensions/workspace-indicator/stylesheet-dark.css +@@ -1,3 +1,8 @@ ++.workspace-indicator.previews:active { ++ background-color: none !important; ++ box-shadow: none !important; ++} ++ + .workspace-indicator .status-label { + padding: 0 8px; + } +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index 54912746..ca4466cc 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -496,6 +496,8 @@ class WorkspaceIndicator extends PanelMenu.Button { + baseStyleClassName = baseStyleClass; + this.add_style_class_name(baseStyleClassName); + ++ this.setMenu(new WorkspacesMenu(this)); ++ + let container = new St.Widget({ + layout_manager: new Clutter.BinLayout(), + x_expand: true, +@@ -516,6 +518,14 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._thumbnails = new WorkspacePreviews(); + container.add_child(this._thumbnails); + ++ this._thumbnails.connect('button-press-event', (a, event) => { ++ if (event.get_button() !== Clutter.BUTTON_SECONDARY) ++ return Clutter.EVENT_PROPAGATE; ++ ++ this.menu.toggle(); ++ return Clutter.EVENT_STOP; ++ }); ++ + this._workspaceManagerSignals = [ + workspaceManager.connect_after('workspace-switched', + this._onWorkspaceSwitched.bind(this)), +@@ -550,15 +560,16 @@ class WorkspaceIndicator extends PanelMenu.Button { + } + + _updateThumbnailVisibility() { +- const useMenu = !this._settings.get_boolean('embed-previews'); +- this.reactive = useMenu; ++ const usePreviews = this._settings.get_boolean('embed-previews'); ++ this.reactive = !usePreviews; + +- this._statusLabel.visible = useMenu; +- this._thumbnails.visible = !useMenu; ++ this._thumbnails.visible = usePreviews; ++ this._statusLabel.visible = !usePreviews; + +- this.setMenu(useMenu +- ? new WorkspacesMenu(this) +- : null); ++ if (usePreviews) ++ this.add_style_class_name('previews'); ++ else ++ this.remove_style_class_name('previews'); + + this._updateTopBarRedirect(); + } +-- +2.50.0 + + +From 8548119bca73b1dbf7f5e5e3c850e0b4af03f729 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 29 May 2025 14:53:37 +0200 +Subject: [PATCH 11/19] workspace-indicator: Expose active workspace name on + menu + +When not using previews, we currently use a numerical presentation +like "1 / 4" for the top bar button. We will change that to use +the active workspace name instead. + +As the menu already has to track workspace switches and name changes, +expose the active workspace name there, so that the button doesn't +have to duplicate the tracking. + +Part-of: +--- + .../workspace-indicator/workspaceIndicator.js | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index ca4466cc..8e22e6b1 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -420,8 +420,10 @@ class WorkspacesMenu extends PopupMenu.PopupMenu { + this._desktopSettings = + new Gio.Settings({schema_id: 'org.gnome.desktop.wm.preferences'}); + this._workspaceNamesChangedId = +- this._desktopSettings.connect('changed::workspace-names', +- () => this._updateWorkspaceLabels()); ++ this._desktopSettings.connect('changed::workspace-names', () => { ++ this._updateWorkspaceLabels(); ++ this.emit('active-name-changed'); ++ }); + + const {workspaceManager} = global; + this._workspaceManagerSignals = [ +@@ -433,6 +435,12 @@ class WorkspacesMenu extends PopupMenu.PopupMenu { + this._updateWorkspaceItems(); + } + ++ get activeName() { ++ const {workspaceManager} = global; ++ const active = workspaceManager.get_active_workspace_index(); ++ return Meta.prefs_get_workspace_name(active); ++ } ++ + _updateWorkspaceItems() { + const {workspaceManager} = global; + const {nWorkspaces} = workspaceManager; +@@ -470,6 +478,7 @@ class WorkspacesMenu extends PopupMenu.PopupMenu { + ? PopupMenu.Ornament.CHECK + : PopupMenu.Ornament.NONE); + }); ++ this.emit('active-name-changed'); + } + + _onDestroy() { +-- +2.50.0 + + +From 1d176bb2cce5dd4d89a316846fb2125b8373493e Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 22 May 2025 20:59:58 +0200 +Subject: [PATCH 12/19] workspace-indicator: Show full name when using menu + +With workspace names becoming a more prominent feature, it makes +sense to expose them without opening the menu. + +Part-of: +--- + .../workspace-indicator/stylesheet-dark.css | 8 +++++ + .../workspace-indicator/workspaceIndicator.js | 34 +++++++------------ + 2 files changed, 21 insertions(+), 21 deletions(-) + +diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css +index 1ca929f9..d35a5dfc 100644 +--- a/extensions/workspace-indicator/stylesheet-dark.css ++++ b/extensions/workspace-indicator/stylesheet-dark.css +@@ -4,8 +4,16 @@ + } + + .workspace-indicator .status-label { ++ width: 8em; + padding: 0 8px; + } ++.workspace-indicator .status-label:ltr { padding-right: 4px; } ++.workspace-indicator .status-label:rtl { padding-left: 4px; } ++ ++.workspace-indicator .system-status-icon { ++ padding: 0 !important; ++ margin: 0 !important; ++} + + .workspace-indicator .workspaces-view.hfade { + -st-hfade-offset: 20px; +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index 8e22e6b1..ced16256 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -514,15 +514,23 @@ class WorkspaceIndicator extends PanelMenu.Button { + }); + this.add_child(container); + +- let workspaceManager = global.workspace_manager; ++ this._statusBox = new St.BoxLayout(); ++ container.add_child(this._statusBox); + +- this._currentWorkspace = workspaceManager.get_active_workspace_index(); + this._statusLabel = new St.Label({ + style_class: 'status-label', ++ x_expand: true, + y_align: Clutter.ActorAlign.CENTER, +- text: this._getStatusText(), ++ text: this.menu.activeName, + }); +- container.add_child(this._statusLabel); ++ this._statusBox.add_child(this._statusLabel); ++ this._statusBox.add_child(new St.Icon({ ++ icon_name: 'pan-down-symbolic', ++ style_class: 'system-status-icon', ++ })); ++ ++ this.menu.connect('active-name-changed', ++ () => this._statusLabel.set_text(this.menu.activeName)); + + this._thumbnails = new WorkspacePreviews(); + container.add_child(this._thumbnails); +@@ -535,11 +543,6 @@ class WorkspaceIndicator extends PanelMenu.Button { + return Clutter.EVENT_STOP; + }); + +- this._workspaceManagerSignals = [ +- workspaceManager.connect_after('workspace-switched', +- this._onWorkspaceSwitched.bind(this)), +- ]; +- + this.connect('scroll-event', + (a, event) => Main.wm.handleWorkspaceScroll(event)); + +@@ -573,7 +576,7 @@ class WorkspaceIndicator extends PanelMenu.Button { + this.reactive = !usePreviews; + + this._thumbnails.visible = usePreviews; +- this._statusLabel.visible = !usePreviews; ++ this._statusBox.visible = !usePreviews; + + if (usePreviews) + this.add_style_class_name('previews'); +@@ -593,15 +596,4 @@ class WorkspaceIndicator extends PanelMenu.Button { + ? Clutter.OffscreenRedirect.ALWAYS + : Clutter.OffscreenRedirect.AUTOMATIC_FOR_OPACITY); + } +- +- _onWorkspaceSwitched() { +- this._currentWorkspace = global.workspace_manager.get_active_workspace_index(); +- this._statusLabel.set_text(this._getStatusText()); +- } +- +- _getStatusText() { +- const {nWorkspaces} = global.workspace_manager; +- const current = this._currentWorkspace + 1; +- return `${current} / ${nWorkspaces}`; +- } + }); +-- +2.50.0 + + +From 9951956a6e17772bf9fd9e9ca470493b6707b7a5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Mon, 9 Jun 2025 18:10:14 +0200 +Subject: [PATCH 13/19] workspace-indicator: Add background when using name + label + +Panel buttons are flat, so the name+arrow are not immediately +recognizable as a single control. Address this by adding a +background to the button when using the name label. + +Part-of: +--- + extensions/workspace-indicator/stylesheet-dark.css | 14 ++++++++++++++ + .../workspace-indicator/stylesheet-light.css | 14 ++++++++++++++ + .../workspace-indicator/workspaceIndicator.js | 7 +++++-- + 3 files changed, 33 insertions(+), 2 deletions(-) + +diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css +index d35a5dfc..f1f9ec8f 100644 +--- a/extensions/workspace-indicator/stylesheet-dark.css ++++ b/extensions/workspace-indicator/stylesheet-dark.css +@@ -3,6 +3,20 @@ + box-shadow: none !important; + } + ++.workspace-indicator.name-label { ++ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.17) !important; ++} ++.workspace-indicator.name-label:hover, ++.workspace-indicator.name-label:focus { ++ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.28) !important; ++} ++.workspace-indicator.name-label:active { ++ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.32) !important; ++} ++.workspace-indicator.name-label:active:hover { ++ box-shadow: inset 0 0 0 100px rgba(255, 255, 255, 0.36) !important; ++} ++ + .workspace-indicator .status-label { + width: 8em; + padding: 0 8px; +diff --git a/extensions/workspace-indicator/stylesheet-light.css b/extensions/workspace-indicator/stylesheet-light.css +index 049b6a38..5191923c 100644 +--- a/extensions/workspace-indicator/stylesheet-light.css ++++ b/extensions/workspace-indicator/stylesheet-light.css +@@ -7,6 +7,20 @@ + + @import url("stylesheet-dark.css"); + ++.workspace-indicator.name-label { ++ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.17) !important; ++} ++.workspace-indicator.name-label:hover, ++.workspace-indicator.name-label:focus { ++ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.28) !important; ++} ++.workspace-indicator.name-label:active { ++ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.32) !important; ++} ++.workspace-indicator.name-label:active:hover { ++ box-shadow: inset 0 0 0 100px rgba(34, 34, 38, 0.36) !important; ++} ++ + .workspace-indicator .workspace { + background-color: #ccc; + } +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index ced16256..11ae9f5f 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -578,10 +578,13 @@ class WorkspaceIndicator extends PanelMenu.Button { + this._thumbnails.visible = usePreviews; + this._statusBox.visible = !usePreviews; + +- if (usePreviews) ++ if (usePreviews) { + this.add_style_class_name('previews'); +- else ++ this.remove_style_class_name('name-label'); ++ } else { + this.remove_style_class_name('previews'); ++ this.add_style_class_name('name-label'); ++ } + + this._updateTopBarRedirect(); + } +-- +2.50.0 + + +From 8b60e81922f6b9ee6ac48bc63226e082e482b3fd Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 22 May 2025 21:07:08 +0200 +Subject: [PATCH 14/19] workspace-indicator: Reimplement some libadwaita prefs + widgets + +Upstream now makes more use of libawaita, so reimplement the API we +need to make backporting a bit less painful. +--- + .../workspace-indicator/workspacePrefs.js | 238 ++++++++++++++++++ + 1 file changed, 238 insertions(+) + +diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js +index 77c333f1..871bbf0c 100644 +--- a/extensions/workspace-indicator/workspacePrefs.js ++++ b/extensions/workspace-indicator/workspacePrefs.js +@@ -16,6 +16,244 @@ const N_ = e => e; + const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; + const WORKSPACE_KEY = 'workspace-names'; + ++const PreferencesGroup = GObject.registerClass({ ++ Properties: { ++ 'title': GObject.ParamSpec.string( ++ 'title', '', '', ++ GObject.ParamFlags.READWRITE, ++ null), ++ }, ++}, class PreferencesGroup extends Gtk.Box { ++ _init(params) { ++ super._init({ ++ ...params, ++ orientation: Gtk.Orientation.VERTICAL, ++ }); ++ ++ const titleLabel = new Gtk.Label({ ++ halign: Gtk.Align.START, ++ }); ++ titleLabel.add_css_class('heading'); ++ ++ this.bind_property('title', ++ titleLabel, 'label', ++ GObject.BindingFlags.SYNC_CREATE); ++ this.append(titleLabel); ++ ++ this._list = new Gtk.ListBox({ ++ selection_mode: Gtk.SelectionMode.NONE, ++ valign: Gtk.Align.START, ++ show_separators: true, ++ }); ++ this._list.add_css_class('boxed-list'); ++ this.append(this._list); ++ ++ this._list.connect('row-activated', ++ (l, row) => row.activate()); ++ } ++ ++ get title() { ++ return this._title || ''; ++ } ++ ++ set title(title) { ++ if (this._title === title) ++ return; ++ ++ this._title = title; ++ this.notify('title'); ++ } ++ ++ add(child) { ++ this._list.append(child); ++ } ++ ++ remove(child) { ++ this._list.remove(child); ++ } ++}); ++ ++const ActionRow = GObject.registerClass({ ++ Properties: { ++ 'title': GObject.ParamSpec.string( ++ 'title', '', '', ++ GObject.ParamFlags.READWRITE, ++ null), ++ 'subtitle': GObject.ParamSpec.string( ++ 'subtitle', '', '', ++ GObject.ParamFlags.READWRITE, ++ null), ++ 'activatable-widget': GObject.ParamSpec.object( ++ 'activatable-widget', '', '', ++ GObject.ParamFlags.READWRITE, ++ Gtk.Widget), ++ }, ++}, class ActionRow extends Gtk.ListBoxRow { ++ _init(params) { ++ super._init(params); ++ ++ const provider = new Gtk.CssProvider(); ++ provider.load_from_data(`* { ++ border-spacing: 6px 6px; ++ min-height: 40px; ++ margin-left: 12px; ++ margin-right: 12px; ++ }`, -1); ++ ++ const mainBox = new Gtk.Box({ ++ valign: Gtk.Align.CENTER, ++ hexpand: false, ++ }); ++ mainBox.get_style_context().add_provider(provider, ++ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); ++ this.set_child(mainBox); ++ ++ this._prefixes = new Gtk.Box({ ++ visible: false, ++ }); ++ mainBox.append(this._prefixes); ++ ++ const titleBox = new Gtk.Box({ ++ orientation: Gtk.Orientation.VERTICAL, ++ valign: Gtk.Align.CENTER, ++ hexpand: true, ++ }); ++ mainBox.append(titleBox); ++ ++ this._suffixes = new Gtk.Box({ ++ visible: false, ++ }); ++ mainBox.append(this._suffixes); ++ ++ const titleLabel = new Gtk.Label({ ++ lines: 0, ++ wrap: true, ++ wrap_mode: Pango.WrapMode.WORD_CHAR, ++ xalign: 0, ++ }); ++ ++ this.bind_property('title', ++ titleLabel, 'label', ++ GObject.BindingFlags.SYNC_CREATE); ++ titleBox.append(titleLabel); ++ ++ const subtitleLabel = new Gtk.Label({ ++ ellipsize: Pango.EllipsizeMode.NONE, ++ lines: 0, ++ wrap: true, ++ wrap_mode: Pango.WrapMode.WORD_CHAR, ++ xalign: 0, ++ visible: this.subtitle.length > 0, ++ }); ++ subtitleLabel.add_css_class('dim-label'); ++ ++ this.bind_property('subtitle', ++ subtitleLabel, 'label', ++ GObject.BindingFlags.SYNC_CREATE); ++ titleBox.append(subtitleLabel); ++ } ++ ++ get title() { ++ return this._title || ''; ++ } ++ ++ set title(title) { ++ if (this._title === title) ++ return; ++ ++ this._title = title; ++ this.notify('title'); ++ } ++ ++ get subtitle() { ++ return this._subtitle || ''; ++ } ++ ++ set subtitle(subtitle) { ++ if (this._subtitle === subtitle) ++ return; ++ ++ this._subtitle = subtitle; ++ this.notify('subtitle'); ++ } ++ ++ get activitable_widget() { ++ return this._activatableWidget; ++ } ++ ++ set activatable_widget(widget) { ++ if (this._activatableWidget === widget) ++ return; ++ ++ this._activatableWidget = widget; ++ this.notify('activatable-widget'); ++ } ++ ++ add_prefix(child) { ++ this._prefixes.append(child); ++ this._prefixes.set_visible(true); ++ } ++ ++ add_suffix(child) { ++ this._suffixes.append(child); ++ this._suffixes.set_visible(true); ++ } ++ ++ activate() { ++ if (this._activatableWidget) ++ this._activatableWidget.mnemonic_activate(false); ++ } ++}); ++ ++const SpinRow = GObject.registerClass({ ++ Properties: { ++ 'adjustment': GObject.ParamSpec.object( ++ 'adjustment', '', '', ++ GObject.ParamFlags.READWRITE, ++ Gtk.Adjustment), ++ 'value': GObject.ParamSpec.double( ++ 'value', '', '', ++ GObject.ParamFlags.READWRITE, ++ -Infinity, Infinity, 0), ++ }, ++}, class SpinRow extends ActionRow { ++ _init(params) { ++ this._spinButton = new Gtk.SpinButton({ ++ valign: Gtk.Align.CENTER, ++ hexpand: true, ++ xalign: 1, ++ }); ++ super._init(params); ++ this.add_suffix(this._spinButton); ++ } ++ ++ get adjustment() { ++ return this._spinButton.get_adjustment(); ++ } ++ ++ set adjustment(adj) { ++ if (this.adjustment === adj) ++ return; ++ ++ this._spinButton.set_adjustment(adj); ++ this.notify('adjustment'); ++ } ++ ++ get value() { ++ return this._spinButton.get_value(); ++ } ++ ++ set value(value) { ++ const EPSILON = 0.005; ++ ++ if (Math.abs(this.value, value) < EPSILON) ++ return; ++ ++ this._spinButton.set_value(value); ++ this.notify('value'); ++ } ++}); ++ + const GeneralGroup = GObject.registerClass( + class GeneralGroup extends Gtk.Box { + _init() { +-- +2.50.0 + + +From c621184851f590c4b7938a059724317783cdfe78 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Sun, 29 Jun 2025 21:26:40 +0200 +Subject: [PATCH 15/19] workspace-indicator: Refine preview settings + +Add a group title, and change the single switch row to radio rows +to explicitly choose between "Previews" and "Workspace Name". + +Part-of: +--- + .../workspace-indicator/workspacePrefs.js | 35 ++++++++++++------- + 1 file changed, 22 insertions(+), 13 deletions(-) + +diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js +index 871bbf0c..1f706dad 100644 +--- a/extensions/workspace-indicator/workspacePrefs.js ++++ b/extensions/workspace-indicator/workspacePrefs.js +@@ -255,29 +255,38 @@ const SpinRow = GObject.registerClass({ + }); + + const GeneralGroup = GObject.registerClass( +-class GeneralGroup extends Gtk.Box { ++class GeneralGroup extends PreferencesGroup { + _init() { + super._init({ +- orientation: Gtk.Orientation.VERTICAL, ++ title: _('Indicator'), + }); + +- const row = new Gtk.Box(); +- this.append(row); +- +- row.append(new Gtk.Label({ +- label: _('Show Previews'), +- })); ++ const previewCheck = new Gtk.CheckButton(); ++ const previewRow = new ActionRow({ ++ title: _('Previews'), ++ activatable_widget: previewCheck, ++ }); ++ previewRow.add_prefix(previewCheck); ++ this.add(previewRow); + +- const sw = new Gtk.Switch({ +- hexpand: true, +- halign: Gtk.Align.END, ++ const nameCheck = new Gtk.CheckButton({ ++ group: previewCheck, ++ }); ++ const nameRow = new ActionRow({ ++ title: _('Workspace Name'), ++ activatable_widget: nameCheck, + }); +- row.append(sw); ++ nameRow.add_prefix(nameCheck); ++ this.add(nameRow); + + const settings = ExtensionUtils.getSettings(); ++ if (settings.get_boolean('embed-previews')) ++ previewCheck.active = true; ++ else ++ nameCheck.active = true; + + settings.bind('embed-previews', +- sw, 'active', ++ previewCheck, 'active', + Gio.SettingsBindFlags.DEFAULT); + } + }); +-- +2.50.0 + + +From 589abbc74cbbde57e4ad2f01084b01b7f828d01c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Thu, 22 May 2025 16:20:05 +0200 +Subject: [PATCH 16/19] workspace-indicator: Include workspace settings + +While the "Multitasking" panel in Settings already exposes workspace +settings, it makes sense to expose them in our prefs dialog as well +where they are more in context. + +Part-of: +--- + .../workspace-indicator/workspacePrefs.js | 67 +++++++++++++++++++ + 1 file changed, 67 insertions(+) + +diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js +index 1f706dad..c5e311ef 100644 +--- a/extensions/workspace-indicator/workspacePrefs.js ++++ b/extensions/workspace-indicator/workspacePrefs.js +@@ -291,6 +291,72 @@ class GeneralGroup extends PreferencesGroup { + } + }); + ++const BehaviorGroup = GObject.registerClass( ++class BehaviorGroup extends PreferencesGroup { ++ _init() { ++ super._init({ ++ title: _('Behavior'), ++ }); ++ ++ const dynamicCheck = new Gtk.CheckButton(); ++ const dynamicRow = new ActionRow({ ++ title: _('Dynamic'), ++ subtitle: _('Automatically removes empty workspaces.'), ++ activatable_widget: dynamicCheck, ++ }); ++ dynamicRow.add_prefix(dynamicCheck); ++ this.add(dynamicRow); ++ ++ const fixedCheck = new Gtk.CheckButton({ ++ group: dynamicCheck, ++ }); ++ const fixedRow = new ActionRow({ ++ title: _('Fixed Number'), ++ subtitle: _('Specify a number of permanent workspaces.'), ++ activatable_widget: fixedCheck, ++ }); ++ fixedRow.add_prefix(fixedCheck); ++ this.add(fixedRow); ++ ++ const adjustment = new Gtk.Adjustment({ ++ lower: 1, ++ step_increment: 1, ++ value: 4, ++ upper: 36, // hard limit in mutter ++ }); ++ const numRow = new SpinRow({ ++ title: _('Number of Workspaces'), ++ adjustment, ++ }); ++ this.add(numRow); ++ ++ const mutterSettings = new Gio.Settings({ ++ schema_id: 'org.gnome.mutter', ++ }); ++ ++ if (mutterSettings.get_boolean('dynamic-workspaces')) ++ dynamicCheck.active = true; ++ else ++ fixedCheck.active = true; ++ ++ mutterSettings.bind('dynamic-workspaces', ++ dynamicCheck, 'active', ++ Gio.SettingsBindFlags.DEFAULT); ++ ++ const desktopSettings = new Gio.Settings({ ++ schema_id: 'org.gnome.desktop.wm.preferences', ++ }); ++ ++ desktopSettings.bind('num-workspaces', ++ numRow, 'value', ++ Gio.SettingsBindFlags.DEFAULT); ++ ++ fixedCheck.bind_property('active', ++ numRow, 'sensitive', ++ GObject.BindingFlags.SYNC_CREATE); ++ } ++}); ++ + var WorkspacesPage = GObject.registerClass( + class WorkspacesPage extends Gtk.ScrolledWindow { + _init() { +@@ -311,6 +377,7 @@ class WorkspacesPage extends Gtk.ScrolledWindow { + this.set_child(box); + + box.append(new GeneralGroup()); ++ box.append(new BehaviorGroup()); + + box.append(new Gtk.Label({ + label: '%s'.format(_('Workspace Names')), +-- +2.50.0 + + +From 6ca15a8289d3308d4bb87e55d48ebd25ad9807a1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 28 May 2025 21:01:08 +0200 +Subject: [PATCH 17/19] workspace-indicator: Allow changing workspace names + from menu + +Instead of requiring the user to open the prefs dialog to change +workspace names, make the menu items themselves editable. + +Part-of: +--- + .../workspace-indicator/stylesheet-dark.css | 48 +++++++ + .../workspace-indicator/stylesheet-light.css | 16 +++ + .../workspace-indicator/workspaceIndicator.js | 130 +++++++++++++++++- + 3 files changed, 192 insertions(+), 2 deletions(-) + +diff --git a/extensions/workspace-indicator/stylesheet-dark.css b/extensions/workspace-indicator/stylesheet-dark.css +index f1f9ec8f..446c78de 100644 +--- a/extensions/workspace-indicator/stylesheet-dark.css ++++ b/extensions/workspace-indicator/stylesheet-dark.css +@@ -74,3 +74,51 @@ + .workspace-indicator-window-preview.active { + background-color: #d4d4d4; + } ++ ++.workspace-indicator-menu { ++ min-width: 17em; ++} ++ ++.workspace-indicator-menu .editable-menu-item.popup-menu-item { ++ padding: 3px 12px; ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button { ++ border-radius: 99px; ++ padding: 6px; ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat { ++ background-color: transparent; ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:hover { ++ background-color: rgba(255, 255, 255, 0.1); ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:active { ++ background-color: rgba(255, 255, 255, 0.15); ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked { ++ color: white; ++ background-color: #3584e4; ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:hover { ++ background-color: #629fea; ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:active { ++ background-color: #78aded; ++} ++ ++.workspace-indicator-menu .editable-menu-item .label { ++ padding: 0 11px; ++ width: 6.5em; ++} ++ ++.workspace-indicator-menu .editable-menu-item .entry { ++ padding: 9px 9px; ++ width: 6.5em; ++} +diff --git a/extensions/workspace-indicator/stylesheet-light.css b/extensions/workspace-indicator/stylesheet-light.css +index 5191923c..e4f2b45a 100644 +--- a/extensions/workspace-indicator/stylesheet-light.css ++++ b/extensions/workspace-indicator/stylesheet-light.css +@@ -37,3 +37,19 @@ + .workspace-indicator-window-preview.active { + background-color: #f6f5f4; + } ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:hover { ++ background-color: rgba(0, 0, 0, 0.1); ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:active { ++ background-color: rgba(0, 0, 0, 0.15); ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:hover { ++ background-color: #1b6acb; ++} ++ ++.workspace-indicator-menu .editable-menu-item .icon-button.flat:checked:active { ++ background-color: #185fb4; ++} +diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js +index 11ae9f5f..4f374653 100644 +--- a/extensions/workspace-indicator/workspaceIndicator.js ++++ b/extensions/workspace-indicator/workspaceIndicator.js +@@ -4,7 +4,7 @@ + // + // SPDX-License-Identifier: GPL-2.0-or-later + +-const { Clutter, Gio, GObject, Meta, St } = imports.gi; ++const { Clutter, Gio, GObject, Meta, Shell, St } = imports.gi; + + const ExtensionUtils = imports.misc.extensionUtils; + const Me = ExtensionUtils.getCurrentExtension(); +@@ -403,6 +403,125 @@ const WorkspacePreviews = GObject.registerClass({ + } + }); + ++const EditableMenuItem = GObject.registerClass({ ++ Signals: { ++ 'edited': {}, ++ }, ++}, class EditableMenuItem extends PopupMenu.PopupBaseMenuItem { ++ _init() { ++ super._init({ ++ style_class: 'editable-menu-item', ++ }); ++ this.get_accessible()?.set_description(0, ++ _('Press %s to edit').format('e')); ++ ++ this._ornamentLabel.y_align = Clutter.ActorAlign.CENTER; ++ ++ const stack = new Shell.Stack({ ++ x_expand: true, ++ x_align: Clutter.ActorAlign.START, ++ }); ++ this.add_child(stack); ++ ++ this.label = new St.Label({ ++ style_class: 'label', ++ y_align: Clutter.ActorAlign.CENTER, ++ }); ++ stack.add_child(this.label); ++ this.label_actor = this.label; ++ ++ this._entry = new St.Entry({ ++ style_class: 'entry', ++ opacity: 0, ++ reactive: false, ++ }); ++ stack.add_child(this._entry); ++ ++ this.label.bind_property('text', ++ this._entry, 'text', ++ GObject.BindingFlags.DEFAULT); ++ ++ this._entry.clutter_text.connect('activate', ++ () => this._stopEditing()); ++ ++ this._editButton = new St.Button({ ++ style_class: 'icon-button flat', ++ child: new St.Icon({ ++ icon_name: 'document-edit-symbolic', ++ icon_size: 16, ++ }), ++ button_mask: St.ButtonMask.ONE, ++ toggle_mode: true, ++ x_align: Clutter.ActorAlign.END, ++ y_align: Clutter.ActorAlign.CENTER, ++ }); ++ this.add_child(this._editButton); ++ ++ this._editButton.connect('notify::checked', () => { ++ if (this._editButton.checked) { ++ this._editButton.child.icon_name = 'object-select-symbolic'; ++ this._startEditing(); ++ } else { ++ this._editButton.child.icon_name = 'document-edit-symbolic'; ++ this._stopEditing(); ++ } ++ }); ++ this.connect('key-release-event', (o, event) => { ++ if (event.get_key_symbol() === Clutter.KEY_e) ++ this._editButton.checked = true; ++ }); ++ ++ this._keyFocusId = global.stage.connect('notify::key-focus', () => { ++ const {keyFocus} = global.stage; ++ if (!keyFocus || !this.contains(keyFocus)) ++ this._stopEditing(); ++ }); ++ ++ this.connect('destroy', () => { ++ global.stage.disconnect(this._keyFocusId); ++ delete this._keyFocusId; ++ }); ++ } ++ ++ _switchActor(from, to) { ++ to.reactive = true; ++ to.ease({ ++ opacity: 255, ++ duration: 300, ++ mode: Clutter.AnimationMode.EASE_OUT_QUAD, ++ }); ++ ++ from.ease({ ++ opacity: 0, ++ duration: 300, ++ mode: Clutter.AnimationMode.EASE_OUT_QUAD, ++ onComplete: () => { ++ from.reactive = false; ++ }, ++ }); ++ } ++ ++ _startEditing() { ++ this._switchActor(this.label, this._entry); ++ ++ this._entry.clutter_text.set_selection(0, -1); ++ this._entry.clutter_text.grab_key_focus(); ++ } ++ ++ _stopEditing() { ++ if (this.label.text !== this._entry.text) { ++ this.label.text = this._entry.text; ++ this.emit('edited'); ++ } ++ ++ if (this._editButton.checked) ++ this._editButton.checked = false; ++ ++ this._switchActor(this._entry, this.label); ++ this.navigate_focus(this, St.DirectionType.TAB_FORWARD, false); ++ } ++}); ++ + class WorkspacesMenu extends PopupMenu.PopupMenu { + constructor(sourceActor) { + super(sourceActor, 0.5, St.Side.TOP); +@@ -447,12 +566,19 @@ class WorkspacesMenu extends PopupMenu.PopupMenu { + + const section = this._workspacesSection.actor; + while (section.get_n_children() < nWorkspaces) { +- const item = new PopupMenu.PopupMenuItem(''); ++ const item = new EditableMenuItem(); + item.connect('activate', (o, event) => { + const index = [...section].indexOf(item); + const workspace = workspaceManager.get_workspace_by_index(index); + workspace?.activate(event.get_time()); + }); ++ item.connect('edited', () => { ++ const nLabels = section.get_n_children(); ++ const oldNames = this._desktopSettings.get_strv('workspace-names'); ++ const newNames = [...section].map(c => c.label.text); ++ this._desktopSettings.set_strv('workspace-names', ++ [...newNames, ...oldNames.slice(nLabels)]); ++ }); + this._workspacesSection.addMenuItem(item); + } + +-- +2.50.0 + + +From 67b4ea20adda268c05a037ae189b8ac55c8e1e2b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Wed, 28 May 2025 21:04:36 +0200 +Subject: [PATCH 18/19] workspace-indicator: Remove workspace names from prefs + +Now that names can be changed from the extension itself, we no +longer need to expose them in the prefs dialog. + +Part-of: +--- + .../workspace-indicator/workspacePrefs.js | 183 +----------------- + 1 file changed, 1 insertion(+), 182 deletions(-) + +diff --git a/extensions/workspace-indicator/workspacePrefs.js b/extensions/workspace-indicator/workspacePrefs.js +index c5e311ef..f638b93d 100644 +--- a/extensions/workspace-indicator/workspacePrefs.js ++++ b/extensions/workspace-indicator/workspacePrefs.js +@@ -4,17 +4,13 @@ + // SPDX-License-Identifier: GPL-2.0-or-later + + /* exported WorkspacesPage */ +-const { Gio, GLib, GObject, Gtk, Pango } = imports.gi; ++const { Gio, GObject, Gtk, Pango } = imports.gi; + + const ExtensionUtils = imports.misc.extensionUtils; + const Me = ExtensionUtils.getCurrentExtension(); + + const Gettext = imports.gettext.domain(Me.metadata['gettext-domain']); + const _ = Gettext.gettext; +-const N_ = e => e; +- +-const WORKSPACE_SCHEMA = 'org.gnome.desktop.wm.preferences'; +-const WORKSPACE_KEY = 'workspace-names'; + + const PreferencesGroup = GObject.registerClass({ + Properties: { +@@ -378,182 +374,5 @@ class WorkspacesPage extends Gtk.ScrolledWindow { + + box.append(new GeneralGroup()); + box.append(new BehaviorGroup()); +- +- box.append(new Gtk.Label({ +- label: '%s'.format(_('Workspace Names')), +- use_markup: true, +- halign: Gtk.Align.START, +- })); +- +- this._list = new Gtk.ListBox({ +- selection_mode: Gtk.SelectionMode.NONE, +- valign: Gtk.Align.START, +- show_separators: true, +- }); +- this._list.connect('row-activated', (l, row) => row.edit()); +- box.append(this._list); +- +- const context = this._list.get_style_context(); +- const cssProvider = new Gtk.CssProvider(); +- cssProvider.load_from_data( +- 'list { min-width: 25em; }', -1); +- +- context.add_provider(cssProvider, +- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); +- context.add_class('frame'); +- +- this._list.append(new NewWorkspaceRow()); +- +- this._actionGroup = new Gio.SimpleActionGroup(); +- this._list.insert_action_group('workspaces', this._actionGroup); +- +- let action; +- action = new Gio.SimpleAction({ name: 'add' }); +- action.connect('activate', () => { +- const names = this._settings.get_strv(WORKSPACE_KEY); +- this._settings.set_strv(WORKSPACE_KEY, [ +- ...names, +- _('Workspace %d').format(names.length + 1), +- ]); +- }); +- this._actionGroup.add_action(action); +- +- action = new Gio.SimpleAction({ +- name: 'remove', +- parameter_type: new GLib.VariantType('s'), +- }); +- action.connect('activate', (a, param) => { +- const removed = param.deepUnpack(); +- this._settings.set_strv(WORKSPACE_KEY, +- this._settings.get_strv(WORKSPACE_KEY) +- .filter(name => name !== removed)); +- }); +- this._actionGroup.add_action(action); +- +- action = new Gio.SimpleAction({ name: 'update' }); +- action.connect('activate', () => { +- const names = this._getWorkspaceRows().map(row => row.name); +- this._settings.set_strv(WORKSPACE_KEY, names); +- }); +- this._actionGroup.add_action(action); +- +- this._settings = new Gio.Settings({ +- schema_id: WORKSPACE_SCHEMA, +- }); +- this._settings.connect(`changed::${WORKSPACE_KEY}`, +- this._sync.bind(this)); +- this._sync(); +- } +- +- _getWorkspaceRows() { +- return [...this._list].filter(row => row.name); +- } +- +- _sync() { +- const rows = this._getWorkspaceRows(); +- +- const oldNames = rows.map(row => row.name); +- const newNames = this._settings.get_strv(WORKSPACE_KEY); +- +- const removed = oldNames.filter(n => !newNames.includes(n)); +- const added = newNames.filter(n => !oldNames.includes(n)); +- +- removed.forEach(n => this._list.remove(rows.find(r => r.name === n))); +- added.forEach(n => { +- this._list.insert(new WorkspaceRow(n), newNames.indexOf(n)); +- }); +- } +-}); +- +-const WorkspaceRow = GObject.registerClass( +-class WorkspaceRow extends Gtk.ListBoxRow { +- _init(name) { +- super._init({ name }); +- +- const controller = new Gtk.ShortcutController(); +- controller.add_shortcut(new Gtk.Shortcut({ +- trigger: Gtk.ShortcutTrigger.parse_string('Escape'), +- action: Gtk.CallbackAction.new(this._stopEdit.bind(this)), +- })); +- this.add_controller(controller); +- +- const box = new Gtk.Box({ +- spacing: 12, +- margin_top: 6, +- margin_bottom: 6, +- margin_start: 6, +- margin_end: 6, +- }); +- +- const label = new Gtk.Label({ +- hexpand: true, +- xalign: 0, +- max_width_chars: 25, +- ellipsize: Pango.EllipsizeMode.END, +- }); +- this.bind_property('name', label, 'label', +- GObject.BindingFlags.SYNC_CREATE); +- box.append(label); +- +- const button = new Gtk.Button({ +- action_name: 'workspaces.remove', +- action_target: new GLib.Variant('s', name), +- icon_name: 'edit-delete-symbolic', +- }); +- box.append(button); +- +- this._entry = new Gtk.Entry({ +- max_width_chars: 25, +- }); +- +- this._stack = new Gtk.Stack(); +- this._stack.add_named(box, 'display'); +- this._stack.add_named(this._entry, 'edit'); +- this.child = this._stack; +- +- this._entry.connect('activate', () => { +- this.name = this._entry.text; +- this._stopEdit(); +- }); +- this._entry.connect('notify::has-focus', () => { +- if (this._entry.has_focus) +- return; +- this._stopEdit(); +- }); +- +- this.connect('notify::name', () => { +- button.action_target = new GLib.Variant('s', this.name); +- this.activate_action('workspaces.update', null); +- }); +- } +- +- edit() { +- this._entry.text = this.name; +- this._entry.grab_focus(); +- this._stack.visible_child_name = 'edit'; +- } +- +- _stopEdit() { +- this.grab_focus(); +- this._stack.visible_child_name = 'display'; +- } +-}); +- +-const NewWorkspaceRow = GObject.registerClass( +-class NewWorkspaceRow extends Gtk.ListBoxRow { +- _init() { +- super._init({ +- action_name: 'workspaces.add', +- child: new Gtk.Image({ +- icon_name: 'list-add-symbolic', +- pixel_size: 16, +- margin_top: 12, +- margin_bottom: 12, +- margin_start: 12, +- margin_end: 12, +- }), +- }); +- this.update_property( +- [Gtk.AccessibleProperty.LABEL], [_('Add Workspace')]); + } + }); +-- +2.50.0 + + +From 6664250dcca0dcde5967ceae49f61dd1f026ef11 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Florian=20M=C3=BCllner?= +Date: Fri, 30 May 2025 16:39:22 +0200 +Subject: [PATCH 19/19] window-list: Adjust to workspace-indicator changes + +Keep the `.panel-button` class to get the expected hover/focus/active +styling when using a regular menu button, but remove the horizontal +padding when using previews for fittsability. + +Part-of: +--- + extensions/window-list/extension.js | 6 ------ + extensions/window-list/stylesheet.css | 5 +++++ + 2 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js +index 477ed8fe..f0d7564f 100644 +--- a/extensions/window-list/extension.js ++++ b/extensions/window-list/extension.js +@@ -1531,12 +1531,6 @@ class WindowList extends St.Widget { + + const BottomWorkspaceIndicator = GObject.registerClass( + class BottomWorkspaceIndicator extends WorkspaceIndicator { +- _init(params) { +- super._init(params); +- +- this.remove_style_class_name('panel-button'); +- } +- + setMenu(menu) { + super.setMenu(menu); + +diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css +index 88ef0a25..ef9df230 100644 +--- a/extensions/window-list/stylesheet.css ++++ b/extensions/window-list/stylesheet.css +@@ -6,6 +6,11 @@ + */ + @import url("stylesheet-workspace-switcher-dark.css"); + ++.window-list-workspace-indicator.previews { ++ -natural-hpadding: 0 !important; ++ -minimum-hpadding: 0 !important; ++} ++ + .window-list { + spacing: 2px; + font-size: 10pt; +-- +2.50.0 + diff --git a/SOURCES/window-list-reordering.patch b/SOURCES/window-list-reordering.patch index 73ad855..459ae4a 100644 --- a/SOURCES/window-list-reordering.patch +++ b/SOURCES/window-list-reordering.patch @@ -1,4 +1,4 @@ -From 60b46c8d82dfbdcfdf54d3f022318637870a3756 Mon Sep 17 00:00:00 2001 +From 6f3e804a4910b43b55848d7bbe35916753c098c0 Mon Sep 17 00:00:00 2001 From: Jakub Steiner Date: Tue, 16 Jul 2024 09:40:53 +0200 Subject: [PATCH 01/24] window-list: Update styling @@ -17,7 +17,7 @@ Part-of: StWidget { -+ background-color: st-darken(#eee,5%); ++ background-color: #e1e1e1; +} - .bottom-panel .window-button.focused:hover > StWidget { - background-color: #e9e9e9; +.window-button:active > StWidget, +.window-button:focus > StWidget { -+ background-color: st-darken(#eee, 10%); ++ background-color: #d4d4d4; +} + +.window-button.focused > StWidget { -+ background-color: st-darken(#eee,15%); ++ background-color: #c7c7c7; +} + + .window-button.focused:hover > StWidget { -+ background-color: st-darken(#eee, 20%); ++ background-color: #bbb; } - .bottom-panel .window-button.minimized > StWidget { - color: #888; - box-shadow: none; + .window-button.focused:active > StWidget { -+ background-color: st-darken(#eee, 25%); ++ background-color: #aeaeae; } + +.window-button.minimized > StWidget { @@ -115,7 +115,7 @@ index d7ceb062..088c9478 100644 + background-color: #f9f9f9; +} diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css -index 4ba47f07..b9087971 100644 +index 4ba47f07..2a835a1b 100644 --- a/extensions/window-list/stylesheet.css +++ b/extensions/window-list/stylesheet.css @@ -1,3 +1,9 @@ @@ -187,7 +187,7 @@ index 4ba47f07..b9087971 100644 .window-button:active > StWidget, .window-button:focus > StWidget { - box-shadow: inset 2px 2px 4px rgba(255,255,255,0.5); -+ background-color: st-lighten(#303030, 5%); ++ background-color: #3c3c3c; } -.window-button.focused > StWidget, @@ -203,11 +203,11 @@ index 4ba47f07..b9087971 100644 - box-shadow: inset 2px 2px 4px rgba(255,255,255,0.7); -} + .window-button.focused:hover > StWidget { -+ background-color: st-lighten(#5b5b5b, 5%); ++ background-color: #676767; + } + + .window-button.focused:active > StWidget { -+ background-color: st-lighten(#5b5b5b, 10%); ++ background-color: #747474; + } .window-button.minimized > StWidget { @@ -285,10 +285,10 @@ index 017d844a..872c6afc 100644 .workspace-indicator-window-preview { -- -2.47.0 +2.49.0 -From b36d05f6d827a9063fb35a5120207718a2f30af1 Mon Sep 17 00:00:00 2001 +From 43bc977b5a0883707e6b326afa2424a96472f747 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 25 Sep 2024 03:36:08 +0200 Subject: [PATCH 02/24] window-list: Small stylesheet cleanup @@ -303,7 +303,7 @@ Part-of: StWidget { - background-color: st-darken(#eee,5%); + background-color: #e1e1e1; } -- -2.47.0 +2.49.0 -From ad30fc0976bface7944beacc276c4ca85961f0d0 Mon Sep 17 00:00:00 2001 +From 452acc5dec2e81530f30d5d55681f76670f12ddd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 25 Jun 2024 19:24:35 +0200 Subject: [PATCH 03/24] window-list: Don't use homogeneous layout @@ -378,10 +378,10 @@ index 688ca761..a59307e2 100644 let indicatorsBox = new St.BoxLayout({ x_align: Clutter.ActorAlign.END }); -- -2.47.0 +2.49.0 -From 987a526802bae4970cc41c7504f98b5ac568d62d Mon Sep 17 00:00:00 2001 +From 1a8a31bc63d2001359894f443706401c5df5dff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 18 Jun 2024 18:55:05 +0200 Subject: [PATCH 04/24] window-list: Don't hide window button while unmanaging @@ -427,10 +427,10 @@ index a59307e2..8ac59dd0 100644 global.display.disconnect(this._notifyFocusId); this._contextMenu.destroy(); -- -2.47.0 +2.49.0 -From 9d37d880dacb3a29c4976b5442128e7269048d0e Mon Sep 17 00:00:00 2001 +From a11b4ec2b7eaea3c02d7966459f7e680686d74a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 18 Jun 2024 18:59:38 +0200 Subject: [PATCH 05/24] window-list: Animate buttons in and out @@ -581,10 +581,10 @@ index 8ac59dd0..cb9e7160 100644 _monitorDrag() { -- -2.47.0 +2.49.0 -From 1f2213658f6d80ab7a9710dd5aa773499747efce Mon Sep 17 00:00:00 2001 +From d8a3b7c4604936eb4bef7ab51de3d5b32ea0e890 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 18 Jun 2024 20:08:56 +0200 Subject: [PATCH 06/24] window-list: Replace custom tooltip implementation @@ -636,10 +636,10 @@ index cb9e7160..0dd3775e 100644 if (this._longPressTimeoutId) return; -- -2.47.0 +2.49.0 -From 59d45cbef4ab701146325c46aea8bc6ffd13ca1f Mon Sep 17 00:00:00 2001 +From 761fe142b4ba63f8be725758ed73c2022938d098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Sat, 13 Jul 2024 00:11:19 +0200 Subject: [PATCH 07/24] window-list: Fix .focused styling @@ -673,10 +673,10 @@ index 0dd3775e..ec37f50f 100644 _windowEnteredOrLeftMonitor(_metaDisplay, _monitorIndex, _metaWindow) { -- -2.47.0 +2.49.0 -From ab1c5fc68916cbc2dff6302cb425f3afb4f4ea68 Mon Sep 17 00:00:00 2001 +From af63f529d679ebd0331d182c04ce393b54e9edcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 25 Sep 2024 02:23:41 +0200 Subject: [PATCH 08/24] window-list: Split out AppTitle class @@ -790,10 +790,10 @@ index ec37f50f..e778a4d4 100644 this.app.disconnect(this._windowsChangedId); this._menu.destroy(); -- -2.47.0 +2.49.0 -From c2cd38942205b33920002d35f347f1051501ccbe Mon Sep 17 00:00:00 2001 +From 9b7b6d0f4f7ed077738ae3be2c08ff4c0d52e402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 25 Sep 2024 02:55:14 +0200 Subject: [PATCH 09/24] window-list: Simplify app button @@ -909,10 +909,10 @@ index e778a4d4..f4434afa 100644 _onClicked(actor, button) { -- -2.47.0 +2.49.0 -From beadfe2a6f6a7627096cad5a2161add902edf039 Mon Sep 17 00:00:00 2001 +From 904be2f12f75eda75d85426f054b06b26e422a72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Mon, 7 Oct 2024 17:22:04 +0200 Subject: [PATCH 10/24] window-list: Fix minimized styling @@ -947,10 +947,10 @@ index f4434afa..6c00686c 100644 _windowEnteredOrLeftMonitor(metaDisplay, monitorIndex, metaWindow) { -- -2.47.0 +2.49.0 -From 77a1b57678e62ad091e09d5e97299d53999a3521 Mon Sep 17 00:00:00 2001 +From 29013aca96261a1ba5c87310bdb391f75a8b801e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Mon, 7 Oct 2024 17:10:43 +0200 Subject: [PATCH 11/24] window-list: Fix active state @@ -982,10 +982,10 @@ index 6c00686c..936dd9e4 100644 // eslint-disable-next-line camelcase -- -2.47.0 +2.49.0 -From 8ab9ab5cc43ccea7a3208b72e08f32685584c869 Mon Sep 17 00:00:00 2001 +From 7e8255f99b49a373bd93203567acfe895b852245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 15 Oct 2024 17:48:52 +0200 Subject: [PATCH 12/24] window-list: Remove outdated style @@ -1001,7 +1001,7 @@ with notification styling, so stop doing that. 1 file changed, 4 deletions(-) diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css -index b9087971..f02fca60 100644 +index 2a835a1b..99d47e32 100644 --- a/extensions/window-list/stylesheet.css +++ b/extensions/window-list/stylesheet.css @@ -81,7 +81,3 @@ @@ -1013,10 +1013,10 @@ index b9087971..f02fca60 100644 - font-weight: normal; -} -- -2.47.0 +2.49.0 -From 807da4082a3a78789ab4926fd1074a8040f5d794 Mon Sep 17 00:00:00 2001 +From 7bb47650a0c80a7950aa7f87a93543125009ec53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 26 Sep 2024 19:07:11 +0200 Subject: [PATCH 13/24] window-list: Split out some common code @@ -1067,10 +1067,10 @@ index 936dd9e4..d92a4155 100644 _removeWindow(win) { -- -2.47.0 +2.49.0 -From e10c1fd24bc86c7d980f50efd9e663b42097d2f1 Mon Sep 17 00:00:00 2001 +From 0b4da110e6539e209cf2ea75533e22b9d1a970ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 3 Oct 2024 17:19:31 +0200 Subject: [PATCH 14/24] window-list: Split out common TitleWidget class @@ -1183,10 +1183,10 @@ index d92a4155..69058fcd 100644 this.connect('destroy', this._onDestroy.bind(this)); -- -2.47.0 +2.49.0 -From e29fb2e04541157a6233b702588a3d206ad68615 Mon Sep 17 00:00:00 2001 +From a4373e1ceac4955325da97ce2deb9d7f2c8714d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 3 Oct 2024 17:27:57 +0200 Subject: [PATCH 15/24] window-list: Add TitleWidget:abstract-label property @@ -1241,7 +1241,7 @@ index 69058fcd..fc47d2e6 100644 }); diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css -index f02fca60..fce6bcc5 100644 +index 99d47e32..ee500299 100644 --- a/extensions/window-list/stylesheet.css +++ b/extensions/window-list/stylesheet.css @@ -81,3 +81,9 @@ @@ -1255,10 +1255,10 @@ index f02fca60..fce6bcc5 100644 + margin: 6px; +} -- -2.47.0 +2.49.0 -From e0a5584a79d938d649c17b54267bfb83d547f984 Mon Sep 17 00:00:00 2001 +From 0fb4950e013eea7513029e9a5f18e602c0925dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 25 Sep 2024 03:20:52 +0200 Subject: [PATCH 16/24] window-list: Split out `_createTitleActor()` hook @@ -1340,10 +1340,10 @@ index fc47d2e6..a65e2108 100644 let menuWasOpen = this._menu.isOpen; if (menuWasOpen) -- -2.47.0 +2.49.0 -From 75e0bbd671101dea9803d3fdcfe10d67e5f71e5d Mon Sep 17 00:00:00 2001 +From 3047fdf423f395ac677d1184a8a71680563635f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 19 Jun 2024 13:01:37 +0200 Subject: [PATCH 17/24] window-list: Rename XDND related methods and props @@ -1407,10 +1407,10 @@ index a65e2108..263a2af8 100644 Main.xdndHandler.disconnect(this._dragEndId); -- -2.47.0 +2.49.0 -From 4ae3577e50907cdf0f257fd559475b1decdf4af0 Mon Sep 17 00:00:00 2001 +From 41888462f1675a1f9ce8abbdac5c66e154c24432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 25 Sep 2024 04:13:25 +0200 Subject: [PATCH 18/24] window-list: Allow rearranging window buttons @@ -1430,7 +1430,7 @@ Closes https://gitlab.gnome.org/GNOME/gnome-shell-extensions/issues/4 3 files changed, 157 insertions(+), 2 deletions(-) diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css -index 3a6ffd02..74945657 100644 +index 63e5e48c..a43f11cf 100644 --- a/extensions/window-list/classic.css +++ b/extensions/window-list/classic.css @@ -56,3 +56,8 @@ @@ -1653,7 +1653,7 @@ index 263a2af8..574c85ac 100644 DND.addDragMonitor(this._xdndDragMonitor); } diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css -index fce6bcc5..c92081d2 100644 +index ee500299..afa1aaf0 100644 --- a/extensions/window-list/stylesheet.css +++ b/extensions/window-list/stylesheet.css @@ -17,10 +17,19 @@ @@ -1688,10 +1688,10 @@ index fce6bcc5..c92081d2 100644 max-width: 18.75em; } -- -2.47.0 +2.49.0 -From 324236e9f4ba7a1ca743c0a432b246dfc9216001 Mon Sep 17 00:00:00 2001 +From 1175589f3e0a11ffda5460259a5fac161b79b864 Mon Sep 17 00:00:00 2001 From: Jakub Steiner Date: Thu, 3 Oct 2024 14:18:32 +0200 Subject: [PATCH 19/24] window-list: Indicate drop target more prominently @@ -1704,7 +1704,7 @@ its styling more prominent. 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/extensions/window-list/classic.css b/extensions/window-list/classic.css -index 74945657..1147984c 100644 +index a43f11cf..81b161c9 100644 --- a/extensions/window-list/classic.css +++ b/extensions/window-list/classic.css @@ -23,7 +23,6 @@ @@ -1724,7 +1724,7 @@ index 74945657..1147984c 100644 + border-color: rgba(0,0,0,0.5); +} diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css -index c92081d2..4c06ebc0 100644 +index afa1aaf0..24747442 100644 --- a/extensions/window-list/stylesheet.css +++ b/extensions/window-list/stylesheet.css @@ -56,6 +56,12 @@ @@ -1741,10 +1741,10 @@ index c92081d2..4c06ebc0 100644 background-color: #303030; } -- -2.47.0 +2.49.0 -From 5b35516962e6c326f9ae4236a798b6e521d0c850 Mon Sep 17 00:00:00 2001 +From 9117f214d2ccf8cd7d88c7dca44127349eca2fb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Thu, 3 Oct 2024 17:05:42 +0200 Subject: [PATCH 20/24] window-list: Fade out drag source during drag @@ -1793,10 +1793,10 @@ index 574c85ac..5aca473c 100644 this._clearDragPlaceholder(); }); -- -2.47.0 +2.49.0 -From bfbb54b4c903ec41f61748868d5f175ad469d811 Mon Sep 17 00:00:00 2001 +From 8a43b5dfe8fa5c6e896480c10b69fa51aedbaccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 9 Oct 2024 19:15:16 +0200 Subject: [PATCH 21/24] window-list: Shrink drag-actor size during drags @@ -1872,10 +1872,10 @@ index 5aca473c..2d5ce525 100644 getDragActorSource() { -- -2.47.0 +2.49.0 -From be721d3fee4faf5060dcf1a83fa5adc8e7ee5f89 Mon Sep 17 00:00:00 2001 +From a69401b07fa2e01932b847fdb3704755710e6c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 8 Oct 2024 19:25:53 +0200 Subject: [PATCH 22/24] window-list: Handle DND events near the drop target @@ -1942,10 +1942,10 @@ index 2d5ce525..b6c00f8b 100644 DND.addDragMonitor(this._xdndDragMonitor); } -- -2.47.0 +2.49.0 -From 66672ca11281deb9326dd164759db749263c143c Mon Sep 17 00:00:00 2001 +From b3dcf28250968bd6f3e1ddbab52ea9be768ad168 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Wed, 26 Jun 2024 00:58:18 +0200 Subject: [PATCH 23/24] window-list: Add `id` property to buttons @@ -1983,10 +1983,10 @@ index b6c00f8b..feefc66e 100644 if (this._windowTracker.get_window_app(metaWindow) === this.app && monitorIndex === this._monitorIndex) { -- -2.47.0 +2.49.0 -From 6f11b79c65085a49e6907571ad51f972c1579685 Mon Sep 17 00:00:00 2001 +From 9344fce65ca3b8705f05cc55395b2cd002a5dd83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Tue, 24 Sep 2024 20:31:06 +0200 Subject: [PATCH 24/24] window-list: Save and restore positions as runtime @@ -2061,5 +2061,5 @@ index feefc66e..bb9ca80f 100644 DND.addDragMonitor(this._itemDragMonitor); } -- -2.47.0 +2.49.0 diff --git a/SPECS/gnome-shell-extensions.spec b/SPECS/gnome-shell-extensions.spec index 2faf43e..1905a64 100644 --- a/SPECS/gnome-shell-extensions.spec +++ b/SPECS/gnome-shell-extensions.spec @@ -7,7 +7,7 @@ Name: gnome-shell-extensions Version: 40.7 -Release: 25%{?dist} +Release: 28%{?dist} Summary: Modify and extend GNOME Shell functionality and behavior License: GPLv2+ @@ -52,6 +52,8 @@ Patch029: 0001-workspace-indicator-Re-fittsify-workspace-previews.patch Patch030: window-list-reordering.patch Patch031: 0001-dash-to-panel-Remove-faulty-version-check.patch Patch032: window-list-attention-indicator.patch +Patch033: 0001-dash-to-panel-Stop-messing-with-overview-allocation.patch +Patch034: improve-workspace-names.patch %description GNOME Shell Extensions is a collection of extensions providing additional and @@ -471,6 +473,18 @@ workspaces. %changelog +* Mon Jun 30 2025 Florian Müllner - 40.7-28 +- Make workspace names more prominent + Resolves: RHEL-96218 + +* Mon Jun 09 2025 Florian Müllner - 40.7-27 +- Fix window-list styling + Resolves: RHEL-95787 + +* Mon May 05 2025 Florian Müllner - 40.7-26 +- Stop overriding gnome-shell's overview allocation + Resolves: RHEL-70892 + * Wed Jan 08 2025 Florian Müllner - 40.7-25 - Indicate urgency-hint in window-list Resolves: RHEL-73146