Skip to content
Open
Show file tree
Hide file tree
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
16 changes: 9 additions & 7 deletions lib/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,8 @@ export class TilingController {
}

_resolveTilingContext(window, wrapper) {
let workspace = window.get_workspace ? window.get_workspace() : null;
let monitorIndex = window.get_monitor ? window.get_monitor() : -1;
let workspace = wrapper ? wrapper.effectiveWorkspace : (window.get_workspace ? window.get_workspace() : null);
let monitorIndex = wrapper ? wrapper.effectiveMonitorIndex : (window.get_monitor ? window.get_monitor() : -1);

if (!workspace) workspace = global.workspace_manager.get_active_workspace();
if (monitorIndex < 0) monitorIndex = global.display.get_current_monitor();
Expand All @@ -146,7 +146,7 @@ export class TilingController {
const preferredSlot = isRestoring ? this._restoringWindows.get(window) : undefined;
if (isRestoring) {
monitorIndex = wrapper.monitorIndex;
let currentMon = window.get_monitor ? window.get_monitor() : -1;
let currentMon = wrapper ? wrapper.effectiveMonitorIndex : (window.get_monitor ? window.get_monitor() : -1);
if (!window.minimized && currentMon === wrapper.monitorIndex) {
this._restoringWindows.delete(window);
}
Expand Down Expand Up @@ -324,10 +324,11 @@ export class TilingController {
*/
moveWindowDirection(window, direction) {
if (!window) return;
const workspace = window.get_workspace();
const wrapper = this._windowWrappers.get(window);
const workspace = wrapper ? wrapper.effectiveWorkspace : window.get_workspace();
if (!workspace) return;

const monitorIndex = window.get_monitor();
const monitorIndex = wrapper ? wrapper.effectiveMonitorIndex : window.get_monitor();
const monitorId = this.monitorManager.getMonitorId(monitorIndex);
const layout = this.workspaceManager.getLayout(workspace);

Expand All @@ -338,10 +339,11 @@ export class TilingController {

focusWindowDirection(window, direction) {
if (!window) return;
const workspace = window.get_workspace();
const wrapper = this._windowWrappers.get(window);
const workspace = wrapper ? wrapper.effectiveWorkspace : window.get_workspace();
if (!workspace) return;

const monitorIndex = window.get_monitor();
const monitorIndex = wrapper ? wrapper.effectiveMonitorIndex : window.get_monitor();
const monitorId = this.monitorManager.getMonitorId(monitorIndex);
const layout = this.workspaceManager.getLayout(workspace);

Expand Down
14 changes: 11 additions & 3 deletions lib/monitor.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ export class MonitorManager {
this.controller.setBatchMode(true);
const windows = workspace.list_windows();
windows.forEach(w => {
if (w.get_monitor() === monitorIndex && (!w.minimized || includeMinimized)) {
const wrapper = this.controller._windowWrappers.get(w);
const m = wrapper ? wrapper.effectiveMonitorIndex : w.get_monitor();
if (m === monitorIndex && (!w.minimized || includeMinimized)) {
w.delete(global.get_current_time());
}
});
Expand Down Expand Up @@ -221,10 +223,13 @@ export class MonitorManager {
this.controller.setBatchMode(true);
const windows = workspace.list_windows();
windows.forEach(w => {
const m = w.get_monitor();
const wrapper = this.controller._windowWrappers.get(w);
const m = wrapper ? wrapper.effectiveMonitorIndex : w.get_monitor();
if (m === activeMonitorIndex) {
if (wrapper) wrapper._expectedMonitorIndex = targetMonitorIndex;
w.move_to_monitor(targetMonitorIndex);
} else if (m === targetMonitorIndex) {
if (wrapper) wrapper._expectedMonitorIndex = activeMonitorIndex;
w.move_to_monitor(activeMonitorIndex);
}
});
Expand All @@ -251,7 +256,10 @@ export class MonitorManager {
this.controller.setBatchMode(true);
const windows = activeWorkspace.list_windows();
windows.forEach(w => {
if (w.get_monitor() === monitorIndex) {
const wrapper = this.controller._windowWrappers.get(w);
const m = wrapper ? wrapper.effectiveMonitorIndex : w.get_monitor();
if (m === monitorIndex) {
if (wrapper) wrapper._expectedWorkspace = targetWorkspace;
w.change_workspace(targetWorkspace);
}
});
Expand Down
31 changes: 31 additions & 0 deletions lib/window.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@ export class WindowWrapper {
return (this.window.get_title && this.window.get_title()) || 'Unknown';
}

// Expected State Cache to prevent race condition when working with monitors in rapid succession
get effectiveMonitorIndex() {
let m = this.window.get_monitor ? this.window.get_monitor() : -1;
if (this._expectedMonitorIndex !== undefined) {
if (m !== this._expectedMonitorIndex) {
m = this._expectedMonitorIndex;
} else {
delete this._expectedMonitorIndex;
}
}
return m;
}

// Expected State Cache to prevent race condition when working with workspaces in rapid succession
get effectiveWorkspace() {
let w = this.window.get_workspace ? this.window.get_workspace() : null;
if (this._expectedWorkspace !== undefined) {
if (w !== this._expectedWorkspace) {
w = this._expectedWorkspace;
} else {
delete this._expectedWorkspace;
}
}
return w;
}

bindSignals() {
if (!this.signals.has('unmanaged')) {
this.signals.set('unmanaged', this.window.connect('unmanaged', () => this.controller.untile(this.window)));
Expand Down Expand Up @@ -90,6 +116,11 @@ export class WindowWrapper {
applyGeometry(rect) {
if (this.unmanaged || !this.window.move_resize_frame || this.window.minimized) return;

// Prevent infinite resize loops caused by Wayland clamping premature out-of-bounds resizes.
// Wait for Mutter's asynchronous state to catch up to our Expected State Cache.
if (this._expectedMonitorIndex !== undefined && this.window.get_monitor() !== this._expectedMonitorIndex) return;
if (this._expectedWorkspace !== undefined && this.window.get_workspace() !== this._expectedWorkspace) return;

try {
if (this.window.get_monitor && this.monitorIndex >= 0 && this.window.get_monitor() !== this.monitorIndex) {
if (this.window.move_to_monitor) {
Expand Down
Loading