diff --git a/lib/extension/tree.js b/lib/extension/tree.js index ea957d29..eb5c6722 100644 --- a/lib/extension/tree.js +++ b/lib/extension/tree.js @@ -709,9 +709,33 @@ export class Tree extends Node { global.window_group.remove_child(existingWsNode.actorBin); this.removeChild(existingWsNode); + // GNOME renumbered the workspaces after it: rename their nodes to match + this._renumberWorkspaces(wsIndex + 1); return true; } + /** + * Workspace and monitor nodes are named by workspace index (`ws{n}`, `mo{m}ws{n}`), and GNOME + * renumbers the workspaces after one that is removed. Rename the nodes of the workspaces from + * `fromIndex` on down by one, so that each keeps the windows of its workspace. Without this, a + * window was filed under the node of another workspace (#470). (GNOME only ever adds a workspace + * at the end; a window dropped between two in the overview goes to a new last workspace and the + * windows after it move one up, each through its own workspace change.) + */ + _renumberWorkspaces(fromIndex) { + const indexOf = (node) => parseInt(String(node.nodeValue).slice(2), 10); + this.nodeWorkpaces + .filter((ws) => indexOf(ws) >= fromIndex) + .sort((a, b) => indexOf(a) - indexOf(b)) // lowest first: the new names are free already + .forEach((ws) => { + const index = indexOf(ws) - 1; + ws._data = `ws${index}`; + ws.getNodeByType(NODE_TYPES.MONITOR).forEach((monitor) => { + monitor._data = String(monitor.nodeValue).replace(/ws\d+$/, `ws${index}`); + }); + }); + } + get nodeWorkpaces() { let nodeWorkspaces = this.getNodeByType(NODE_TYPES.WORKSPACE); return nodeWorkspaces;