gnome-shell-extensions/window-list-reordering.patch

1623 lines
53 KiB
Diff

From 21e087ef90891e703338b00cea0cf38e11feae8f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 25 Sep 2024 03:36:08 +0200
Subject: [PATCH 01/22] window-list: Small stylesheet cleanup
The light stylesheet duplicates some declarations, and the
last occurrence matches what we already inherit from the
dark stylesheet.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/337>
---
extensions/window-list/stylesheet-light.css | 10 ----------
1 file changed, 10 deletions(-)
diff --git a/extensions/window-list/stylesheet-light.css b/extensions/window-list/stylesheet-light.css
index 375fd1bf..f9c51f8e 100644
--- a/extensions/window-list/stylesheet-light.css
+++ b/extensions/window-list/stylesheet-light.css
@@ -21,21 +21,11 @@
text-shadow: none;
}
- .bottom-panel .window-button > StWidget {
- -st-natural-width: 18.7em;
- max-width: 18.75em;
- }
-
.window-button > StWidget {
color: #000;
background-color: transparent;
}
-.window-button > StWidget {
- -st-natural-width: 18.75em;
- max-width: 18.75em;
-}
-
.window-button:hover > StWidget {
background-color: st-darken(#eee,5%);
}
--
2.47.0
From 5ac12f0ec7c378e4b65073823b0e03a0e9c219eb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 25 Sep 2024 02:14:47 +0200
Subject: [PATCH 02/22] window-list: Don't recreate icons on theme changes
All icons use `StIcon`, which already updates itself correctly
on icon theme changes.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/337>
---
extensions/window-list/extension.js | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 3edbf8bf..9441fad1 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -125,10 +125,6 @@ class WindowTitle extends St.BoxLayout {
this.label_actor.clutter_text.single_line_mode = true;
this.add_child(this.label_actor);
- this._textureCache = St.TextureCache.get_default();
- this._textureCache.connectObject('icon-theme-changed',
- () => this._updateIcon(), this);
-
this._metaWindow.connectObject(
'notify::wm-class',
() => this._updateIcon(), GObject.ConnectFlags.AFTER,
@@ -591,11 +587,6 @@ class AppButton extends BaseButton {
this._appContextMenu.actor.hide();
Main.uiGroup.add_child(this._appContextMenu.actor);
- this._textureCache = St.TextureCache.get_default();
- this._textureCache.connectObject('icon-theme-changed', () => {
- this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
- }, this);
-
this.app.connectObject('windows-changed',
() => this._windowsChanged(), this);
this._windowsChanged();
--
2.47.0
From 8c3a3f3b8a625bcfeedcfa367866f37ae9087c72 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 03/22] 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 | 47 ++++++++++++++++++-----------
1 file changed, 30 insertions(+), 17 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 9441fad1..a5bb55f6 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -166,6 +166,35 @@ class WindowTitle extends St.BoxLayout {
}
}
+class AppTitle extends St.BoxLayout {
+ static {
+ GObject.registerClass(this);
+ }
+
+ constructor(app) {
+ super({
+ 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.add_child(icon);
+
+ let label = new St.Label({
+ text: app.get_name(),
+ y_align: Clutter.ActorAlign.CENTER,
+ });
+ this.add_child(label);
+ this.label_actor = label;
+ }
+}
+
class BaseButton extends DashItemContainer {
static {
GObject.registerClass({
@@ -553,25 +582,9 @@ class AppButton extends BaseButton {
});
stack.add_child(this._singleWindowTitle);
- this._multiWindowTitle = new St.BoxLayout({
- style_class: 'window-button-box',
- x_expand: true,
- });
+ this._multiWindowTitle = new AppTitle(app);
stack.add_child(this._multiWindowTitle);
- this._icon = new St.Bin({
- style_class: 'window-button-icon',
- child: app.create_icon_texture(ICON_TEXTURE_SIZE),
- });
- this._multiWindowTitle.add_child(this._icon);
-
- let label = new St.Label({
- text: app.get_name(),
- y_align: Clutter.ActorAlign.CENTER,
- });
- this._multiWindowTitle.add_child(label);
- this._multiWindowTitle.label_actor = label;
-
this._menuManager = new PopupMenu.PopupMenuManager(this);
this._menu = new PopupMenu.PopupMenu(this, 0.5, St.Side.BOTTOM);
this._menu.connect('open-state-changed',
--
2.47.0
From 0cc25fbf6e996e3d9b0352b728a23f8c308f01e5 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 04/22] 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 | 71 ++++++++++-------------------
1 file changed, 25 insertions(+), 46 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index a5bb55f6..9b9ea7b9 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -574,17 +574,6 @@ class AppButton extends BaseButton {
this.app = app;
this._updateVisibility();
- let stack = new St.Widget({layout_manager: new Clutter.BinLayout()});
- this._button.set_child(stack);
-
- this._singleWindowTitle = new St.Bin({
- x_expand: true,
- });
- stack.add_child(this._singleWindowTitle);
-
- this._multiWindowTitle = new AppTitle(app);
- stack.add_child(this._multiWindowTitle);
-
this._menuManager = new PopupMenu.PopupMenuManager(this);
this._menu = new PopupMenu.PopupMenu(this, 0.5, St.Side.BOTTOM);
this._menu.connect('open-state-changed',
@@ -594,12 +583,6 @@ class AppButton extends BaseButton {
this._menuManager.addMenu(this._menu);
Main.uiGroup.add_child(this._menu.actor);
- this._appContextMenu = new AppContextMenu(this);
- this._appContextMenu.connect('open-state-changed',
- this._onMenuStateChanged.bind(this));
- this._appContextMenu.actor.hide();
- Main.uiGroup.add_child(this._appContextMenu.actor);
-
this.app.connectObject('windows-changed',
() => this._windowsChanged(), this);
this._windowsChanged();
@@ -646,37 +629,33 @@ class AppButton extends BaseButton {
}
_windowsChanged() {
- let windows = this.getWindowList();
- this._singleWindowTitle.visible = windows.length === 1;
- this._multiWindowTitle.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;
- this._windowContextMenu = new WindowContextMenu(this, this.metaWindow);
- this._windowContextMenu.connect(
- 'open-state-changed', this._onMenuStateChanged.bind(this));
- Main.uiGroup.add_child(this._windowContextMenu.actor);
- this._windowContextMenu.actor.hide();
- this._contextMenuManager.addMenu(this._windowContextMenu);
- }
- this._contextMenuManager.removeMenu(this._appContextMenu);
- this._contextMenu = this._windowContextMenu;
- this.label_actor = this._windowTitle.label_actor;
+ const windows = this.getWindowList();
+ const singleWindowMode = windows.length === 1;
+
+ if (this._singleWindowMode === singleWindowMode)
+ return;
+
+ this._singleWindowMode = singleWindowMode;
+
+ this._button.child?.destroy();
+ this._contextMenu?.destroy();
+
+ if (this._singleWindowMode) {
+ const [window] = windows;
+ this._button.child = new WindowTitle(window);
+ this._contextMenu = new WindowContextMenu(this, 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.label_actor = this._multiWindowTitle.label_actor;
+ this._button.child = new AppTitle(this.app);
+ this._contextMenu = new AppContextMenu(this);
}
+
+ this.label_actor = this._button.child.label_actor;
+
+ this._contextMenu.connect(
+ 'open-state-changed', this._onMenuStateChanged.bind(this));
+ Main.uiGroup.add_child(this._contextMenu.actor);
+ this._contextMenu.actor.hide();
+ this._contextMenuManager.addMenu(this._contextMenu);
}
_onClicked(actor, button) {
--
2.47.0
From 88d42e3ac829f90a3b3e1b56fcfac483a8563449 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 7 Oct 2024 17:22:04 +0200
Subject: [PATCH 05/22] window-list: Fix minimized styling
Commit 039c66e7b7c wrapped the button in a container to
animate transitions, but didn't adjust the `.minimized`
styling to still apply to the button (where it is
expected) rather than the wrapper.
Fix this just like commit c72b8b21 did for the
`.focused` styling.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/342>
---
extensions/window-list/extension.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 9b9ea7b9..3a8f612a 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -478,9 +478,9 @@ class WindowButton extends BaseButton {
super._updateStyle();
if (this.metaWindow.minimized)
- this.add_style_class_name('minimized');
+ this._button.add_style_class_name('minimized');
else
- this.remove_style_class_name('minimized');
+ this._button.remove_style_class_name('minimized');
}
_windowEnteredOrLeftMonitor(metaDisplay, monitorIndex, metaWindow) {
--
2.47.0
From ce37919c1e3643363858f67fc749981a0afc1b8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Mon, 7 Oct 2024 17:10:43 +0200
Subject: [PATCH 06/22] window-list: Fix active state
Commit c72b8b21 fixed the styling of the active window's button,
but missed that the `active` property uses the style information
as well.
Adjust it to use the correct actor when checking for the style class.
Closes https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/529
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/342>
---
extensions/window-list/extension.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 3a8f612a..e7a1c777 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -252,7 +252,7 @@ class BaseButton extends DashItemContainer {
}
get active() {
- return this.has_style_class_name('focused');
+ return this._button.has_style_class_name('focused');
}
// eslint-disable-next-line camelcase
--
2.47.0
From 0c0115c847188838c3132dbba5fc99c7a6052f8e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 1 Oct 2024 14:52:02 +0200
Subject: [PATCH 07/22] window-list: Add missing action
Commit 24ba03fe9 added a new setting, but forgot to create the
corresponding action.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/341>
---
extensions/window-list/prefs.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index 194d1f9d..5da645df 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -30,6 +30,8 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
this._settings.create_action('show-on-all-monitors'));
this._actionGroup.add_action(
this._settings.create_action('display-all-workspaces'));
+ this._actionGroup.add_action(
+ this._settings.create_action('embed-previews'));
const groupingGroup = new Adw.PreferencesGroup({
title: _('Window Grouping'),
--
2.47.0
From b3401e8354892c82e0198bb8fb4d99210a9fc494 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 1 Oct 2024 14:46:15 +0200
Subject: [PATCH 08/22] window-list: Remove superfluous bindings
The setting is already bound to the switch via the corresponding action,
no need to also set up a binding.
In fact, the second binding is actively harmful, as it keeps the
connection alive until dispose, so the setting is reset on
garbage collection.
Closes https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/issues/511
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/341>
---
extensions/window-list/prefs.js | 4 ----
1 file changed, 4 deletions(-)
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index 5da645df..cf56be5b 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -75,8 +75,6 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
action_name: 'window-list.display-all-workspaces',
valign: Gtk.Align.CENTER,
});
- this._settings.bind('display-all-workspaces',
- toggle, 'active', Gio.SettingsBindFlags.DEFAULT);
row = new Adw.ActionRow({
title: _('Show windows from all workspaces'),
activatable_widget: toggle,
@@ -88,8 +86,6 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
action_name: 'window-list.embed-previews',
valign: Gtk.Align.CENTER,
});
- this._settings.bind('embed-previews',
- toggle, 'active', Gio.SettingsBindFlags.DEFAULT);
row = new Adw.ActionRow({
title: _('Show workspace previews'),
activatable_widget: toggle,
--
2.47.0
From 101043326755dda2144e9939681e5f6be4ed116d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 1 Oct 2024 14:55:44 +0200
Subject: [PATCH 09/22] window-list: Switch to Adw.SwitchRow
libadwaita fixed the actionable implementation of Adw.SwitchRow,
so can use the convenience widget instead of composing our own.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/341>
---
extensions/window-list/prefs.js | 27 ++++++---------------------
1 file changed, 6 insertions(+), 21 deletions(-)
diff --git a/extensions/window-list/prefs.js b/extensions/window-list/prefs.js
index cf56be5b..0633d590 100644
--- a/extensions/window-list/prefs.js
+++ b/extensions/window-list/prefs.js
@@ -60,37 +60,22 @@ class WindowListPrefsWidget extends Adw.PreferencesPage {
const miscGroup = new Adw.PreferencesGroup();
this.add(miscGroup);
- let toggle = new Gtk.Switch({
- action_name: 'window-list.show-on-all-monitors',
- valign: Gtk.Align.CENTER,
- });
- let row = new Adw.ActionRow({
+ let row = new Adw.SwitchRow({
title: _('Show on all monitors'),
- activatable_widget: toggle,
+ action_name: 'window-list.show-on-all-monitors',
});
- row.add_suffix(toggle);
miscGroup.add(row);
- toggle = new Gtk.Switch({
- action_name: 'window-list.display-all-workspaces',
- valign: Gtk.Align.CENTER,
- });
- row = new Adw.ActionRow({
+ row = new Adw.SwitchRow({
title: _('Show windows from all workspaces'),
- activatable_widget: toggle,
+ action_name: 'window-list.display-all-workspaces',
});
- row.add_suffix(toggle);
miscGroup.add(row);
- toggle = new Gtk.Switch({
- action_name: 'window-list.embed-previews',
- valign: Gtk.Align.CENTER,
- });
- row = new Adw.ActionRow({
+ row = new Adw.SwitchRow({
title: _('Show workspace previews'),
- activatable_widget: toggle,
+ action_name: 'window-list.embed-previews',
});
- row.add_suffix(toggle);
miscGroup.add(row);
}
}
--
2.47.0
From 1774cead56dcda6abdce8a1e6427dbeb866d7a0d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 15 Oct 2024 17:48:52 +0200
Subject: [PATCH 10/22] window-list: Remove outdated style
A long time ago, the window list used to embed the bottom message
tray, which caused notifications to inherit the window-list's
font style.
Since that's no longer the case, we have no business in messing
with notification styling, so stop doing that.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/stylesheet-dark.css | 4 ----
1 file changed, 4 deletions(-)
diff --git a/extensions/window-list/stylesheet-dark.css b/extensions/window-list/stylesheet-dark.css
index b9087971..f02fca60 100644
--- a/extensions/window-list/stylesheet-dark.css
+++ b/extensions/window-list/stylesheet-dark.css
@@ -81,7 +81,3 @@
width: 24px;
height: 24px;
}
-
-.notification {
- font-weight: normal;
-}
--
2.47.0
From cba87ff1919c3075ee428a73d3870c92cc5e214b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 26 Sep 2024 19:07:11 +0200
Subject: [PATCH 11/22] window-list: Split out some common code
Adding an app button and adding a window button involves some
shared steps, move those to a shared `_addButton()` method.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index e7a1c777..6eb08da0 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -964,14 +964,18 @@ class WindowList extends St.Widget {
this._removeApp(app);
}
- _addApp(app, animate) {
- let button = new AppButton(app, this._perMonitor, this._monitor.index);
+ _addButton(button, animate) {
this._settings.bind('display-all-workspaces',
button, 'ignore-workspace', Gio.SettingsBindFlags.GET);
this._windowList.add_child(button);
button.show(animate);
}
+ _addApp(app, animate) {
+ const button = new AppButton(app, this._perMonitor, this._monitor.index);
+ this._addButton(button, animate);
+ }
+
_removeApp(app) {
let children = this._windowList.get_children();
let child = children.find(c => c.app === app);
@@ -992,11 +996,8 @@ class WindowList extends St.Widget {
this._windowSignals.set(
win, win.connect('unmanaged', () => this._removeWindow(win)));
- let button = new WindowButton(win, this._perMonitor, this._monitor.index);
- this._settings.bind('display-all-workspaces',
- button, 'ignore-workspace', Gio.SettingsBindFlags.GET);
- this._windowList.add_child(button);
- button.show(animate);
+ const button = new WindowButton(win, this._perMonitor, this._monitor.index);
+ this._addButton(button, animate);
}
_removeWindow(win) {
--
2.47.0
From 02f295445a3383d2cf346860fefeace65be28c2c 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 12/22] window-list: Split out common TitleWidget class
Both app- and window title use the same structure, so add a shared
base class.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 61 +++++++++++++++--------------
1 file changed, 32 insertions(+), 29 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 6eb08da0..383d0b72 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -105,25 +105,42 @@ class WindowContextMenu extends PopupMenu.PopupMenu {
}
}
-class WindowTitle extends St.BoxLayout {
+class TitleWidget extends St.BoxLayout {
static {
- GObject.registerClass(this);
+ GObject.registerClass({
+ GTypeFlags: GObject.TypeFlags.ABSTRACT,
+ }, this);
}
- constructor(metaWindow) {
+ constructor() {
super({
style_class: 'window-button-box',
x_expand: true,
y_expand: true,
});
- this._metaWindow = metaWindow;
-
- this._icon = new St.Bin({style_class: 'window-button-icon'});
+ this._icon = new St.Bin({
+ style_class: 'window-button-icon',
+ });
this.add_child(this._icon);
- this.label_actor = new St.Label({y_align: Clutter.ActorAlign.CENTER});
- this.label_actor.clutter_text.single_line_mode = true;
- this.add_child(this.label_actor);
+
+ this._label = new St.Label({
+ y_align: Clutter.ActorAlign.CENTER,
+ });
+ this.add_child(this._label);
+ this.label_actor = this._label;
+ }
+}
+
+class WindowTitle extends TitleWidget {
+ static {
+ GObject.registerClass(this);
+ }
+
+ constructor(metaWindow) {
+ super();
+
+ this._metaWindow = metaWindow;
this._metaWindow.connectObject(
'notify::wm-class',
@@ -148,9 +165,9 @@ class WindowTitle extends St.BoxLayout {
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() {
@@ -166,32 +183,18 @@ class WindowTitle extends St.BoxLayout {
}
}
-class AppTitle extends St.BoxLayout {
+class AppTitle extends TitleWidget {
static {
GObject.registerClass(this);
}
constructor(app) {
- super({
- 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.add_child(icon);
-
- let label = new St.Label({
- text: app.get_name(),
- y_align: Clutter.ActorAlign.CENTER,
- });
- this.add_child(label);
- this.label_actor = label;
+ this._icon.child = app.create_icon_texture(ICON_TEXTURE_SIZE);
+ this._label.text = app.get_name();
}
}
--
2.47.0
From 426f72d1991316b927495ca7385d95b15022da77 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 3 Oct 2024 17:27:57 +0200
Subject: [PATCH 13/22] window-list: Add TitleWidget:abstract-label property
When true, the real label is replaced by a more abstract
representation. When used as drag actor, the focus is not
on identifying the window/app, but about picking a drop
location, and the reduced style helps with that.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 22 ++++++++++++++++++++++
extensions/window-list/stylesheet-dark.css | 6 ++++++
2 files changed, 28 insertions(+)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 383d0b72..3ed1c357 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -109,6 +109,12 @@ class TitleWidget extends St.BoxLayout {
static {
GObject.registerClass({
GTypeFlags: GObject.TypeFlags.ABSTRACT,
+ Properties: {
+ 'abstract-label': GObject.ParamSpec.boolean(
+ 'abstract-label', null, null,
+ GObject.ParamFlags.READWRITE,
+ false),
+ },
}, this);
}
@@ -129,6 +135,22 @@ class TitleWidget extends St.BoxLayout {
});
this.add_child(this._label);
this.label_actor = this._label;
+
+ this.bind_property('abstract-label',
+ this._label, 'visible',
+ GObject.BindingFlags.SYNC_CREATE |
+ GObject.BindingFlags.INVERT_BOOLEAN);
+
+ this._abstractLabel = new St.Widget({
+ style_class: 'window-button-abstract-label',
+ x_expand: true,
+ y_expand: true,
+ });
+ this.add_child(this._abstractLabel);
+
+ this.bind_property('abstract-label',
+ this._abstractLabel, 'visible',
+ GObject.BindingFlags.SYNC_CREATE);
}
}
diff --git a/extensions/window-list/stylesheet-dark.css b/extensions/window-list/stylesheet-dark.css
index f02fca60..fce6bcc5 100644
--- a/extensions/window-list/stylesheet-dark.css
+++ b/extensions/window-list/stylesheet-dark.css
@@ -81,3 +81,9 @@
width: 24px;
height: 24px;
}
+
+.window-button-abstract-label {
+ background-color: #888;
+ border-radius: 99px;
+ margin: 6px;
+}
--
2.47.0
From 509e41d89e4f7d661ec9a749e04d583e1affada5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 25 Sep 2024 03:20:52 +0200
Subject: [PATCH 14/22] window-list: Split out `_createTitleActor()` hook
This will allow creating a suitable drag actor that matches the
current title. In particular this allows for a drag actor that
isn't based on `ClutterClone`, and therefore doesn't inherit
focus/active/minimize/etc. styles that don't make sense outside
the actual window list.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 3ed1c357..21823cf8 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -357,6 +357,11 @@ class BaseButton extends DashItemContainer {
this._onClicked(this, 1);
}
+ _createTitleActor() {
+ throw new GObject.NotImplementedError(
+ `_createTitleActor in ${this.constructor.name}`);
+ }
+
_onClicked(_actor, _button) {
throw new GObject.NotImplementedError(
`_onClicked in ${this.constructor.name}`);
@@ -467,7 +472,7 @@ class WindowButton extends BaseButton {
this._updateVisibility();
- this._windowTitle = new WindowTitle(this.metaWindow);
+ this._windowTitle = this._createTitleActor();
this._button.set_child(this._windowTitle);
this.label_actor = this._windowTitle.label_actor;
@@ -483,6 +488,10 @@ class WindowButton extends BaseButton {
this._updateStyle();
}
+ _createTitleActor() {
+ return new WindowTitle(this.metaWindow);
+ }
+
_onClicked(actor, button) {
if (this._contextMenu.isOpen) {
this._contextMenu.close();
@@ -667,13 +676,12 @@ class AppButton extends BaseButton {
if (this._singleWindowMode) {
const [window] = windows;
- this._button.child = new WindowTitle(window);
this._contextMenu = new WindowContextMenu(this, window);
} else {
- this._button.child = new AppTitle(this.app);
this._contextMenu = new AppContextMenu(this);
}
+ this._button.child = this._createTitleActor();
this.label_actor = this._button.child.label_actor;
this._contextMenu.connect(
@@ -683,6 +691,15 @@ class AppButton extends BaseButton {
this._contextMenuManager.addMenu(this._contextMenu);
}
+ _createTitleActor() {
+ if (this._singleWindowMode) {
+ const [window] = this.getWindowList();
+ return new WindowTitle(window);
+ } else {
+ return new AppTitle(this.app);
+ }
+ }
+
_onClicked(actor, button) {
let menuWasOpen = this._menu.isOpen;
if (menuWasOpen)
--
2.47.0
From 62c8cd20e2c425909ff361ec05cba4e847c12886 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 19 Jun 2024 13:01:37 +0200
Subject: [PATCH 15/22] window-list: Rename XDND related methods and props
The window list buttons themselves will become draggable, so
include "xdnd" in the existing drag handling to disambiguate
it.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 21823cf8..d765f58f 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -866,12 +866,12 @@ class WindowList extends St.Widget {
'window-created', (dsp, win) => this._addWindow(win, true), this);
Main.xdndHandler.connectObject(
- 'drag-begin', () => this._monitorDrag(),
- 'drag-end', () => this._stopMonitoringDrag(),
+ 'drag-begin', () => this._monitorXdndDrag(),
+ 'drag-end', () => this._stopMonitoringXdndDrag(),
this);
- this._dragMonitor = {
- dragMotion: this._onDragMotion.bind(this),
+ this._xdndDragMonitor = {
+ dragMotion: this._onXdndDragMotion.bind(this),
};
this._dndTimeoutId = 0;
@@ -1059,16 +1059,16 @@ class WindowList extends St.Widget {
child?.animateOutAndDestroy();
}
- _monitorDrag() {
- DND.addDragMonitor(this._dragMonitor);
+ _monitorXdndDrag() {
+ DND.addDragMonitor(this._xdndDragMonitor);
}
- _stopMonitoringDrag() {
- DND.removeDragMonitor(this._dragMonitor);
+ _stopMonitoringXdndDrag() {
+ DND.removeDragMonitor(this._xdndDragMonitor);
this._removeActivateTimeout();
}
- _onDragMotion(dragEvent) {
+ _onXdndDragMotion(dragEvent) {
if (Main.overview.visible ||
!this.contains(dragEvent.targetActor)) {
this._removeActivateTimeout();
@@ -1116,7 +1116,7 @@ class WindowList extends St.Widget {
this._windowSignals.forEach((id, win) => win.disconnect(id));
this._windowSignals.clear();
- this._stopMonitoringDrag();
+ this._stopMonitoringXdndDrag();
this._settings.disconnectObject();
this._settings = null;
--
2.47.0
From d85fae629186c66d7fb2ebf665ee185b8f8763ae Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 25 Sep 2024 04:13:25 +0200
Subject: [PATCH 16/22] window-list: Allow rearranging window buttons
We currently sort buttons by the stable sequence to get a persistent
and predictable order. However some users want to customize that
order, and rearrange the buttons as they see fit.
Support that use case by implementing drag-and-drop behavior based
on the overview's dash.
Closes https://gitlab.gnome.org/GNOME/gnome-shell-extensions/issues/4
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 147 ++++++++++++++++++++
extensions/window-list/stylesheet-dark.css | 14 +-
extensions/window-list/stylesheet-light.css | 5 +
3 files changed, 164 insertions(+), 2 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index d765f58f..bd361646 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -26,12 +26,25 @@ import {WorkspaceIndicator} from './workspaceIndicator.js';
const ICON_TEXTURE_SIZE = 24;
const DND_ACTIVATE_TIMEOUT = 500;
+const MIN_DRAG_UPDATE_INTERVAL = 500 * GLib.TIME_SPAN_MILLISECOND;
+
const GroupingMode = {
NEVER: 0,
AUTO: 1,
ALWAYS: 2,
};
+class DragPlaceholderItem extends DashItemContainer {
+ static {
+ GObject.registerClass(this);
+ }
+
+ constructor() {
+ super();
+ this.setChild(new St.Bin({style_class: 'placeholder'}));
+ }
+}
+
/**
* @param {Shell.App} app - an app
* @returns {number} - the smallest stable sequence of the app's windows
@@ -220,6 +233,22 @@ class AppTitle extends TitleWidget {
}
}
+class DragActor extends St.Bin {
+ static {
+ GObject.registerClass(this);
+ }
+
+ constructor(source, titleActor) {
+ super({
+ style_class: 'window-button-drag-actor',
+ child: titleActor,
+ width: source.width,
+ });
+
+ this.source = source;
+ }
+}
+
class BaseButton extends DashItemContainer {
static {
GObject.registerClass({
@@ -230,6 +259,10 @@ class BaseButton extends DashItemContainer {
GObject.ParamFlags.READWRITE,
false),
},
+ Signals: {
+ 'drag-begin': {},
+ 'drag-end': {},
+ },
}, this);
}
@@ -274,6 +307,15 @@ class BaseButton extends DashItemContainer {
this._windowEnteredOrLeftMonitor.bind(this),
this);
}
+
+ this._button._delegate = this;
+ this._draggable = DND.makeDraggable(this._button);
+ this._draggable.connect('drag-begin', () => {
+ this._removeLongPressTimeout();
+ this.emit('drag-begin');
+ });
+ this._draggable.connect('drag-cancelled', () => this.emit('drag-end'));
+ this._draggable.connect('drag-end', () => this.emit('drag-end'));
}
get active() {
@@ -357,6 +399,17 @@ class BaseButton extends DashItemContainer {
this._onClicked(this, 1);
}
+ getDragActor() {
+ const titleActor = this._createTitleActor();
+ titleActor.set({abstractLabel: true});
+
+ return new DragActor(this, titleActor);
+ }
+
+ getDragActorSource() {
+ return this;
+ }
+
_createTitleActor() {
throw new GObject.NotImplementedError(
`_createTitleActor in ${this.constructor.name}`);
@@ -874,9 +927,19 @@ class WindowList extends St.Widget {
dragMotion: this._onXdndDragMotion.bind(this),
};
+ this._itemDragMonitor = {
+ dragMotion: this._onItemDragMotion.bind(this),
+ };
+
this._dndTimeoutId = 0;
this._dndWindow = null;
+ this._dragPlaceholder = null;
+ this._dragPlaceholderPos = -1;
+ this._lastPlaceholderUpdate = 0;
+
+ this._delegate = this;
+
this._settings = settings;
this._settings.connectObject('changed::grouping-mode',
() => this._groupingModeChanged(), this);
@@ -1009,6 +1072,14 @@ class WindowList extends St.Widget {
_addButton(button, animate) {
this._settings.bind('display-all-workspaces',
button, 'ignore-workspace', Gio.SettingsBindFlags.GET);
+
+ button.connect('drag-begin',
+ () => this._monitorItemDrag());
+ button.connect('drag-end', () => {
+ this._stopMonitoringItemDrag();
+ this._clearDragPlaceholder();
+ });
+
this._windowList.add_child(button);
button.show(animate);
}
@@ -1059,6 +1130,82 @@ class WindowList extends St.Widget {
child?.animateOutAndDestroy();
}
+ _clearDragPlaceholder() {
+ this._dragPlaceholder?.animateOutAndDestroy();
+ this._dragPlaceholder = null;
+ this._dragPlaceholderPos = -1;
+ }
+
+ handleDragOver(source, _actor, x, _y, _time) {
+ if (!(source instanceof BaseButton))
+ return DND.DragMotionResult.NO_DROP;
+
+ const buttons = this._windowList.get_children().filter(c => c instanceof BaseButton);
+ const buttonPos = buttons.indexOf(source);
+ const numButtons = buttons.length;
+ let boxWidth = this._windowList.width;
+
+ // Transform to window list coordinates for index calculation
+ // (mostly relevant for RTL to discard workspace indicator etc.)
+ x -= this._windowList.x;
+
+ const rtl = this.text_direction === Clutter.TextDirection.RTL;
+ let pos = rtl
+ ? numButtons - Math.round(x * numButtons / boxWidth)
+ : Math.round(x * numButtons / boxWidth);
+
+ pos = Math.clamp(pos, 0, numButtons);
+
+ const timeDelta =
+ GLib.get_monotonic_time() - this._lastPlaceholderUpdate;
+
+ if (pos !== this._dragPlaceholderPos && timeDelta >= MIN_DRAG_UPDATE_INTERVAL) {
+ this._clearDragPlaceholder();
+ this._dragPlaceholderPos = pos;
+
+ this._lastPlaceholderUpdate = GLib.get_monotonic_time();
+
+ // Don't allow positioning before or after self
+ if (pos === buttonPos || pos === buttonPos + 1)
+ return DND.DragMotionResult.CONTINUE;
+
+ this._dragPlaceholder = new DragPlaceholderItem();
+ const sibling = buttons[pos] ?? null;
+ if (sibling)
+ this._windowList.insert_child_below(this._dragPlaceholder, sibling);
+ else
+ this._windowList.insert_child_above(this._dragPlaceholder, null);
+ this._dragPlaceholder.show(true);
+ }
+
+ return this._dragPlaceholder
+ ? DND.DragMotionResult.MOVE_DROP
+ : DND.DragMotionResult.NO_DROP;
+ }
+
+ acceptDrop(source, _actor, _x, _y, _time) {
+ if (this._dragPlaceholderPos >= 0)
+ this._windowList.set_child_at_index(source, this._dragPlaceholderPos);
+
+ this._clearDragPlaceholder();
+
+ return true;
+ }
+
+ _monitorItemDrag() {
+ DND.addDragMonitor(this._itemDragMonitor);
+ }
+
+ _stopMonitoringItemDrag() {
+ DND.removeDragMonitor(this._itemDragMonitor);
+ }
+
+ _onItemDragMotion(dragEvent) {
+ if (!this._windowList.contains(dragEvent.targetActor))
+ this._clearDragPlaceholder();
+ return DND.DragMotionResult.CONTINUE;
+ }
+
_monitorXdndDrag() {
DND.addDragMonitor(this._xdndDragMonitor);
}
diff --git a/extensions/window-list/stylesheet-dark.css b/extensions/window-list/stylesheet-dark.css
index fce6bcc5..c92081d2 100644
--- a/extensions/window-list/stylesheet-dark.css
+++ b/extensions/window-list/stylesheet-dark.css
@@ -17,10 +17,19 @@
height: 2.45em;
}
-.window-button {
+.window-button,
+.window-button-drag-actor {
padding: 4px, 3px;
}
+.window-button-drag-actor {
+ background-color: #444;
+ border-radius: 7px;
+ border-width: 2px;
+ border-color: #fff;
+ box-shadow: 0 1px 2px rgba(0,0,0,0.1);
+}
+
.window-button:first-child:ltr {
padding-left: 2px;
}
@@ -41,7 +50,8 @@
transition: 100ms ease;
}
-.window-button > StWidget {
+.window-button > StWidget,
+.window-list .placeholder {
-st-natural-width: 18.75em;
max-width: 18.75em;
}
diff --git a/extensions/window-list/stylesheet-light.css b/extensions/window-list/stylesheet-light.css
index f9c51f8e..5fb39b2f 100644
--- a/extensions/window-list/stylesheet-light.css
+++ b/extensions/window-list/stylesheet-light.css
@@ -56,3 +56,8 @@
color: #aaa;
background-color: #f9f9f9;
}
+
+.window-button-drag-actor {
+ background-color: #ddd;
+ border-color: #888;
+}
--
2.47.0
From fc37241b994da3a846f5d7457e4fd21dd2fcf855 Mon Sep 17 00:00:00 2001
From: Jakub Steiner <jimmac@gmail.com>
Date: Thu, 3 Oct 2024 14:18:32 +0200
Subject: [PATCH 17/22] window-list: Indicate drop target more prominently
The drop target is the main focus of the drag operation, so make
its styling more prominent.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/stylesheet-dark.css | 6 ++++++
extensions/window-list/stylesheet-light.css | 5 ++++-
2 files changed, 10 insertions(+), 1 deletion(-)
diff --git a/extensions/window-list/stylesheet-dark.css b/extensions/window-list/stylesheet-dark.css
index c92081d2..4c06ebc0 100644
--- a/extensions/window-list/stylesheet-dark.css
+++ b/extensions/window-list/stylesheet-dark.css
@@ -56,6 +56,12 @@
max-width: 18.75em;
}
+.window-list .placeholder {
+ border: 1px solid rgba(255,255,255,0.4);
+ border-radius: 7px;
+ margin: 4px;
+}
+
.window-button:hover > StWidget {
background-color: #303030;
}
diff --git a/extensions/window-list/stylesheet-light.css b/extensions/window-list/stylesheet-light.css
index 5fb39b2f..1ecb83a9 100644
--- a/extensions/window-list/stylesheet-light.css
+++ b/extensions/window-list/stylesheet-light.css
@@ -23,7 +23,6 @@
.window-button > StWidget {
color: #000;
- background-color: transparent;
}
.window-button:hover > StWidget {
@@ -61,3 +60,7 @@
background-color: #ddd;
border-color: #888;
}
+
+.window-list .placeholder {
+ border-color: rgba(0,0,0,0.5);
+}
--
2.47.0
From e8daa4529a03c863588230fbac55bedf4c821ac3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Thu, 3 Oct 2024 17:05:42 +0200
Subject: [PATCH 18/22] window-list: Fade out drag source during drag
During a drag operation, the focus is on the where to drop the dragged
item, not to identify it or its origin.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 18 ++++++++++++++++--
1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index bd361646..7825710f 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -28,6 +28,9 @@ const DND_ACTIVATE_TIMEOUT = 500;
const MIN_DRAG_UPDATE_INTERVAL = 500 * GLib.TIME_SPAN_MILLISECOND;
+const DRAG_OPACITY = 0.3;
+const DRAG_FADE_DURATION = 200;
+
const GroupingMode = {
NEVER: 0,
AUTO: 1,
@@ -1073,9 +1076,20 @@ class WindowList extends St.Widget {
this._settings.bind('display-all-workspaces',
button, 'ignore-workspace', Gio.SettingsBindFlags.GET);
- button.connect('drag-begin',
- () => this._monitorItemDrag());
+ button.connect('drag-begin', () => {
+ button.ease({
+ opacity: 255 * DRAG_OPACITY,
+ duration: DRAG_FADE_DURATION,
+ });
+
+ this._monitorItemDrag();
+ });
button.connect('drag-end', () => {
+ button.ease({
+ opacity: 255,
+ duration: DRAG_FADE_DURATION,
+ });
+
this._stopMonitoringItemDrag();
this._clearDragPlaceholder();
});
--
2.47.0
From 58e06bd93f886b31ae24cb6871738dfdd9f60e85 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 9 Oct 2024 19:15:16 +0200
Subject: [PATCH 19/22] window-list: Shrink drag-actor size during drags
Like the previous commit, this helps with putting the focus on
the target location instead of the dragged item.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 33 +++++++++++++++++++++++++++--
1 file changed, 31 insertions(+), 2 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 7825710f..43395d1c 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -31,6 +31,8 @@ const MIN_DRAG_UPDATE_INTERVAL = 500 * GLib.TIME_SPAN_MILLISECOND;
const DRAG_OPACITY = 0.3;
const DRAG_FADE_DURATION = 200;
+const DRAG_RESIZE_DURATION = 400;
+
const GroupingMode = {
NEVER: 0,
AUTO: 1,
@@ -250,6 +252,24 @@ class DragActor extends St.Bin {
this.source = source;
}
+
+ setTargetWidth(width) {
+ const currentWidth = this.width;
+
+ // set width immediately so shell's DND code uses correct values
+ this.set({width});
+
+ // then transition from the original to the new width
+ const laters = global.compositor.get_laters();
+ laters.add(Meta.LaterType.BEFORE_REDRAW, () => {
+ this.set({width: currentWidth});
+ this.ease({
+ width,
+ duration: DRAG_RESIZE_DURATION,
+ });
+ return GLib.SOURCE_REMOVE;
+ });
+ }
}
class BaseButton extends DashItemContainer {
@@ -317,7 +337,10 @@ class BaseButton extends DashItemContainer {
this._removeLongPressTimeout();
this.emit('drag-begin');
});
- this._draggable.connect('drag-cancelled', () => this.emit('drag-end'));
+ this._draggable.connect('drag-cancelled', () => {
+ this._draggable._dragActor?.setTargetWidth(this.width);
+ this.emit('drag-end');
+ });
this._draggable.connect('drag-end', () => this.emit('drag-end'));
}
@@ -406,7 +429,13 @@ class BaseButton extends DashItemContainer {
const titleActor = this._createTitleActor();
titleActor.set({abstractLabel: true});
- return new DragActor(this, titleActor);
+ const dragActor = new DragActor(this, titleActor);
+
+ const [, natWidth] = this.get_preferred_width(-1);
+ const targetWidth = Math.min(natWidth / 2, this.width);
+ dragActor.setTargetWidth(targetWidth);
+
+ return dragActor;
}
getDragActorSource() {
--
2.47.0
From be0234ced2cb32e7ae253097d5ba8a285ca78c5d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 8 Oct 2024 19:25:53 +0200
Subject: [PATCH 20/22] window-list: Handle DND events near the drop target
Even with the previous change, the dragged actor has the tendency
of obscuring the possible drop target. To alleviate this, handle
DND events near drop targets as if they occurred on the target.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 26 ++++++++++++++++++++++++--
1 file changed, 24 insertions(+), 2 deletions(-)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 43395d1c..169b5518 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -33,6 +33,8 @@ const DRAG_FADE_DURATION = 200;
const DRAG_RESIZE_DURATION = 400;
+const DRAG_PROXIMITY_THRESHOLD = 30;
+
const GroupingMode = {
NEVER: 0,
AUTO: 1,
@@ -961,6 +963,7 @@ class WindowList extends St.Widget {
this._itemDragMonitor = {
dragMotion: this._onItemDragMotion.bind(this),
+ dragDrop: this._onItemDragDrop.bind(this),
};
this._dndTimeoutId = 0;
@@ -1244,11 +1247,30 @@ class WindowList extends St.Widget {
}
_onItemDragMotion(dragEvent) {
- if (!this._windowList.contains(dragEvent.targetActor))
- this._clearDragPlaceholder();
+ const {source, targetActor, dragActor, x, y} = dragEvent;
+
+ const hasTarget = this._windowList.contains(targetActor);
+ const isNear = Math.abs(y - this.y) < DRAG_PROXIMITY_THRESHOLD;
+
+ if (hasTarget || isNear)
+ return this.handleDragOver(source, dragActor, x, y);
+
+ this._clearDragPlaceholder();
return DND.DragMotionResult.CONTINUE;
}
+ _onItemDragDrop(dropEvent) {
+ if (this._dragPlaceholderPos < 0)
+ return DND.DragDropResult.CONTINUE;
+
+ const {source} = dropEvent.dropActor;
+ this.acceptDrop(source);
+ dropEvent.dropActor.destroy();
+ // HACK: SUCESS would make more sense, but results in gnome-shell
+ // skipping all drag-end code
+ return DND.DragDropResult.CONTINUE;
+ }
+
_monitorXdndDrag() {
DND.addDragMonitor(this._xdndDragMonitor);
}
--
2.47.0
From 3e707e6fa6ee4c23e3f6f220a93fdbc651757763 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Wed, 26 Jun 2024 00:58:18 +0200
Subject: [PATCH 21/22] window-list: Add `id` property to buttons
A string ID that uniquely identifies a button will allow to
serialize/deserialize the positions in the next commit.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index 169b5518..b5be15e6 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -575,6 +575,10 @@ class WindowButton extends BaseButton {
this._updateStyle();
}
+ get id() {
+ return `window:${this.metaWindow.get_id()}`;
+ }
+
_createTitleActor() {
return new WindowTitle(this.metaWindow);
}
@@ -714,6 +718,10 @@ class AppButton extends BaseButton {
this._updateStyle();
}
+ get id() {
+ return `app:${this.app.get_id()}`;
+ }
+
_windowEnteredOrLeftMonitor(metaDisplay, monitorIndex, metaWindow) {
if (this._windowTracker.get_window_app(metaWindow) === this.app &&
monitorIndex === this._monitorIndex) {
--
2.47.0
From f6f3176f3fb004a5410de83ee1aceae7e594150f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
Date: Tue, 24 Sep 2024 20:31:06 +0200
Subject: [PATCH 22/22] window-list: Save and restore positions as runtime
state
While it doesn't make sense for window list positions to be truly
persistent like dash items, some persistence is desirable.
Otherwise any manually set position is lost when the extension
is disabled, for example when locking the screen.
To address this, serialize the positions as runtime state on drop,
and restore them when populating the list.
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell-extensions/-/merge_requests/338>
---
extensions/window-list/extension.js | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/extensions/window-list/extension.js b/extensions/window-list/extension.js
index b5be15e6..885bb5ac 100644
--- a/extensions/window-list/extension.js
+++ b/extensions/window-list/extension.js
@@ -35,6 +35,8 @@ const DRAG_RESIZE_DURATION = 400;
const DRAG_PROXIMITY_THRESHOLD = 30;
+const SAVED_POSITIONS_KEY = 'window-list-positions';
+
const GroupingMode = {
NEVER: 0,
AUTO: 1,
@@ -1095,6 +1097,8 @@ class WindowList extends St.Widget {
for (let i = 0; i < apps.length; i++)
this._addApp(apps[i], false);
}
+
+ this._restorePositions();
}
_updateKeyboardAnchor() {
@@ -1243,9 +1247,33 @@ class WindowList extends St.Widget {
this._clearDragPlaceholder();
+ this._savePositions();
+
return true;
}
+ _getPositionStateKey() {
+ return `${SAVED_POSITIONS_KEY}:${this._monitor.index}`;
+ }
+
+ _savePositions() {
+ const buttons = this._windowList.get_children()
+ .filter(b => b instanceof BaseButton);
+ global.set_runtime_state(this._getPositionStateKey(),
+ new GLib.Variant('as', buttons.map(b => b.id)));
+ }
+
+ _restorePositions() {
+ const positions = global.get_runtime_state('as',
+ this._getPositionStateKey())?.deepUnpack() ?? [];
+
+ for (const button of this._windowList.get_children()) {
+ const pos = positions.indexOf(button.id);
+ if (pos > -1)
+ this._windowList.set_child_at_index(button, pos);
+ }
+ }
+
_monitorItemDrag() {
DND.addDragMonitor(this._itemDragMonitor);
}
--
2.47.0