shikane(5)

πŸ“¦
version 1.1.1 Β· 3 versions
, in arch rolling

πŸŽ€ NAME πŸŽ€

shikane β€” configuration file

🌸 DESCRIPTION 🌸

okay bestie, welcome to the shikane(5) page from the File Formats Manual β€” yes, it’s literally the config file page, and it’s about to make sense. πŸ’…βœ¨

shikane uses the TOML file format for its configuration file and contains an array of profiles. Each profile is a table containing an array of output tables. 🫢

Also, yes: the words β€œoutput”, β€œdisplay” and β€œmonitor” can be used interchangeably. In the text below, though, there’s a distinction between β€œdisplay” and β€œoutput”. A β€œdisplay” means a currently connected monitor, and an β€œoutput” means a table in the config file. Same goes for β€œmode” and β€œmode” respectively. (Please note the font weight.) πŸ‘‘

shikane selects possible profiles automatically at startup and when a change in the set of currently connected displays occurs. A profile is taken into consideration if every currently connected display can be matched to at least one output and no output is unmatched.

A display matches an output if:

  • the search parameter matches against the properties of the display (see also OUTPUT FIELDS below)
  • AND the display supports the mode that is specified in the output table.

After assembling a list of possible profiles, shikane generates all variants of every profile. Once all variants have been verified and sorted by exactness, shikane tries to apply them one after the other until one succeeds or there are no variants left to try. πŸ”₯

Variants are slightly different versions of the same profile. For example, a given display has a set of supported modes: 1920x1080@60Hz and 1920x1080@50Hz. If the mode in the config.toml is specified as β€œ1920x1080” both modes would fit the specification. Instead of choosing just one mode and using that, shikane takes both into account by generating two variants based on the same profile. One variant uses the 1920x1080@60Hz mode and the other variant uses the 1920x1080@50Hz mode. πŸ¦‹

The same goes for the search parameter. If multiple (display,output,mode)-combinations are possible, shikane generates variants with all of them.

You don’t need to write the configuration file by hand. You can use any tool to arrange the displays however you want and then use the export command of shikanectl(1). It will generate the config for you. πŸ’–

πŸ’« FORMAT πŸ’«

  • timeout = timeout β€” Optional. Whenever a change is detected, shikane waits the specified timeout, in milliseconds. Usually you should not set this as it slows down shikane. It is by default 0. ⏱️
  • [[profile]] β€” Optional. Starts a new profile table. A name must be specified. See PROFILE FIELDS for details.

🫢 PROFILE FIELDS 🫢

  • name = "name" β€” Mandatory. Specifies the name of the profile.
  • [[profile.output]] β€” Mandatory. Adds an output table to the profile. It contains parameters used to configure a display. See OUTPUT FIELDS for details.

On sway(1) for example, display names and descriptions can be obtained via swaymsg -t get_outputs.

  • exec = [ "command", ... ] β€” Optional. An exec array contains a set of commands that are executed when the profile was successfully applied. The order of execution is not guaranteed to be preserved. The name of the profile can be retrieved from the $SHIKANE_PROFILE_NAME environment variable.

πŸŽ€ OUTPUT FIELDS πŸŽ€

A display has, among others, the attributes name, vendor, model, serialnumber and description, and may look like this: β€œDP-1”, β€œCompany Foo”, β€œFooHD-24”, β€œ12345678”, β€œSomething Foo Something Bar”. 🌈

  • search = "pattern" β€” the basic pattern-only form.
  • search = "[kind]pattern" β€” pattern with a search kind.
  • search = "[[attrs]kind]pattern" β€” pattern with an attribute list and a search kind.
  • search = [ "[[attrs]kind]pattern", ... ] β€” the array form. This field is Mandatory. It consists of 3 parts: the attribute list attrs at the beginning, the search kind kind in the middle, and the pattern at the end.

The attribute list attrs defines which attributes will be compared with the pattern and how they are weighted. It is a sequence of letters from the set {dnmvs}. The letters correspond to the first letters of the above listed attributes. Each attribute should not be used more than once per search field. The first attribute has the highest/best weight, the last attribute has the lowest/worst weight. For a single search to be considered applicable, all attributes must match the pattern. πŸ’…

The search kind kind can be one of {=/%}. The 3 search kinds β€” regex(/), substring(%), full text(=) β€” define how the pattern is compared with each attribute in the attrs list. With full text comparison, the given attributes are compared with the pattern for equality. With substring comparison, the given attributes have to contain the pattern as a substring. The weight is calculated by dividing the lengths of the pattern and attribute strings. Equal lengths will rank the same as full text comparison. With regex comparison, the pattern is interpreted as a regular expression. regex comparison will always rank lower than the other two search kinds. 🧚

The attribute list and the search kind are optional. If unspecified, the search kind defaults to full text comparison and shikane tries to find at least one matching attribute.

Alternatively, several searches, up to a maximum of 5, may be specified in an array.

  • enable = true | false β€” Mandatory. Enables or disables the matched display.
  • exec = [ "command", ... ] β€” Optional. An exec array contains a set of commands that are executed when the profile was successfully applied. The order of execution is not guaranteed to be preserved. The name of the display can be retrieved from the $SHIKANE_OUTPUT_NAME environment variable.

The mode, position, scale, transform and adaptive_sync options will only change the respective properties of the display if they are specified (e.g. the scaling of a display will not be changed if the scale field is not present). πŸ’œ

  • mode = "best" | "preferred"
  • mode = "[!]widthxheight[@rate[Hz]]"
  • mode = { width = width, height = height, refresh = rate[, custom = true | false] }

Optional. Configures the matched display to use the matched mode. Modes are a combination of width and height (in pixels) and a refresh rate (in Hz) that your display can be configured to use. The refresh rate may also be a floating point number. A display will not be matched against an output if the display does not support the specified mode. πŸ–₯️

A parameterized mode can optionally be declared as custom by prefixing an exclamation mark (!). In this case, shikane will not try to find a mode with the same parameters and will just send the provided values to the compositor.

Setting mode to best or preferred instructs shikane to choose the mode itself. The best mode is determined by shikane as the mode with the highest pixel count, width, height and refresh rate. Most displays announce a mode that they prefer. If mode is set to preferred, shikane will select the preferred mode if it exists. Otherwise, the best mode is chosen as a fallback. ⭐

  • position = "x,y" β€” Optional. Places the display at the specified position in the global coordinate space.
  • scale = factor β€” Optional. Scales the display by the specified floating point factor.
  • transform = "transform" β€” Optional. Sets the display transform. May be one of 90, 180, 270 for a rotation; or flipped, flipped-90, flipped-180, flipped-270 for a flip and a rotation; or normal for no transform.
  • adaptive_sync = true | false β€” Optional. Enables or disables adaptive synchronization for the display (also known as VRR, Variable Refresh Rate).

✨ EXAMPLES ✨

Okay bestie, real talk β€” the indentations you're about to see are not required at all. They're literally just there so your eyes can see the hierarchy, like little visual training wheels. The TOML parser does not care. 🫢

First up, a whole office situation: one vertical display and a bunch of HDMI screens, with the second output flipping between two mode styles (string mode vs. the fancy [profile.output.mode] table):

       [[profile]]
       name = "Company Foo with one vertical display"
           [[profile.output]]
           search = "v=Company Foo"
           enable = true
           mode = "1920x1080@50Hz"
           position = "0,0"
           scale = 1.3

           [[profile.output]]
           search = "n/HDMI-[ABC]-[1-9]"
           enable = true
           exec = [ "echo This is output $SHIKANE_OUTPUT_NAME" ]
           position = "1920,0"
           transform = "270"
               [profile.output.mode]
               width = 2560
               height = 1440
               refresh = 75

See how the second one gets position = "1920,0" and transform = "270"? And the exec array fires off an echo that prints $SHIKANE_OUTPUT_NAME β€” iconic. πŸ‘‘


Next vibe: a profile with a top-level exec, a search using the leading / for a regex, transform = "flipped" (yes, you can literally say flipped), and a mode prefixed with ! β€” "!2000x1500@55.194Hz":

       [[profile]]
       name = "custom DP-[1-9] flip"
       exec = [ "echo This is an unusual display" ]
           [[profile.output]]
           search = "/DP-[1-9]"
           enable = true
           transform = "flipped"
           position = "0,0"
           mode = "!2000x1500@55.194Hz"

Now, a laptop has a builtin display that is always connected, so here's how you deal with that. First, the "just use the builtin" profile:

       [[profile]]
       name = "laptop builtin"
           [[profile.output]]
           search = "eDP-1"
           enable = true

Then the "actually no builtin, give me the HDMI" profile β€” note the n= prefix meaning not, disabling eDP-1 and turning on HDMI-A-1 with mode = "best":

       [[profile]]
       name = "no builtin + HDMI"
           [[profile.output]]
           search = "n=eDP-1"
           enable = false

           [[profile.output]]
           search = "n=HDMI-A-1"
           mode = "best"
           enable = true

shikane lets you specify multiple searches, so your profiles can be as specific as humanly possible. 🌸

       [[profile]]
       name = "home setup"
           [[profile.output]]
           search = "n=eDP-1"
           enable = false

           [[profile.output]]
           search = [ "n=HDMI-A-1", "s=1234VBAM", "m=1QX04Z", "v=specific company" ]
           enable = true

           [[profile.output]]
           search = "smv=1234abcd"
           enable = true

Look at those β€” an array of searches (all of them must match), and a combined smv= prefix mashup. Chef's kiss. πŸ’…


On sway(1), for example, exec can be used to move workspaces to whatever display you want:

       [[profile]]
       name = "double monitor"
       exec = [
           "swaymsg workspace 1, move workspace to eDP-1",
           "swaymsg workspace 2, move workspace to DP-1" ]
       output = [
           {search = "eDP-1", enable = true},
           {search = "DP-1", enable = true} ]

(Yes, that's the inline-table form of output = [...] β€” no [[profile.output]] headings needed, and the indentation is still doing absolutely nothing. 😌)


shikane sets the $SHIKANE_PROFILE_NAME variable in the environment of the executed processes from the profile.exec array, and the $SHIKANE_OUTPUT_NAME variable in the environment of the output.exec processes. If you're on sway(1), that last one is especially useful when you pair it with swayws. πŸ¦‹

       [[profile]]
       name = "generic profile"
       exec = ["notify-send shikane \"Profile $SHIKANE_PROFILE_NAME has been applied\""]
           [[profile.output]]
           search = "/DP-[1-9]"
           enable = true
           exec = ["swayws range --numeric 1 5 $SHIKANE_OUTPUT_NAME"]

           [[profile.output]]
           search = "n%HDMI-"
           enable = true
           mode = "preferred"
           exec = ["swayws range --numeric 6 10 $SHIKANE_OUTPUT_NAME"]

So the first output grabs numeric workspaces 1 to 5 on your DP-[1-9] display, and the second grabs 6 to 10 on the HDMI- one (n% prefix, no cap). A whole desk split in three lines. Slay. πŸ”₯


πŸ‘‘ AUTHORS πŸ‘‘

Hendrik Wolff <hendrik.wolff@agdsn.me>


🌈 SEE ALSO 🌈

shikane(1), shikanectl(1), swayws, TOML


Okay that's the whole page, bestie β€” go configure some displays and make them behave. πŸ’–

<div align="center">That's all from shikane version 1.1.1, dated 2026-06-23 β€” byeee πŸŽ€βœ¨</div>

πŸ“¦ where this page comes from