Created
July 16, 2026 01:23
-
-
Save sapjax/bacd8db9b10ae18971ee7baca3401e4c to your computer and use it in GitHub Desktop.
phoenix config
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const WINDOW_MODIFIERS = ['alt']; | |
| const FRAME_TOLERANCE = 12; | |
| const TRAVERSAL_EXCLUDED_APP_NAMES = ['otty']; | |
| let windowTraversal; | |
| function focusedNormalWindow() { | |
| const window = Window.focused(); | |
| if (!window || !window.isNormal()) { | |
| Phoenix.log('No focused normal window.'); | |
| return undefined; | |
| } | |
| return window; | |
| } | |
| function windowsAtTopOfStack(focusedWindow) { | |
| return [focusedWindow].concat( | |
| Window.recent().filter((window) => { | |
| return ( | |
| window.isNormal() && | |
| window.isVisible() && | |
| !window.isEqual(focusedWindow) | |
| ); | |
| }) | |
| ); | |
| } | |
| function splitFrames(screen) { | |
| const frame = screen.flippedVisibleFrame(); | |
| const leftWidth = Math.floor(frame.width / 2); | |
| return { | |
| left: { | |
| x: frame.x, | |
| y: frame.y, | |
| width: leftWidth, | |
| height: frame.height, | |
| }, | |
| right: { | |
| x: frame.x + leftWidth, | |
| y: frame.y, | |
| width: frame.width - leftWidth, | |
| height: frame.height, | |
| }, | |
| }; | |
| } | |
| function framesMatch(first, second) { | |
| return ( | |
| Math.abs(first.x - second.x) <= FRAME_TOLERANCE && | |
| Math.abs(first.y - second.y) <= FRAME_TOLERANCE && | |
| Math.abs(first.width - second.width) <= FRAME_TOLERANCE && | |
| Math.abs(first.height - second.height) <= FRAME_TOLERANCE | |
| ); | |
| } | |
| function topWindowOnOtherSide(focusedWindow, windows) { | |
| const screen = focusedWindow.screen(); | |
| if (!screen) { | |
| return undefined; | |
| } | |
| const frames = splitFrames(screen); | |
| const focusedFrame = focusedWindow.frame(); | |
| let otherFrame; | |
| if (framesMatch(focusedFrame, frames.left)) { | |
| otherFrame = frames.right; | |
| } else if (framesMatch(focusedFrame, frames.right)) { | |
| otherFrame = frames.left; | |
| } else { | |
| return undefined; | |
| } | |
| return windows.find((window) => { | |
| return ( | |
| !window.isEqual(focusedWindow) && | |
| framesMatch(window.frame(), otherFrame) | |
| ); | |
| }); | |
| } | |
| function resetWindowTraversal() { | |
| windowTraversal = undefined; | |
| } | |
| function isExcludedFromTraversal(window) { | |
| const app = window.app(); | |
| const appName = app && app.name(); | |
| return ( | |
| appName && | |
| TRAVERSAL_EXCLUDED_APP_NAMES.indexOf(appName.toLowerCase()) !== -1 | |
| ); | |
| } | |
| function traverseWindowStack(direction) { | |
| const focusedWindow = focusedNormalWindow(); | |
| if (!focusedWindow) { | |
| resetWindowTraversal(); | |
| return; | |
| } | |
| const stack = windowsAtTopOfStack(focusedWindow); | |
| const fixedWindow = topWindowOnOtherSide(focusedWindow, stack); | |
| const fixedHash = fixedWindow ? fixedWindow.hash() : null; | |
| const focusedHash = focusedWindow.hash(); | |
| const eligibleWindows = stack.filter((window) => { | |
| if (window.isEqual(focusedWindow)) { | |
| return true; | |
| } | |
| return ( | |
| (!fixedWindow || !window.isEqual(fixedWindow)) && | |
| !isExcludedFromTraversal(window) | |
| ); | |
| }); | |
| const windowsByHash = Object.create(null); | |
| const currentOrder = []; | |
| eligibleWindows.forEach((window) => { | |
| const hash = window.hash(); | |
| windowsByHash[String(hash)] = window; | |
| currentOrder.push(hash); | |
| }); | |
| if (currentOrder.length < 2) { | |
| Phoenix.log('There is no other visible normal window to focus.'); | |
| resetWindowTraversal(); | |
| return; | |
| } | |
| const canContinue = | |
| windowTraversal && | |
| windowTraversal.focusedHash === focusedHash && | |
| windowTraversal.fixedHash === fixedHash; | |
| let order; | |
| if (canContinue) { | |
| order = windowTraversal.order.filter((hash) => { | |
| return windowsByHash[String(hash)]; | |
| }); | |
| currentOrder.forEach((hash) => { | |
| if (order.indexOf(hash) === -1) { | |
| order.push(hash); | |
| } | |
| }); | |
| } else { | |
| order = currentOrder; | |
| } | |
| const currentIndex = order.indexOf(focusedHash); | |
| const targetIndex = (currentIndex + direction + order.length) % order.length; | |
| const targetWindow = windowsByHash[String(order[targetIndex])]; | |
| if (!targetWindow || targetWindow.isEqual(focusedWindow)) { | |
| Phoenix.log('Could not find the next window in the stack.'); | |
| resetWindowTraversal(); | |
| return; | |
| } | |
| if (!targetWindow.setFrame(focusedWindow.frame()) || !targetWindow.focus()) { | |
| Phoenix.log('Could not replace or focus the next window.'); | |
| resetWindowTraversal(); | |
| return; | |
| } | |
| windowTraversal = { | |
| order, | |
| focusedHash: targetWindow.hash(), | |
| fixedHash, | |
| }; | |
| } | |
| // Alt + 1: maximise the focused window on its current screen. | |
| Key.on('1', WINDOW_MODIFIERS, () => { | |
| resetWindowTraversal(); | |
| const window = focusedNormalWindow(); | |
| if (window) { | |
| window.maximise(); | |
| } | |
| }); | |
| // Alt + 2: tile the top two windows in the global app/window stack. | |
| // The focused window is always placed on the left. | |
| Key.on('2', WINDOW_MODIFIERS, () => { | |
| resetWindowTraversal(); | |
| const focusedWindow = focusedNormalWindow(); | |
| if (!focusedWindow) { | |
| return; | |
| } | |
| const windows = windowsAtTopOfStack(focusedWindow); | |
| if (windows.length < 2) { | |
| Phoenix.log('There is no second visible normal window in the stack.'); | |
| return; | |
| } | |
| const screen = focusedWindow.screen(); | |
| if (!screen) { | |
| Phoenix.log('The focused window is not on an available screen.'); | |
| return; | |
| } | |
| const frames = splitFrames(screen); | |
| windows[0].setFrame(frames.left); | |
| windows[1].setFrame(frames.right); | |
| windows[0].focus(); | |
| }); | |
| // Alt + L: replace the focused window with the next window in the stack. | |
| Key.on('l', WINDOW_MODIFIERS, () => { | |
| traverseWindowStack(1); | |
| }); | |
| // Alt + H: replace the focused window with the previous window in the stack. | |
| Key.on('h', WINDOW_MODIFIERS, () => { | |
| traverseWindowStack(-1); | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment