Tips from a Mac user on customising Hyprland for dev, gaming, MacOS keyboard & Magic Trackpad

Last updated
~Erratically hitting keyboard shortcuts in Hyprland~

Inspired by r/unixporn, I tried out Hyprland on Arch, and have been mainlining it for several months. I still use my Macbook with MacOS and have Mac input peripherals so I’ve aimed to keep things similar enough where it feels mostly seamless switching between the two. I installed it on an Intel Nuc 11 Enthusiast with a mobile RTX 2060.

Contents

  1. 1. General recommendations, so far.
  2. 2. Apple Keyboard and familiar MacOS Shortcuts
  3. 3. Apple Magic Trackpad 2
  4. 4. Nvidia, Intel and Hyprland
  5. 5. Steam, Nvidia and Gamescope
  6. 6. Fixing Systemd Network Stalling
  7. 7. Things lacking

1. General recommendations, so far

  • Use the Arch installer wizard to fast-forward you into a minimum viable system.
  • Make things work first, good later, rice latest. Find out potential deal-breakers early. Be wary of customisation addiction / losing sleep making one more thing work.
  • When you’re trying to find out what you should do consult things in this order: Hyprland Docs -> Arch Wiki -> -> Man page -> LLM/Search engine.
  • Try the default hyprland ecosystem tools first e.g. hypridle - idle state management (sleep), hyprlock - lock screen
  • Don’t bother with a greeter just add [[ $(tty) == "/dev/tty1" ]] && Hyprland in your zshrc/bashrc to automatically start Hyprland. But maybe set up a nice welcome message.
  • If you get really stuck on a particular problem, you can always keep a minimal xfce4 (or whatever) on the same OS. Also, you can always bail out with ctrl+alt+f1, f2, f3 etc to switch TTYs
  • Use Rofi as an app launcher (default cmd is super+r)
  • Bind screen capture utils to shortcuts that make sense for you with ~/.config/hypr/hyprland.conf

2. Apple Keyboard and familiar MacOS Shortcuts

In my experience, Apple has better keyboard shortcuts. I don’t have to contort my hand as much in tab switching & native text editing, I can jump word or to line extents & there’s a left to right notion of heirarchy.

I’m using my Apple keyboard so here is what I’m aiming for:

[global]
cmd+c=copy
cmd+v=paste
cmd+left=beginning of line
cmd+right=beginning of line
option+left=previous word
option+right=next word
[hyprland]
Control=meta key
[terminal]
ctrl+c=cancel

We can’t go up and down various application stacks to get macos-like text shortcuts, but I’ve found 80% is good enough. The easiest way to get there is to simply swap ctrl+meta keys and then add some custom key-binds per application. You can do this with xremap or with hyrpland.conf.

hyprland.conf
input {
kb_model = apple
kb_options = apple:alupckeys,ctrl:swap_lwin_lctl
}

Or xremap:

Terminal window
curl -Lo https://github.com/xremap/xremap/releases/download/v0.10.2/xremap-linux-x86_64-hypr.zip
unzip xremap-linux-x86_64-hypr.zip
chmod +x xremap
cp xremap /usr/bin/
mkdir ~/.config/xremap
touch ~/.config/xremap/config.yml # and copy contents below
cp xremap.service /etc/systemd/system/xremap.service
sudo systemctl enable xremap
sudo systemctl start xremap

Make sure this is copied for xremap to work

~/.config/xremap/config.yml
modmap:
- name: Global
remap:
Super_L: Ctrl_L
Ctrl_L: Super_L
Super_R: Ctrl_L

For zed, I created a config that is 98% close to my day-to-day zed profile (I use vi-keys mostly but I like some standard non-modal key jumping too that’s default on MacOS). You can find it as a github gist. Copy and paste it in zed shift+cmd+p->open keymap.

For ghostty I simply used:

~/.config/ghostty/config
keybind = cmd+c=text:\x03
keybind = ctrl+c=copy_to_clipboard
keybind = ctrl+v=paste_from_clipboard

And finally, I want cmd+opt+left/right to jump back and forth between tabs respectively, so I’ve made a gist with 2 files you can copy https://gist.github.com/danielgormly/04f2c24917a2b1e21a2817202f3677e4.

3. Apple Magic Trackpad 2

I prefer a trackpad to a mouse and three-finger drag & text selection on Mac is the best (you have to enable it in accessibility settings). The Magic Trackpad 2 is by far the best trackpad I’ve ever used. It’s pretty good on Arch but not quite MacOS level - maybe you could get 98% with some extra time spent tuning - but here’s a quick pain-free path.

Terminal window
# You will need paru if you don't have it
sudo pacman -S --needed base-devel
git clone https://aur.archlinux.org/paru.git
cd paru
makepkg -si
# https://aur.archlinux.org/packages/libinput-three-finger-drag
# Installing AURS can feel sketchy, I recommend that you scan through the PKGBUILD
# This should *just work™*
sudo paru -S libinput-three-finger-drag
reboot

Back in ~/.config/hypr/hyprland.conf I added.

hyprland.conf
input {
...
touchpad {
natural_scroll = true
scroll_factor = 0.5 # default scroll was crazy fast
clickfinger_behavior = true # enables context click on two finger click (not just tap)
}
}

But Zed editor starts scrolling way too slow, so I had to double the scroll sensitivity here. In Zed, use cmd+p->zed: open settings & add "scroll_sensitivity": 2 to the top level config

Kitty scrolling is really slow too. We can fix that by adding touch_scroll_multiplier 10 >> ~/.config/kitty/kitty.conf, however Ghostty was good out of the box.

4. Nvidia, Intel and Hyprland

Firstly, Hyprland runs well on my Nvidia RTX2060 Mobile, but there is a guide I followed. If you have an integrated GPU alongside your DGPU, as the Hyprland Multi-GPU guide says, you should definitely consider it to reduce power draw & free up gpu for gpu intensive tasks. I have an Intel NUC 11 Enthusiast with a dedicated Nvidia RTX 2060 GPU & an integrated Intel Iris Xe GPU. Hyprland chose the 2060 by default but I switched to Iris. I did have a couple of very small bugs with Hyprland on Nvidia like my Bluetooth applet not rendering in Waybar.

I am using drivers Nvidia proprietary drivers version 565.77 in this post

Setting up the hardware:

Terminal window
# Install Nvidia drivers
pacman -Sy nvidia-open nvidia-utils
# Install Intel drivers
pacman -Sy mesa intel-media-driver vulkan-intel
# For Intel (Optional): Enable GuC on Intel via kernel parameter, allows low level video decoding/encoding software to use Intel GPU (VAAPI)
echo "options i915 enable_guc=2" > /etc/modprobe.d/i915
# For Nvidia: Turn on Nvidia DRM, required for Hyprland w Nvidia via kernel parameter, https://en.wikipedia.org/wiki/Direct_Rendering_Manager
# This allows Kernel Mode Setting (KMS); allows kernel programmes to set graphics mode (resolution, colour space etc) - Intel already allows this by default
echo "options nvidia_drm modeset=1" > /etc/modprobe.d/nvidia
# Load above kernel parameters into initram
sudo mkinitcpio -P

If you want your Intel GPU to drive Hyprland, find your Intel GPU’s file descriptor:

Terminal window
# Find your Intel GPU
lspci -nn | grep -iE 'vga|3d'
> 0000:00:02.0 VGA compatible controller: Intel Corporation TigerLake-LP GT2 [Iris Xe Graphics] (rev 01)
> 0000:01:00.0 VGA compatible controller: NVIDIA Corporation TU106M [GeForce RTX 2060 Mobile] (rev a1)
# Now remember the associated identifier `[Domain:]Bus:Device.Function` e.g. "0000:00:02.0"
# And confirm its file descriptor is available
ls -lha /dev/dri/by-path/
> lrwxrwxrwx 1 root root 8 Dec 13 19:59 /dev/dri/by-path/pci-0000:00:02.0-card -> ../card2
# We're going to use that /dev/dri/card2 address (as the docs say, don't use the symlink - I tried it & Hyprland won't start with it)

and then to your Hyprland config add:

env = AQ_DRM_DEVICES,/dev/dri/card2

Now reboot everything & hopefully, you have Hyprland running on the Intel GPU. You can confirm this by using intel_gpu_top:

Terminal window
sudo pacman -Sy intel-gpu-tools
intel_gpu_top # and hopefully you can see Hyprland there
# Conversely, we can check that it's NOT running on the Nvidia GPU:
nvidia-smi

Scaling is a problem though. Many apps don’t have Wayland versions yet and only have Xorg versions. Xorg apps are rendered through Xwayland, and Xwayland doesn’t respect Wayland’s scaling. Xorg itself handles scaling differently. Px value is concrete but apps can consult the X Server’s DPI settings. Blah blah blah, Xwayland just uses the default scaling of 1:1px and this scale is global across all apps as there’s only 1 X Server in its current implementation. This is a problem in Hyprland because Wayland is very HiDPI aware & scale is inherent to its protocol. It is also worth noting that fractional scaling (1.25, 1.5 etc) on Xorg can be problematic in any case.

Popular examples include electron apps like Signal & Bitwarden. They’ll be blurry on your HiDPI screen. But we can fix it by first, prevent scaling. Edit your hyprland.conf like so:

xwayland {
force_zero_scaling = true
}

But now all xwayland apps are small. But many apps have their own scaling methods. Most electron apps let you use ctrl + and ctrl - because they are web views after all! Some apps might have cli args, internal settings or you might just have to squint!

ctrl + & ctrl - on Signal

You can actually try to bypass the Xwayland problem altogether with electron apps specifically, by forcing them to use Wayland e.g. bitwarden-desktop features=UseOzonePlatform --ozone-platform=wayland, however, my experience with this was very buggy. Sometimes the window would render literally 2min after I typed the command - though it did render well.

5. Steam, Nvidia and Gamescope

Steam is tricky but and ymmv depending on your card. Nvidia cards may present different problems, but the story seems to improving. This is my primary matrix of choices running Steam:

SetupCardSteam GPU AccelInterface performance (subjective)Verdict
Desktop modeIntel iGPUOffOk but low responsiveness, FPS😵
Big Picture ModeIntel iGPUOffVery low FPS😵
GamescopeIntel iGPUOffVery low FPS😵
Desktop modeIntel iGPUOnMost of the interface is black😵
Big Picture ModeIntel iGPUOnSets up a pane but no interface😵
GamescopeIntel iGPUOnRuns well* but then some games freeze!😵
Desktop modeRTX2060OffRuns pretty well
Big Picture ModeRTX2060OffVery low FPS😵
GamescopeRTX2060OffVery low FPS😵
Desktop modeRTX2060OnPretty well
Big Picture ModeRTX2060OnPretty well
GamescopeRTX2060OnVulkan error - does not open😵

Gamescope in theory is amazing with Hyprland as it keeps everything contained and performs well. But you might be victim to the game freeze bug where the game loop continues but the rendering fails.

So based on the above matrix, my preference is running desktop mode on the the RTX2060 with GPU acceleration on. To turn on GPU acceleration:

Steam Settings -> Interface:

  • Turn ON Enable GPU accelerated rendering in web views
  • Turn ON Enable hardware video decoding, if supported
  • Turn OFF Enable smooth scrolling webviews (I found this didn’t mesh well with trackpad, ymmv)

And to run Steam in desktop mode: prime-run steam or prime-run steam -bigpicture.

Steam desktop is built for X too, so it has the same scaling problem. So assuming we applied the force_zero_scaling = true in the previous secion, we can solve it easily by running steam with steam -forcedesktopscaling 1.5 or whatever scale sits well with you.

Steam set to scale = 10
steam -forcedesktopscaling 10

Lastly, when you switch windows while playing a game without gamescope compositing, consider using these rules. I found that INSIDE would quit when I left its focus without the stayfocused prop, and would not size normally without fullscreen. immediate renders it without hyprland’s vsync in fullscreen.

windowrulev2 = immediate,class:^(steam_app).*$
windowrulev2 = stayfocused,class:^(steam_app).*$
windowrulev2 = fullscreen,class:^(steam_app).*$

Gamescope doesn’t play nice with Nvidia so I wouldn’t bother but I did make some attempts and thought I’d record them. By default Gamescope will run on the same device as the compositor is, so for me that’s Intel. I can also specify a device using lspci (referenced earlier) e.g. for the Nvidia

QT_QPA_PLATFORM=wayland gamescope -W 2560 -H 1440 --force-grab-cursor --prefer-vk-device $(lspci -nn | grep -iE "vga|3d" | tr -d "][" | tr " " "\n" | grep 10de) -e -- steam -tenfoot

But that will give me a crash! See gamescope/issues/497.

I can run gamescope --prefer-vk-device $(lspci -nn | grep -iE "vga|3d" | tr -d "][" | tr " " "\n" | grep 10de) -e --backend sdl -- steam and it boots but the FPS is not great & the colours are off:

gamescope --backend sdl
gamescope --backend sdl with my RTX2060 mobile. Fried colour space.

prime-run gamescope -- steam seems to be the way to go.

Now everything works great and I can open up games (rendered with the RTX2060) and they all work great but we’re on Linux on Nvidia so it’s not going to work - gamescope/issues/1592. This was a difficult issue to track down. I was only trying two games - INSIDE & Dark Souls Remastered. Both games would freeze on a frame and stop accepting input but continue playing sound. Interestingly, gamescope is unaffected & I can hit controller hotkey to open up Steam - but the game won’t die without a dirty killall -9 /usr/bin/gamescope && killall -9 /usr/bin/gamescopereaper. Running the same setup on the iGPU directly from a TTY (no Hyprland). I tried to recompile Proton with a suggested patch related to Vulkan but no noticeable improvements.

As it seemed like a framebuffer issue which led me to try various fixes including turning off vsync in game. That actually works for Dark Souls Remastered and I got no freezes, but for INSIDE there’s no VSYNC option. I tried disabling VK_KHR_present_wait for gamescope with env VKD3D_DISABLE_EXTENSIONS=VK_KHR_present_id,VK_KHR_present_wait which is a Vulkan extension that helps with frame timing, pacing etc but no dice. Running gamescope through Intel but via Nvidia could put me in a weird spot.

A brief description of the command:

  • -W 2560 -H 1440: 2k gaming is good enough for my RTX2060
  • —force-grab-cursor: This steals the cursor away from Wayland. It’s not a perfect experience because the sensitivity is slightly off, but without it, gamescope will just close when you leave a game.
  • —prefer-vk-device $(lspci -nn | grep -iE ‘vga|3d’ | tr -d ’][’ | tr ’ ’ $‘\n’ | grep 8086): This spits out the vendor id : device id (in my case 8086:9a49) of the Intel card - you might want to confirm that. I found Steam works perfectly running under the Intel GPU with mesa & like absolute shit (especially Big Picture mode) on my Nvidia card. Don’t worry, your games will still boot up on your DGPU.
  • -e: This is a flag to tell gamescope you’re running steam and makes it friendly with child processes launched from it.
  • -f: Optional (gamescope option); but this will let you start in fullscreen.
  • -tenfoot: kicks you off into Big Picture mode - when I didn’t do this I would sometimes lose the game in gamescope.

Summing it up:

So yeah Gamescope + Nvidia = not yet, so let’s solidify our normal approach with a Desktop shortcut your app launcher (i.e. ctrl+r) will pick up.

[Desktop Entry]
Name=Steam Hyprland Big Picture
Exec=sh -c 'prime-run steam -bigpicture'
Type=Application
Categories=Game;
Icon=steam
Terminal=false
Comment=Launch Steam in Big Picture Mode with Gamescope

Copy this to ~/.local/share/applications/steam-hyprland-big-picture.desktop and it will appear in your app launchers.

6. Fixing systemd network stalling

I will note that xremap wouldn’t launch for the first 2 minutes after launching Hyprland at first because its default service file waits for multi-user.target to complete, but my ethernet port wasn’t connecting (because I don’t use it), so multi-user’s dependency systemd-networkd-wait-online would time out first as it waits for ALL interfaces! If you come across the same headache, here’s the fix:

This will wait for --any (including lo interface I believe) to come online - basically I am establishing my computer as a local computer rather than inherently networked. Add this override with sudo -E systemctl edit systemd-networkd-wait-online.service. Note the -E will export your local environment vars so will save you from dealing with nano.

systemd-networkd-wait-online.service (override)
[Service]
Type=oneshot
ExecStart=
ExecStart=/usr/lib/systemd/systemd-networkd-wait-online --any
RemainAfterExit=yes

YES you need the first blank ExecStart! This clears the existing ExecStart. Actually, I suppose you could just disable the systemd-networkd-wait-online altogether.

7. Things lacking

  • I can’t use Sketch, Photomator & Final Cut Pro. Mac still has a monopoly on the best creative tools. I might try PenPot. I’ve tried the photo tools in the past they’re not great.
  • Airplay is proprietary, Google Cast or whatever is proprietary. No convenient solution for wireless casting from Linux.
  • Magic Trackpad is the best - but Apple isn’t very friendly with the BT implementation to outside devices so I have to repair from scratch if I want to use it on my Macbook.