feat: adding resizing
This commit is contained in:
@@ -16,7 +16,7 @@ export default class WindowContainer {
|
||||
_tiledWindowLookup: Map<number, WindowWrapper>;
|
||||
_orientation: Orientation = Orientation.HORIZONTAL;
|
||||
_workArea: Rect;
|
||||
_customSizes: Map<number, number>;
|
||||
_customSizes: Map<number, number>; // Maps index to custom width (horizontal) or height (vertical)
|
||||
|
||||
constructor(workspaceArea: Rect,) {
|
||||
this._tiledItems = [];
|
||||
@@ -74,9 +74,10 @@ 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);
|
||||
// Shift custom sizes after removed index
|
||||
this._shiftCustomSizesAfterRemoval(index);
|
||||
} else {
|
||||
for (const item of this._tiledItems) {
|
||||
if (item instanceof WindowContainer) {
|
||||
@@ -87,6 +88,22 @@ export default class WindowContainer {
|
||||
this.tileWindows()
|
||||
}
|
||||
|
||||
_shiftCustomSizesAfterRemoval(removedIndex: number): void {
|
||||
// Rebuild the custom sizes map with shifted indices
|
||||
const newCustomSizes = new Map<number, number>();
|
||||
this._customSizes.forEach((size, index) => {
|
||||
if (index < removedIndex) {
|
||||
// Keep indices before removal
|
||||
newCustomSizes.set(index, size);
|
||||
} else if (index > removedIndex) {
|
||||
// Shift down indices after removal
|
||||
newCustomSizes.set(index - 1, size);
|
||||
}
|
||||
// Skip the removed index
|
||||
});
|
||||
this._customSizes = newCustomSizes;
|
||||
}
|
||||
|
||||
disconnectSignals(): void {
|
||||
this._tiledItems.forEach((item) => {
|
||||
if (item instanceof WindowContainer) {
|
||||
@@ -139,23 +156,31 @@ export default class WindowContainer {
|
||||
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())!;
|
||||
this._tiledItems.forEach((item, index) => {
|
||||
if (this._customSizes.has(index)) {
|
||||
totalCustomHeight += this._customSizes.get(index)!;
|
||||
} else {
|
||||
numFlexibleItems++;
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure custom sizes don't exceed container height
|
||||
if (totalCustomHeight > this._workArea.height) {
|
||||
Logger.warn("Custom heights exceed container, resetting all sizes");
|
||||
this._customSizes.clear();
|
||||
totalCustomHeight = 0;
|
||||
numFlexibleItems = this._tiledItems.length;
|
||||
}
|
||||
|
||||
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) => {
|
||||
return this._tiledItems.map((item, index) => {
|
||||
let height = flexHeight;
|
||||
if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
|
||||
height = this._customSizes.get(item.getWindowId())!;
|
||||
if (this._customSizes.has(index)) {
|
||||
height = this._customSizes.get(index)!;
|
||||
}
|
||||
|
||||
const rect = {
|
||||
@@ -174,23 +199,31 @@ export default class WindowContainer {
|
||||
let totalCustomWidth = 0;
|
||||
let numFlexibleItems = 0;
|
||||
|
||||
this._tiledItems.forEach((item) => {
|
||||
if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
|
||||
totalCustomWidth += this._customSizes.get(item.getWindowId())!;
|
||||
this._tiledItems.forEach((item, index) => {
|
||||
if (this._customSizes.has(index)) {
|
||||
totalCustomWidth += this._customSizes.get(index)!;
|
||||
} else {
|
||||
numFlexibleItems++;
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure custom sizes don't exceed container width
|
||||
if (totalCustomWidth > this._workArea.width) {
|
||||
Logger.warn("Custom widths exceed container, resetting all sizes");
|
||||
this._customSizes.clear();
|
||||
totalCustomWidth = 0;
|
||||
numFlexibleItems = this._tiledItems.length;
|
||||
}
|
||||
|
||||
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) => {
|
||||
return this._tiledItems.map((item, index) => {
|
||||
let width = flexWidth;
|
||||
if (item instanceof WindowWrapper && this._customSizes.has(item.getWindowId())) {
|
||||
width = this._customSizes.get(item.getWindowId())!;
|
||||
if (this._customSizes.has(index)) {
|
||||
width = this._customSizes.get(index)!;
|
||||
}
|
||||
|
||||
const rect = {
|
||||
@@ -227,7 +260,7 @@ export default class WindowContainer {
|
||||
Logger.error("Item not found in container during drag op", item.getWindowId());
|
||||
return;
|
||||
}
|
||||
let new_index = this.getIndexOfItemNested(item);
|
||||
let new_index = original_index;
|
||||
this.getBounds().forEach((rect, index) => {
|
||||
if (rect.x < x && rect.x + rect.width > x && rect.y < y && rect.y + rect.height > y) {
|
||||
new_index = index;
|
||||
@@ -253,13 +286,20 @@ export default class WindowContainer {
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the index of the window
|
||||
const index = this._getIndexOfWindow(win_id);
|
||||
if (index === -1) {
|
||||
Logger.error("Window not found in container during resize");
|
||||
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}`);
|
||||
this._customSizes.set(index, rect.width);
|
||||
Logger.log(`Window at index ${index} 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}`);
|
||||
this._customSizes.set(index, rect.height);
|
||||
Logger.log(`Window at index ${index} manually resized to height: ${rect.height}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,5 +314,80 @@ export default class WindowContainer {
|
||||
}
|
||||
}
|
||||
|
||||
windowResizing(win_id: number, resizeOp: Meta.GrabOp): void {
|
||||
const window = this.getWindow(win_id);
|
||||
if (!window) {
|
||||
// Check nested containers
|
||||
for (const item of this._tiledItems) {
|
||||
if (item instanceof WindowContainer) {
|
||||
item.windowResizing(win_id, resizeOp);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the resize direction matches the container orientation
|
||||
const isHorizontalResize = resizeOp === Meta.GrabOp.RESIZING_E || resizeOp === Meta.GrabOp.RESIZING_W;
|
||||
const isVerticalResize = resizeOp === Meta.GrabOp.RESIZING_N || resizeOp === Meta.GrabOp.RESIZING_S;
|
||||
|
||||
if ((this._orientation === Orientation.HORIZONTAL && !isHorizontalResize) ||
|
||||
(this._orientation === Orientation.VERTICAL && !isVerticalResize)) {
|
||||
// Resize direction doesn't match container orientation, ignore
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the index of the window
|
||||
const index = this._getIndexOfWindow(win_id);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the new size
|
||||
const rect = window.getRect();
|
||||
const newSize = this._orientation === Orientation.HORIZONTAL ? rect.width : rect.height;
|
||||
const oldSize = this._customSizes.get(index);
|
||||
|
||||
if (oldSize === undefined) {
|
||||
// First time resizing this window, just set the size
|
||||
this._customSizes.set(index, newSize);
|
||||
this.tileWindows();
|
||||
return;
|
||||
}
|
||||
|
||||
// Calculate the delta (how much the window changed)
|
||||
const delta = newSize - oldSize;
|
||||
|
||||
// Determine which adjacent window to adjust based on resize direction
|
||||
let adjacentIndex = -1;
|
||||
if (resizeOp === Meta.GrabOp.RESIZING_E || resizeOp === Meta.GrabOp.RESIZING_S) {
|
||||
// Resizing right/down edge - adjust the next window
|
||||
adjacentIndex = index + 1;
|
||||
} else if (resizeOp === Meta.GrabOp.RESIZING_W || resizeOp === Meta.GrabOp.RESIZING_N) {
|
||||
// Resizing left/up edge - adjust the previous window
|
||||
adjacentIndex = index - 1;
|
||||
}
|
||||
|
||||
// Update current window size
|
||||
this._customSizes.set(index, newSize);
|
||||
|
||||
// Adjust adjacent window only if it has a custom size
|
||||
if (adjacentIndex >= 0 && adjacentIndex < this._tiledItems.length &&
|
||||
this._customSizes.has(adjacentIndex)) {
|
||||
const adjacentSize = this._customSizes.get(adjacentIndex)!;
|
||||
const newAdjacentSize = adjacentSize - delta;
|
||||
|
||||
// Ensure the adjacent window doesn't go below minimum size (e.g., 100px)
|
||||
if (newAdjacentSize >= 100) {
|
||||
this._customSizes.set(adjacentIndex, newAdjacentSize);
|
||||
} else {
|
||||
// Don't allow the resize if it would make adjacent window too small
|
||||
this._customSizes.set(index, oldSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Re-tile all windows in real-time
|
||||
this.tileWindows();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -68,7 +68,6 @@ export default class Monitor {
|
||||
this._workArea = global.workspace_manager.get_active_workspace().get_work_area_for_monitor(this._id);
|
||||
const activeWorkspace = global.workspace_manager.get_active_workspace();
|
||||
this._workspaces[activeWorkspace.index()].move(this._workArea);
|
||||
this._workspaces[activeWorkspace.index()].tileWindows()
|
||||
}
|
||||
|
||||
removeWorkspace(workspaceId: number): void {
|
||||
@@ -100,4 +99,15 @@ export default class Monitor {
|
||||
}
|
||||
}
|
||||
|
||||
windowResizing(win_id: number, resizeOp: Meta.GrabOp): 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.windowResizing(win_id, resizeOp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -104,6 +104,9 @@ export class WindowWrapper {
|
||||
this._window.connect("position-changed", (_metaWindow) => {
|
||||
windowManager.handleWindowPositionChanged(this);
|
||||
}),
|
||||
this._window.connect("size-changed", (_metaWindow) => {
|
||||
windowManager.handleWindowSizeChanged(this);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ export interface IWindowManager {
|
||||
|
||||
handleWindowPositionChanged(winWrap: WindowWrapper): void;
|
||||
|
||||
handleWindowSizeChanged(winWrap: WindowWrapper): void;
|
||||
|
||||
syncActiveWindow(): number | null;
|
||||
}
|
||||
|
||||
@@ -45,6 +47,8 @@ export default class WindowManager implements IWindowManager {
|
||||
_grabbedWindowMonitor: number = _UNUSED_MONITOR_ID;
|
||||
_grabbedWindowId: number = _UNUSED_WINDOW_ID;
|
||||
_changingGrabbedMonitor: boolean = false;
|
||||
_resizingWindow: boolean = false;
|
||||
_resizeOp: Meta.GrabOp | null = null;
|
||||
|
||||
_showingOverview: boolean = false;
|
||||
|
||||
@@ -202,7 +206,15 @@ export default class WindowManager implements IWindowManager {
|
||||
Logger.log("Grab Op Start", op);
|
||||
Logger.log(display, window, op)
|
||||
Logger.log(window.get_monitor())
|
||||
|
||||
const isResizing = this._isResizeOperation(op);
|
||||
if (isResizing) {
|
||||
this._resizingWindow = true;
|
||||
this._resizeOp = op;
|
||||
} else {
|
||||
this._getWrappedWindow(window)?.startDragging();
|
||||
}
|
||||
|
||||
this._grabbedWindowMonitor = window.get_monitor();
|
||||
this._grabbedWindowId = window.get_id();
|
||||
}
|
||||
@@ -230,6 +242,8 @@ export default class WindowManager implements IWindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
this._resizingWindow = false;
|
||||
this._resizeOp = null;
|
||||
this._grabbedWindowId = _UNUSED_WINDOW_ID;
|
||||
this._getWrappedWindow(window)?.stopDragging();
|
||||
this._tileMonitors();
|
||||
@@ -263,7 +277,7 @@ export default class WindowManager implements IWindowManager {
|
||||
let wrapped = this._getAndRemoveWrappedWindow(window);
|
||||
if (wrapped === undefined) {
|
||||
Logger.error("WINDOW NOT DEFINED")
|
||||
wrapped = new WindowWrapper(window, this.handleWindowMinimized);
|
||||
wrapped = new WindowWrapper(window, this.handleWindowMinimized.bind(this));
|
||||
wrapped.connectWindowSignals(this);
|
||||
}
|
||||
let new_mon = this._monitors.get(monitorId);
|
||||
@@ -300,6 +314,16 @@ export default class WindowManager implements IWindowManager {
|
||||
}
|
||||
}
|
||||
|
||||
public handleWindowSizeChanged(winWrap: WindowWrapper): void {
|
||||
if (this._resizingWindow && winWrap.getWindowId() === this._grabbedWindowId) {
|
||||
// Check if this is a valid resize direction for the container
|
||||
const monitor = this._monitors.get(winWrap.getWindow().get_monitor());
|
||||
if (monitor && this._resizeOp) {
|
||||
monitor.windowResizing(winWrap.getWindowId(), this._resizeOp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public handleWindowMinimized(winWrap: WindowWrapper): void {
|
||||
const monitor_id = winWrap.getWindow().get_monitor()
|
||||
@@ -364,7 +388,7 @@ export default class WindowManager implements IWindowManager {
|
||||
public addWindowToMonitor(window: Meta.Window) {
|
||||
|
||||
Logger.log("ADDING WINDOW TO MONITOR", window, window);
|
||||
var wrapper = new WindowWrapper(window, this.handleWindowMinimized)
|
||||
var wrapper = new WindowWrapper(window, this.handleWindowMinimized.bind(this))
|
||||
wrapper.connectWindowSignals(this);
|
||||
this._addWindowWrapperToMonitor(wrapper);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user