Installing and configuring Hyprland on a Surface Pro 7 (1866)

Preface

This guide explains how I install and customize Hyprland on a Surface Pro 7 (1866). The steps themselves are not specific to Surface devices.
The title matches my Arch on Surface write up, and the system used here happens to be a Surface device.
For that reason, this guide assumes you are using Arch Linux.

All commands in this post target Arch Linux, for example pacman and yay.
Your distribution may already include some packages by default, such as PipeWire.

If you are using another distribution, you will need to adapt the commands or packages accordingly.

Info
Customizing Hyprland is often called “ricing”.

1. Install base components

Ly is a lightweight TUI display manager that can start your Wayland session without logging in on the console first.
brightnessctl is used to control screen brightness on laptops and notebooks.

sudo pacman -S ly hyprland brightnessctl
sudo systemctl enable ly

Hyprland also needs a few companion packages:

  • Fonts for proper text rendering.
  • PipeWire, pipewire-pulse, Pavucontrol, and WirePlumber for audio.
  • dunst for notifications.
  • xdg-desktop-portal-hyprland for system dialogs under Wayland.
  • Qt Wayland backends for running Qt applications under Wayland.
  • hyprpolkitagent for GUI privilege prompts.
  • uwsm (User Wayland Session Manager) for proper session startup and shutdown.
  • kitty (terminal), Firefox (browser), rofi (app launcher), and swww (wallpapers).
  • rofi-bluetooth-git for a graphical Bluetooth interface.
sudo pacman -S dunst pipewire pipewire-pulse pavucontrol wireplumber \
xdg-desktop-portal-hyprland hyprpolkitagent qt5-wayland qt6-wayland \
noto-fonts noto-fonts-cjk noto-fonts-emoji ttf-jetbrains-mono-nerd \
uwsm kitty firefox rofi swww
Info
If a package asks if you want to use jack2 or pipewire-jack, choose the latter.

Reboot the system:

sudo reboot now

At the Ly prompt, switch from “login” to “wayland”, then use the arrow keys to select “Hyprland (uwsm-managed)”.

Info
“Hyprland (uwsm-managed)” launches via uwsm, which sets environment variables, starts portals and D-Bus, and cleans up processes.

2. Edit the autogenerated config

On first start you will see a warning about the autogenerated configuration. Fix this before you do anything else.

Open a terminal with “SUPER+Q” (kitty).

Info
“SUPER” means the Windows key in Hyprland terminology.
Warning
The default keyboard layout is us!

Edit the config file:

nano /home/yourusername/.config/hypr/hyprland.conf

Delete everything up to this line:

# You can split this configuration into multiple files

Search for input and set your keyboard layout:

input {
  kb_layout = de   # or your layout
}

Save the file so you can use your keyboard layout. Hyprland applies configuration changes automatically.

Note
Launch Firefox from your terminal by typing firefox & disown to easily copy and paste commands from this guide.
You can continue with the guide afterwards.

Open hyprland.conf again and set rofi as the app launcher:

$menu = pkill rofi || ~/.config/rofi/launchers/type-1/launcher.sh
Info
While you are here, this is a good moment to choose a file manager. I’d recommend YAZI.
No pressure to set it up right now, though, I’ve linked my my blog post further down so you can handle the installation later.

2.1 Display scaling

For the Surface display I use a scaling factor of 1.5 for readability, or 1.26667 if you want more screen space.

# was: monitor=,preferred,auto,auto
monitor=,preferred,auto,1.5

Keep the file open, you still need it for keybindings.

2.2 Keybinds

A minimal set of keybindings:

  • SUPER+Q: close focused window
  • SUPER+T: terminal
  • SUPER+B: browser
  • SUPER+E: file manager
  • SUPER+SPACE: app launcher
  • SUPER+V: toggle floating
  • SUPER+J: toggles the tiling split mode

Search for “KEYBINDINGS” (CTRL+F) and edit:

bind = $mainMod, Q, killactive
bind = $mainMod, T, exec, $terminal
bind = $mainMod, B, exec, firefox
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating
bind = $mainMod, SPACE, exec, $menu
bind = $mainMod, J, togglesplit

SUPER+J toggles the tiling split mode. Open two terminals and press SUPER+J to observe the layout change.


3. Get some wallpapers!

Download wallpapers from a site like Wallhaven.

Store them in:

~/Pictures/wallpapers/

You can use a different folder, but adjust the paths in later steps accordingly. You do not need wallpapers immediately, but having them prepared is convenient.


4. Waybar

Install Waybar:

sudo pacman -S waybar

In ~/.config/hypr/hyprland.conf, under AUTOSTART, enable Waybar and swww:

# exec-once = waybar & hyprpaper & firefox
exec-once = waybar
exec-once = swww-daemon

Start Waybar in the current session:

waybar & disown

4.1 Waybar config (minimal)

Create a minimal configuration:

mkdir -p ~/.config/waybar
nano ~/.config/waybar/config.jsonc

Paste:

{
  "layer": "top",
  "modules-left": ["clock", "hyprland/window"],
  "modules-right": ["network", "bluetooth", "pulseaudio", "battery"],
  "modules-center": ["hyprland/workspaces"],

  "battery": {
    "format": "{capacity}% {icon}",
    "format-icons": ["","","","",""]
  },
  "clock": {
    "format-alt": "{:%a, %d. %b  %H:%M}"
  }
}

4.2 Reload helper

Create a small helper script to restart Waybar:

mkdir -p ~/.config/waybar/scripts
nano ~/.config/waybar/scripts/launch.sh

Paste:

#!/bin/bash
killall -9 waybar 2>/dev/null
waybar &

Make it executable:

chmod +x ~/.config/waybar/scripts/launch.sh

Bind it in Hyprland:

bind = $mainMod, R, exec, ~/.config/waybar/scripts/launch.sh

Reload Waybar with SUPER+R.

4.3 Minimal styling

Warning
This will not work until you have completed all steps up to Step 8!
nano ~/.config/waybar/style.css

Paste:

@import "colors.css";

* {
    border: none;
    border-radius: 0;
    font-family: Roboto, "JetBrainsMono Nerd Font", Helvetica, Arial, sans-serif;
    font-size: 1rem;
    min-height: 1rem;
}

#waybar>box {
    margin: 10px 10px 0 10px;
}

#window {
    margin: 0px 10px;
}

window#waybar {
    background: transparent;
    color: @on_surface;
}

tooltip {
    background: @background;
    border: 1px solid rgba(100, 114, 125, 0.5);
}

tooltip label {
    color: @on_surface;
}

#workspaces button {
    padding: 0 5px;
    background: transparent;
    color: white;
    border-bottom: 3px solid transparent;
}

#workspaces button.focused {
    background: #64727D;
    border-bottom: 3px solid white;
}

#clock,
#battery,
#bluetooth,
#pulseaudio,
#network {
    border-radius: 100px;
    background-color: @primary;
    color: #121212;
    padding: 0px 20px;
    margin: 0 10px;
}

#workspaces {
    margin-top: 10px;
}

#clock {
    padding: 0 7px;
    font-weight: 500;
}

#pulseaudio {
    padding: 0 15px;
}

#battery {
    padding: 0 15px;
}

4.4 Workspaces, window titles, volume, bluetooth, wifi

Editing JSONC files is easier in VSCodium. VSCodium is not available in the official Arch repositories, so you will need an AUR helper.

Install yay:

sudo pacman -S --needed git base-devel
git clone https://aur.archlinux.org/yay.git && cd yay && makepkg -si
yay -S vscodium-bin
Info
If it asks “Packages to cleanBuild?” choose “A”.

Open “VSCodium - Wayland” by typing vscodium --ozone-platform-hint=wayland, and open:

~/.config/waybar/config.jsonc
Info
To show hidden files, right click an empty area and enable “Show hidden files”.

In config.jsonc, make sure the clock block ends with a comma:

clock {
...
},
Note
Make sure there is a comma after the closing brace of the clock block.

Add the workspaces configuration:

"hyprland/workspaces": {
  "format": "{name}",
  "persistent-workspaces": {
    "*": 5,
    "HDMI-A-1": 3
  }
},

Add the focused window module:

"hyprland/window": {
  "format": "{}",
  "max-length": 20,
  "separate-outputs": true
},

This displays the focused window title next to the workspace list.

Add a PulseAudio widget:

"pulseaudio": {
  "format": "{volume}% {icon}",
  "format-bluetooth": "{volume}% {icon}",
  "format-muted": "x",
  "format-icons": {
    "headphone": "",
    "default": ["", ""]
  },
  "scroll-step": 1,
  "on-click": "pavucontrol",
  "ignored-sinks": ["Easy Effects Sink"]
},

VSCodium may not render the icons correctly by default.
Go to Settings, search for “Font Family”, and replace "Droid Sans Mono" with "JetBrainsMono Nerd Font".

Add a Bluetooth widget:

  "bluetooth": {
    "on-click": "rofi-bluetooth",
    "format-on": "󰂯",
    "format-off": "󰂲",
    "format-disabled": "", // an empty format will hide the module
    "format-connected": "󰂱 {num_connections}",
    "tooltip-format-connected": "{device_enumerate}",
    "tooltip-format-enumerate-connected": "{device_alias}\t{device_address}"
  },

Add a WiFi widget:

"network": {
    "interface": "wlp2s0",
    "format": "{ifname}",
    "format-wifi": "{essid} ",
    "format-ethernet": "{ipaddr}/{cidr} 󰊗",
    "format-disconnected": "",
    "tooltip-format": "{ifname} via {gwaddr} 󰊗",
    "tooltip-format-wifi": "{essid} ({signalStrength}%) ",
    "tooltip-format-ethernet": "{ifname} ",
    "tooltip-format-disconnected": "Disconnected",
    "max-length": 50
}
Info
Change "interface": "wlp2s0" to the name of your WiFi interface, for example wlan0.

Format the file (Ctrl+Shift+I), save and close, then press SUPER+R to reload Waybar.


5. Material colors from wallpapers (matugen)

matugen generates Material-style color palettes and CSS from wallpapers. It is available in the AUR:

yay -S matugen-bin
cd ~/.config && mkdir -p matugen && cd matugen && mkdir -p templates && nano config.toml
Info
You can build matugen-bin manually, but installing it through yay simplifies maintenance.

Paste into config.toml:


[config.wallpaper]
set = true
command = "swww"
arguments = ["img", "--transition-type", "center", "--transition-step", "255"]

[templates.hyprland]
input_path = '~/.config/matugen/templates/hyprland-colors.conf'
output_path = '~/.config/hypr/colors.conf'
post_hook = 'hyprctl reload'

[templates.kitty]
input_path = '~/.config/matugen/templates/kitty-colors.conf'
output_path = '~/.config/kitty/colors.conf'
post_hook = 'kill -SIGUSR1 $(pgrep kitty)'

[templates.rofi]
input_path = '~/.config/matugen/templates/rofi-colors.rasi'
output_path = '~/.config/rofi/colors/colors.rasi'

[templates.waybar]
input_path = '~/.config/matugen/templates/colors.css'
output_path = '~/.config/waybar/colors.css'
post_hook = 'pkill waybar; waybar & disown'

Now add hyprland-colors.conf to ~/.config/matugen/templates:

nano ~/.config/matugen/templates/hyprland-colors.conf

Paste:


<* for name, value in colors *>
$image = {{image}}
${{name}} = rgba({{value.default.hex_stripped}}ff)
<* endfor *>

Add kitty-colors.conf in the same directory:

nano ~/.config/matugen/templates/kitty-colors.conf

Paste:


cursor {{colors.on_surface.default.hex}}
cursor_text_color {{colors.on_surface_variant.default.hex}}

foreground            {{colors.on_surface.default.hex}}
background            {{colors.surface.default.hex}}
selection_foreground  {{colors.on_secondary.default.hex}}
selection_background  {{colors.secondary_fixed_dim.default.hex}}
url_color             {{colors.primary.default.hex}}

# black
color8   #262626
color0   #4c4c4c

# red
color1   #ac8a8c
color9   #c49ea0

# green
color2   #8aac8b
color10  #9ec49f

# yellow
color3   #aca98a
color11  #c4c19e

# blue
/* color4  #8f8aac */
color4  {{colors.primary.default.hex}}
color12 #a39ec4

# magenta
color5   #ac8aac
color13  #c49ec4

# cyan
color6   #8aacab
color14  #9ec3c4

# white
color15   #e7e7e7
color7  #f0f0f0

Add a file called rofi-colors.rasi in the same directory:

nano ~/.config/matugen/templates/rofi-colors.rasi

Paste:


* {
    background: {{colors.surface.default.hex}};
    background-alt: {{colors.surface_dim.default.hex}};
    foreground: {{colors.on_surface.default.hex}};
    selected: {{colors.primary.default.hex}};
    active: {{colors.secondary.default.hex}};
    urgent: {{colors.error.default.hex}};
}

Add a file called colors.css in the same directory:

nano ~/.config/matugen/templates/colors.css

Paste:


/*
* Css Colors
* Generated with Matugen
*/
<* for name, value in colors *>
    @define-color {{name}} {{value.default.hex}};
<* endfor *>

6. Set your wallpaper

Open a new terminal and run:

swww-daemon & disown
matugen image Pictures/wallpapers/yourwallpaper.png
Info
Replace yourwallpaper.png with a file from your wallpapers directory.

Whatever wallpaper you choose, Waybar will update its colors accordingly. At this point the dynamic color system becomes useful.

A few pieces are still missing. You will add them next.


7. Hyprland colors

Open ~/.config/hypr/hyprland.conf:

nano ~/.config/hypr/hyprland.conf

At the top of the file, add:

source = ~/.config/hypr/colors.conf

Search for col.active_border, remove everything after = for both col.active_border and col.inactive_border and replace with:


# was col.active_border = rgba() rgba() 45deg
# was col.inactive_border = rgba()
col.active_border = $primary
col.inactive_border = $outline_variant

This makes Hyprland use the colors generated by matugen.


8. Kitty colors

Set nano as your default editor in this shell:

export EDITOR="/usr/bin/nano"

Close the terminal and open a new one so $EDITOR takes effect.

In kitty, press Ctrl+Shift+F2 to open the configuration file.

At the top of the file, add:

include colors.conf

Next:

  • Search for window_padding, uncomment it, and set it to 10.
  • Search for cursor_shape, uncomment it, and add this on a new line:
shell_integration no-cursor
  • Search for background_opacity, uncomment it, and set it to 0.8.

Save and close the kitty config file, then close the terminal.


9. Configure rofi

Open a terminal and run:

git clone --depth=1 https://github.com/adi1090x/rofi.git
cd rofi/files/launchers/type-1/
mkdir -p ~/.config/rofi
cp -r launcher.sh shared style-9.rasi ~/.config/rofi
cd ~/.config/rofi
chmod +x launcher.sh
mkdir -p launchers/type-1
mv launcher.sh shared/ style-9.rasi launchers/type-1/
cd launchers/type-1/
nano launcher.sh

In launcher.sh, change the theme variable to:

theme="style-9"

Save and exit.

Then:

nano shared/colors.rasi

Change the @import line to:

@import "~/.config/rofi/colors/colors.rasi"

Save and exit.

The only remaining adjustment is spacing between icons and text in rofi. Run:

nano ~/.config/rofi/launchers/type-1/style-9.rasi

Add a single space after the icon for “Files”, “SSH”, “Apps”, “Run”, and “Windows”. Edit further so that all text lines are neatly aligned after each icon.

Info
You can now open rofi with SUPER+SPACE.

10. Automating wallpaper changes

Create a helper script to set a random wallpaper from your directory.

Run:

mkdir -p ~/.local/bin/
cd ~/.local/bin/
nano wallset

Paste:


#!/bin/bash
wallpapers_dir=~/Pictures/wallpapers
cd "$wallpapers_dir" || exit 1

img=$(find . -type f  \( -iname "*.jpg" -o -iname "*.png" -o -iname "*.jpeg" \) | shuf -n 1)

matugen image "$img" &> /dev/null

Save and exit, then:

chmod +x wallset
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc
source ~/.bashrc

You can now call:

wallset

from anywhere to set a random wallpaper and apply matching colors.


11. Get bluetooth working

Install rofi-bluetooth-git using yay:

yay -S rofi-bluetooth-git

Clicking the Bluetooth icon in Waybar should now open a small interface for selecting Bluetooth devices.


Postface

You have completed the setup! Yay! :D

I hope you found this guide useful. I will update the post as I make improvements.

Cheers.


This post is part of a series. Read the previous part: Installing Arch Linux with Secure Boot on a Surface Pro 7.

Other posts in this series: