feat: adding in ability to resize windows in a container

This commit is contained in:
Lucas Oskorep
2025-10-16 00:09:11 -04:00
parent 265ff05436
commit 2446520ced
5 changed files with 156 additions and 21 deletions

View File

@@ -53,6 +53,11 @@ export default class aerospike extends Extension {
this.refreshKeybinding('join-with-right'); this.refreshKeybinding('join-with-right');
}); });
this.settings.connect('changed::reset-window-sizes', () => {
log(`Reset window sizes keybinding changed to: ${this.settings.get_strv('reset-window-sizes')}`);
this.refreshKeybinding('reset-window-sizes');
});
this.settings.connect('changed::dropdown-option', () => { this.settings.connect('changed::dropdown-option', () => {
log(`Dropdown option changed to: ${this.settings.get_string('dropdown-option')}`); log(`Dropdown option changed to: ${this.settings.get_string('dropdown-option')}`);
}); });
@@ -88,6 +93,11 @@ export default class aerospike extends Extension {
Logger.info('Keybinding 4 was pressed!'); Logger.info('Keybinding 4 was pressed!');
}); });
break; break;
case 'reset-window-sizes':
this.bindKeybinding('reset-window-sizes', () => {
this.windowManager.resetAllWindowSizes();
});
break;
} }
} }
@@ -114,6 +124,10 @@ export default class aerospike extends Extension {
this.bindKeybinding('join-with-right', () => { this.bindKeybinding('join-with-right', () => {
Logger.info('Keybinding 4 was pressed!'); Logger.info('Keybinding 4 was pressed!');
}); });
this.bindKeybinding('reset-window-sizes', () => {
this.windowManager.resetAllWindowSizes();
});
} }
private bindKeybinding(settingName: string, callback: () => void) { private bindKeybinding(settingName: string, callback: () => void) {

View File

@@ -37,5 +37,11 @@
<description>Keyboard shortcut for triggering action 4</description> <description>Keyboard shortcut for triggering action 4</description>
</key> </key>
<key name="reset-window-sizes" type="as">
<default><![CDATA[['<Alt>z']]]></default>
<summary>Reset all window sizes</summary>
<description>Remove all custom window sizes and return to equal distribution</description>
</key>
</schema> </schema>
</schemalist> </schemalist>

View File

@@ -16,12 +16,13 @@ export default class WindowContainer {
_tiledWindowLookup: Map<number, WindowWrapper>; _tiledWindowLookup: Map<number, WindowWrapper>;
_orientation: Orientation = Orientation.HORIZONTAL; _orientation: Orientation = Orientation.HORIZONTAL;
_workArea: Rect; _workArea: Rect;
_customSizes: Map<number, number>;
constructor(workspaceArea: Rect,) { constructor(workspaceArea: Rect,) {
// this._id = monitorId;
this._tiledItems = []; this._tiledItems = [];
this._tiledWindowLookup = new Map<number, WindowWrapper>(); this._tiledWindowLookup = new Map<number, WindowWrapper>();
this._workArea = workspaceArea; this._workArea = workspaceArea;
this._customSizes = new Map<number, number>();
} }
@@ -34,7 +35,6 @@ export default class WindowContainer {
// Add window to managed windows // Add window to managed windows
this._tiledItems.push(winWrap); this._tiledItems.push(winWrap);
this._tiledWindowLookup.set(winWrap.getWindowId(), winWrap); this._tiledWindowLookup.set(winWrap.getWindowId(), winWrap);
// winWrap.setParent(this);
queueEvent({ queueEvent({
name: "tiling-windows", name: "tiling-windows",
callback: () => { callback: () => {
@@ -74,6 +74,7 @@ export default class WindowContainer {
removeWindow(win_id: number): void { removeWindow(win_id: number): void {
if (this._tiledWindowLookup.has(win_id)) { if (this._tiledWindowLookup.has(win_id)) {
this._tiledWindowLookup.delete(win_id); this._tiledWindowLookup.delete(win_id);
this._customSizes.delete(win_id); // Clean up custom size when window is removed
const index = this._getIndexOfWindow(win_id) const index = this._getIndexOfWindow(win_id)
this._tiledItems.splice(index, 1); this._tiledItems.splice(index, 1);
} else { } else {
@@ -104,10 +105,7 @@ export default class WindowContainer {
tileWindows() { tileWindows() {
Logger.log("TILING WINDOWS IN CONTAINER") Logger.log("TILING WINDOWS IN CONTAINER")
Logger.log("WorkArea", this._workArea); Logger.log("WorkArea", this._workArea);
// Get all windows for current workspaceArea
this._tileItems() this._tileItems()
return true return true
@@ -137,30 +135,72 @@ export default class WindowContainer {
} }
getVerticalBounds(): Rect[] { getVerticalBounds(): Rect[] {
const items = this._tiledItems // Calculate available height after accounting for custom-sized windows
const containerHeight = Math.floor(this._workArea.height / items.length); let totalCustomHeight = 0;
return items.map((_, index) => { let numFlexibleItems = 0;
const y = this._workArea.y + (index * containerHeight);
return { this._tiledItems.forEach((item) => {
if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
totalCustomHeight += this._customSizes.get(item.getWindowId())!;
} else {
numFlexibleItems++;
}
});
const remainingHeight = this._workArea.height - totalCustomHeight;
const flexHeight = numFlexibleItems > 0 ? Math.floor(remainingHeight / numFlexibleItems) : 0;
// Build the bounds array
let currentY = this._workArea.y;
return this._tiledItems.map((item) => {
let height = flexHeight;
if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
height = this._customSizes.get(item.getWindowId())!;
}
const rect = {
x: this._workArea.x, x: this._workArea.x,
y: y, y: currentY,
width: this._workArea.width, width: this._workArea.width,
height: containerHeight height: height
} as Rect; } as Rect;
currentY += height;
return rect;
}); });
} }
getHorizontalBounds(): Rect[] { getHorizontalBounds(): Rect[] {
const windowWidth = Math.floor(this._workArea.width / this._tiledItems.length); // Calculate available width after accounting for custom-sized windows
let totalCustomWidth = 0;
let numFlexibleItems = 0;
return this._tiledItems.map((_, index) => { this._tiledItems.forEach((item) => {
const x = this._workArea.x + (index * windowWidth); if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
return { totalCustomWidth += this._customSizes.get(item.getWindowId())!;
x: x, } else {
numFlexibleItems++;
}
});
const remainingWidth = this._workArea.width - totalCustomWidth;
const flexWidth = numFlexibleItems > 0 ? Math.floor(remainingWidth / numFlexibleItems) : 0;
// Build the bounds array
let currentX = this._workArea.x;
return this._tiledItems.map((item) => {
let width = flexWidth;
if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
width = this._customSizes.get(item.getWindowId())!;
}
const rect = {
x: currentX,
y: this._workArea.y, y: this._workArea.y,
width: windowWidth, width: width,
height: this._workArea.height height: this._workArea.height
} as Rect; } as Rect;
currentX += width;
return rect;
}); });
} }
@@ -201,5 +241,38 @@ export default class WindowContainer {
} }
windowManuallyResized(win_id: number): void {
const window = this.getWindow(win_id);
if (!window) {
// Check nested containers
for (const item of this._tiledItems) {
if (item instanceof WindowContainer) {
item.windowManuallyResized(win_id);
}
}
return;
}
const rect = window.getRect();
if (this._orientation === Orientation.HORIZONTAL) {
this._customSizes.set(win_id, rect.width);
Logger.log(`Window ${win_id} manually resized to width: ${rect.width}`);
} else {
this._customSizes.set(win_id, rect.height);
Logger.log(`Window ${win_id} manually resized to height: ${rect.height}`);
}
}
resetAllWindowSizes(): void {
Logger.log("Clearing all custom window sizes in container");
this._customSizes.clear();
// Also clear nested containers
for (const item of this._tiledItems) {
if (item instanceof WindowContainer) {
item.resetAllWindowSizes();
}
}
}
} }

View File

@@ -83,4 +83,21 @@ export default class Monitor {
this._workspaces[item.getWorkspace()].itemDragged(item, x, y); this._workspaces[item.getWorkspace()].itemDragged(item, x, y);
} }
windowManuallyResized(win_id: number): void {
// Find which workspace contains the window and notify it
for (const container of this._workspaces) {
const win = container.getWindow(win_id);
if (win) {
container.windowManuallyResized(win_id);
return;
}
}
}
resetAllWindowSizes(): void {
for (const container of this._workspaces) {
container.resetAllWindowSizes();
}
}
} }

View File

@@ -199,9 +199,6 @@ export default class WindowManager implements IWindowManager {
handleGrabOpBegin(display: Meta.Display, window: Meta.Window, op: Meta.GrabOp): void { handleGrabOpBegin(display: Meta.Display, window: Meta.Window, op: Meta.GrabOp): void {
if (op === Meta.GrabOp.MOVING_UNCONSTRAINED){
}
Logger.log("Grab Op Start", op); Logger.log("Grab Op Start", op);
Logger.log(display, window, op) Logger.log(display, window, op)
Logger.log(window.get_monitor()) Logger.log(window.get_monitor())
@@ -210,9 +207,29 @@ export default class WindowManager implements IWindowManager {
this._grabbedWindowId = window.get_id(); this._grabbedWindowId = window.get_id();
} }
_isResizeOperation(op: Meta.GrabOp): boolean {
return op === Meta.GrabOp.RESIZING_E ||
op === Meta.GrabOp.RESIZING_W ||
op === Meta.GrabOp.RESIZING_N ||
op === Meta.GrabOp.RESIZING_S ||
op === Meta.GrabOp.RESIZING_NE ||
op === Meta.GrabOp.RESIZING_NW ||
op === Meta.GrabOp.RESIZING_SE ||
op === Meta.GrabOp.RESIZING_SW;
}
handleGrabOpEnd(display: Meta.Display, window: Meta.Window, op: Meta.GrabOp): void { handleGrabOpEnd(display: Meta.Display, window: Meta.Window, op: Meta.GrabOp): void {
Logger.log("Grab Op End ", op); Logger.log("Grab Op End ", op);
Logger.log("primary display", display.get_primary_monitor()) Logger.log("primary display", display.get_primary_monitor())
// Check if this was a resize operation
if (this._isResizeOperation(op)) {
const monitor = this._monitors.get(window.get_monitor());
if (monitor) {
monitor.windowManuallyResized(window.get_id());
}
}
this._grabbedWindowId = _UNUSED_WINDOW_ID; this._grabbedWindowId = _UNUSED_WINDOW_ID;
this._getWrappedWindow(window)?.stopDragging(); this._getWrappedWindow(window)?.stopDragging();
this._tileMonitors(); this._tileMonitors();
@@ -419,5 +436,13 @@ export default class WindowManager implements IWindowManager {
return null; return null;
} }
public resetAllWindowSizes(): void {
Logger.log("Resetting all custom window sizes");
this._monitors.forEach((monitor: Monitor) => {
monitor.resetAllWindowSizes();
});
this._tileMonitors();
}
} }