diff --git a/extension.ts b/extension.ts
index a503b40..77813ff 100644
--- a/extension.ts
+++ b/extension.ts
@@ -53,6 +53,11 @@ export default class aerospike extends Extension {
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', () => {
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!');
});
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', () => {
Logger.info('Keybinding 4 was pressed!');
});
+
+ this.bindKeybinding('reset-window-sizes', () => {
+ this.windowManager.resetAllWindowSizes();
+ });
}
private bindKeybinding(settingName: string, callback: () => void) {
diff --git a/schemas/org.gnome.shell.extensions.aerospike.gschema.xml b/schemas/org.gnome.shell.extensions.aerospike.gschema.xml
index cdea8da..e8a8f68 100644
--- a/schemas/org.gnome.shell.extensions.aerospike.gschema.xml
+++ b/schemas/org.gnome.shell.extensions.aerospike.gschema.xml
@@ -37,5 +37,11 @@
Keyboard shortcut for triggering action 4
+
+ z']]]>
+ Reset all window sizes
+ Remove all custom window sizes and return to equal distribution
+
+
\ No newline at end of file
diff --git a/src/wm/container.ts b/src/wm/container.ts
index 159d477..4135dd7 100644
--- a/src/wm/container.ts
+++ b/src/wm/container.ts
@@ -16,12 +16,13 @@ export default class WindowContainer {
_tiledWindowLookup: Map;
_orientation: Orientation = Orientation.HORIZONTAL;
_workArea: Rect;
+ _customSizes: Map;
constructor(workspaceArea: Rect,) {
- // this._id = monitorId;
this._tiledItems = [];
this._tiledWindowLookup = new Map();
this._workArea = workspaceArea;
+ this._customSizes = new Map();
}
@@ -34,7 +35,6 @@ export default class WindowContainer {
// Add window to managed windows
this._tiledItems.push(winWrap);
this._tiledWindowLookup.set(winWrap.getWindowId(), winWrap);
- // winWrap.setParent(this);
queueEvent({
name: "tiling-windows",
callback: () => {
@@ -74,6 +74,7 @@ export default class WindowContainer {
removeWindow(win_id: number): void {
if (this._tiledWindowLookup.has(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)
this._tiledItems.splice(index, 1);
} else {
@@ -104,10 +105,7 @@ export default class WindowContainer {
tileWindows() {
Logger.log("TILING WINDOWS IN CONTAINER")
-
Logger.log("WorkArea", this._workArea);
-
- // Get all windows for current workspaceArea
this._tileItems()
return true
@@ -137,30 +135,72 @@ export default class WindowContainer {
}
getVerticalBounds(): Rect[] {
- const items = this._tiledItems
- const containerHeight = Math.floor(this._workArea.height / items.length);
- return items.map((_, index) => {
- const y = this._workArea.y + (index * containerHeight);
- return {
+ // Calculate available height after accounting for custom-sized windows
+ let totalCustomHeight = 0;
+ let numFlexibleItems = 0;
+
+ 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,
- y: y,
+ y: currentY,
width: this._workArea.width,
- height: containerHeight
+ height: height
} as Rect;
+ currentY += height;
+ return 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) => {
- const x = this._workArea.x + (index * windowWidth);
- return {
- x: x,
+ this._tiledItems.forEach((item) => {
+ if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
+ totalCustomWidth += this._customSizes.get(item.getWindowId())!;
+ } 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,
- width: windowWidth,
+ width: width,
height: this._workArea.height
} 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();
+ }
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/wm/monitor.ts b/src/wm/monitor.ts
index 640f74d..6d12a6c 100644
--- a/src/wm/monitor.ts
+++ b/src/wm/monitor.ts
@@ -83,4 +83,21 @@ export default class Monitor {
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();
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/wm/windowManager.ts b/src/wm/windowManager.ts
index d095593..1fd5ac6 100644
--- a/src/wm/windowManager.ts
+++ b/src/wm/windowManager.ts
@@ -199,9 +199,6 @@ export default class WindowManager implements IWindowManager {
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(display, window, op)
Logger.log(window.get_monitor())
@@ -210,9 +207,29 @@ export default class WindowManager implements IWindowManager {
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 {
Logger.log("Grab Op End ", op);
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._getWrappedWindow(window)?.stopDragging();
this._tileMonitors();
@@ -419,5 +436,13 @@ export default class WindowManager implements IWindowManager {
return null;
}
+ public resetAllWindowSizes(): void {
+ Logger.log("Resetting all custom window sizes");
+ this._monitors.forEach((monitor: Monitor) => {
+ monitor.resetAllWindowSizes();
+ });
+ this._tileMonitors();
+ }
+
}