148 lines
7.1 KiB
Plaintext
148 lines
7.1 KiB
Plaintext
# A compositor that exists only so Sunshine has something to capture.
|
|
# mainframe has no desktop: the only connected output (HDMI-A-2) hangs off the
|
|
# Intel iGPU, while the RTX 3060 that does the encoding drives no monitor at
|
|
# all. Capturing the real output would mean grabbing on Intel and encoding on
|
|
# NVIDIA — a cross-GPU copy every frame. A virtual output on the 3060 keeps
|
|
# capture and NVENC on one card.
|
|
|
|
output HEADLESS-1 mode 1920x1080@60Hz position 0,0
|
|
output HEADLESS-1 background #101920 solid_color
|
|
|
|
# Start Xwayland eagerly rather than on first X client. Steam is an X app, and
|
|
# with the default lazy start DISPLAY does not exist yet when the line below
|
|
# imports the environment — so Steam launched by Sunshine got
|
|
# "Unable to open a connection to X" and showed a blank stream.
|
|
xwayland force
|
|
|
|
# Sunshine is a systemd user unit and inherits nothing from this session, so
|
|
# hand it the display variables before starting it.
|
|
#
|
|
# ONE exec with &&, not two. sway runs exec lines asynchronously and does not
|
|
# order them, so as two separate lines Sunshine won every time: it started in
|
|
# the same second as the compositor, before DISPLAY was imported, and passed no
|
|
# DISPLAY to the apps it launched. Steam then failed with "Unable to open a
|
|
# connection to X" even though Xwayland was up and the manager environment was
|
|
# correct.
|
|
exec systemctl --user import-environment WAYLAND_DISPLAY DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP && systemctl --user start sunshine.service
|
|
|
|
# Input arrives from the Moonlight client, so keybinds are worth having even
|
|
# though nobody is sitting at this machine. Without them the Desktop app
|
|
# streams an empty screen with no way to open anything.
|
|
#
|
|
# Mod1 (Alt), not Mod4 (Super). The client machines run Hyprland with SUPER as
|
|
# their own modifier, and a compositor grabs its own modifier before Moonlight
|
|
# ever sees the key, so every Super bind here was unreachable from the stream —
|
|
# it acted on the client instead. Alt is not grabbed there, so it arrives. The
|
|
# cost is that an Alt bind here shadows the focused app's menu mnemonics
|
|
# (Alt+F, Alt+D), which is acceptable on a session that shows one fullscreen
|
|
# app at a time.
|
|
set $mod Mod1
|
|
|
|
# Tiling, sway's default. This used to float every window, which left a
|
|
# single-app stream at whatever size the app opened at instead of filling the
|
|
# output. Each Sunshine app switches to its own workspace first (apps.json), so
|
|
# its window is alone there and fills the screen. Dialogs sway recognizes as
|
|
# dialogs still float.
|
|
|
|
# Title bars are the handle you grab with the mouse, so floating windows keep
|
|
# a real border rather than the thin default.
|
|
default_floating_border normal 2
|
|
|
|
# Alt+drag moves a window, Alt+right-drag resizes it. Without this the
|
|
# only way to move a window is the title bar, which a fullscreen app has none of.
|
|
floating_modifier $mod normal
|
|
|
|
# Hyprland takes $browser from hosts/<host>/hypr/local-env.conf; mainframe links
|
|
# no hypr config, so it is named here. qutebrowser, to match the laptops.
|
|
set $browser qutebrowser
|
|
|
|
# These mirror common/hypr/hyprland.conf, so the muscle memory from the laptops
|
|
# carries over the stream. Only binds whose target exists on this host are
|
|
# ported: mainframe has no grim/grimblast, no udiskie, no
|
|
# networkmanager_dmenu, no ydotool, no julia, no ncmpcpp and no swayimg, so
|
|
# Hyprland's $mainMod+P, Shift+P, M, W, A, S and V are deliberately absent
|
|
# rather than bound to a missing binary — sway reports nothing when an exec
|
|
# target does not exist, so a ported bind would look correct and silently do
|
|
# nothing. The brightness keys are out for the same reason twice over:
|
|
# brightnessctl is absent and /sys/class/backlight is empty.
|
|
#
|
|
# $mainMod+N and Shift+N are out too, less obviously. The daemon here is mako,
|
|
# not swaync, and mako's do-not-disturb is not built in — it needs a
|
|
# [mode=do-not-disturb] invisible=1 section, and this host has no mako config at
|
|
# all. `makoctl mode -t do-not-disturb` would therefore succeed and suppress
|
|
# nothing. Write that config first if these binds are wanted.
|
|
#
|
|
# $mainMod+Ctrl+L is not ported: there is no lock screen here on purpose, and
|
|
# locking the session Sunshine captures would blank the stream.
|
|
|
|
bindsym $mod+Return exec kitty
|
|
bindsym $mod+Shift+Return exec wofi --show drun
|
|
bindsym $mod+b exec $browser
|
|
bindsym $mod+q kill
|
|
bindsym $mod+Shift+q exit
|
|
bindsym $mod+f fullscreen
|
|
bindsym $mod+t floating toggle
|
|
|
|
# Hyprland moves focus with both vim keys and arrows; so does this.
|
|
bindsym $mod+h focus left
|
|
bindsym $mod+j focus down
|
|
bindsym $mod+k focus up
|
|
bindsym $mod+l focus right
|
|
bindsym $mod+Left focus left
|
|
bindsym $mod+Down focus down
|
|
bindsym $mod+Up focus up
|
|
bindsym $mod+Right focus right
|
|
|
|
# Not a Hyprland bind, kept because a Moonlight client arrives with a pointer
|
|
# and little else: this is the only way to reach a window the pointer cannot
|
|
# see. Spelled literally rather than as $mod so it stays Alt+Tab if $mod moves.
|
|
bindsym Alt+Tab focus next
|
|
bindsym Alt+Shift+Tab focus prev
|
|
|
|
# Workspaces, and $mod+scroll to cycle them, as on the laptops. Sway has no
|
|
# master layout, so Hyprland's $mainMod+Space, Y, U, O and I have no
|
|
# counterpart; nor do its
|
|
# movecurrentworkspacetomonitor binds, with one virtual output.
|
|
bindsym $mod+1 workspace number 1
|
|
bindsym $mod+2 workspace number 2
|
|
bindsym $mod+3 workspace number 3
|
|
bindsym $mod+4 workspace number 4
|
|
bindsym $mod+5 workspace number 5
|
|
bindsym $mod+6 workspace number 6
|
|
bindsym $mod+7 workspace number 7
|
|
bindsym $mod+8 workspace number 8
|
|
bindsym $mod+9 workspace number 9
|
|
bindsym $mod+0 workspace number 10
|
|
|
|
bindsym $mod+Shift+1 move container to workspace number 1
|
|
bindsym $mod+Shift+2 move container to workspace number 2
|
|
bindsym $mod+Shift+3 move container to workspace number 3
|
|
bindsym $mod+Shift+4 move container to workspace number 4
|
|
bindsym $mod+Shift+5 move container to workspace number 5
|
|
bindsym $mod+Shift+6 move container to workspace number 6
|
|
bindsym $mod+Shift+7 move container to workspace number 7
|
|
bindsym $mod+Shift+8 move container to workspace number 8
|
|
bindsym $mod+Shift+9 move container to workspace number 9
|
|
bindsym $mod+Shift+0 move container to workspace number 10
|
|
|
|
bindsym --whole-window $mod+button4 workspace prev_on_output
|
|
bindsym --whole-window $mod+button5 workspace next_on_output
|
|
|
|
# Volume reaches the client: the default sink is sink-sunshine-stereo, which is
|
|
# the one Sunshine captures. --locked because there is no lock screen to respect.
|
|
# XF86AudioMicMute is not ported — this host has no audio source at all.
|
|
bindsym --locked XF86AudioRaiseVolume exec wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
|
|
bindsym --locked XF86AudioLowerVolume exec wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
|
|
bindsym --locked XF86AudioMute exec wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
|
|
|
|
bindsym --locked XF86AudioNext exec playerctl next
|
|
bindsym --locked XF86AudioPause exec playerctl play-pause
|
|
bindsym --locked XF86AudioPlay exec playerctl play-pause
|
|
bindsym --locked XF86AudioPrev exec playerctl previous
|
|
|
|
# Something visible on login, so a working capture is obviously working rather
|
|
# than indistinguishable from a broken one.
|
|
exec kitty
|
|
|
|
# No bar, no idle daemon, no lock screen — there is no one sitting here.
|