docs/custom-layouts.md
Amethyst supports implementing custom layouts via JavaScript.
Layouts are located in ~/Library/Application Support/Amethyst/Layouts/. This directory is automatically created when Amethyst is first launched. JavaScript files in this directory will automatically be picked up and keyed by the name of the file; e.g., my-cool-layout.js will be available as a layout with the key my-cool-layout.
At the moment, files must be manually moved to this directory. There is no way to import them through the app.
At the root of the file you must define a function named layout. This function should return an object with the following properties.
nameA string defining the name of the layout. If no name is specified it will default to the layout key.
initialStateAn object defining any initial state to be tracked by the layout.
commandsAn object defining the commands the layout responds to. There are four available custom commands keyed as command1, command2, command3, and command4, in addition to paned layout commands keyed as expandMain, shrinkMain, increaseMain, and decreaseMain. Commands are objects with a description string to describe what the command does and an updateState function.
The updateState function takes two arguments—state and focusedWindowID—and must return a new state object.
state: the current layout statefocusedWindowID: the currently focused windowextendsThe key for a layout that the custom layout extends. Each call to getFrameAssignments will include the frames determined by the extended layout for reference. There are some limitations to this extension—you cannot affect the state of the extended layout, for example—but this is useful for small modifications to existing native layout algorithms.
getFrameAssignmentsA function that takes four arguments—windows, screenFrame, state, and extendedFrames—and returns a mapping of window ids to window frames.
windows: the list of active windows on the screenscreenFrame: the frame of the screen containing the layoutstate: the current layout stateextendedFrames: the frames that are inherited from the extended layout if any is definedThe return should be an object with new frames keyed by the window id.
updateWithChangeA function that takes two arguments—change and state—and must return a new layout state based on the provided change.
change: the particular change the layout needs to respond to.recommendMainPaneRatioA function that takes two arguments—ratio and state—and must return a new layout state based on the recommended ratio.
ratio: the ratio recommended for the layout based on windows being resized by mouse controls.Amethyst supports changing the relative ratios of windows when changing the size of windows by dragging them with the cursor. By default, these ratios are recommended by calling the recommendMainPaneRatio layout property, and happen on the horizontal axis. When the window is resized, the system determines what ratio is appropriate for the new width given the dimensions of the screen it is on. These values are clamped to [0, 1].
To scale along a different axis, you can specify the unconstrainedDimension and isMain properties of each window's frame. The dimension determines the axis along which window frame changes will cause recommended ratio changes, and the isMain property determines which part of the ratio the window applies to.
Note that currently the recommended ratio is global to the layout and not specific to a given window, so it is not particularly meaningful to specify multiple unconstrainedDimension values among frames.
A window is an object with three properties.
id: an opaque identifier for referencing the window both within getFrameAssignments and across the layout stateframe: the current frame of the window in the screen spaceisFocused: boolean for whether or not the window is currently focusedA frame is an object with four required properties and two optional properties.
x: x-coordinate in the screen spacey: y-coordinate in the screen spacewidth: pixel widthheight: pixel heightisMain: boolean indicating whether the window is in the main pane (default: true)unconstrainedDimension: a string indicating on which axis the window is able to be resized via mouse (values: horizontal, vertical; default: horizontal)Note that frames are in a global space, not relative to a given screen.
A change represents the outcome of an event in the system. It is an object with up to two properties.
change: the string key of the type of event (see below)windowID: the window id for relevant changesotherWindowID: the second window id for relevant changesCurrent changes are:
"add": a window has been added to tracking
windowID for the new window"remove": a window has been removed from tracking
windowID for the removed window"focus_changed": the currently focused window has changed
windowID for the newly focused window"window_swap": two windows have been swapped in position
windowID for the first window and an otherWindowID for the second window"application_activate": an application has been activated
"application_deactivate": an application has been deactivated
"space_change": the current space on a screen has changed
"layout_change": the layout of a screen changed
"unknown": an unknown event
There are several layouts defined for automated tests that can serve as examples. They are in AmethystTests/Model/CustomLayouts/.