Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 85 additions & 9 deletions lib/extension/window.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,8 @@ export class WindowManager extends GObject.Object {
let wmId = metaWindow.get_id();

for (let override of overrides) {
// ignore already floating and find correct window instance
if (override.wmClass === wmClass && override.mode === "float" && !override.wmTitle) {
if (withWmId && override.wmId !== wmId) {
continue;
}
return;
}
// if the window is already floating
if (override.wmClass === wmClass && override.mode === "float" && !override.wmTitle) return;
}
overrides.push({
wmClass: wmClass,
Expand All @@ -120,7 +115,6 @@ export class WindowManager extends GObject.Object {
// Save the updated overrides back to the ConfigManager
currentProps.overrides = overrides;
this.ext.configMgr.windowProps = currentProps;
this.windowProps = currentProps;
}

removeFloatOverride(metaWindow, withWmId) {
Expand All @@ -141,7 +135,6 @@ export class WindowManager extends GObject.Object {
// Save the updated overrides back to the ConfigManager
currentProps.overrides = overrides;
this.ext.configMgr.windowProps = currentProps;
this.windowProps = currentProps;
}

toggleFloatingMode(action, metaWindow) {
Expand Down Expand Up @@ -2453,10 +2446,61 @@ export class WindowManager extends GObject.Object {

focusNodeWindow.initGrabOp = grabOp;
focusNodeWindow.initRect = Utils.removeGapOnRect(frameRect, gaps);

// Start live-resize polling loop for resize grabs
if (focusNodeWindow.grabMode === GRAB_TYPES.RESIZING) {
this._startLiveResizeLoop(focusNodeWindow);
}
}
}

_startLiveResizeLoop(focusNodeWindow) {
this._stopLiveResizeLoop();

// Cache gaps once — they don't change during a resize
const gaps = this.calculateGaps(focusNodeWindow);
let lastWidth = focusNodeWindow.initRect?.width;
let lastHeight = focusNodeWindow.initRect?.height;

this._liveResizeSrcId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 16, () => {
const metaWindow = focusNodeWindow.nodeValue;
if (!metaWindow || !focusNodeWindow.grabMode) {
this._liveResizeSrcId = 0;
return GLib.SOURCE_REMOVE;
}

const frameRect = metaWindow.get_frame_rect();
const currentRect = Utils.removeGapOnRect(frameRect, gaps);

// Skip if size hasn't changed — also prevents double-processing on X11
// where size-changed signals fire alongside this loop
if (currentRect.width === lastWidth && currentRect.height === lastHeight) {
return GLib.SOURCE_CONTINUE;
}
lastWidth = currentRect.width;
lastHeight = currentRect.height;

this._handleResizing(focusNodeWindow);

// Update initRect so next tick delta is relative to current frame,
// not the grab start (prevents percent accumulation)
focusNodeWindow.initRect = currentRect;

this._liveResizeNeighbors(focusNodeWindow);

return GLib.SOURCE_CONTINUE;
});
}

_stopLiveResizeLoop() {
if (this._liveResizeSrcId) {
GLib.Source.remove(this._liveResizeSrcId);
this._liveResizeSrcId = 0;
}
}

_handleGrabOpEnd(_display, _metaWindow, grabOp) {
this._stopLiveResizeLoop();
this.unfreezeRender();
let focusMetaWindow = this.focusMetaWindow;
if (!focusMetaWindow) return;
Expand Down Expand Up @@ -2665,6 +2709,38 @@ export class WindowManager extends GObject.Object {
}
}

/**
* During a mouse-drag resize, immediately re-layout all tiled windows
* EXCEPT the one currently being dragged (GNOME owns its position).
* Bypasses this.move() which is blocked by metaWindow.grabbed on Wayland.
*/
_liveResizeNeighbors(draggingNodeWindow) {
const draggingMetaWin = draggingNodeWindow.nodeValue;

// Only reprocess the affected container subtree, not the entire tree
const parentNode = draggingNodeWindow.parentNode;
if (parentNode) {
this.tree.processNode(parentNode);
}

// Move all tiled windows except the one being dragged
const tiledWindows = this.tree.getNodeByType(NODE_TYPES.WINDOW);
tiledWindows.forEach((nodeWin) => {
if (nodeWin.nodeValue === draggingMetaWin) return; // GNOME owns this
if (nodeWin.isFloat()) return;
if (!nodeWin.renderRect) return;
const r = nodeWin.renderRect;
if (r.width > 0 && r.height > 0) {
// Call move_resize_frame directly — this.move() bails out because
// metaWindow.grabbed is true for all windows during a Wayland grab
const actor = nodeWin.nodeValue.get_compositor_private();
if (!actor) return;
actor.remove_all_transitions();
nodeWin.nodeValue.move_resize_frame(true, r.x, r.y, r.width, r.height);
}
});
}

_handleMoving(focusNodeWindow) {
if (!focusNodeWindow || focusNodeWindow.mode !== WINDOW_MODES.GRAB_TILE) return;

Expand Down
Loading