summaryrefslogtreecommitdiff
path: root/config/kwin/sz-window-layout/contents/code/main.js
blob: 2b498a2637e62e30ec16b8f043b1deb84ccf6e0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// The window shortcuts from config/hammerspoon/init.lua, for KWin on Plasma 6.
// Linked into ~/.local/share/kwin/scripts/ and enabled by link.sh.
//
// Every action is registered twice, because Toshy sits between the keyboard
// and KWin. On a Mac keyboard it turns physical Ctrl into Meta in GUI apps but
// leaves it as Ctrl in terminals, so the same physical Ctrl+Opt+2 reaches KWin
// as Meta+Alt+2 in a browser and as Ctrl+Alt+2 in Ghostty. The Ctrl variant
// also covers Toshy being paused or absent.
//
// KWin compiles this at load: after an edit, toggle the script off and on in
// System Settings -> Window Management -> KWin Scripts. A changed default key
// may not replace one already saved in kglobalshortcutsrc.

// [key, name, left edge, width], as fractions of the usable screen area.
const layouts = [
    ["1", "Maximize", 0, 1],
    ["2", "Left 50%", 0, 0.5],
    ["3", "Right 50%", 0.5, 0.5],
    ["4", "Left 30%", 0, 0.3],
    ["5", "Right 70%", 0.3, 0.7],
    ["6", "Left 25%", 0, 0.25],
    ["7", "Right 75%", 0.25, 0.75],
    ["8", "Left 20%", 0, 0.2],
    ["9", "Right 80%", 0.2, 0.8],
];

function place(x, w) {
    const win = workspace.activeWindow;
    if (!win) return;
    const area = workspace.clientArea(KWin.MaximizeArea, win);
    // Rounding both edges rather than the width keeps a left/right pair flush.
    const left = Math.round(area.x + area.width * x);
    const right = Math.round(area.x + area.width * (x + w));
    // A window left in a quick tile (Meta+Left/Right) or maximized would
    // otherwise be pulled back to that geometry.
    win.tile = null;
    win.setMaximize(false, false);
    win.frameGeometry = { x: left, y: area.y, width: right - left, height: area.height };
}

function nextScreen() {
    const win = workspace.activeWindow;
    if (!win) return;
    const screens = workspace.screens;
    // By name: the wrappers of one output are not guaranteed to be ===.
    let i = 0;
    while (i < screens.length && screens[i].name !== win.output.name) i++;
    workspace.sendClientToScreen(win, screens[(i + 1) % screens.length]);
}

for (const [key, name, x, w] of layouts) {
    const fn = () => place(x, w);
    registerShortcut(`sz ${name}`, `sz: ${name}`, `Meta+Alt+${key}`, fn);
    registerShortcut(`sz ${name} (Ctrl)`, `sz: ${name} (Ctrl)`, `Ctrl+Alt+${key}`, fn);
}
registerShortcut("sz Next Screen", "sz: Next Screen", "Meta+Shift+Space", nextScreen);
registerShortcut("sz Next Screen (Ctrl)", "sz: Next Screen (Ctrl)", "Ctrl+Shift+Space", nextScreen);