sway

1. Prerequisites

This configuration assumes the following packages are installed:

  • Essentials:
    • sway is the compositor (user service).
    • swayidle provides power management (user service).
    • swaylock provides screen locking functionality (user service).
    • swaybar provides a status bar which only appears on demand (user service).
    • swaybg provides wallpaper functionality (user service).
    • foot is the terminal emulator (user service).
    • systemd glues everything together (oversees the user services).
  • Utilities:
    • wlsunset is a gamma adjustment tool (user service).
    • mako is the notification daemon (user service).
    • fuzzel, scriptable application launcher.
    • citron, presents system state via notifications.
    • qutebrowser, the cutest browser to ever exist.
    • brightnessctl controls screen backlight.
    • wireplumber manages multimedia devices (user service).
    • playerctl controls MPRIS-compliant media players.

2. Variable definitions

Variables make my life easier and they can be referenced across different files, too. The following variable definitions are used all throughout this configuration to preserve a level of consistency that could not be achieved otherwise.

2.1. Keys

Define the modifiers and directional keys:

set {
    $Super  Mod4
    $Alt    Mod1
    $Left   h
    $Down   j
    $Up     k
    $Right  l
}

2.2. Workspaces

Moving between workspaces is the most common operation one does in a window manager so their key placement should be very convenient. Qtile happens to utilize a layout that is particularly easy to remember, by default it uses "qsdfuiop" as the default workspace names, each character being the name of an individual workspace and the key to reach it. I have borrowed this intuitive pattern and have been using it ever since, no matter the window manager.

set {
    $ws1  1:q
    $ws2  2:s
    $ws3  3:d
    $ws4  4:f
}

2.3. Modes

set {
    $session_mode "(L)ock ⋅ (R)eload ⋅ (Q)uit ⋅ (I)nhibit Idle ⋅ (S)uspend ⋅ (H)ibernate ⋅ (P)ower-off"
    $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.
  • screenshot_mode: Represents the mode used for getting the system status via notifications.

2.4. Miscellaneous

resize_factor represents the amount of pixels a particular window should expand/shrink in size when resized.

set $resize_factor 40px

3. Inputs

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

3.1. Keyboard

It is possible to remap many keys and fool around with different keyboard layouts and formats using xkb_options, for more information, see xkeyboard-config(1).

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

It's very helpful, especially in text editors, to have a very short repeat_delay and a very high repeat_rate.

3.2. Touchpad

Nothing fancy is going on here, just natural scrolling as if one is paging through a book and adaptive acceleration because why would one have it any other way.

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

3.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

4. Outputs

output * resolution 1920x1080@60Hz

5. Keybindings

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

5.1. Highlighting windows

bindsym {
  $Super+$Left   focus Left
  $Super+$Down   focus down
  $Super+$Up     focus up
  $Super+$Right  focus right
}

5.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
}

5.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
}

5.4. Moving between workspaces

bindsym {
  $Super+q    workspace $ws1
  $Super+s    workspace $ws2
  $Super+d    workspace $ws3
  $Super+f    workspace $ws4
  $Super+tab  workspace back_and_forth
}

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

5.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
}

5.6. Window actions

bindsym {
  $Super+w        kill
  $Super+a        fullscreen
  $Super+o        fullscreen disable; floating toggle
  $Super+i        scratchpad show
  $Super+Shift+i  move scratchpad
  $Super+m        layout toggle split tabbed
  $Super+Space    focus mode_toggle
}

5.7. Playback control

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

5.8. Volume control

bindsym {
  XF86AudioRaiseVolume  exec wpctl set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 0.05+
  XF86AudioLowerVolume  exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 0.05-
  XF86AudioMute         exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
}

5.9. Brightness control

bindsym {
  XF86MonBrightnessUp    exec brightnessctl set +5%
  XF86MonBrightnessDown  exec brightnessctl set 5%-
}

5.10. 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
  $Super+asterisk  mode $screenshot_mode
}

5.11. Applications and menus

bindsym {
  # Terminal emulator
  $Super+Return  exec swaymsg '[app_id=foot]' focus || footclient
  $Super+Shift+Return  exec footclient
  # Application launcher
  $Super+r  exec fuzzel --log-level error --prompt "⌘ "
  # Graphical file manager
  $Super+n  exec swaymsg '[app_id=pcmanfm-qt]' focus || pcmanfm-qt
  # Text editor
  $Super+e  exec swaymsg '[app_id=emacs]' focus || emacsclient --create-frame
  $Super+Shift+e  exec emacsclient --create-frame
  # User script that captures a task
  $Super+t  exec capture-task
  # User script that opens today's journal entry
  $Super+g  exec giornata
  # User script that copies a password from the password store into the
  # clipboard via a menu
  $Super+p  exec password-menu
  # User script that presents the browser's saved sessions via a menu
  $Super+b  exec qutebrowser-sessions
}

6. Modes

6.1. Manipulating the graphical 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 $session_mode bindsym {
  r       reload, mode "default"
  i       exec swayidle-toggle, mode "default"
  l       exec loginctl lock-session, mode "default"
  s       exec systemctl suspend, mode "default"
  h       exec systemctl hibernate, mode "default"
  q       exec systemctl --user stop sway-session.target, mode "default"
  p       exec systemctl poweroff, mode "default"
  escape  mode "default"
}

6.2. Taking screenshots

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 predefined location.

mode $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"
}

7. Options

The status bar is configured to display only if the Super modifier is held, its primary role is to guide me as I navigate between workspaces which makes Super the most convenient and sensible modifier to use.

The philosophy here is that the status bar is less of an information center and more of a navigational guide.

bar {
    mode hide
    position bottom
    font Sans Serif 16
    strip_workspace_numbers yes
    swaybar_command true
    colors {
        statusline #FFFFFF
        background #32323200
        inactive_workspace #323232 #323232 #5C5C5C
        binding_mode #323232 #323232 #ffffff
    }
}

Configure the default workspace layout to be "tabbed" which works really well for my single-screen setup:

workspace_layout tabbed

Configure the default typeface:

font Sans Serif 13

Hide the cursor after a set period of inactivity to reduce distraction:

seat * hide_cursor 10000

Remove any thickness applied to the window borders adjacent to the title and remove the borders adjacent to the window buffer:

set $border_thickness 2
title_align center
titlebar_border_thickness 0
titlebar_padding 8 6
hide_edge_borders smart
default_border normal $border_thickness

8. Window rules

Window rules allow me to customize the properties of windows declaratively, such properties mainly consist in:

  • The location of said windows:
    • (X,Y) coordinates and/or the workspace to which they belong
  • Their geometry and decorations
  • Their effect on the compositor:
    • Inhibiting the idle manager
for_window {
   [app_id="pinentry-qt"] floating enable, border pixel $border_thickness
   [app_id="lxqt-policykit-agent"] floating enable, border pixel $border_thickness
   [app_id="pavucontrol"] floating enable
   [app_id="org.twosheds.iwgtk|iwgtk"] floating enable
   [app_id="pcmanfm-qt"] floating enable, sticky enable
}

qutebrowser should inhibit the idle manager from allowing the system to sleep when the window is full-screen.

for_window [app_id="qutebrowser|mpv"] {
   inhibit_idle fullscreen
   focus
}

Capturing a task should overlay the editor on the screen with a slight bit of opacity to allow me to see what's underneath.

for_window [app_id=emacs title="^capture-task$"] {
   floating enable
   sticky enable
   resize set width  900
   resize set height 700
   move absolute position center
   border pixel $border_thickness
   focus
}       

9. Integration

Given that the compositor is managed by systemd and that a number of other services (like wlsunset, swaybg and others) require certain environment variables (for example, WAYLAND_DISPLAY) to be set in order to function properly, the compositor must therefore expose these two variables (without hard-coding them) and notify the service manager when it's ready, the latter will respond to this by starting the other services all while respecting their sequencing (specified using the After or Before directives under the Unit section).

exec systemctl --user import-environment WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP XDG_SESSION_DESKTOP XDG_SESSION_TYPE
exec systemd-notify --ready

Force the compositor to ignore requests to load xwayland because it's not installed.

xwayland disable

GTK seems to hard-code the fixed width typeface and I like to keep fonts consistent between applications, one way to do that is to rely on the font families declared in fontconfig (as aliases), a program that handles all kinds of typography settings.

set  $schema org.gnome.desktop.interface
exec gsettings set $schema monospace-font-name 'Monospace 10'

Setting the cursor size through gsettings is the most effective technique.

exec gsettings set $schema cursor-size 24