sway

1. Prerequisites

This configuration assumes that the following packages are installed:

  • Essentials:
    • sway, obviously.
    • swayidle, provides power management.
    • swaylock, provides screen locking.
    • foot, my terminal emulator of choice.
    • systemd, for lower-level functionalities, though not a hard requirement.
  • Utilities:
    • wlsunset, wonderful day/night gamma adjustment tool.
    • light, to control backlight.
    • pamixer, to control volume.
    • playerctl, to control media players.
    • mako, notification daemon.
    • fuzzel, scriptable application launcher.
    • i3blocks, block definition for sway-bar.
  • Typeface:
    • ttf-inconsolata

2. Related configurations

3. File structure

This configuration is currently laid out as follows:

~/.config/sway/
├── config
├── rules
└── colorschemes/
    ├── nord
    ├── solarized
    └── zenburn

4. Variable definitions

Variables will make your life easier and you can reference them across different files, too. To create your own variables, precede them with $.

The following variable definitions are used all throughout the configuration, so keep your eyes peeled.

4.1. Keys

Let's define the modifiers and directional keys:

set {
    $super  Mod4
    $alt    Mod1
    $left   h
    $down   j
    $up     k
    $right  l
}

4.2. Workspaces

Switching between workspaces is the most basic operation you will find yourself doing in a window manager, so why not make it as seamless as can be. Qtile by default uses "qsdfuiop" as the default workspace names, where each character in the aforementioned string represents the name of an individual workspace and the key to reach it.

I have borrowed this brilliant and intuitive pattern and have been using it ever since, no matter which window manager I find myself using.

set {
    $ws1  1:q
    $ws2  2:s
    $ws3  3:d
    $ws4  4:f
    $ws5  5:u
    $ws6  6:i
    $ws7  7:o
    $ws8  8:p
}

4.3. Modes

set {
    $session_mode  "(L)ock ⋅ (S)leep ⋅ (R)eload ⋅ (Q)uit"
    $screenshot_mode  "(A)rea ⋅ (O)utput ⋅ (W)indow"
}
  • session_mode: Represents the mode used for managing the desktop session.
  • screenshot_mode: Represents the mode used for capturing screenshots.

4.4. Miscellaneous

resize_factor represents by how many pixels a particular window should get resized.

set $resize_factor 30px

5. Inputs

For more information on this topic, see sway-input(5).

5.1. Keyboard

You can remap many keys with the use of xkb_options. For more information, see xkeyboard-config(1).

input "type:keyboard" {
    xkb_layout    fr
    xkb_options   compose:prsc
    repeat_rate   50
    repeat_delay  300
}

5.2. Touchpad

input "type:touchpad" {
    tap             enabled
    natural_scroll  enabled
    accel_profile   "adaptive"
    pointer_accel   0.4
}

5.3. Mouse

Move and resize windows with the mouse by holding the $super key and the left and right mouse buttons respectively.

floating_modifier $super normal

6. Outputs

I switch between a single and dual screen setup constantly, however my output configuration remains pretty simple.

output * bg #1E5071 solid_color

7. Keybindings

While this section uses bindsym to bind keys to commands, it does also use bindgesture to bind actions to touchpad gestures.

7.1. Highlighting windows

bindsym {
  $super+$left   focus left
  $super+$down   focus down
  $super+$up     focus up
  $super+$right  focus right
}

7.2. Tiling windows

bindsym {
  $super+Shift+$left   move left
  $super+Shift+$down   move down
  $super+Shift+$up     move up
  $super+Shift+$right  move right
}

bindgesture {
  swipe:3:up           move up
  swipe:3:down         move down
  swipe:3:left         move left
  swipe:3:right        move right
}

7.3. Resizing windows

bindsym {
  $super+Control+$left   resize shrink width $resize_factor
  $super+Control+$down   resize shrink height $resize_factor
  $super+Control+$up     resize grow height $resize_factor
  $super+Control+$right  resize grow width $resize_factor
}

7.4. Moving between workspaces

bindsym {
  $super+q      workspace $ws1
  $super+s      workspace $ws2
  $super+d      workspace $ws3
  $super+f      workspace $ws4
  $super+u      workspace $ws5
  $super+i      workspace $ws6
  $super+o      workspace $ws7
  $super+p      workspace $ws8
  $super+tab    workspace back_and_forth
}

bindgesture {
  swipe:4:right workspace prev
  swipe:4:left  workspace next
}

7.5. Moving windows between workspaces

bindsym {
  $super+shift+q  move container to workspace $ws1; workspace $ws1
  $super+shift+s  move container to workspace $ws2; workspace $ws2
  $super+shift+d  move container to workspace $ws3; workspace $ws3
  $super+shift+f  move container to workspace $ws4; workspace $ws4
  $super+shift+u  move container to workspace $ws5; workspace $ws5
  $super+shift+i  move container to workspace $ws6; workspace $ws6
  $super+shift+o  move container to workspace $ws7; workspace $ws7
  $super+shift+p  move container to workspace $ws8; workspace $ws8
}

7.6. Splitting windows

bindsym {
  $super+greater  splith
  $super+less     splitv
  $super+m        layout toggle all
}

7.7. Window actions

bindsym {
  $super+w          kill
  $super+n          fullscreen
  $super+b          floating toggle
  $super+z          scratchpad show
  $super+space      focus mode_toggle
  $super+comma      sticky toggle 
  $super+backspace  move scratchpad
  $super+up         opacity plus 0.1
  $super+down       opacity minus 0.1
}

7.8. Playback control

bindsym {
  XF86AudioPlay  exec playerctl play-pause
  XF86AudioNext  exec playerctl next
  XF86AudioPrev  exec playerctl previous
}

7.9. Volume control

bindsym {
  XF86AudioRaiseVolume  exec pamixer -i 5
  XF86AudioLowerVolume  exec pamixer -d 5
  XF86AudioMute         exec pamixer -t
}

7.10. Brightness control

bindsym {
  XF86MonBrightnessUp    exec light -A 5
  XF86MonBrightnessDown  exec light -U 5
}

7.11. Modes

Modes allow us to define keychords, which combine different actions into the same context and are much more ergonomic. The keybindings in this section are merely activators for the listed modes.

bindsym $super+exclam  mode $session_mode
bindsym $super+asterisk  mode $screenshot_mode

7.12. Miscellaneous

bindsym {
  $super+Return        exec footclient
  $super+Shift+Return  exec footclient --app-id=foot-dropdown
  $super+e             exec emacsclient -c
  $super+0             exec passmenu
  $super+r             exec fuzzel --log-no-syslog
}

8. Modes

8.1. Session

Upon entering this mode, I can choose to execute one of many session-related actions as listed below. I can also cancel at any time by hitting ESC.

mode --pango_markup $session_mode bindsym {
  l        exec swaylock, mode "default"
  s        exec systemctl suspend, mode "default"
  r        reload, mode "default"
  q        exit, mode "default"
  escape   mode "default"
}

8.2. Screenshot

Upon entering this mode, I have the choice of selecting the kind of screenshot I would like to take, which will then be placed in a standard directory for me to grab.

mode --pango_markup $screenshot_mode bindsym {
  a        exec grimshot save area, mode "default"
  o        exec grimshot save area, mode "default"
  w        exec grimshot save window, mode "default"
  escape   mode "default"
}

9. Options

Configure the status bar:

bar {
    position top
    # mode hide
    # modifier $super+shift
    strip_workspace_numbers yes
    status_command i3blocks
    font Inconsolata 12

    # colors {
    #    statusline         $base00
    #    separator          $base03
    #    background         $base06
    #    focused_workspace  $blue $blue $base06
    #    inactive_workspace $base06 $base06 $base00 
    # }
}

Configure the default typeface:

font Inconsolata 10

Don't show borders unless there's more than one visible window:

smart_borders on

Declutter the desktop by hiding the cursor after a set period of inactivity:

seat * hide_cursor 10000

10. Colorschemes

This section defines a set of colorschemes which modify the many client properties exposed by sway.

Colorschemes are contained in separate files. Only one may be used at a time, as they conflict with each other. To start using one, e.g. solarized, include the colorschemes/solarized file.

10.1. Default

This snippet will configure the properties of the status bar; it should be placed inside the bar configuration.

statusline #ffffff
background #323232
inactive_workspace #323232 #323232 #5c5c5c

10.2. Solarized

Define the palette:

set {
    $base03   #002B36
    $base02   #073642
    $base01   #586E75
    $base00   #657B83
    $base0    #839496
    $base1    #93A1A1
    $base2    #EEE8D5
    $base3    #FDF6E3
    $yellow   #B58900
    $orange   #CB4B16
    $red      #DC322F
    $magenta  #D33682
    $violet   #6C71C4
    $blue     #268BD2
    $cyan     #2AA198
    $green    #859900
}

Set the different client properties:

client.focused            $base02  $base00  $base02  $green
client.focused_inactive   $base02  $base03  $base0
client.unfocused          $base02  $base03  $base0
client.urgent             $yellow  $yellow  $base03

10.3. Nord

Define the palette:

set {
    $base06   #2E3440
    $base05   #3B4252
    $base04   #434C5E
    $base03   #4C566A
    $base02   #D8DEE9
    $base01   #E5E9F0
    $base00   #ECEFF4
    $blue     #5E81AC
    $yellow   #EBCB8B
    $orange   #D08770
    $red      #BF616A
    $magenta  #B48EAD
    $green    #A3BE8C
}

Set the different client properties:

client.focused            $base03  $base03  $base00  $orange
client.focused_inactive   $base04  $base04  $base00
client.unfocused          $base06  $base06  $base00
client.urgent             $red     $red     $red

This snippet defines the properties of the status bar; it should only be placed inside the bar.colors directive.

statusline         $base00
separator          $base03
background         $base06
focused_workspace  $blue $blue $base06
inactive_workspace $base06 $base06 $base00 

10.4. Zenburn

Define the palette:

set {
    $base00   #292929
    $base01   #DCDCCC
    $base02   #3F3F3F
    $base03   #DCDCCC
    $base04   #AB6C71
    $base05   #709080
}

Set the different client properties:

client.focused            $base01  $base01  $base02  $base02
client.focused_inactive   $base02  $base02  $base03
client.unfocused          $base02  $base02  $base03
client.urgent             $base04  $base04  $base01

11. Imports

Import configurations1 bundled by my distribution:

include /etc/sway/config.d/*

Import the rules file which defines all the window rules:

include rules

12. Startup

Computers are not very useful without daemons; let's start a few.

Launch wlsunset, a wonderful day/night gamma adjustments utility:

exec wlsunset -l 36.8 -L 10.1 -t 3800 -T 6400

foot supports a server/client architecture, launch the server but don't save any logs in the system journal.

exec foot --server --log-no-syslog

Keeping a device on for extended periods of time can be a security nightmare and a total battery-drainer. swayidle allows us to tell it what to do, and at which stages.

I've set it up to behave the following way:

  • Lock the screen after 5 minutes of inactivity.
  • Turn off the screen after another 3 minutes.
  • Suspend the system after another 12 minutes.

The screen will also lock itself upon suspension, e.g. when closing the laptop's lid.

Timers are started simultaneously, which is why the timeout values are the way they are.

exec swayidle -w \
      timeout 300 'swaylock' \
      timeout 480 'swaymsg "output * dpms off"' \
             resume 'swaymsg "output * dpms on"' \
     timeout 1020 'systemctl suspend' \
     before-sleep 'swaylock'

Launch the authentication agent which allows applications to escalate their privileges in a secure manner when required:

exec --no-startup-id /usr/bin/lxqt-policykit-agent

Every other daemon is started as a user service with systemctl(1).

13. Window rules

Window rules allow me to customize the properties of windows programmatically, such properties include:

  • The location of said windows:
    • XY coordinates and/or which workspace they belongs to
  • Their geometry and decorations
  • Their effect on the window manager:
    • Inhibiting sleep
  • And so much more

Define what workspaces certain applications should appear in:

for_window [app_id="emacs"]            move window to workspace $ws3; focus
for_window [app_id="org.pwmt.zathura"] move window to workspace $ws4; focus
for_window [app_id="mpv"]              move window to workspace $ws5; focus
for_window [app_id="virt-manager"]     move window to workspace $ws7; focus
for_window [app_id="signal"]           move window to workspace $ws8

Define which applications should float:

for_window [app_id="pinentry-qt"] floating enable
for_window [app_id="lxqt-policykit-agent"] floating enable
for_window [app_id="pavucontrol"] floating enable

Define some window rules for Firefox such that it appears in the same workspace every time as well as inhibit sleep when the window is in fullscreen mode.

for_window [app_id="firefox"] {
   move window to workspace $ws1
   inhibit_idle fullscreen
   focus
}

Define the appearance and geometry of Picture-in-Picture windows. This article explains the rationale behind the settings of this window rule.

for_window [title="^Picture-in-Picture$"] {
   floating enable
   sticky enable
   border none
   move position 1420 800
   resize set height 280px
   resize set width 500px
   opacity 0.7
}

Terminals should default to tabbed mode by default, this eases navigating between them and ensures that text doesn't get wrapped.

for_window [app_id="^foot$"] {
    move window to workspace $ws2
    focus
}

It's nice to be able to pop open a terminal right where you are, kind of a like those dropdown terminals.

for_window [app_id="^foot-dropdown$"] {
   move scratchpad
   scratchpad show
   floating enable
   sticky enable
   border none
   resize set height 500px
   resize set width 1920px
   move position 0 0
   opacity 0.9
}

There comes a time when a GUI file manager is really useful.

for_window [app_id="pcmanfm-qt"] {
   floating enable
   sticky enable
}
for_window [app_id="(org.twosheds.iwgtk|iwgtk)"] floating enable

Footnotes

1

Different distributions package their software differently, verify that the directory exists and is populated.