Compare commits

...

No commits in common. "c8" and "c8-beta" have entirely different histories.
c8 ... c8-beta

11 changed files with 9 additions and 8188 deletions

View File

@ -1,49 +0,0 @@
From d418620dd765a3b13fd6445e29efe5a375f3734c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 29 Apr 2025 12:22:38 +0200
Subject: [PATCH] dash-to-panel: Consider range around edges for dwelling
Rather than only reacting on a single pixel, unhide the dock when
within 5 pixels of the edge (when not using pressure barriers).
---
extensions/dash-to-panel/intellihide.js | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/extensions/dash-to-panel/intellihide.js b/extensions/dash-to-panel/intellihide.js
index 8fb1e976..6649d4a6 100644
--- a/extensions/dash-to-panel/intellihide.js
+++ b/extensions/dash-to-panel/intellihide.js
@@ -38,6 +38,8 @@ const CHECK_GRAB_MS = 400;
const POST_ANIMATE_MS = 50;
const MIN_UPDATE_MS = 250;
+const DWELL_RANGE = 5;
+
//timeout names
const T1 = 'checkGrabTimeout';
const T2 = 'limitUpdateTimeout';
@@ -282,10 +284,10 @@ var Intellihide = Utils.defineClass({
let position = this._dtpPanel.geom.position;
if (!this._panelBox.hover && !Main.overview.visible &&
- ((position == St.Side.TOP && y <= this._monitor.y + 1) ||
- (position == St.Side.BOTTOM && y >= this._monitor.y + this._monitor.height - 1) ||
- (position == St.Side.LEFT && x <= this._monitor.x + 1) ||
- (position == St.Side.RIGHT && x >= this._monitor.x + this._monitor.width - 1)) &&
+ ((position == St.Side.TOP && y <= this._monitor.y + DWELL_RANGE) ||
+ (position == St.Side.BOTTOM && y >= this._monitor.y + this._monitor.height - DWELL_RANGE) ||
+ (position == St.Side.LEFT && x <= this._monitor.x + DWELL_RANGE) ||
+ (position == St.Side.RIGHT && x >= this._monitor.x + this._monitor.width - DWELL_RANGE)) &&
((x >= this._monitor.x && x < this._monitor.x + this._monitor.width) &&
(y >= this._monitor.y && y < this._monitor.y + this._monitor.height))) {
this._queueUpdatePanelPosition(true);
@@ -398,4 +400,4 @@ var Intellihide = Utils.defineClass({
this._hoveredOut = false;
},
-});
\ No newline at end of file
+});
--
2.50.1

View File

@ -1,114 +0,0 @@
From 7b6dbfdd727ce5a5b593394893489bafc02ccea6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 25 Sep 2025 14:18:03 +0200
Subject: [PATCH] dash-to-panel: Don't create main panel without a monitor
---
extensions/dash-to-panel/extension.js | 5 ++--
extensions/dash-to-panel/panelManager.js | 35 +++++++++++++++++-------
2 files changed, 28 insertions(+), 12 deletions(-)
diff --git a/extensions/dash-to-panel/extension.js b/extensions/dash-to-panel/extension.js
index 8ab108f2..8ffff041 100644
--- a/extensions/dash-to-panel/extension.js
+++ b/extensions/dash-to-panel/extension.js
@@ -111,7 +111,8 @@ function _enable() {
// Pretend I'm the dash: meant to make appgrd swarm animation come from the
// right position of the appShowButton.
oldDash = Main.overview._dash;
- Main.overview._dash = panelManager.primaryPanel.taskbar;
+ if (panelManager.primaryPanel)
+ Main.overview._dash = panelManager.primaryPanel.taskbar;
}
function disable(reset) {
@@ -141,4 +142,4 @@ function disable(reset) {
(extensionSystem._callExtensionEnable || extensionSystem.enableExtension).call(extensionSystem, UBUNTU_DOCK_UUID);
}
}
-}
\ No newline at end of file
+}
diff --git a/extensions/dash-to-panel/panelManager.js b/extensions/dash-to-panel/panelManager.js
index 20ee12d8..87a85504 100755
--- a/extensions/dash-to-panel/panelManager.js
+++ b/extensions/dash-to-panel/panelManager.js
@@ -73,16 +73,20 @@ var dtpPanelManager = Utils.defineClass({
enable: function(reset) {
let dtpPrimaryIndex = Me.settings.get_int('primary-monitor');
+ this.allPanels = [];
this.dtpPrimaryMonitor = Main.layoutManager.monitors[dtpPrimaryIndex] || Main.layoutManager.primaryMonitor;
this.proximityManager = new Proximity.ProximityManager();
Utils.wrapActor(Main.panel);
Utils.wrapActor(Main.overview.dash || 0);
- this.primaryPanel = this._createPanel(this.dtpPrimaryMonitor, Me.settings.get_boolean('stockgs-keep-top-panel'));
- this.allPanels = [ this.primaryPanel ];
-
- this.overview.enable(this.primaryPanel);
+ if (this.dtpPrimaryMonitor) {
+ this.primaryPanel = this._createPanel(this.dtpPrimaryMonitor, Me.settings.get_boolean('stockgs-keep-top-panel'));
+ this.allPanels.push(this.primaryPanel);
+ this.overview.enable(this.primaryPanel);
+
+ this.setFocusedMonitor(this.dtpPrimaryMonitor);
+ }
if (Me.settings.get_boolean('multi-monitors')) {
Main.layoutManager.monitors.filter(m => m != this.dtpPrimaryMonitor).forEach(m => {
@@ -121,18 +125,20 @@ var dtpPanelManager = Utils.defineClass({
}
this._updatePanelElementPositions();
- this.setFocusedMonitor(this.dtpPrimaryMonitor);
- if (this.primaryPanel.checkIfVertical()) {
+ if (this.primaryPanel && this.primaryPanel.checkIfVertical()) {
Main.wm._getPositionForDirection = newGetPositionForDirection;
}
if (reset) return;
this._oldViewSelectorAnimateIn = Main.overview.viewSelector._animateIn;
- Main.overview.viewSelector._animateIn = Lang.bind(this.primaryPanel, newViewSelectorAnimateIn);
this._oldViewSelectorAnimateOut = Main.overview.viewSelector._animateOut;
- Main.overview.viewSelector._animateOut = Lang.bind(this.primaryPanel, newViewSelectorAnimateOut);
+
+ if (this.primaryPanel) {
+ Main.overview.viewSelector._animateIn = Lang.bind(this.primaryPanel, newViewSelectorAnimateIn);
+ Main.overview.viewSelector._animateOut = Lang.bind(this.primaryPanel, newViewSelectorAnimateOut);
+ }
if (Config.PACKAGE_VERSION > '3.35.1') {
this._oldDoSpringAnimation = AppDisplay.BaseAppView.prototype._doSpringAnimation;
@@ -265,14 +271,23 @@ var dtpPanelManager = Utils.defineClass({
);
Panel.panelBoxes.forEach(c => this._signalsHandler.add(
- [Main.panel[c], 'actor-added', (parent, child) => this._adjustPanelMenuButton(this._getPanelMenuButton(child), this.primaryPanel.monitor, this.primaryPanel.getPosition())]
+ [
+ Main.panel[c],
+ 'actor-added',
+ (parent, child) => {
+ if (this.primaryPanel)
+ this._adjustPanelMenuButton(this._getPanelMenuButton(child),
+ this.primaryPanel.monitor, this.primaryPanel.getPosition());
+ }
+ ]
));
this._setKeyBindings(true);
},
disable: function(reset) {
- this.overview.disable();
+ if (this.primaryPanel)
+ this.overview.disable();
this.proximityManager.destroy();
this.allPanels.forEach(p => {
--
2.51.0

View File

@ -1,42 +0,0 @@
From f65b9f2df5bf913f8c152ea770795d2cdcb14c6a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 7 Jan 2025 19:09:01 +0100
Subject: [PATCH] desktop-icons: Fix '%k' in .desktop files
In order to support Link-type .desktop files, we load the file
ourselves, and then create the AppInfo from the loaded keyfile
to avoid reading the file twice.
Unfortunately that means that the AppInfo loses the filename
information, which is necessary to substitute the '%k' macro.
In order to support both the macro and Link-type .desktop files,
we have to take the hit and let GIO read the file again.
---
extensions/desktop-icons/fileItem.js | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/extensions/desktop-icons/fileItem.js b/extensions/desktop-icons/fileItem.js
index 1c9a1e55..c765967b 100644
--- a/extensions/desktop-icons/fileItem.js
+++ b/extensions/desktop-icons/fileItem.js
@@ -241,13 +241,14 @@ var FileItem = class {
if (this._isDesktopFile) {
try {
const keyFile = new GLib.KeyFile();
- keyFile.load_from_file(this._file.get_path(), GLib.KeyFileFlags.NONE);
+ const path = this._file.get_path();
+ keyFile.load_from_file(path, GLib.KeyFileFlags.NONE);
const type = keyFile.get_string(
GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_TYPE);
switch (type) {
case GLib.KEY_FILE_DESKTOP_TYPE_APPLICATION:
- this._desktopFile = Gio.DesktopAppInfo.new_from_keyfile(keyFile);
+ this._desktopFile = Gio.DesktopAppInfo.new_from_filename(path);
if (!this._desktopFile) {
log(`Couldnt parse ${this._displayName} as a desktop file, will treat it as a regular file.`);
this._isValidDesktopFile = false;
--
2.47.1

View File

@ -1,215 +0,0 @@
From 735602e7d3cfea688f741082d8cd8abb97c6b0d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 19 Mar 2026 16:07:46 +0100
Subject: [PATCH 1/3] desktop-icons: Always add icons when backgrounds are
updated
We currently assume that backgrounds are only updated when the
monitor setup changed, so we explicitly track that.
However backgrounds may be updated for other reasons as well (for
example when enabling the custom-menu extension).
So instead of making assumptions about when updateBackgrounds()
is called, hook into the function itself to recreate the icons
whenever the backgrounds are updated.
---
extensions/desktop-icons/desktopManager.js | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/extensions/desktop-icons/desktopManager.js b/extensions/desktop-icons/desktopManager.js
index 84bd79ce..80633901 100644
--- a/extensions/desktop-icons/desktopManager.js
+++ b/extensions/desktop-icons/desktopManager.js
@@ -45,6 +45,8 @@ const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;
var S_IWOTH = 0x00002;
+let updateBackgroundsOrig = null;
+
function getDpy() {
return global.screen || global.display;
}
@@ -96,7 +98,12 @@ var DesktopManager = GObject.registerClass({
this._writableByOthers = null;
this._rubberBandActive = false;
- this._monitorsChangedId = Main.layoutManager.connect('monitors-changed', () => this._recreateDesktopIcons());
+ updateBackgroundsOrig = Main.layoutManager._updateBackgrounds;
+ Main.layoutManager._updateBackgrounds = () => {
+ updateBackgroundsOrig.call(Main.layoutManager);
+ this._recreateDesktopIcons();
+ };
+
this._rubberBand = new St.Widget({ style_class: 'rubber-band' });
this._rubberBand.hide();
Main.layoutManager._backgroundGroup.add_child(this._rubberBand);
@@ -778,6 +785,8 @@ var DesktopManager = GObject.registerClass({
}
destroy() {
+ Main.layoutManager._updateBackgrounds = updateBackgroundsOrig;
+
if (this._monitorDesktopDir)
this._monitorDesktopDir.cancel();
this._monitorDesktopDir = null;
@@ -797,9 +806,6 @@ var DesktopManager = GObject.registerClass({
GLib.source_remove(this._deleteChildrenId);
this._deleteChildrenId = 0;
- if (this._monitorsChangedId)
- Main.layoutManager.disconnect(this._monitorsChangedId);
- this._monitorsChangedId = 0;
if (this._stageReleaseEventId)
global.stage.disconnect(this._stageReleaseEventId);
this._stageReleaseEventId = 0;
--
2.53.0
From bd110b928c8343e9b595cf38b97e9bc07d209879 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 19 Mar 2026 16:40:23 +0100
Subject: [PATCH 2/3] desktop-icons: Merge custom-menu entries into desktop
background menu
When both the desktop-icons and custom-menu extensions are enabled,
the desktop-icons extension creates its own right-click context menu
for the desktop background, bypassing the BackgroundMenu mechanism
that custom-menu hooks into. This causes the custom-menu entries to
be completely hidden when desktop-icons is active.
This patch adds integration between the two extensions: when the
desktop background menu is created in desktop-icons, it checks if
the custom-menu extension is enabled. If so, it reads the user's
custom menu configuration (~/.entries.json) and appends those entries
below a separator at the bottom of the desktop-icons context menu.
The integration is non-intrusive:
- If custom-menu is not enabled, no changes are visible
- If ~/.entries.json does not exist or is invalid, the menu
remains unchanged (errors are logged)
- Only affects the desktop background right-click menu, not
file icon context menus
Resolves: RHEL-136187
---
extensions/desktop-icons/desktopGrid.js | 30 +++++++++++++++++++++++++
1 file changed, 30 insertions(+)
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
index bd27e2ab..f0509595 100644
--- a/extensions/desktop-icons/desktopGrid.js
+++ b/extensions/desktop-icons/desktopGrid.js
@@ -49,6 +49,8 @@ const Gettext = imports.gettext.domain('gnome-shell-extensions');
const _ = Gettext.gettext;
+const CUSTOM_MENU_UUID = 'custom-menu@gnome-shell-extensions.gcampax.github.com';
+const CUSTOM_MENU_CONFIG = '/.entries.json';
/* From NautilusFileUndoManagerState */
var UndoStatus = {
@@ -319,6 +321,32 @@ var DesktopGrid = class {
this._syncUndoRedo();
}
+ _appendCustomMenuEntries(menu) {
+ const ext = Main.extensionManager.lookup(CUSTOM_MENU_UUID);
+ if (!ext || ext.state !== ExtensionUtils.ExtensionState.ENABLED)
+ return;
+
+ const CustomMenuConfig = ext.imports.config;
+ const configLoader = new CustomMenuConfig.Loader();
+
+ try {
+ configLoader.loadConfig(GLib.get_home_dir() + CUSTOM_MENU_CONFIG);
+ } catch (e) {
+ log('desktop-icons: Error loading custom menu entries: ' + e.message);
+ return;
+ }
+
+ if (configLoader.entries.length === 0)
+ return;
+
+ menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
+
+ for (let i in configLoader.entries) {
+ const item = configLoader.entries[i].createItem();
+ menu.addMenuItem(item);
+ }
+ }
+
_createDesktopBackgroundMenu() {
let menu = new PopupMenu.PopupMenu(Main.layoutManager.dummyCursor,
0, St.Side.TOP);
@@ -361,6 +389,8 @@ var DesktopGrid = class {
);
this._pasteMenuItem.setSensitive(false);
+ this._appendCustomMenuEntries(menu);
+
return menu;
}
--
2.53.0
From b37776779b713b19129a664cfc913488bdff0226 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 19 Mar 2026 16:32:51 +0100
Subject: [PATCH 3/3] desktop-icons: Recreate desktop menu on custom-menu
changes
We now add custom menu entries to the background menu when the custom-menu
extension is enabled. That means that the menu contents now depend on
the extension state, so we should make sure to update the menu as
necessary.
---
extensions/desktop-icons/desktopGrid.js | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/extensions/desktop-icons/desktopGrid.js b/extensions/desktop-icons/desktopGrid.js
index f0509595..2457d0c7 100644
--- a/extensions/desktop-icons/desktopGrid.js
+++ b/extensions/desktop-icons/desktopGrid.js
@@ -131,6 +131,14 @@ var DesktopGrid = class {
this._grid.connect('key-press-event', this._onKeyPress.bind(this));
this._grid.connect('allocation-changed', () => Extension.desktopManager.scheduleReLayoutChildren());
+
+ this._extensionStateChangedId =
+ Main.extensionManager.connect('extension-state-changed', (mgr, ext) => {
+ // the custom-menu extension influences the menu contents when enabled,
+ // so recreate the menu on state changes
+ if (ext.uuid === CUSTOM_MENU_UUID)
+ this._addDesktopBackgroundMenu();
+ });
}
_onKeyPress(actor, event) {
@@ -194,6 +202,10 @@ var DesktopGrid = class {
this._bgManager.backgroundActor.disconnect(this._bgDestroyedId);
this._bgDestroyedId = 0;
this._bgManager = null;
+
+ if (this._extensionStateChangedId)
+ Main.extensionManager.disconnect(this._extensionStateChangedId);
+ this._extensionStateChangedId = 0;
}
_onNewFolderClicked() {
@@ -557,6 +569,9 @@ var DesktopGrid = class {
}
_addDesktopBackgroundMenu() {
+ if (this.actor._desktopBackgroundMenu)
+ this.actor._desktopBackgroundMenu.destroy();
+
this.actor._desktopBackgroundMenu = this._createDesktopBackgroundMenu();
this.actor._desktopBackgroundManager = new PopupMenu.PopupMenuManager({ actor: this.actor });
this.actor._desktopBackgroundManager.addMenu(this.actor._desktopBackgroundMenu);
--
2.53.0

View File

@ -1,4 +1,4 @@
From b87a0085342b9828e7e57e8db892b79e345bfbc3 Mon Sep 17 00:00:00 2001 From 1f9f4af38f991b462ee5f872a697d88a9e115499 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org> From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 Jan 2021 20:18:39 +0100 Date: Wed, 20 Jan 2021 20:18:39 +0100
Subject: [PATCH 1/2] workspace-indicator: Add tooltips to workspace thumbnails Subject: [PATCH 1/2] workspace-indicator: Add tooltips to workspace thumbnails
@ -11,7 +11,7 @@ those, so expose them as tooltip on hover.
1 file changed, 40 insertions(+) 1 file changed, 40 insertions(+)
diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js diff --git a/extensions/workspace-indicator/extension.js b/extensions/workspace-indicator/extension.js
index 69eef88c..d377f288 100644 index 69eef88c..b10e37ff 100644
--- a/extensions/workspace-indicator/extension.js --- a/extensions/workspace-indicator/extension.js
+++ b/extensions/workspace-indicator/extension.js +++ b/extensions/workspace-indicator/extension.js
@@ -8,6 +8,7 @@ const ExtensionUtils = imports.misc.extensionUtils; @@ -8,6 +8,7 @@ const ExtensionUtils = imports.misc.extensionUtils;
@ -72,7 +72,7 @@ index 69eef88c..d377f288 100644
+ +
+ Tweener.addTween(this._tooltip, { + Tweener.addTween(this._tooltip, {
+ opacity: this.hover ? 255 : 0, + opacity: this.hover ? 255 : 0,
+ time: TOOLTIP_ANIMATION_TIME / 1000, + time: TOOLTIP_ANIMATION_TIME * 1000,
+ transition: 'easeOutQuad', + transition: 'easeOutQuad',
+ onComplete: () => (this._tooltip.visible = this.hover), + onComplete: () => (this._tooltip.visible = this.hover),
+ }); + });
@ -85,10 +85,10 @@ index 69eef88c..d377f288 100644
this._workspace.disconnect(this._windowRemovedId); this._workspace.disconnect(this._windowRemovedId);
global.display.disconnect(this._restackedId); global.display.disconnect(this._restackedId);
-- --
2.44.0 2.31.1
From 36f2762c8c6cda512f164ea22b62d10d03a369b6 Mon Sep 17 00:00:00 2001 From 19e19e11214b6b9deae110cd6a4c9232d77c18cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org> From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 20 Jan 2021 20:29:01 +0100 Date: Wed, 20 Jan 2021 20:29:01 +0100
Subject: [PATCH 2/2] window-list: Add tooltips to workspace thumbnails Subject: [PATCH 2/2] window-list: Add tooltips to workspace thumbnails
@ -101,7 +101,7 @@ expose them as tooltip on hover.
1 file changed, 40 insertions(+) 1 file changed, 40 insertions(+)
diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js diff --git a/extensions/window-list/workspaceIndicator.js b/extensions/window-list/workspaceIndicator.js
index ca476111..8ae9b288 100644 index ca476111..33ec9b0e 100644
--- a/extensions/window-list/workspaceIndicator.js --- a/extensions/window-list/workspaceIndicator.js
+++ b/extensions/window-list/workspaceIndicator.js +++ b/extensions/window-list/workspaceIndicator.js
@@ -5,10 +5,14 @@ const DND = imports.ui.dnd; @@ -5,10 +5,14 @@ const DND = imports.ui.dnd;
@ -159,7 +159,7 @@ index ca476111..8ae9b288 100644
+ +
+ Tweener.addTween(this._tooltip, { + Tweener.addTween(this._tooltip, {
+ opacity: this.hover ? 255 : 0, + opacity: this.hover ? 255 : 0,
+ time: TOOLTIP_ANIMATION_TIME / 1000, + time: TOOLTIP_ANIMATION_TIME * 1000,
+ transition: 'easeOutQuad', + transition: 'easeOutQuad',
+ onComplete: () => (this._tooltip.visible = this.hover), + onComplete: () => (this._tooltip.visible = this.hover),
+ }); + });
@ -172,5 +172,5 @@ index ca476111..8ae9b288 100644
this._workspace.disconnect(this._windowRemovedId); this._workspace.disconnect(this._windowRemovedId);
global.display.disconnect(this._restackedId); global.display.disconnect(this._restackedId);
-- --
2.44.0 2.31.1

View File

@ -1,188 +0,0 @@
From c32e7e78fbb310ac79e2aa1638d0ef50eb08a41c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 23 Nov 2023 21:08:31 +0100
Subject: [PATCH 1/3] apps-menu: Use stylesheet to set width
The `style` property is useful for computed CSS declarations,
but for regular styling the stylesheet is preferable.
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/290>
---
extensions/apps-menu/extension.js | 1 -
extensions/apps-menu/stylesheet.css | 2 ++
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index 1de00df3..3c8c1c9d 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -617,7 +617,6 @@ class ApplicationsButton extends PanelMenu.Button {
_display() {
this._applicationsButtons.clear();
- this.mainBox.style = 'width: 35em;';
this.mainBox.hide();
//Load categories
diff --git a/extensions/apps-menu/stylesheet.css b/extensions/apps-menu/stylesheet.css
index 5bd0d29e..e6d8d8a9 100644
--- a/extensions/apps-menu/stylesheet.css
+++ b/extensions/apps-menu/stylesheet.css
@@ -1,3 +1,5 @@
+.apps-menu {width: 26em;}
+
.apps-menu:ltr {
padding-right: 3px;
}
--
2.43.0
From c6e7573d84dfc5f7850f90220935107ac4027888 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 23 Nov 2023 15:38:25 +0100
Subject: [PATCH 2/3] apps-menu: Remove vertical separator
Ever since gnome-shell stopped using a stippled separator in the
calendar menu, the styling required by the separator has been
missing.
There haven't been any complaints about the invisible separator,
so we can just as well drop it altogether.
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/290>
---
extensions/apps-menu/extension.js | 29 -----------------------------
1 file changed, 29 deletions(-)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index 3c8c1c9d..34fb24cf 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -425,15 +425,6 @@ class ApplicationsButton extends PanelMenu.Button {
}
}
- _createVertSeparator() {
- let separator = new St.DrawingArea({
- style_class: 'calendar-vertical-separator',
- pseudo_class: 'highlighted'
- });
- separator.connect('repaint', this._onVertSepRepaint.bind(this));
- return separator;
- }
-
_onDestroy() {
super._onDestroy();
@@ -464,21 +455,6 @@ class ApplicationsButton extends PanelMenu.Button {
return super._onMenuKeyPress(actor, event);
}
- _onVertSepRepaint(area) {
- let cr = area.get_context();
- let themeNode = area.get_theme_node();
- let [width, height] = area.get_surface_size();
- let stippleColor = themeNode.get_color('-stipple-color');
- let stippleWidth = themeNode.get_length('-stipple-width');
- let x = Math.floor(width / 2) + 0.5;
- cr.moveTo(x, 0);
- cr.lineTo(x, height);
- Clutter.cairo_set_source_color(cr, stippleColor);
- cr.setDash([1, 3], 1); // Hard-code for now
- cr.setLineWidth(stippleWidth);
- cr.stroke();
- }
-
_onOpenStateChanged(menu, open) {
if (open) {
if (this.reloadFlag) {
@@ -602,11 +578,6 @@ class ApplicationsButton extends PanelMenu.Button {
this.categoriesScrollBox.add_actor(this.categoriesBox);
this.mainBox.add(this.leftBox);
- this.mainBox.add(this._createVertSeparator(), {
- expand: false,
- x_fill: false,
- y_fill: true
- });
this.mainBox.add(this.applicationsScrollBox, {
expand: true,
x_fill: true,
--
2.43.0
From 9c01f6f056e29bebc4a291f9aa3844b473a8b89a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 23 Nov 2023 20:59:57 +0100
Subject: [PATCH 3/3] apps-menu: Use customized layout manager to limit height
To avoid continuous height changes while browsing through categories,
we let the list of categories determine the overall height, and rely
on scrolling for the list of apps within a category.
We currently achieve this by assigning a fixed height via the
`style` property. This has been found to trigger a crash when
running headless, as we end up querying an actor's height request
before a valid resource scale is available.
Instead, use a custom layout manager, which seems more elegant anyway.
Close:
https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/472
Part-of:
<https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/290>
---
extensions/apps-menu/extension.js | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/extensions/apps-menu/extension.js b/extensions/apps-menu/extension.js
index 34fb24cf..68068cc4 100644
--- a/extensions/apps-menu/extension.js
+++ b/extensions/apps-menu/extension.js
@@ -348,6 +348,17 @@ class DesktopTarget {
}
Signals.addSignalMethods(DesktopTarget.prototype);
+let MainLayout = GObject.registerClass(
+class MainLayout extends Clutter.BoxLayout {
+ vfunc_get_preferred_height(container, forWidth) {
+ const mainChild = container.get_first_child();
+ const [minHeight, natHeight] =
+ mainChild.get_preferred_height(forWidth);
+
+ return [minHeight, natHeight + MENU_HEIGHT_OFFSET];
+ }
+});
+
let ApplicationsButton = GObject.registerClass(
class ApplicationsButton extends PanelMenu.Button {
_init(includeIcon) {
@@ -539,7 +550,7 @@ class ApplicationsButton extends PanelMenu.Button {
_createLayout() {
let section = new PopupMenu.PopupMenuSection();
this.menu.addMenuItem(section);
- this.mainBox = new St.BoxLayout({ vertical: false });
+ this.mainBox = new St.BoxLayout({ layoutManager: new MainLayout() });
this.leftBox = new St.BoxLayout({ vertical: true });
this.applicationsScrollBox = new St.ScrollView({
x_fill: true,
@@ -617,12 +628,6 @@ class ApplicationsButton extends PanelMenu.Button {
//Load applications
this._displayButtons(this._listApplications(null));
-
- let themeContext = St.ThemeContext.get_for_stage(global.stage);
- let scaleFactor = themeContext.scale_factor;
- let categoriesHeight = this.categoriesBox.height / scaleFactor;
- let height = Math.round(categoriesHeight) + MENU_HEIGHT_OFFSET;
- this.mainBox.style += `height: ${height}px`;
}
selectCategory(dir) {
--
2.43.0

View File

@ -1,272 +0,0 @@
From f6ccd2e00f5568ee3140cd7aaa72b19466eae39f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 23 Apr 2025 08:43:56 +0200
Subject: [PATCH 1/2] windowPreview: Add attention indicator
Some X11 clients still rely on the traditional urgent/demands-attention
hints instead of notifications to request the user's attention.
Support these by adding a visual indication to the corresponding
previews, based on the visual indicator in libadwaita's tabs.
---
extensions/dash-to-panel/stylesheet.css | 5 +++
extensions/dash-to-panel/windowPreview.js | 42 ++++++++++++++++++++++-
2 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/extensions/dash-to-panel/stylesheet.css b/extensions/dash-to-panel/stylesheet.css
index 6917e24d..1dcd3ae1 100644
--- a/extensions/dash-to-panel/stylesheet.css
+++ b/extensions/dash-to-panel/stylesheet.css
@@ -149,3 +149,8 @@
-progress-bar-border: rgba(0.9, 0.9, 0.9, 1);
*/
}
+
+.window-preview-attention-indicator {
+ background-color: rgba(27, 106, 203, 1.0);
+ height: 2px;
+}
diff --git a/extensions/dash-to-panel/windowPreview.js b/extensions/dash-to-panel/windowPreview.js
index 45d08a04..12fe18bb 100644
--- a/extensions/dash-to-panel/windowPreview.js
+++ b/extensions/dash-to-panel/windowPreview.js
@@ -50,6 +50,8 @@ const FOCUSED_COLOR_OFFSET = 24;
const HEADER_COLOR_OFFSET = -12;
const FADE_SIZE = 36;
const PEEK_INDEX_PROP = '_dtpPeekInitialIndex';
+const ATTENTION_INDICATOR_MAX_SCALE = 0.4;
+const ATTENTION_INDICATOR_TRANSITION_DURATION = 0.3;
let headerHeight = 0;
let alphaBg = 0;
@@ -740,14 +742,29 @@ var Preview = Utils.defineClass({
setStyle(headerBox, this._getBackgroundColor(HEADER_COLOR_OFFSET, 1));
this._workspaceIndicator = new St.Label({ y_align: Clutter.ActorAlign.CENTER });
+ let titleBox = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
+ x_expand: true,
+ y_expand: true,
+ });
this._windowTitle = new St.Label({ y_align: Clutter.ActorAlign.CENTER, x_expand: true });
+ this._attentionIndicator = new St.Widget({
+ style_class: 'window-preview-attention-indicator',
+ x_expand: true,
+ y_expand: true,
+ y_align: Clutter.ActorAlign.END,
+ scale_x: 0,
+ });
+
+ titleBox.add_child(this._windowTitle);
+ titleBox.add_child(this._attentionIndicator);
this._iconBin = new St.Widget({ layout_manager: new Clutter.BinLayout() });
this._iconBin.set_size(headerHeight, headerHeight);
headerBox.add_child(this._iconBin);
headerBox.insert_child_at_index(this._workspaceIndicator, isLeftButtons ? 0 : 1);
- headerBox.insert_child_at_index(this._windowTitle, isLeftButtons ? 1 : 2);
+ headerBox.insert_child_at_index(titleBox, isLeftButtons ? 1 : 2);
box.insert_child_at_index(headerBox, isTopHeader ? 0 : 1);
}
@@ -942,6 +959,14 @@ var Preview = Utils.defineClass({
this.window.disconnect(this._titleWindowChangeId);
this._titleWindowChangeId = 0;
}
+ if (this._attentionHintChangeId) {
+ this.window.disconnect(this._attentionHintChangeId)
+ this._attentionHintChangeId = 0
+ }
+ if (this._urgentHintChangeId) {
+ this.window.disconnect(this._urgentHintChangeId)
+ this._urgentHintChangeId = 0
+ }
},
_updateHeader: function() {
@@ -970,8 +995,11 @@ var Preview = Utils.defineClass({
setStyle(this._workspaceIndicator, workspaceStyle);
this._titleWindowChangeId = this.window.connect('notify::title', () => this._updateWindowTitle());
+ this._attentionHintChangeId = this.window.connect('notify::demands-attention', () => this._updateNeedsAttention());
+ this._urgentHintChangeId = this.window.connect('notify::urgent', () => this._updateNeedsAttention());
setStyle(this._windowTitle, 'max-width: 0px; padding-right: 4px;' + commonTitleStyles);
this._updateWindowTitle();
+ this._updateNeedsAttention();
}
},
@@ -979,6 +1007,18 @@ var Preview = Utils.defineClass({
this._windowTitle.text = this.window.title;
},
+ _updateNeedsAttention: function() {
+ const urgent = this.window.urgent;
+ const demandsAttention = this.window.demands_attention;
+ const needsAttention = urgent || demandsAttention;
+ Utils.animate(
+ this._attentionIndicator,
+ getTweenOpts({
+ scale_x: needsAttention ? ATTENTION_INDICATOR_MAX_SCALE : 0,
+ time: ATTENTION_INDICATOR_TRANSITION_DURATION,
+ }));
+ },
+
_hideOrShowCloseButton: function(hide) {
if (this._needsCloseButton) {
Utils.animate(this._closeButtonBin, getTweenOpts({ opacity: hide ? 0 : 255 }));
--
2.49.0
From 497df374038b1389204bed3bd89983c6fed20836 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 23 Apr 2025 09:38:56 +0200
Subject: [PATCH 2/2] appIcons: Add attention indicator
Some X11 clients still rely on the traditional urgent/demands-attention
hints instead of notifications to request the user's attention.
Tabs in libadwaita use an underline for that purpose, but unfortunately
that indication is already taken by the running indicator; so instead,
add a subtle flash effect to icons with urgent windows.
---
extensions/dash-to-panel/appIcons.js | 86 ++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/extensions/dash-to-panel/appIcons.js b/extensions/dash-to-panel/appIcons.js
index 5cfb1350..46c9030d 100644
--- a/extensions/dash-to-panel/appIcons.js
+++ b/extensions/dash-to-panel/appIcons.js
@@ -25,6 +25,7 @@
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
const Gtk = imports.gi.Gtk;
const Signals = imports.signals;
const Lang = imports.lang;
@@ -114,6 +115,8 @@ var taskbarAppIcon = Utils.defineClass({
_init: function(appInfo, panel, iconParams, previewMenu, iconAnimator) {
this.dtpPanel = panel;
this._nWindows = 0;
+ this._windows = new Set();
+ this._windowSignals = new Map();
this.window = appInfo.window;
this.isLauncher = appInfo.isLauncher;
this._previewMenu = previewMenu;
@@ -187,6 +190,13 @@ var taskbarAppIcon = Utils.defineClass({
this.actor.set_width(panel.geom.w);
}
+ this._flashEffect = new Clutter.BrightnessContrastEffect({
+ name: 'attention-flash',
+ enabled: false,
+ });
+ this.icon.add_effect(this._flashEffect);
+ this._updateTrackedWindows();
+
// Monitor windows-changes instead of app state.
// Keep using the same Id and function callback (that is extended)
if(this._stateChangedId > 0) {
@@ -324,6 +334,8 @@ var taskbarAppIcon = Utils.defineClass({
this._destroyed = true;
this._timeoutsHandler.destroy();
+ this._windowSignals.forEach((ids, w) => ids.forEach(id => w.disconnect(id)));
+ this._windowSignals.clear();
this._previewMenu.close(true);
@@ -367,6 +379,7 @@ var taskbarAppIcon = Utils.defineClass({
},
onWindowsChanged: function() {
+ this._updateTrackedWindows();
this._updateWindows();
this.updateIcon();
},
@@ -1039,6 +1052,79 @@ var taskbarAppIcon = Utils.defineClass({
this._previewMenu.update(this, windows);
},
+ _updateTrackedWindows: function() {
+ const windows = this.window ? [this.window] : this.app.get_windows();
+
+ const removed = [...this._windows].filter(w => !windows.includes(w));
+ removed.forEach(w => this._untrackWindow(w));
+ windows.forEach(w => this._trackWindow(w));
+ this._updateNeedsAttention();
+ },
+
+ _trackWindow: function(window) {
+ if (this._windows.has(window))
+ return;
+
+ this._windowSignals.set(window, [
+ window.connect('notify::urgent', () => this._updateNeedsAttention()),
+ window.connect('notify::demands-attention', () => this._updateNeedsAttention()),
+ ]);
+ this._windows.add(window);
+ },
+
+ _untrackWindow: function(window) {
+ if (!this._windows.delete(window))
+ return;
+
+ for (let id of this._windowSignals.get(window))
+ window.disconnect(id);
+ this._windowSignals.delete(window);
+ },
+
+ _updateNeedsAttention: function() {
+ const needsAttention =
+ [...this._windows].some(w => w.urgent || w.demands_attention);
+
+ if (this._flashEffect.enabled === needsAttention)
+ return;
+
+ this._flashEffect.enabled = needsAttention;
+
+ if (needsAttention) {
+ const flashColor = new Clutter.Color({
+ red: 177,
+ green: 177,
+ blue: 228,
+ });
+ this._flashEffect.set_brightness(0)
+ const flashTransition = new Clutter.PropertyTransition({
+ property_name: '@effects.attention-flash.brightness',
+ interval: new Clutter.Interval({value_type: Clutter.Color}),
+ duration: 1500,
+ repeat_count: -1,
+ auto_reverse: true,
+ progress_mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
+ });
+ this.icon.add_transition('@effects.attention-flash.brightness', flashTransition);
+ flashTransition.set_to(flashColor);
+
+ this.icon.translation_y = 0;
+ const bumpTransition = new Clutter.PropertyTransition({
+ property_name: 'translation-y',
+ interval: new Clutter.Interval({value_type: GObject.TYPE_DOUBLE}),
+ duration: 500,
+ repeat_count: -1,
+ auto_reverse: true,
+ progress_mode: Clutter.AnimationMode.EASE_IN_OUT_QUAD,
+ });
+ this.icon.add_transition('translation-y', bumpTransition);
+ bumpTransition.set_to(-3);
+ } else {
+ this.icon.remove_all_transitions();
+ this.icon.translation_y = 0;
+ }
+ },
+
_getRunningIndicatorCount: function() {
return Math.min(this._nWindows, MAX_INDICATORS);
},
--
2.49.0

File diff suppressed because it is too large Load Diff

View File

@ -1,147 +0,0 @@
From e8665261d2e99b3cfaa4d784bd47f95a5fdc3b52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 3 Mar 2026 12:48:13 +0100
Subject: [PATCH 1/3] workspace-indicator: Use section box to iterate items
Menu items are added to a menu's box, so it is more correct to
use that to access items, even when for menu sections the box
is also used as the menu's actor.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/445>
---
extensions/workspace-indicator/workspaceIndicator.js | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index eb31fc62..af4c69bf 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -595,7 +595,7 @@ class WorkspacesMenu extends PopupMenu.PopupMenu {
const {workspaceManager} = global;
const {nWorkspaces} = workspaceManager;
- const section = this._workspacesSection.actor;
+ const section = this._workspacesSection.box;
while (section.get_n_children() < nWorkspaces) {
const item = new EditableMenuItem();
item.connect('activate', (o, event) => {
@@ -624,7 +624,7 @@ class WorkspacesMenu extends PopupMenu.PopupMenu {
_updateWorkspaceLabels() {
const items =
- this._workspacesSection.actor.get_children().map(c => c._delegate);
+ this._workspacesSection.box.get_children().map(c => c._delegate);
items.forEach(
(item, i) => (item.label.text = Meta.prefs_get_workspace_name(i)));
}
@@ -634,7 +634,7 @@ class WorkspacesMenu extends PopupMenu.PopupMenu {
const active = workspaceManager.get_active_workspace_index();
const items =
- this._workspacesSection.actor.get_children().map(c => c._delegate);
+ this._workspacesSection.box.get_children().map(c => c._delegate);
items.forEach((item, i) => {
item.setOrnament(i === active
? PopupMenu.Ornament.CHECK
--
2.53.0
From 6f2fba8eba7f09834448a5588b825235213314a2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 2 Mar 2026 18:49:16 +0100
Subject: [PATCH 2/3] workspace-indicator: Support scrolling in workspace menu
While we should always have enough screen estate to fit a reasonable
number of workspaces, the number can go up to 36 where we are pretty
much guaranteed to run out of space.
Support those less common cases by making the workspace list scrollable.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/445>
---
.../workspace-indicator/workspaceIndicator.js | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/extensions/workspace-indicator/workspaceIndicator.js b/extensions/workspace-indicator/workspaceIndicator.js
index af4c69bf..287fa13c 100644
--- a/extensions/workspace-indicator/workspaceIndicator.js
+++ b/extensions/workspace-indicator/workspaceIndicator.js
@@ -6,6 +6,7 @@ const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Tweener = imports.ui.tweener;
+const { ensureActorVisibleInScrollView } = imports.misc.util;
const Signals = imports.signals;
@@ -548,6 +549,16 @@ class WorkspacesMenu extends PopupMenu.PopupMenu {
this.actor.connect('destroy', () => this._onDestroy());
this._workspacesSection = new PopupMenu.PopupMenuSection();
+
+ // make the section scrollable to avoid growing indefinitely
+ const scrollView = new St.ScrollView({
+ style_class: 'vfade',
+ hscrollbar_policy: St.PolicyType.NEVER,
+ });
+ scrollView.add_actor(this._workspacesSection.box);
+ scrollView._delegate = this._workspacesSection;
+ this._workspacesSection.actor = scrollView;
+
this.addMenuItem(this._workspacesSection);
this.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
@@ -612,6 +623,11 @@ class WorkspacesMenu extends PopupMenu.PopupMenu {
this._desktopSettings.set_strv('workspace-names',
[...newNames, ...oldNames.slice(nLabels)]);
});
+ item.connect('active-changed', (i, active) => {
+ const view = this._workspacesSection.actor;
+ if (active)
+ ensureActorVisibleInScrollView(view, item.actor);
+ });
this._workspacesSection.addMenuItem(item);
}
--
2.53.0
From 05615be8a57199d3137692bb9c4537437001628f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 18 Mar 2026 14:04:34 +0100
Subject: [PATCH 3/3] window-list: Fix flipping menu arrow
The `updateArrowSide()` method changes the effective arrow side,
but not the "user arrow side" that tracks the explicitly requested
side.
This breaks scrolling the workspaces menu, because when checking
whether the menu needs flipping due to size constraints, it does
not fit on either side and boxpointer reverts to the originally
requested side.
This is a shell issue[0], but we can work around it to fix the
immediate issue without a shell update.
[0] https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/4120
---
extensions/window-list/extension.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 37b5ea09..d1342898 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -1243,6 +1243,7 @@ class BottomWorkspaceIndicator extends WorkspaceIndicator {
return;
this.menu.actor.updateArrowSide(St.Side.BOTTOM);
+ this.menu.actor._userArrowSide = St.Side.BOTTOM;
this.menu.actor.remove_style_class_name('panel-menu');
}
});
--
2.53.0

View File

@ -1,552 +0,0 @@
From f5fca95984f387a4abf10bff27b06f59d366353f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 25 Sep 2024 02:23:41 +0200
Subject: [PATCH 1/4] window-list: Split out AppTitle class
Even though it's just a box with icon and label, it's cleaner to
have a dedicated class.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/337>
---
extensions/window-list/extension.js | 69 ++++++++++++++++++-----------
1 file changed, 43 insertions(+), 26 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 0baaeecb..3f13bb82 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -206,6 +206,46 @@ class WindowTitle {
}
}
+class AppTitle {
+ constructor(app) {
+ this.actor = new St.BoxLayout({
+ style_class: 'window-button-box',
+ x_expand: true,
+ y_expand: true,
+ });
+
+ this._app = app;
+
+ const icon = new St.Bin({
+ style_class: 'window-button-icon',
+ child: app.create_icon_texture(ICON_TEXTURE_SIZE),
+ });
+ this.actor.add_child(icon);
+
+ let label = new St.Label({
+ text: app.get_name(),
+ y_align: Clutter.ActorAlign.CENTER,
+ });
+ this.actor.add_child(label);
+ this.label_actor = label;
+
+ this._textureCache = St.TextureCache.get_default();
+ this._iconThemeChangedId =
+ this._textureCache.connect('icon-theme-changed', () => {
+ icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
+ });
+
+ this.actor.connect('destroy', this._onDestroy.bind(this));
+ }
+
+ _onDestroy() {
+ if (this._iconThemeChangedId)
+ this._textureCache.disconnect(this._iconThemeChangedId);
+ this._iconThemeChangedId = 0;
+ this._textureCache = null;
+ }
+}
+
class BaseButton {
constructor(perMonitor, monitorIndex) {
@@ -519,24 +559,8 @@ class AppButton extends BaseButton {
});
stack.add_actor(this._singleWindowTitle);
- this._multiWindowTitle = new St.BoxLayout({
- style_class: 'window-button-box',
- x_expand: true
- });
- stack.add_actor(this._multiWindowTitle);
-
- this._icon = new St.Bin({
- style_class: 'window-button-icon',
- child: app.create_icon_texture(ICON_TEXTURE_SIZE)
- });
- this._multiWindowTitle.add(this._icon);
-
- let label = new St.Label({
- text: app.get_name(),
- y_align: Clutter.ActorAlign.CENTER
- });
- this._multiWindowTitle.add(label);
- this._multiWindowTitle.label_actor = label;
+ this._multiWindowTitle = new AppTitle(app);
+ stack.add_actor(this._multiWindowTitle.actor);
this._menuManager = new PopupMenu.PopupMenuManager(this);
this._menu = new PopupMenu.PopupMenu(this.actor, 0.5, St.Side.BOTTOM);
@@ -551,12 +575,6 @@ class AppButton extends BaseButton {
this._appContextMenu.actor.hide();
Main.uiGroup.add_actor(this._appContextMenu.actor);
- this._textureCache = St.TextureCache.get_default();
- this._iconThemeChangedId =
- this._textureCache.connect('icon-theme-changed', () => {
- this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
- });
-
this._windowsChangedId =
this.app.connect('windows-changed',
this._windowsChanged.bind(this));
@@ -605,7 +623,7 @@ class AppButton extends BaseButton {
_windowsChanged() {
let windows = this.getWindowList();
this._singleWindowTitle.visible = windows.length == 1;
- this._multiWindowTitle.visible = !this._singleWindowTitle.visible;
+ this._multiWindowTitle.actor.visible = !this._singleWindowTitle.visible;
if (this._singleWindowTitle.visible) {
if (!this._windowTitle) {
@@ -684,7 +702,6 @@ class AppButton extends BaseButton {
_onDestroy() {
super._onDestroy();
- this._textureCache.disconnect(this._iconThemeChangedId);
this._windowTracker.disconnect(this._notifyFocusId);
this.app.disconnect(this._windowsChangedId);
this._menu.destroy();
--
2.47.1
From 5875892c2579f622ca4bcc54e5f25801869e14ef Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 25 Sep 2024 02:55:14 +0200
Subject: [PATCH 2/4] window-list: Simplify app button
Depending on the number of windows, the button either shows the
title of the lone window, or the app title for multiple windows.
While we always recreate the single-window title, we only create
the app title once and hide it as necessary. Avoiding re-creating
a simple actor 50% of mode transitions isn't worth the additional
complexity, so just handle both single- and multi-window titles
the same way.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/337>
---
extensions/window-list/extension.js | 73 ++++++++++-------------------
1 file changed, 26 insertions(+), 47 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 3f13bb82..0723e9e2 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -549,19 +549,6 @@ class AppButton extends BaseButton {
this.app = app;
this._updateVisibility();
- let stack = new St.Widget({ layout_manager: new Clutter.BinLayout() });
- this.actor.set_child(stack);
-
- this._singleWindowTitle = new St.Bin({
- x_expand: true,
- y_fill: true,
- x_align: St.Align.START
- });
- stack.add_actor(this._singleWindowTitle);
-
- this._multiWindowTitle = new AppTitle(app);
- stack.add_actor(this._multiWindowTitle.actor);
-
this._menuManager = new PopupMenu.PopupMenuManager(this);
this._menu = new PopupMenu.PopupMenu(this.actor, 0.5, St.Side.BOTTOM);
this._menu.connect('open-state-changed', _onMenuStateChanged);
@@ -570,11 +557,6 @@ class AppButton extends BaseButton {
this._menuManager.addMenu(this._menu);
Main.uiGroup.add_actor(this._menu.actor);
- this._appContextMenu = new AppContextMenu(this.actor, this);
- this._appContextMenu.connect('open-state-changed', _onMenuStateChanged);
- this._appContextMenu.actor.hide();
- Main.uiGroup.add_actor(this._appContextMenu.actor);
-
this._windowsChangedId =
this.app.connect('windows-changed',
this._windowsChanged.bind(this));
@@ -621,38 +603,35 @@ class AppButton extends BaseButton {
}
_windowsChanged() {
- let windows = this.getWindowList();
- this._singleWindowTitle.visible = windows.length == 1;
- this._multiWindowTitle.actor.visible = !this._singleWindowTitle.visible;
-
- if (this._singleWindowTitle.visible) {
- if (!this._windowTitle) {
- this.metaWindow = windows[0];
- this._windowTitle = new WindowTitle(this.metaWindow);
- this._singleWindowTitle.child = this._windowTitle.actor;
- this._windowContextMenu = new WindowContextMenu(this.actor, this.metaWindow);
- this._windowContextMenu.connect('open-state-changed',
- _onMenuStateChanged);
- Main.uiGroup.add_actor(this._windowContextMenu.actor);
- this._windowContextMenu.actor.hide();
- this._contextMenuManager.addMenu(this._windowContextMenu);
- }
- this._contextMenuManager.removeMenu(this._appContextMenu);
- this._contextMenu = this._windowContextMenu;
- this.actor.label_actor = this._windowTitle.label_actor;
+ const windows = this.getWindowList();
+ const singleWindowMode = windows.length === 1;
+
+ if (this._singleWindowMode === singleWindowMode)
+ return;
+
+ this._singleWindowMode = singleWindowMode;
+
+ if (this.actor.child)
+ this.actor.child.destroy();
+ if (this._contextMenu)
+ this._contextMenu.destroy();
+
+ if (this._singleWindowMode) {
+ const [window] = windows;
+ this._titleWidget = new WindowTitle(window);
+ this._contextMenu = new WindowContextMenu(this.actor, window);
} else {
- if (this._windowTitle) {
- this.metaWindow = null;
- this._singleWindowTitle.child = null;
- this._windowTitle = null;
- this._windowContextMenu.destroy();
- this._windowContextMenu = null;
- }
- this._contextMenu = this._appContextMenu;
- this._contextMenuManager.addMenu(this._appContextMenu);
- this.actor.label_actor = this._multiWindowTitle.label_actor;
+ this._titleWidget = new AppTitle(this.app);
+ this._contextMenu = new AppContextMenu(this.actor);
}
+ this.actor.child = this._titleWidget.actor;
+ this.actor.label_actor = this._titleWidget.label_actor;
+
+ this._contextMenu.connect('open-state-changed', _onMenuStateChanged);
+ Main.uiGroup.add_child(this._contextMenu.actor);
+ this._contextMenu.actor.hide();
+ this._contextMenuManager.addMenu(this._contextMenu);
}
_onClicked(actor, button) {
--
2.47.1
From 68fe36c199c9d68ed8ad739e9419f052a253afa4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 3 Oct 2024 17:19:31 +0200
Subject: [PATCH 3/4] window-list: Split out common TitleWidget class
Both app- and window title use the same structure, so add a shared
base class.
---
extensions/window-list/extension.js | 55 ++++++++++++++---------------
1 file changed, 27 insertions(+), 28 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 0723e9e2..9cbfd4fb 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -134,19 +134,32 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
}
}
-class WindowTitle {
- constructor(metaWindow) {
- this._metaWindow = metaWindow;
+class TitleWidget {
+ constructor() {
this.actor = new St.BoxLayout({
style_class: 'window-button-box',
x_expand: true,
y_expand: true
});
- this._icon = new St.Bin({ style_class: 'window-button-icon' });
- this.actor.add(this._icon);
- this.label_actor = new St.Label({ y_align: Clutter.ActorAlign.CENTER });
- this.actor.add(this.label_actor);
+ this._icon = new St.Bin({
+ style_class: 'window-button-icon',
+ });
+ this.actor.add_child(this._icon);
+
+ this._label = new St.Label({
+ y_align: Clutter.ActorAlign.CENTER,
+ });
+ this.actor.add_child(this._label);
+ this.label_actor = this._label;
+ }
+}
+
+class WindowTitle extends TitleWidget {
+ constructor(metaWindow) {
+ super();
+
+ this._metaWindow = metaWindow;
this._textureCache = St.TextureCache.get_default();
this._iconThemeChangedId =
@@ -181,9 +194,9 @@ class WindowTitle {
return;
if (this._metaWindow.minimized)
- this.label_actor.text = '[%s]'.format(this._metaWindow.title);
+ this._label.text = '[%s]'.format(this._metaWindow.title);
else
- this.label_actor.text = this._metaWindow.title;
+ this._label.text = this._metaWindow.title;
}
_updateIcon() {
@@ -206,33 +219,19 @@ class WindowTitle {
}
}
-class AppTitle {
+class AppTitle extends TitleWidget {
constructor(app) {
- this.actor = new St.BoxLayout({
- style_class: 'window-button-box',
- x_expand: true,
- y_expand: true,
- });
+ super();
this._app = app;
- const icon = new St.Bin({
- style_class: 'window-button-icon',
- child: app.create_icon_texture(ICON_TEXTURE_SIZE),
- });
- this.actor.add_child(icon);
-
- let label = new St.Label({
- text: app.get_name(),
- y_align: Clutter.ActorAlign.CENTER,
- });
- this.actor.add_child(label);
- this.label_actor = label;
+ this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
+ this._label.text = app.get_name();
this._textureCache = St.TextureCache.get_default();
this._iconThemeChangedId =
this._textureCache.connect('icon-theme-changed', () => {
- icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
+ this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
});
this.actor.connect('destroy', this._onDestroy.bind(this));
--
2.47.1
From 822d2ba9a8545f2af2664768c1ca9a7938059088 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 17 Dec 2024 01:09:34 +0100
Subject: [PATCH 4/4] window-list: Add attention indicator
Some X11 clients still rely on the traditional urgent/demand-attention
hints instead of notifications to request the user's attention.
Support these by adding a visual indication to the corresponding
buttons, based on the visual indicator in libadwaita's tabs.
Closes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/543
---
extensions/window-list/extension.js | 90 +++++++++++++++++++++++++--
extensions/window-list/stylesheet.css | 9 +++
2 files changed, 95 insertions(+), 4 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 9cbfd4fb..11ac393b 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -136,22 +136,46 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
class TitleWidget {
constructor() {
- this.actor = new St.BoxLayout({
- style_class: 'window-button-box',
+ this.actor = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
x_expand: true,
y_expand: true
});
+ const hbox = new St.BoxLayout({
+ style_class: 'window-button-box',
+ x_expand: true,
+ y_expand: true,
+ });
+ this.actor.add_child(hbox);
+
this._icon = new St.Bin({
style_class: 'window-button-icon',
});
- this.actor.add_child(this._icon);
+ hbox.add_child(this._icon);
this._label = new St.Label({
y_align: Clutter.ActorAlign.CENTER,
});
- this.actor.add_child(this._label);
+ hbox.add_child(this._label);
this.label_actor = this._label;
+
+ this._attentionIndicator = new St.Widget({
+ style_class: 'window-button-attention-indicator',
+ x_expand: true,
+ y_expand: true,
+ y_align: Clutter.ActorAlign.END,
+ scale_x: 0,
+ });
+ this._attentionIndicator.set_pivot_point(0.5, 0.5);
+ this.actor.add_child(this._attentionIndicator);
+ }
+
+ setNeedsAttention(enable) {
+ Tweener.addTween(this._attentionIndicator, {
+ scaleX: enable ? 0.4 : 0,
+ time: 0.3,
+ });
}
}
@@ -181,7 +205,12 @@ class WindowTitle extends TitleWidget {
this._notifyMinimizedId =
this._metaWindow.connect('notify::minimized',
this._minimizedChanged.bind(this));
+ this._notifyDemandsAttentionId = this._metaWindow.connect(
+ 'notify::demands-attention', this._updateNeedsAttention.bind(this));
+ this._notifyUrgentId = this._metaWindow.connect(
+ 'notify::urgent', this._updateNeedsAttention.bind(this));
this._minimizedChanged();
+ this._updateNeedsAttention();
}
_minimizedChanged() {
@@ -189,6 +218,11 @@ class WindowTitle extends TitleWidget {
this._updateTitle();
}
+ _updateNeedsAttention() {
+ const { urgent, demandsAttention } = this._metaWindow;
+ this.setNeedsAttention(urgent || demandsAttention);
+ }
+
_updateTitle() {
if (!this._metaWindow.title)
return;
@@ -216,6 +250,8 @@ class WindowTitle extends TitleWidget {
this._metaWindow.disconnect(this._notifyMinimizedId);
this._metaWindow.disconnect(this._notifyWmClass);
this._metaWindow.disconnect(this._notifyAppId);
+ this._metaWindow.disconnect(this._notifyDemandsAttentionId);
+ this._metaWindow.disconnect(this._notifyUrgentId);
}
}
@@ -224,6 +260,7 @@ class AppTitle extends TitleWidget {
super();
this._app = app;
+ this._windows = new Map();
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
this._label.text = app.get_name();
@@ -234,6 +271,10 @@ class AppTitle extends TitleWidget {
this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
});
+ this._windowsChangedId = this._app.connect(
+ 'windows-changed', this._onWindowsChanged.bind(this));
+ this._onWindowsChanged();
+
this.actor.connect('destroy', this._onDestroy.bind(this));
}
@@ -242,6 +283,47 @@ class AppTitle extends TitleWidget {
this._textureCache.disconnect(this._iconThemeChangedId);
this._iconThemeChangedId = 0;
this._textureCache = null;
+
+ for (const [window, ids] of this._windows)
+ ids.forEach(id => window.disconnect(id));
+ this._windows.clear();
+ this._app.disconnect(this._windowsChangedId);
+ }
+
+ _onWindowsChanged() {
+ const windows = this._app.get_windows();
+ const removed = [...this._windows].filter(w => !windows.includes(w));
+ removed.forEach(w => this._untrackWindow(w));
+ windows.forEach(w => this._trackWindow(w));
+ this._updateNeedsAttention();
+ }
+
+ _trackWindow(window) {
+ if (this._windows.has(window))
+ return;
+
+ const signals = [
+ window.connect('notify::urgent',
+ () => this._updateNeedsAttention()),
+ window.connect('notify::demands-attention',
+ () => this._updateNeedsAttention()),
+ ];
+ this._windows.set(window, signals);
+ }
+
+ _untrackWindow(window) {
+ if (!this._windows.has(window))
+ return;
+
+ const ids = this._windows.get(window);
+ ids.forEach(id => window.disconnect(id));
+ this._windows.delete(window);
+ }
+
+ _updateNeedsAttention() {
+ const needsAttention =
+ [...this._windows.keys()].some(w => w.urgent || w.demandsAttention);
+ this.setNeedsAttention(needsAttention);
}
}
diff --git a/extensions/window-list/stylesheet.css b/extensions/window-list/stylesheet.css
index 79d56bad..2c98aafe 100644
--- a/extensions/window-list/stylesheet.css
+++ b/extensions/window-list/stylesheet.css
@@ -134,3 +134,12 @@
.notification {
font-weight: normal;
}
+
+.window-button-attention-indicator {
+ background-color: rgba(27, 106, 203, 1.0);
+ height: 2px;
+}
+
+.window-button.minimized .window-button-attention-indicator {
+ background-color: rgba(27, 106, 203, 0.6);
+}
--
2.47.1

View File

@ -6,7 +6,7 @@
Name: gnome-shell-extensions Name: gnome-shell-extensions
Version: 3.32.1 Version: 3.32.1
Release: 52%{?dist} Release: 38%{?dist}
Summary: Modify and extend GNOME Shell functionality and behavior Summary: Modify and extend GNOME Shell functionality and behavior
Group: User Interface/Desktops Group: User Interface/Desktops
@ -59,15 +59,6 @@ Patch0030: 0001-desktop-icons-Don-t-use-blocking-IO.patch
Patch0031: 0001-panel-favorites-Update-to-upstream-version.patch Patch0031: 0001-panel-favorites-Update-to-upstream-version.patch
Patch0032: 0001-desktop-icons-Don-t-try-spawn-with-non-existent-work.patch Patch0032: 0001-desktop-icons-Don-t-try-spawn-with-non-existent-work.patch
Patch0033: 0001-classification-banner-Hide-from-picks.patch Patch0033: 0001-classification-banner-Hide-from-picks.patch
Patch0034: 0001-desktop-icons-Fix-k-in-.desktop-files.patch
Patch0035: window-list-attention-indicator.patch
Patch0036: apps-menu-custom-layout-manager.patch
Patch0037: dash-to-panel-attention-indicator.patch
Patch0038: improve-workspace-names.patch
Patch0039: 0001-dash-to-panel-Consider-range-around-edges-for-dwelli.patch
Patch0040: 0001-dash-to-panel-Don-t-create-main-panel-without-a-moni.patch
Patch0041: scrollable-workspace-menu.patch
Patch0042: 0001-desktop-icons-Merge-custom-menu-entries-into-desktop.patch
%description %description
GNOME Shell Extensions is a collection of extensions providing additional and GNOME Shell Extensions is a collection of extensions providing additional and
@ -579,76 +570,13 @@ cp $RPM_SOURCE_DIR/gnome-classic.desktop $RPM_BUILD_ROOT%{_datadir}/xsessions
%files -n %{pkg_prefix}-workspace-indicator %files -n %{pkg_prefix}-workspace-indicator
%{_datadir}/gnome-shell/extensions/workspace-indicator*/ %{_datadir}/gnome-shell/extensions/workspace-indicator*/
%{_datadir}/glib-2.0/schemas/org.gnome.shell.extensions.workspace-indicator.gschema.xml
%changelog %changelog
* Thu Mar 19 2026 Tomas Pelka <tpelka@redhat.com> - 3.32.1-52
- Merge custom-menu entries into desktop-icons background menu
Resolves: RHEL-136187
* Wed Mar 18 2026 Florian Müllner <fmuellner@redhat.com> - 3.32.1-51
- Fix menu flip in window-list
Related: RHEL-143030
* Tue Mar 03 2026 Florian Müllner <fmuellner@redhat.com> - 3.32.1-50
- Support scrolling in workspace menu
Resolves: RHEL-143030
* Mon Jan 26 2026 Florian Müllner <fmuellner@redhat.com> - 3.32.1-49
- Fix style regressions in GNOME classic
Resolves: RHEL-136283
* Tue Nov 18 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-48
- Fix workspace-indicator cleanup
Resolves: RHEL-129131
* Mon Nov 17 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-47
- Fix applying num-workspace setting
Resolves: RHEL-129121
* Thu Oct 16 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-46
- Skip creating main panel with no monitor
Resolves: RHEL-110378
* Thu Oct 16 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-45
- Fix issues in workspace-names backport
Resolves: RHEL-96219
* Thu Aug 28 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-44
- Consider range around edges for dwelling
Resolves: RHEL-28818
* Wed Jul 16 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-43
- Make workspace names more prominent
Resolves: RHEL-96219
* Tue May 06 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-42
- Indicate urgency-hint in dash-to-panel
Resolves: RHEL-76834
* Tue May 06 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-41
- Use custom layout manager in apps menu
Resolves: RHEL-14936
* Tue Jan 07 2025 Florian Müllner <fmuellner@redhat.com> - 3.32.1-40
- Fix '%k' macro in .desktop files
Resolves: RHEL-72966
- Indicate urgency-hint in window-list
Resolves: RHEL-70534
* Tue Apr 23 2024 Florian Müllner <fmuellner@redhat.com> - 3.32.1-39
- Fix tooltip animation times
Resolves: RHEL-33681
* Wed Feb 07 2024 Florian Müllner <fmuellner@redhat.com> - 3.32.1-38 * Wed Feb 07 2024 Florian Müllner <fmuellner@redhat.com> - 3.32.1-38
- Hide classification banners from picks - Hide classification banners from picks
Resolves: RHEL-24438 Resolves: RHEL-24438
* Thu Nov 02 2023 Florian Müllner <fmuellner@redhat.com> - 3.32.1-37
- Fix spawning terminal without a desktop directory
Resolves: RHEL-15031
* Fri Sep 15 2023 Florian Müllner <fmuellner@redhat.com> - 3.32.1-36 * Fri Sep 15 2023 Florian Müllner <fmuellner@redhat.com> - 3.32.1-36
- Update panel-favorites to matching upstream release - Update panel-favorites to matching upstream release
Resolves: RHEL-3536 Resolves: RHEL-3536