🖥 Window management à la Rectangle (+ align all windows at once)

Manage the current apps windows. You can do all window alignments Rectangle has to offer:

  • max,
  • almost maximize,
  • half (left, right),
  • thirds (left, center, right, left two thirds, right two thirds),
  • quarters (top-left, top-right, bottom-left, bottom-right),
  • fourths (horizontally: first, second, third, forth, first three, last three),
  • sixths (top-left, top-center, top-left, bottom-left, bottom-center, bottom-right),
  • and move to next screen.

Why another window manager? You can align all windows of the current app at once. This comes in handy every time you work with an additional display or you like to have a clear window structure for an application. On top, you can easily use it with Karabiner without wasting another shortcut.

Example cli usage:~/.kit/kar align-windows 'ALL' 'LEFT_HALF'

align-windows


Open align-windows in Script Kit

// Name: Move current apps windows
// Author: Eduard Uffelmann
// Twitter: @schmedu_
// Example cli usage: ~/.kit/kar align-windows 'ALL' 'LEFT_HALF'
import "@johnlindquist/kit";
const Windows = {
FRONTMOST: "frontmost",
ALL: "all",
};
const WindowAlignments = {
LEFT_HALF: {
name: "left half",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width / 2,
height: screen.workArea.height,
}),
},
LEFT_THIRD: {
name: "left third",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width / 3,
height: screen.workArea.height,
}),
},
LEFT_TWO_THIRDS: {
name: "first / left two thirds",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: (screen.workArea.width / 3) * 2,
height: screen.workArea.height,
}),
},
RIGHT_HALF: {
name: "right half",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 2,
y: screen.workArea.y,
width: screen.workArea.width / 2,
height: screen.workArea.height,
}),
},
RIGHT_THIRD: {
name: "right third",
workArea: (screen) => ({
x: screen.workArea.x + (screen.workArea.width / 3) * 2,
y: screen.workArea.y,
width: screen.workArea.width / 3,
height: screen.workArea.height,
}),
},
RIGHT_TWO_THIRDS: {
name: "last / right two thirds",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 3,
y: screen.workArea.y,
width: (screen.workArea.width / 3) * 2,
height: screen.workArea.height,
}),
},
CENTER_THIRD: {
name: "center third",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 3,
y: screen.workArea.y,
width: screen.workArea.width / 3,
height: screen.workArea.height,
}),
},
TOP_HALF: {
name: "top half",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width,
height: screen.workArea.height / 2,
}),
},
TOP_THIRD: {
name: "top third",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width,
height: screen.workArea.height / 3,
}),
},
TOP_TWO_THIRDS: {
name: "top two thirds",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width,
height: (screen.workArea.height / 3) * 2,
}),
},
BOTTOM_HALF: {
name: "bottom half",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y + screen.workArea.height / 2,
width: screen.workArea.width,
height: screen.workArea.height / 2,
}),
},
BOTTOM_THIRD: {
name: "bottom third",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y + (screen.workArea.height / 3) * 2,
width: screen.workArea.width,
height: screen.workArea.height / 3,
}),
},
BOTTOM_TWO_THIRDS: {
name: "bottom two thirds",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y + screen.workArea.height / 3,
width: screen.workArea.width,
height: (screen.workArea.height / 3) * 2,
}),
},
TOP_LEFT: {
name: "top left quarter",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width / 2,
height: screen.workArea.height / 2,
}),
},
TOP_RIGHT: {
name: "top right quarter",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 2,
y: screen.workArea.y,
width: screen.workArea.width / 2,
height: screen.workArea.height / 2,
}),
},
BOTTOM_LEFT: {
name: "bottom left quarter",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y + screen.workArea.height / 2,
width: screen.workArea.width / 2,
height: screen.workArea.height / 2,
}),
},
BOTTOM_RIGHT: {
name: "bottom right quarter",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 2,
y: screen.workArea.y + screen.workArea.height / 2,
width: screen.workArea.width / 2,
height: screen.workArea.height / 2,
}),
},
CENTERED: {
name: "centered",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 6,
y: screen.workArea.y + screen.workArea.height / 6,
width: (screen.workArea.width * 2) / 3,
height: (screen.workArea.height * 2) / 3,
}),
},
FIRST_FOURTH: {
name: "first fourth",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width / 4,
height: screen.workArea.height,
}),
},
SECOND_FOURTH: {
name: "second fourth",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 4,
y: screen.workArea.y,
width: screen.workArea.width / 4,
height: screen.workArea.height,
}),
},
THIRD_FOURTH: {
name: "third fourth",
workArea: (screen) => ({
x: screen.workArea.x + (screen.workArea.width / 4) * 2,
y: screen.workArea.y,
width: screen.workArea.width / 4,
height: screen.workArea.height,
}),
},
FOURTH_FOURTH: {
name: "fourth fourth",
workArea: (screen) => ({
x: screen.workArea.x + (screen.workArea.width / 4) * 3,
y: screen.workArea.y,
width: screen.workArea.width / 4,
height: screen.workArea.height,
}),
},
FIRST_THREE_FOURTHS: {
name: "first three fourths",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: (screen.workArea.width / 4) * 3,
height: screen.workArea.height,
}),
},
LAST_THREE_FOURTHS: {
name: "last three fourths",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 4,
y: screen.workArea.y,
width: (screen.workArea.width / 4) * 3,
height: screen.workArea.height,
}),
},
TOP_LEFT_SIXTH: {
name: "top left sixth",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width / 3,
height: screen.workArea.height / 2,
}),
},
TOP_MIDDLE_SIXTH: {
name: "top middle sixth",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 3,
y: screen.workArea.y,
width: screen.workArea.width / 3,
height: screen.workArea.height / 2,
}),
},
TOP_RIGHT_SIXTH: {
name: "top right sixth",
workArea: (screen) => ({
x: screen.workArea.x + (screen.workArea.width / 3) * 2,
y: screen.workArea.y,
width: screen.workArea.width / 3,
height: screen.workArea.height / 2,
}),
},
BOTTOM_LEFT_SIXTH: {
name: "bottom left sixth",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y + screen.workArea.height / 2,
width: screen.workArea.width / 3,
height: screen.workArea.height / 2,
}),
},
BOTTOM_MIDDLE_SIXTH: {
name: "bottom middle sixth",
workArea: (screen) => ({
x: screen.workArea.x + screen.workArea.width / 3,
y: screen.workArea.y + screen.workArea.height / 2,
width: screen.workArea.width / 3,
height: screen.workArea.height / 2,
}),
},
BOTTOM_RIGHT_SIXTH: {
name: "bottom right sixth",
workArea: (screen) => ({
x: screen.workArea.x + (screen.workArea.width / 3) * 2,
y: screen.workArea.y + screen.workArea.height / 2,
width: screen.workArea.width / 3,
height: screen.workArea.height / 2,
}),
},
MAX: {
name: "max",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width,
height: screen.workArea.height,
}),
},
ALMOST_MAX: {
name: "almost maximize",
workArea: (screen) => ({
x: screen.workArea.x + (screen.workArea.width / 24),
y: screen.workArea.y + (screen.workArea.height / 24),
width: (screen.workArea.width * 11) / 12,
height: (screen.workArea.height * 11) / 12,
}),
},
NEXT_SCREEN: {
name: "next screen",
workArea: (screen) => ({
x: screen.workArea.x,
y: screen.workArea.y,
width: screen.workArea.width,
height: screen.workArea.height,
}),
},
};
async function setActiveAppsWindows(workArea) {
await applescript(String.raw`
tell application "System Events"
set processName to name of first application process whose frontmost is true as text
tell process processName to set the position of every window to {${workArea.x}, ${workArea.y}}
tell process processName to set the size of every window to {${workArea.width}, ${workArea.height}}
end tell
`);
}
async function getActiveAppsFrontMostWindowsPosition() {
let positionStr = await applescript(String.raw`
tell application "System Events"
set processName to name of first application process whose frontmost is true as text
tell process processName to get position of window 1
end tell
`);
let positionArray = positionStr.split(",").map((str) => parseInt(str.trim()));
return {
x: positionArray[0],
y: positionArray[1],
};
}
async function getFrontWindowsScreen() {
let position = await getActiveAppsFrontMostWindowsPosition();
let screens = await getScreens();
return screens.find((screen) => {
return (
position.x >= screen.bounds.x &&
position.x <= screen.bounds.x + screen.bounds.width &&
position.y >= screen.bounds.y &&
position.y <= screen.bounds.y + screen.bounds.height
);
});
}
let windowMode =
Windows[
await arg(
"Which window(s) to move?",
Object.keys(Windows).map((key) => {
return {
name: Windows[key],
value: key,
};
})
)
];
let windowAlignment =
WindowAlignments[
await arg(
"Window Alignment",
Object.keys(WindowAlignments).map((key) => {
return {
name: WindowAlignments[key].name,
value: key,
};
})
)
];
let activeScreen = await getFrontWindowsScreen();
let nextScreen;
if (windowAlignment === WindowAlignments.NEXT_SCREEN) {
let screens = await getScreens();
let nextScreens = screens.filter((screen) => screen.id > activeScreen.id);
nextScreen = nextScreens.length === 0 ? screens[0] : nextScreens[0];
}
let workArea =
windowAlignment === WindowAlignments.NEXT_SCREEN ?
windowAlignment.workArea(nextScreen) :
windowAlignment.workArea(activeScreen);
if (windowMode === Windows.ALL) {
await setActiveAppsWindows(workArea);
} else {
await setActiveAppPosition({
x: workArea.x,
y: workArea.y,
});
await setActiveAppSize({
width: workArea.width,
height: workArea.height,
});
}