Skip to content
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea
.xml
80 changes: 80 additions & 0 deletions gnome-window-manager/gwm-almost-maximize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
const {
execCommand,
ensureWmctrl,
ensureXprop,
ensureXdotool,
ensureXrandr,
getTargetWindowId,
isMaximizedState,
isFullscreenState,
updateWindowStates,
findMonitorForWindow,
delay,
getWindowGeometry,
getMonitors,
} = require("./utils");

const SCALE = 0.8;
const DELAY_AFTER_UNMAXIMIZE_MS = 120;

const run = async (_, { exec, toast, search }) => {
await ensureWmctrl(exec, toast);
await ensureXprop(exec, toast);
await ensureXdotool(exec, toast);
await ensureXrandr(exec, toast);

try {
const { targetWindowId } = await getTargetWindowId(exec);
const targetWindowDec = Number.parseInt(targetWindowId, 16);

if (!Number.isFinite(targetWindowDec)) {
throw new Error(`Invalid window id: ${targetWindowId}`);
}

const stateOutput = await execCommand(
exec,
`xprop -id ${targetWindowId} _NET_WM_STATE`
);

const wasMaximized = isMaximizedState(stateOutput);
const wasFullscreen = isFullscreenState(stateOutput);

if (wasMaximized || wasFullscreen) {
await updateWindowStates(exec, targetWindowId, "remove", [
"fullscreen",
"maximized_vert",
"maximized_horz",
]);
await delay(DELAY_AFTER_UNMAXIMIZE_MS);
}

const windowGeometry = await getWindowGeometry(exec, targetWindowDec);

const monitors = await getMonitors(exec);
const monitor = findMonitorForWindow(monitors, windowGeometry);

if (!monitor) {
throw new Error("Unable to resolve monitor for the target window.");
}

const width = Math.max(1, Math.round(monitor.width * SCALE));
const height = Math.max(1, Math.round(monitor.height * SCALE));
const x = monitor.x + Math.round((monitor.width - width) / 2);
const y = monitor.y + Math.round((monitor.height - height) / 2);

await execCommand(
exec,
`wmctrl -i -r ${targetWindowId} -e 0,${x},${y},${width},${height}`
);
search?.clear?.();
} catch (error) {
const message = `Failed to almost maximize: ${error.message}`;
if (toast?.error) {
toast.error("Command failed", { description: message });
}

throw new Error(message);
}
};

module.exports = { run, actions: [] };
88 changes: 88 additions & 0 deletions gnome-window-manager/gwm-almost-minimize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
const {
execCommand,
ensureWmctrl,
ensureXprop,
ensureXdotool,
ensureXrandr,
getTargetWindowId,
isMaximizedState,
isFullscreenState,
updateWindowStates,
findMonitorForWindow,
delay,
getWindowGeometry,
getMonitors,
} = require("./utils");

const SQUARE_SCALE = 0.5;
const WIDTH_BOOST = 1.40;
const DELAY_AFTER_UNMAXIMIZE_MS = 120;

const run = async (_, { exec, toast, search }) => {
await ensureWmctrl(exec, toast);
await ensureXprop(exec, toast);
await ensureXdotool(exec, toast);
await ensureXrandr(exec, toast);

try {
const { targetWindowId } = await getTargetWindowId(exec);
const targetWindowDec = Number.parseInt(targetWindowId, 16);

if (!Number.isFinite(targetWindowDec)) {
throw new Error(`Invalid window id: ${targetWindowId}`);
}

const stateOutput = await execCommand(
exec,
`xprop -id ${targetWindowId} _NET_WM_STATE`
);

const wasMaximized = isMaximizedState(stateOutput);
const wasFullscreen = isFullscreenState(stateOutput);

if (wasMaximized || wasFullscreen) {
await updateWindowStates(exec, targetWindowId, "remove", [
"fullscreen",
"maximized_vert",
"maximized_horz",
]);
await delay(DELAY_AFTER_UNMAXIMIZE_MS);
}

const windowGeometry = await getWindowGeometry(exec, targetWindowDec);

const monitors = await getMonitors(exec);
const monitor = findMonitorForWindow(monitors, windowGeometry);

if (!monitor) {
throw new Error("Unable to resolve monitor for the target window.");
}

const baseSize = Math.max(
1,
Math.round(Math.min(monitor.width, monitor.height) * SQUARE_SCALE)
);
const height = baseSize;
const width = Math.max(
1,
Math.min(monitor.width, Math.round(baseSize * WIDTH_BOOST))
);
const x = monitor.x + Math.round((monitor.width - width) / 2);
const y = monitor.y + Math.round((monitor.height - height) / 2);

await execCommand(
exec,
`wmctrl -i -r ${targetWindowId} -e 0,${x},${y},${width},${height}`
);
search?.clear?.();
} catch (error) {
const message = `Failed to almost minimize: ${error.message}`;
if (toast?.error) {
toast.error("Command failed", { description: message });
}

throw new Error(message);
}
};

module.exports = { run, actions: [] };
90 changes: 90 additions & 0 deletions gnome-window-manager/gwm-center.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const {
execCommand,
ensureWmctrl,
ensureXprop,
ensureXdotool,
ensureXrandr,
getTargetWindowId,
isMaximizedState,
isFullscreenState,
updateWindowStates,
findMonitorForWindow,
delay,
getWindowGeometry,
getMonitors,
} = require("./utils");

const DELAY_AFTER_UNMAXIMIZE_MS = 120;

const run = async (_, { exec, toast, search }) => {
await ensureWmctrl(exec, toast);
await ensureXprop(exec, toast);
await ensureXdotool(exec, toast);
await ensureXrandr(exec, toast);

try {
const { targetWindowId } = await getTargetWindowId(exec);
const targetWindowDec = Number.parseInt(targetWindowId, 16);

if (!Number.isFinite(targetWindowDec)) {
throw new Error(`Invalid window id: ${targetWindowId}`);
}

const stateOutput = await execCommand(
exec,
`xprop -id ${targetWindowId} _NET_WM_STATE`
);

const wasMaximized = isMaximizedState(stateOutput);
const wasFullscreen = isFullscreenState(stateOutput);

if (wasMaximized || wasFullscreen) {
await updateWindowStates(exec, targetWindowId, "remove", [
"fullscreen",
"maximized_vert",
"maximized_horz",
]);
await delay(DELAY_AFTER_UNMAXIMIZE_MS);
}

const windowGeometry = await getWindowGeometry(exec, targetWindowDec);

const width = Number(windowGeometry.WIDTH);
const height = Number(windowGeometry.HEIGHT);

if ([width, height].some((value) => !Number.isFinite(value))) {
throw new Error("Unable to determine window dimensions.");
}

const monitors = await getMonitors(exec);
const monitor = findMonitorForWindow(monitors, windowGeometry);

if (!monitor) {
throw new Error("Unable to resolve monitor for the target window.");
}

const centeredX = monitor.x + Math.round((monitor.width - width) / 2);
const centeredY = monitor.y + Math.round((monitor.height - height) / 2);

const maxX = monitor.x + Math.max(0, monitor.width - width);
const maxY = monitor.y + Math.max(0, monitor.height - height);

const x = Math.min(Math.max(centeredX, monitor.x), maxX);
const y = Math.min(Math.max(centeredY, monitor.y), maxY);

await execCommand(
exec,
`wmctrl -i -r ${targetWindowId} -e 0,${x},${y},${width},${height}`
);
search?.clear?.();
} catch (error) {
const message = `Failed to center window: ${error.message}`;
if (toast?.error) {
toast.error("Command failed", { description: message });
}

throw new Error(message);
}
};

module.exports = { run, actions: [] };
43 changes: 43 additions & 0 deletions gnome-window-manager/gwm-hide-others.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
const { ensureXprop, ensureXdotool, getTargetWindowId, getStackingOrder, minimizeWindow } = require("./utils");

const run = async (_, { exec, toast, search }) => {
await ensureXprop(exec, toast);
await ensureXdotool(exec, toast);

try {
const { targetWindowId } = await getTargetWindowId(exec);
const stackingOrder = await getStackingOrder(exec);

const minimizeTargets = stackingOrder.filter(
(windowId) =>
windowId &&
windowId !== "0x0" &&
windowId.toLowerCase() !== targetWindowId?.toLowerCase()
);

const errors = [];

for (const windowId of minimizeTargets) {
try {
await minimizeWindow(exec, windowId);
} catch (error) {
errors.push(`${windowId}: ${error.message}`);
}
}

if (errors.length) {
throw new Error(errors.join("; "));
}

search?.clear?.();
} catch (error) {
const message = `Failed to hide other windows: ${error.message}`;
if (toast?.error) {
toast.error("Command failed", { description: message });
}

throw new Error(message);
}
};

module.exports = { run, actions: [] };
79 changes: 79 additions & 0 deletions gnome-window-manager/gwm-left-half.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
const {
execCommand,
ensureWmctrl,
ensureXprop,
ensureXdotool,
ensureXrandr,
getTargetWindowId,
isMaximizedState,
isFullscreenState,
updateWindowStates,
findMonitorForWindow,
delay,
getWindowGeometry,
getMonitors,
} = require("./utils");

const DELAY_AFTER_UNMAXIMIZE_MS = 120;

const run = async (_, { exec, toast, search }) => {
await ensureWmctrl(exec, toast);
await ensureXprop(exec, toast);
await ensureXdotool(exec, toast);
await ensureXrandr(exec, toast);

try {
const { targetWindowId } = await getTargetWindowId(exec);
const targetWindowDec = Number.parseInt(targetWindowId, 16);

if (!Number.isFinite(targetWindowDec)) {
throw new Error(`Invalid window id: ${targetWindowId}`);
}

const stateOutput = await execCommand(
exec,
`xprop -id ${targetWindowId} _NET_WM_STATE`
);

const wasMaximized = isMaximizedState(stateOutput);
const wasFullscreen = isFullscreenState(stateOutput);

if (wasMaximized || wasFullscreen) {
await updateWindowStates(exec, targetWindowId, "remove", [
"fullscreen",
"maximized_vert",
"maximized_horz",
]);

await delay(DELAY_AFTER_UNMAXIMIZE_MS);
}

const windowGeometry = await getWindowGeometry(exec, targetWindowDec);
const monitors = await getMonitors(exec);
const monitor = findMonitorForWindow(monitors, windowGeometry);

if (!monitor) {
throw new Error("Unable to resolve monitor for the target window.");
}

const width = Math.max(1, Math.round(monitor.width / 2));
const height = Math.max(1, monitor.height);
const x = monitor.x;
const y = monitor.y;

await execCommand(
exec,
`wmctrl -i -r ${targetWindowId} -e 0,${x},${y},${width},${height}`
);
search?.clear?.();
} catch (error) {
const message = `Failed to move window left: ${error.message}`;
if (toast?.error) {
toast.error("Command failed", { description: message });
}

throw new Error(message);
}
};

module.exports = { run, actions: [] };
Loading