Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

The Lua API

Everything the compositor puts in the sol table, transcribed from sol.lua, the definitions file lua-language-server reads for completion (how to set it up). A test fails when the compositor and that file disagree about any of its 98 names.

Most calls queue a command and return nothing. The commands a handler queues are applied together when it returns, in the order it queued them, and every animated one uses the timing sol.animate last set in that handler. Desktop modes is the guide to using them.

Events

What sol.on can listen for.

EventHandler arguments and meaning
openA window’s life began: (id).
focusThe keyboard moved to a window: (id).
activateA window asked to be brought forward, after the compositor answered: (id, why). why is "launch" when an application already running answered a launch with a window it had, and "request" for anything else.
closingA close was asked for and the window is fading: (id).
refusedIts application declined, and the window is back: (id).
closeThe window is gone: (id).
fullscreenA window went fullscreen, or left it: (id, entering). Told once the change is made: its client has been sent its new size and it lives at its new rectangle. Once every listener has run, the compositor moves its picture there from where it is drawn, as a layout’s glide does, with the timing a listener set with sol.animate, and at once if none set one. Until the client answers at its new size the window is held there and its last picture stretched into it, for a quarter of a second past the landing at most; the transform is released when the glide lands. With no timing the change puts no transform on the window and holds nothing. A window a mode is presenting is left where the mode draws it. A change a listener makes is made at once and not told.
maximizeA window was maximised, or restored: (id, entering). Told and answered as "fullscreen" is, and on its own, so the two can move differently.
dropA dragged window was let go: (id, x, y).
resizeAn edge is being dragged: (id, edge_x, edge_y, horizontal_side, vertical_side).
scrollThe wheel turned with Super held: (dx, dy).
clickA press while a script holds input: (x, y).
surfaceA hosted scene sent an action: (surface, action, data), data a table, a value or nil. Every action is heard, in the order sent, in a dispatch after the one that sent it; a scene that sets an action string property is heard the same way, with data nil.
directionsol.focus_direction or sol.move_direction was called: (verb, dir), verb being "focus" or "move". The layout in charge answers.
layoutArrange the windows you already hold again: ().
monitorsThe monitors changed, or were announced at startup or after a reload: ().
restoreThese scripts replaced a running session’s, after a reload and never at startup: ().
text_inputThe focused text field changed: (field, why), field being what sol.text_input() answers at that moment and why what changed – "field", one was enabled, or focused again by its window getting the keyboard back; "caret", its client moved its caret; "framed", its window started or stopped being drawn in a frame, as one going fullscreen does. Told at most once a pass of the event loop, before the frame is drawn, as the most that changed: a caret moved twice since the last frame is told once, where it is now, and a field enabled and then given its caret, as kitty gives it with its first key, is told once as "field". A window moving with its field in it is not told. A field disabled, or its window losing the keyboard, is not told: sol.text_input() answers nil from then on, and field is never nil here.
keyboardThe live layout, Caps Lock or Num Lock changed, by a key or by sol.keyboard{ ... }: (state, changed), state being what sol.keyboard() answers now and changed "layout", "caps" or "num". Never for ordinary typing, a new keymap or a configuration starting, nor while the session is locked: what is pressed at the lock screen is the lock screen’s, and a lock screen that wants a Caps Lock warning draws its own. A change a keyboard listener makes is not told back to it.

sol

sol.keep(name, defaults)

State that survives super+shift+r.

Answers the table the last configuration kept under name, or defaults on the first load. Mutate it in place and the next reload gets what you left in it. It may hold numbers, strings, booleans, tables of those, and the trees and strips sol.layout makes, eight tables deep; anything else is named in the log and left out. Asked for twice under one name, it is the same table both times.

Parameters:

  • name: string
  • defaults: table

Returns table.

sol.lua:319

sol.windows()

Every window a layout may arrange, topmost first.

A snapshot taken for this handler, not a live view. A window that closes while you hold its id is ordinary: place and present on an id that no longer exists do nothing.

Returns sol.Window[].

sol.lua:327

sol.apps()

Every installed, visible application (NoDisplay and Hidden entries are left out at the source), by name.

A snapshot taken for this handler, not a live view, and – unlike sol.windows() and sol.monitors() – empty at the top level of a configuration file: it reads before the first real one arrives, and before the index has even scanned once on a first start. A scene reads Solium.Apps instead, which is live from the moment it is drawn.

Returns sol.App[].

sol.lua:338

sol.surface(name, options)

Draw a QML scene: a wallpaper, a bar, a dock, a heads-up display.

Declaring a name again with the same scene changes the live scene: changed properties are written into it, and on a monitor it was already on a new on, layer or interactive keeps it, so what the scene holds survives (an open popup, a running animation). A monitor it newly covers gets a scene built from the current properties, and one it leaves drops its scene. Only another scene file builds it again. A key left out of properties keeps the value the scene last had. A dotted key (["panel.open"] = true) reaches a grouped property. false or nil takes the surface away. Each monitor it is on gets a scene of its own, built when the surface is declared or the monitor arrives and dropped when the monitor goes; Solium.monitor inside it is that monitor. A scene file that is not there is logged, and built once it is there, at the next reload, change of monitors or changed declaration; a scene that will not load is logged once per monitor and not tried again until another scene is declared or the configuration is reloaded.

Parameters:

sol.lua:359

sol.keyboard(options)

Read the keyboard, or change it.

With no argument, answers the layouts, which one is live, its short name, whether Caps Lock and Num Lock are on, and how keys repeat. With a table, changes what it names and leaves the rest alone, so a binding that switches layout does not reset the repeat rate. sol.on("keyboard", ...) hears the layout and the locks change.

Also called as:

Parameters:

Returns sol.KeyboardState|nil.

sol.lua:371

sol.text_input()

The focused text field and where its caret is, or nil when the window with the keyboard has no text field enabled.

Kept by the text-input-v3 protocol: an application with a text field focused says so, and says where its caret is. Applications that do not speak it, and X11 ones, never have one. sol.on("text_input", ...) hears a field being enabled or focused, its caret moving, and its window being framed or left bare.

Returns sol.TextField|nil.

sol.lua:382

sol.monitors(rows)

Read the monitors, or arrange them.

With no argument, answers every monitor. With a list, drives and places the monitors it names; a row with no name is logged and skipped.

Also called as:

Parameters:

Returns sol.Monitor[]|nil.

sol.lua:391

sol.workspaces(declared)

Say what the workspaces are. The compositor does not know what a workspace is: workspaces.lua is the whole feature, and this is how a hosted shell’s Workspaces model learns it. Declare again whenever it changes; the same declaration twice costs nothing. Monitors and windows the compositor does not have are left out, with any group left with no monitor, and so is a workspace whose <group>/<id> an earlier one in a group that stays already has; each is logged once.

Parameters:

sol.lua:423

sol.monitor_power(which, mode)

Turn a monitor’s display off or on, or every monitor’s with "all".

The monitor keeps its place, its work area and its windows. Any key, click, scroll, touch or pointer motion turns every screen back on. A mode that is neither "on" nor "off" is an error; a name no monitor has is a line in the log.

Parameters:

  • which: string — A monitor’s name, or "all".
  • mode: "on"|"off"

sol.lua:434

sol.idle(options)

Set the idle blank: config.idle, which the shipped init.lua hands over.

Parameters:

sol.lua:439

sol.monitor(id)

The work area of the monitor a window is on, or of the active monitor when no window is named or the id is unknown.

Parameters:

  • id: integer (optional)

Returns sol.Rect.

sol.lua:445

sol.cursor()

Where the pointer is.

Returns sol.Point.

sol.lua:449

sol.window_at(x, y, skip)

The window drawn at a point, asked the way the compositor asks it: against where windows are drawn, on the monitors that draw them.

skip leaves one window out, which is what makes it useful while dragging: the dragged window is always the one under the pointer.

Parameters:

  • x: number
  • y: number
  • skip: integer (optional)

Returns integer|nil (id).

sol.lua:460

sol.present(id, options)

Draw a window somewhere other than where it lives, animated.

A transform: the window keeps its place and its client is told nothing, so sol.present_clear puts it back exactly. Input follows the rect it is drawn at.

A present that lands exactly on the window’s own frame (no rect, no rotation, full opacity) lets the window go, as sol.present_clear does, rather than holding it there.

Parameters:

sol.lua:474

sol.present_from(id, options)

Draw a window at a rect and animate it to where it lives: every “appears from somewhere” animation. The rect is required.

Parameters:

  • id: integer
  • options: { x: number, y: number, w: number, h: number, opacity?: number }

sol.lua:481

sol.debug_mode()

Whether the compositor was started with --debug-mode or with SOLIUM_DEBUG_MODE set. The Developer Tweaks panel asks this.

Returns boolean.

sol.lua:486

sol.reload()

Read the configuration again, without ending the session.

A configuration that fails to load leaves the running one in place. See sol.keep and the restore event for what a reload carries.

sol.lua:493

sol.pane(name)

Choose how every window is framed, at once.

A name is a folder under ~/.config/solium/qml/panes or the shipped qml/panes, or a single file under ~/.config/solium/qml/decorations; a path is anyone’s; "none" draws no frame. SOLIUM_PANE, when set, wins over the name given here.

Parameters:

  • name: string (optional)

sol.lua:503

sol.pane_values(values)

Hand values of the configuration’s own to every layer of every pane.

Every layer’s root reads them as one object, values, which PaneStyle declares for an inline layer and a delegated layer declares itself (property var values: ({})): so a setting the configuration reads can reach the QML that draws by it, and the compositor never knows what the setting is. Each call merges its keys into what is there, so two scripts each handing their own keep both; a key, once given, keeps its last value until the configuration is reloaded, which starts with none. Values are what sol.surface’s properties take. A window opened later is told them too.

Parameters:

  • values: table

sol.lua:522

sol.decorations()

Every frame style sol.pane could be given, found in the folders the compositor looks in: sorted, bundles first, each name once.

Returns sol.DecorationEntry[].

sol.lua:527

sol.loading(options)

Set what a window does between being asked for and its application arriving.

Parameters:

sol.lua:532

sol.client_sizes(options)

Set whose own size limits a floating window’s edge drag is held to.

floating = "ignore" lets the drag go wherever the pointer does; anything else believes every application. ignore lists applications, by app_id, whose limits are never believed.

Parameters:

  • options: { floating?: "respect"|"ignore", ignore?: string[] } (optional)

sol.lua:541

sol.resize(options)

Set what fills a window while a resize drag is ahead of its client.

"stretch" (the default) scales the last picture; "hold" leaves it at its own size; "scene" draws the window’s QML scene, which today reaches only a window resized before its application painted. Another name is logged and the default kept.

Parameters:

  • options: { fill?: "stretch"|"hold"|"scene" } (optional)

sol.lua:551

sol.fullscreen(options)

Set what a fullscreen window covers.

"top" (the default) covers the top layer, so bars go under it; "none" leaves bars over it. Another name is logged and the default kept.

Parameters:

  • options: { covers?: "top"|"none" } (optional)

sol.lua:559

sol.cursor_theme(options)

Set the pointer’s XCursor theme, size and scene. Applied at once, so a reload is how a theme or a scene is tried, and a scene whose files changed is built again. Not sol.cursor, which says where the pointer is.

Parameters:

sol.lua:566

sol.qml(options)

Choose how QML renders, and how long the GPU trial may take.

Read once, when the compositor starts, before any scene does; a reload does not change it. --qml, SOLIUM_QML and SOLIUM_QML_GPU override it.

Parameters:

sol.lua:574

sol.session(options)

Say how this session is announced, and how long a signal to end waits.

Read once, when the compositor starts; a reload does not change it. Who is told: the session bus, when Solium is started as the session with solium --tty --session; nobody, for a --tty start by hand or a nested run, unless SOLIUM_SESSION_BUS names a bus to tell instead. The shipped init.lua calls it with config.session.

Parameters:

sol.lua:585

sol.present_clear(id)

Stop presenting a window: animate it back to where it lives.

Parameters:

  • id: integer

sol.lua:590

sol.group(name, selection)

Name a selection of windows, surfaces and monitors, so one transform can carry them together.

Declaring the name again replaces the membership and keeps the transform, so a mode that rebuilds its groups on every pass does not restart its own animation. false or nil takes the name away.

Parameters:

sol.lua:601

sol.present_group(name, shift, motion)

Move, fade or turn a selection as one.

Composes with each member’s own sol.present, so a window tilted inside a moving desk stays tilted within it. motion sets this call’s own timing; left out, it is whatever sol.animate set.

Parameters:

sol.lua:612

sol.present_group_clear(name, motion)

Animate a selection back to where its members live.

Parameters:

sol.lua:618

sol.animate(options)

Set the timing for every animated command queued after this one in the same handler. Left unset, it is 220 ms and "outCubic". In a "fullscreen" or "maximize" listener it is also how the window’s own move is timed; there, left unset, the move is instant.

Parameters:

sol.lua:626

sol.focus(id)

Give a window the keyboard.

Parameters:

  • id: integer

sol.lua:631

sol.toggle_fullscreen(id)

Make a window fullscreen, or give it back its place if it already is. With no id, the focused window; with nothing focused, nothing happens.

Parameters:

  • id: integer (optional)

sol.lua:637

sol.toggle_maximize(id)

Maximise a window to its monitor’s work area, or give it back its place if it already is. With no id, the focused window; with nothing focused, nothing happens.

Parameters:

  • id: integer (optional)

sol.lua:644

sol.focus_direction(dir)

Move the keyboard to the window beside the focused one. Every direction listener is told ("focus", dir), and the layout in charge answers (lua/direction.lua). Anything but the four directions is an error. The listeners’ time counts against the handler that called this, so one stopped at the deadline stops that handler too.

Parameters:

  • dir: "left"|"right"|"up"|"down"

sol.lua:653

sol.move_direction(dir)

Move the focused window in a direction: direction listeners are told ("move", dir). Tiling trades it with its neighbour, scrolling moves it within or between columns, and a fullscreen or maximised window moved to another monitor stays so there. Anything but the four directions is an error. The listeners’ time counts against the handler that called this, so one stopped at the deadline stops that handler too.

Parameters:

  • dir: "left"|"right"|"up"|"down"

sol.lua:663

sol.place(id, options)

Put a window where it lives: the layout’s call.

The client is told the size and asked to redraw. The rect is a tile unless tile = false: a client that will not shrink to it is cut to it rather than drawn over its neighbours. A rect is required.

Parameters:

sol.lua:673

sol.unplace(id)

Let a window go from its tile, when a layout stops arranging it. modes.use sends this for every window when the layout in charge changes.

Parameters:

  • id: integer

sol.lua:679

sol.close(id)

Ask a window to close. A request, not a kill: its application may refuse.

Parameters:

  • id: integer

sol.lua:684

sol.act(action, data, done)

Perform an action of the vocabulary: the same names a scene sends with Solium.send, windows.focus, windows.close, windows.fullscreen and windows.maximize, each with { id = <window id> }; the last two toggle. data is handed over as a surface’s properties are, so a table nested deeper than 64 or holding more than 65 536 values, or one that contains itself, is an error in the handler. Queued like every other request, and answered by done(ok, reason) once the compositor has acted, in a handler of its own; reason is "unknown-action", "unknown-window", "bad-data", for a windows.focus behind the lock "locked", or, for a windows.fullscreen or windows.maximize of an X11 window, which the compositor cannot send there, "unsupported". A window still loading is "unknown-window" to all but windows.close. A done that calls sol.act again is told again in the same dispatch, 16 rounds at most, and the rest at the next one. Answers the attempt’s id, one no earlier sol.act answered. A workspaces.* action is not the compositor’s: the file that keeps the workspaces answers it, with actions.override in lua/actions.lua. An override is a surface listener of its own, under the same deadline, so one stopped three times is taken out alone, and its action goes to sol.act again.

Also called as:

  • sol.act(action: "windows.focus"|"windows.close"|"windows.fullscreen"|"windows.maximize", data: { id: integer }, done?: fun(ok: boolean, reason?: string)) returns integer

Parameters:

  • action: string
  • data: any (optional)
  • done: fun(ok: boolean, reason?: string) (optional)

Returns integer (attempt).

sol.lua:712

sol.spawn(program, ...)

Start a program, with its arguments as separate strings: sol.spawn("foot", "-e", "htop").

The program gets the environment Solium was started with, not what Qt and the libraries it loads have written into Solium’s own since. On top of that: WAYLAND_DISPLAY naming this compositor; DISPLAY naming its own Xwayland, or removed when there is none; XDG_CURRENT_DESKTOP, which is Lilium unless the session named one; XDG_SESSION_TYPE=wayland when it is unset; and XDG_ACTIVATION_TOKEN and DESKTOP_STARTUP_ID, naming the window opened for it. It holds no file descriptor beyond stdin, stdout and stderr. stdin and stdout are /dev/null, and stderr is Solium’s.

Parameters:

  • program: string
  • ...: string

sol.lua:728

sol.which(program)

Whether a program can be found on PATH. A name with a / in it is checked as a path. Nothing is run.

Parameters:

  • program: string

Returns boolean.

sol.lua:734

sol.quit()

End the session. Ctrl+Alt+Backspace does the same and cannot be rebound.

sol.lua:738

sol.grab_input(grabbed)

Take input away from clients, or give it back.

While a script holds it, keys it has not bound are swallowed, pointer presses go to click listeners, and focus stops following the pointer. Release it when you leave, or nothing reaches a window again.

Parameters:

  • grabbed: boolean

sol.lua:747

sol.status(text)

Say which mode is in charge. The compositor keeps the text and logs a change at debug level, and a hosted shell reads it as Solium.status; nothing the compositor draws itself shows it.

Parameters:

  • text: string

sol.lua:754

sol.bind(combo, handler, note)

Bind a key combination to a function.

The combination is normalised, so super+shift+q and Shift+Super+Q are one binding. A later call for the same combination replaces the earlier one. While the session is unlocked, a bound combination never reaches the application with the keyboard. A key a mode needs only while it is up is bound when the mode starts and taken away with sol.unbind when it stops, as overview.lua does with escape. note is a short phrase saying where the binding came from, which solium --check prints beside it.

Parameters:

  • combo: string
  • handler: fun()
  • note: string (optional)

sol.lua:770

sol.bound(combo)

Whether a combination is bound, in whatever spelling it is given.

Parameters:

  • combo: string

Returns boolean.

sol.lua:775

sol.unbind(combo, note)

Take a binding away. The combination then reaches the application with the keyboard again. With a note, solium --check lists the combination as removed by the configuration.

Parameters:

  • combo: string
  • note: string (optional)

sol.lua:783

sol.unknown(key, meant)

Report a setting nothing reads. config.lua calls this for each key of a user.lua its defaults do not define; solium --check lists them and exits with 1. meant is a near-miss suggestion.

Parameters:

  • key: string
  • meant: string (optional)

sol.lua:791

sol.on(event, handler)

Listen for an event. Listeners are added, never replaced, and one that fails is logged while the others still run.

A listener runs under a 100 ms deadline: one that takes longer is stopped with an error and logged with the file and line it was written at and the file and line it was stopped at (for an actions.override, the listener actions.lua writes for it, and the override’s own line), the other listeners still run, and one stopped three times is taken out until the configuration is reloaded. The stops are counted by function, so a function listening for two events counts the stops of both, and from its third on is taken out of each event it is stopped in. Bindings, and each done of sol.act, run under the same deadline, and a stopped binding is logged the same way. A done is struck by function too, and one stopped three times is not called again until the configuration is reloaded; a done written inline is a new function at each sol.act, so it is stopped each time rather than taken out. What a done asked for in the run that was stopped is dropped. The compositor starts each one’s clock itself, so nothing a handler calls puts it off. pcall, xpcall and load hand the stop on rather than catch it, and xpcall’s message handler is not called for it. A __gc finalizer, and the __close of a to-be-closed variable in the function a stop interrupts, run where no hook does, so the deadline cannot stop a loop in either.

Also called as:

  • sol.on(event: "open"|"focus"|"closing"|"refused"|"close", handler: fun(id: integer))
  • sol.on(event: "activate", handler: fun(id: integer, why: "launch"|"request"))
  • sol.on(event: "drop", handler: fun(id: integer, x: number, y: number))
  • sol.on(event: "resize", handler: fun(id: integer, edge_x: number, edge_y: number, horizontal_side: "left"|"right"|nil, vertical_side: "top"|"bottom"|nil))
  • sol.on(event: "scroll", handler: fun(dx: number, dy: number))
  • sol.on(event: "click", handler: fun(x: number, y: number))
  • sol.on(event: "surface", handler: fun(surface: string, action: string, data: any))
  • sol.on(event: "direction", handler: fun(verb: "focus"|"move", dir: "left"|"right"|"up"|"down"))
  • sol.on(event: "layout"|"monitors"|"restore", handler: fun())
  • sol.on(event: "text_input", handler: fun(field: sol.TextField, why: "field"|"caret"|"framed"))
  • sol.on(event: "keyboard", handler: fun(state: sol.KeyboardState, changed: "layout"|"caps"|"num"))

Parameters:

sol.lua:830

sol.log(message)

Write a line to the compositor’s log, at info level.

Parameters:

  • message: string

sol.lua:835

sol.decoration

The old name for sol.pane, from when a style was a single QML file. The same function.

sol.layout

The standard arrangements, from crates/layout. The pure ones take a count or a list and a sol.LayoutOptions and answer rects; tree and scroller make an arrangement the script holds.

sol.layout.master_stack(count, options)

One large window and the rest stacked beside it.

Parameters:

Returns sol.Rect[].

sol.lua:885

sol.layout.tree()

A dwindle tree, held by the script that made it. Stateful because where a window lands depends on which window was split and where the pointer was.

Returns sol.Tree.

sol.lua:890

sol.layout.scroller(options)

A scrolling strip of columns, held by the script that made it.

Reads widths and default_width from the table given, which is meant to be config.scrolling; with none it uses the built-in widths.

Parameters:

  • options: { widths?: number[], default_width?: integer } (optional)

Returns sol.Scroller.

sol.lua:898

sol.layout.strip(columns, options)

A row of columns, each holding a stack, with options.offset as how far the view has scrolled.

Parameters:

Returns sol.Rect[].

sol.lua:905

sol.layout.strip_scroll_to(index, columns, options)

The view offset that brings column index (counting from 1) fully into view, moving as little as possible.

Parameters:

Returns number (offset).

sol.lua:913

sol.layout.scrolling(count, options)

A row of count windows at options.column of the width each, with options.offset as how far the view has scrolled.

Parameters:

Returns sol.Rect[].

sol.lua:920

sol.layout.scroll_to(index, count, options)

The view offset that brings window index (counting from 1) of count fully into view in sol.layout.scrolling.

Parameters:

Returns number (offset).

sol.lua:928

sol.layout.grid(sizes, options)

A grid of thumbnails, as close to square as the count allows. Each size keeps its aspect ratio inside its cell; overview uses this.

Parameters:

Returns sol.Rect[].

sol.lua:935

A dwindle tree

A dwindle tree from sol.layout.tree(). Every call that takes options reads options.floors first, and lays the tree out in options as the work area.

Tree:insert(id, target, x, y, options)

Add a window by splitting target, or the tile under x, y when there is no target. Splits however small that leaves the halves.

Parameters:

  • id: integer
  • target: integer (optional)
  • x: number (optional)
  • y: number (optional)
  • options: sol.LayoutOptions

sol.lua:953

Tree:insert_fitting(id, target, x, y, options)

insert, refusing a split that would leave a tile under options.minimum or a window under its floor: the same side first, then the other axis. Answers false and leaves the tree alone when neither fits.

Parameters:

  • id: integer
  • target: integer (optional)
  • x: number (optional)
  • y: number (optional)
  • options: sol.LayoutOptions

Returns boolean (inserted).

sol.lua:964

Tree:insert_largest(id, options)

Split the largest tile that has room for another window at options.minimum, or answer false and leave the tree alone.

Parameters:

Returns boolean (inserted).

sol.lua:971

Tree:remove(id)

Take a window out of the tree.

Parameters:

  • id: integer

sol.lua:976

Tree:resize(id, axis, by, options)

Move a seam from the keyboard: by is a signed share that grows the window when positive. The seam on the right or below is preferred, and the other one used only when there is none. Without options there is no minimum.

Parameters:

  • id: integer
  • axis: "width"|"height"
  • by: number
  • options: sol.LayoutOptions (optional)

sol.lua:986

Tree:drag_seam(id, edge, edge_x, edge_y, options)

Move a seam from a drag: put the named side of the window at edge_x (for "left" and "right") or edge_y (for "top" and "bottom"). Hand it what the resize event gave you. Clamped to 0.05..0.95 and to options.minimum.

Parameters:

  • id: integer
  • edge: "left"|"right"|"top"|"bottom"
  • edge_x: number
  • edge_y: number
  • options: sol.LayoutOptions

sol.lua:998

Tree:contains(id)

Whether a window is in the tree.

Parameters:

  • id: integer

Returns boolean.

sol.lua:1003

Tree:windows()

Every window in the tree, in tree order.

Returns integer[].

sol.lua:1007

Tree:swap(a, b)

Trade the tiles of windows a and b and change nothing else: every split keeps its axis and its ratio, so a second swap puts it back.

Parameters:

  • a: integer
  • b: integer

Returns boolean (both_were_in_the_tree).

sol.lua:1014

Tree:layout(options)

Where every window in the tree goes, ready for sol.place.

Parameters:

Returns sol.Slot[].

sol.lua:1019

A scrolling strip

A strip of columns from sol.layout.scroller(). Every call that takes options reads options.floors first: a column is never laid out narrower than the widest floor in it.

Scroller:insert(id, options)

Open a window in a new column, to the right of the active one.

Parameters:

sol.lua:1033

Scroller:insert_into_column(id, options)

Add a window to the active column instead of beside it.

Parameters:

sol.lua:1039

Scroller:remove(id)

Take a window out of the strip.

Parameters:

  • id: integer

sol.lua:1044

Scroller:focus_window(id, options)

Focus a window, bringing its column into view.

Parameters:

sol.lua:1050

Scroller:focus_sideways(by, options)

Move focus by columns left (negative) or right, taking the view with it.

Parameters:

sol.lua:1056

Scroller:focus_vertically(by)

Move focus by windows up (negative) or down within the active column.

Parameters:

  • by: integer

sol.lua:1061

Scroller:move_vertically(by)

Swap the focused window with the one above it in its column (by is -1) or below it (1), carrying focus along. Nothing moves at the top or bottom.

Parameters:

  • by: integer

Returns boolean (moved).

sol.lua:1067

Scroller:move_column(by, options)

Swap the active column with its neighbour by places away, carrying focus.

Parameters:

sol.lua:1073

Scroller:consume()

Pull the next column’s focused window into the active column.

sol.lua:1077

Scroller:expel(options)

Push the focused window out into a column of its own.

Parameters:

sol.lua:1082

Scroller:move_to_column_of(id, target, options)

Move a window into the column another window is in.

Parameters:

sol.lua:1089

Scroller:widen(id, by, options)

Widen (positive) or narrow the column a window is in, by a share of the view. Clamped so a column neither vanishes nor grows past the view.

Parameters:

sol.lua:1097

Scroller:cycle_width(options)

Cycle the active column through the preset widths.

Parameters:

sol.lua:1102

Scroller:configure(options)

Take widths and default_width from options as sol.layout.scroller does, keeping the columns, the focus and the view. For a strip sol.keep carried across a reload.

Parameters:

  • options: { widths?: number[], default_width?: integer }

sol.lua:1109

Scroller:scroll_by(delta)

Scroll the view by a distance, without moving focus.

Parameters:

  • delta: number

sol.lua:1114

Scroller:focused()

The focused window, if there is one.

Returns integer|nil.

sol.lua:1118

Scroller:contains(id)

Whether a window is in the strip.

Parameters:

  • id: integer

Returns boolean.

sol.lua:1123

Scroller:windows()

Every window in the strip, left to right and top to bottom within a column.

Returns integer[].

sol.lua:1127

Scroller:layout(options)

Where every window in the strip goes, ready for sol.place.

Parameters:

Returns sol.Slot[].

sol.lua:1132

Types

The shapes of the tables the calls above take and return.

sol.Rect

A rectangle in the one global coordinate space every monitor is a window onto, in logical pixels.

  • x: number
  • y: number
  • w: number
  • h: number

sol.Size

A size in logical pixels.

  • w: number
  • h: number

sol.Point

A point in the global coordinate space.

  • x: number
  • y: number

sol.Window

One row of sol.windows(): a window a layout may arrange, as it was at the moment the handler was called. x, y, w and h are where the window lives, frame included.

Has every field of sol.Rect, and:

  • id: integer — The window’s id, which every other call takes.
  • title: string — The window’s title; the program’s name until its application arrives.
  • focused: boolean — Whether it has the keyboard. While an item of a hosted scene holds the keyboard (Solium.keyboard.wants), the window it was taken from still reads true, is drawn focused, and gets the keyboard back when the scene lets go.
  • monitor: string — The name of the monitor it is on.
  • modal: boolean — Whether it says it is a modal dialog.
  • parent: integer|false (optional) — The window it belongs to; false when the client named a parent that is not on screen, absent when it named none.
  • leaving: boolean — Whether it is closing: between closing and close or refused.
  • app_id: string — The application’s own name: a Wayland app_id, an X11 WM_CLASS class. Empty until the application arrives.
  • min: sol.Size (optional) — The smallest the application says it can be, frame included; absent when it set no limit.
  • max: sol.Size (optional) — The largest the application says it can be, frame included; absent when it set no limit.
  • cramped: boolean — Whether the layout last placed it with cramped = true.
  • shown: boolean — Whether its application has shown its first frame yet.

sol.App

One row of sol.apps(): an installed, visible application.

  • id: string — The desktop file id, such as "org.mozilla.firefox".
  • name: string — Its localised name.
  • generic_name: string — Its localised generic name ("Web Browser"); empty when it named none.
  • icon: string — A theme icon name, or an absolute path when Icon= gave one.
  • categories: string[] — Its Categories=, split on ;.

sol.Monitor

One row of sol.monitors(). x, y, w and h are the work area: the monitor less what layer-shell bars and hosted surfaces reserve.

Has every field of sol.Rect, and:

  • name: string — The connector name, such as "DP-1".
  • scale: number — Device pixels per logical pixel.
  • focused: boolean — Whether the pointer is on it.
  • primary: boolean — Whether it is the primary monitor.
  • transform: string — Its rotation, as Smithay names it in lower case: "normal", "_90", "_180", "_270", "flipped", "flipped90", "flipped180" or "flipped270". Not the spelling sol.monitors{ ... } takes.
  • power: "on"|"off" — Whether its display is on. A monitor that is off keeps its place, its work area and its windows.
  • whole: sol.Rect — The whole monitor, which is what a wallpaper or a fullscreen window covers.

sol.MonitorPlacement

How one monitor should be driven and where it goes, for sol.monitors{ ... }. Every key but name is optional. config.lua’s monitors section explains each one at length.

  • name: string — The connector name. solium --probe lists the ones the machine has.
  • x: integer (optional) — The top-left corner, in the global space.
  • y: integer (optional) — The top-left corner, in the global space.
  • right_of: string (optional) — Beside the monitor with this name.
  • left_of: string (optional) — Beside the monitor with this name.
  • above: string (optional) — Beside the monitor with this name.
  • below: string (optional) — Beside the monitor with this name.
  • align: "start"|"centre"|"end" (optional) — Which way the other axis lines up when placed beside a monitor of another size. "centre" is the default.
  • mode: string|{ w: integer, h: integer, refresh?: integer } (optional) — "2560x1440@165", "2560x1440", or one of "best" (the default), "preferred" and "widest".
  • vrr: boolean (optional) — Variable refresh rate, where the monitor and the driver offer it.
  • transform: string|integer (optional) — Anticlockwise: "normal", "90", "180", "270", "flipped", "flipped-90", "flipped-180" or "flipped-270". A number is read as degrees.
  • enabled: boolean (optional) — false does not drive the monitor at all.
  • primary: boolean (optional) — The monitor things belonging to one screen go on.
  • scale: number|"auto" (optional) — Device pixels per logical pixel, from 0.5 to 8. Left out, it is worked out from the panel’s size.

sol.KeyboardState

The keyboard as sol.keyboard() answers.

  • layouts: string[] — The layout names, in order.
  • active: integer — Which of them is live, counting from 1.
  • layout_name: string — The live layout’s name, such as "Russian"; "" before the keymap is known. Not layout, which sol.keyboard{ ... } takes as the xkb names to compile, so a table read here can be handed back.
  • layout_short: string — The live layout’s short name, such as "RU": the shortDescription xkb’s rules give it, upper-cased, or its first two letters.
  • caps: boolean — Whether Caps Lock is on.
  • num: boolean — Whether Num Lock is on.
  • repeat_rate: integer — Repeats per second.
  • repeat_delay: integer — Milliseconds a key is held before it repeats.

sol.TextField

The focused text field, as sol.text_input() answers: the window it is in, whether that window is framed, and its caret in the global space. The four numbers are there only once the application has said where its caret is, through text-input-v3; an application that never does has a field and no caret.

  • window: integer — The window’s id, as sol.windows() gives it.
  • framed: boolean — Whether the window is drawn in a frame of the compositor’s, or will be once its frame is built, so its pane style’s layers are drawn with it. False for a window drawn bare: fullscreen, one drawing its own decorations, every window under the pane style "none".
  • x: number (optional) — The caret’s rectangle, where it is drawn: its window’s place and scale on screen are in it, presentation transforms included.
  • y: number (optional)
  • w: number (optional)
  • h: number (optional)

sol.KeyboardOptions

What sol.keyboard{ ... } may change. Every key is optional and one left out is left as it is. The first five are xkb names; setting any of them compiles a new keymap, and one left blank falls back to the matching XKB_DEFAULT_* environment variable.

  • rules: string (optional)
  • model: string (optional)
  • layout: string (optional) — A comma-separated list, such as "us,ua".
  • variant: string (optional) — One per layout, in the same order.
  • options: string (optional) — xkb options, comma separated, such as "grp:alt_shift_toggle".
  • repeat_rate: integer (optional) — Repeats per second.
  • repeat_delay: integer (optional) — Milliseconds before repeating starts.
  • active: integer (optional) — Which layout is live, counting from 1.
  • caps: boolean (optional) — Caps Lock on or off. Done by pressing the keymap’s own Caps Lock key inside the compositor, so the window with the keyboard is told and the layout stays; a keymap with no such key cannot have it, and the log says so.
  • num: boolean (optional) — Num Lock on or off, the same way.

sol.SurfaceOptions

A QML scene for sol.surface to draw.

  • scene: string — A file name looked up in ~/.config/solium/qml and then in the shipped QML, or a path (absolute, or starting with ~/).
  • layer: sol.Layer (optional) — Which layer it is drawn in. "background" is the default.
  • on: "primary"|"every-monitor"|string|sol.Rect (optional) — "every-monitor" (the default) draws one instance per monitor, filling it; "primary" one on the primary monitor; a monitor’s name one there; a rect one at that rect.
  • properties: table (optional) — Values for the scene’s properties, handed over as JSON: strings, numbers, booleans and tables of those, nested at most 64 deep and 65 536 values in all, a table counted once for each place it is in. A function, userdata or non-finite number is left out; a table nested deeper or holding more, or one that contains itself, is an error.
  • interactive: boolean (optional) — Whether the pointer reaches it at all, so a Grab in a scene it does not reach holds nothing, and one it held when it is declared so is dismissed; nor does such a scene hold the keyboard. Where it does, the scene’s items decide which points are its (Solium.input), and the rest go to what is under it. An interactive scene sends actions with Solium.send(action, data), and sol.on("surface", ...) hears them.
  • reserve: { top?: integer, right?: integer, bottom?: integer, left?: integer } (optional) — Logical pixels taken out of the work area on those edges of every monitor the surface is on, whatever its size or placement; never negative. A scene’s own Solium.surface.reserve.<edge> wins for an edge it sets. A change re-flows the windows once.
  • outside_click: "swallow"|"pass"|table<string, "swallow"|"pass"> (optional) — What a press outside an open Grab of the scene does once it has dismissed it: swallowed with its release (the default), or passed on to what is under it. A table names grabs, with default for the rest. Any other value fails the load.
  • keyboard: { bindings?: "except_claimed"|"all"|"none" } (optional) — While an item of the scene holds the keyboard (Solium.keyboard.wants): "except_claimed" (the default) keeps every binding but the keys the holding item claims (Solium.keyboard.claims), "all" keeps every binding, and "none" gives the scene every key but the Ctrl+Alt escapes. Any other value fails the load.

sol.Layer

  • "background" — Under everything, including client background surfaces.
  • "bottom" — Above the background, below windows.
  • "top" — Above windows, below client top surfaces, and below a fullscreen window that covers the top layer.
  • "overlay" — Above client top surfaces, below client overlay ones and the pointer.

sol.Easing

A curve by name, or four numbers: the control points of a cubic bezier, as CSS writes cubic-bezier(x1, y1, x2, y2). An unknown name is logged and the default kept.

  • "linear"
  • "outCubic"
  • "outBack"
  • "inOutQuad"
  • "inOutCubic"
  • "spring"
  • number[]

sol.Motion

How long an animation takes and how it moves.

  • duration: integer (optional) — Milliseconds.
  • easing: sol.Easing (optional)

sol.PresentOptions

Where and how sol.present draws a window. A key left out says nothing: with no rect the window is drawn at its own, with no opacity it is opaque, and with no rotation it is flat.

  • x: number (optional) — The rect it is drawn at: all four of x, y, w and h, or none.
  • y: number (optional)
  • w: number (optional)
  • h: number (optional)
  • opacity: number (optional) — From 0 to 1.
  • rotate_x: number (optional) — Degrees about the horizontal axis.
  • rotate_y: number (optional) — Degrees about the vertical axis.
  • rotate_z: number (optional) — Degrees in the plane of the screen.
  • perspective: number (optional) — The viewer’s distance in pixels. Without it a rotation is orthographic.
  • pivot_x: number (optional) — What the rotation turns about, as a share of the width. 0.5 is the default; outside 0..1 is kept.
  • pivot_y: number (optional) — What the rotation turns about, as a share of the height. 0.5 is the default; outside 0..1 is kept.
  • z: number (optional) — Draw order and nothing else: higher is in front, equal keeps the stacking order, 0 is the default. Input still follows the rect.
  • deform: sol.Deform (optional) — A deformation of the window’s mesh.

sol.Deform

A deformation, named by effect. Its other keys are that effect’s parameters.

  • effect: "genie" — The effect, from crates/effects. An unknown one is logged and the window drawn undeformed.
  • to: { window: integer }|{ surface: string }|sol.Rect — What the window is pulled into or drawn out of. A window or a surface is followed as it moves; a rect stays where it is. A surface on several monitors is the one on the window’s own monitor.
  • axis: "down"|"up"|"left"|"right" (optional) — For the genie: which edge leads.
  • spread: number (optional) — For the genie: how much of the window is in motion at once. 0 is rigid.

sol.PlaceOptions

Where sol.place puts a window.

Has every field of sol.Rect, and:

  • tile: boolean|sol.Rect (optional) — true (the default) makes the rect a tile the window is held inside; false places it without tiling it; a rect is the tile, for a window placed smaller than its tile.
  • cramped: boolean (optional) — The layout saying the tile is smaller than the window’s own minimum. sol.windows() reports it back.

sol.Selection

What a selection holds, for sol.group. Every key is optional.

  • windows: integer[] (optional) — Windows, by id.
  • surfaces: string[] (optional) — Surfaces, by the name sol.surface gave them.
  • monitors: string[] (optional) — Everything drawn on these monitors.
  • monitor: string (optional) — Which instance of each surface above: the one on this monitor.

sol.Shift

What sol.present_group does to a selection. x and y are a displacement, not a destination, and the rest compose with each member’s own transform.

  • x: number (optional)
  • y: number (optional)
  • opacity: number (optional)
  • rotate_x: number (optional)
  • rotate_y: number (optional)
  • rotate_z: number (optional)
  • perspective: number (optional)

sol.LoadingOptions

What a window does before its application arrives. Every key is optional and one left out keeps the compositor’s default.

  • scene: string (optional) — The QML scene: a name in qml/loading, the user’s first, or a path.
  • patience: integer (optional) — Milliseconds to wait for an application that never arrives.
  • reserves_a_slot: boolean (optional) — Whether the window takes its place in the layout at once.
  • decorated: boolean (optional) — Whether its frame is drawn while it waits.
  • fade: integer (optional) — Milliseconds the scene takes to fade off the application.

sol.IdleOptions

The idle blank. A key left out, or one that is not a number of 0 or more, keeps the default.

  • screens_off_after: number (optional) — Seconds with nobody at the machine before every screen is turned off. 0 never does.
  • off_frame_interval: number (optional) — How often, in milliseconds, a window on a screen that is off is still told it may draw. 0 stops it.
  • dbus_inhibit: boolean (optional) — Own org.freedesktop.ScreenSaver, so a browser’s D-Bus inhibitor keeps the screens on like a Wayland one. Default true.

sol.CursorOptions

The pointer’s theme. A key left out, or no table, means the configuration did not say, and XCURSOR_THEME and XCURSOR_SIZE have their turn.

  • theme: string (optional) — The name of an XCursor theme.
  • size: integer (optional) — Logical pixels, from 8 to 256.
  • scene: string (optional) — A QML scene to draw the pointer with, for every shape and ahead of the theme: a path, ~ expanded, or a name looked for in ~/.config/solium/qml and then the shipped QML. SOLIUM_QML_CURSOR overrides it for one run.

sol.QmlOptions

How QML is rendered. Read once, before Qt starts.

  • renderer: "auto"|"gpu"|"software" (optional) — "auto" tries the GPU in a child process first.
  • probe_timeout: integer (optional) — Milliseconds the GPU trial may take.

sol.SessionOptions

Telling systemd and D-Bus that Solium is the session. A key left out, or one of the wrong kind, keeps the default.

  • systemd: boolean (optional) — Export the environment to systemd and D-Bus activation and start solium-session.target; undone on exit. true by default.
  • autostart: boolean (optional) — Start solium-autostart.target, XDG autostart, beside it. true by default.
  • stop_timeout: integer (optional) — Milliseconds SIGTERM, SIGINT or SIGHUP waits for a clean stop before Solium ends at once. 5000 by default.

sol.DecorationEntry

One entry of sol.decorations().

  • name: string — What sol.pane takes.
  • kind: "bundle"|"file" — A folder under qml/panes, or a single QML file under qml/decorations.

sol.LayoutOptions

What the layout calls take: the work area to arrange in, and how.

Has every field of sol.Rect, and:

  • gap: number (optional) — Space between windows and around the edge. 12 by default.
  • ratio: number (optional) — The share of the width the main window takes in master_stack. 0.6 by default.
  • column: number (optional) — The share of the width a column takes in scrolling. 0.5 by default.
  • padding: number (optional) — Space around each thumbnail in grid. 24 by default.
  • split: number (optional) — Where a dwindle split falls, as a share of the tile divided. 0.5 by default.
  • minimum: sol.Size (optional) — The smallest a dwindle tile may be. None by default.
  • floors: table<integer, sol.Size> (optional) — Each window’s own floor, by id, frame included.
  • offset: number (optional) — How far the view has scrolled, for strip, strip_scroll_to, scrolling and scroll_to.

sol.Slot

A rect a tree or a strip hands back, tagged with its window.

Has every field of sol.Rect, and:

  • id: integer
  • cramped: boolean (optional) — true on a tile smaller than its window’s own floor; trees only.

sol.Column

One column of a strip, for sol.layout.strip.

  • width: number (optional) — The column’s width as a share of the view. 0.5 by default.
  • windows: integer (optional) — How many windows share the column. 1 by default.

sol.DeclaredWorkspace

What one workspace is, in a sol.workspaces declaration.

  • id: string — Unique within its group.
  • name: string (optional) — What a shell shows; the id when left out.
  • col: integer (optional) — Its column in the arrangement, from 1.
  • row: integer (optional) — Its row in the arrangement, from 1.
  • hidden: boolean (optional) — A workspace a shell should not list, such as a scratchpad.

sol.WorkspaceGroup

A group of workspaces that switch together: one per monitor, or one for every monitor.

  • id: string
  • monitors: string[] — The monitors it is on, by connector name.
  • showing: string[] — The ids it shows now.
  • workspaces: sol.DeclaredWorkspace[]

sol.WorkspaceDeclaration

  • arrangement: { kind?: string, columns?: integer, rows?: integer } (optional) — The shape the workspaces make, for a shell to draw.
  • groups: sol.WorkspaceGroup[]
  • windows: table<integer, string[]> (optional) — Which workspaces each window is on, by window id.

Internal

Tables the compositor keeps in sol for its own use. They are listed so the list is complete; a script should use the functions named.

  • sol._bindings — Internal: the bindings, by normalised combination. Use sol.bind, sol.bound and sol.unbind.
  • sol._handlers — Internal: the listeners, by event. Use sol.on.
  • sol._attempts — Internal: each attempt’s done, by attempt id. Use sol.act.
  • sol._keeps — Internal: what sol.keep holds, by name.
  • sol._strikes — Internal: how many times each listener or done was stopped, by function.
  • sol._binding_sources — Internal: the notes sol.bind and sol.unbind were given, by combination.
  • sol._unknown_settings — Internal: what sol.unknown reported.