Skip to content

Commit 47c1ea1

Browse files
FossoresLPxyproto
authored andcommitted
feat: add Hyprpaper backend
Hyprpaper is designed primarily for Hyprland but works for all wlroots based compositors. It runs as a daemon and is controlled via a socket, which prevents flashes during the transition between images. The Hyprpaper backend is placed first in the order of possible backends but will only be chosen if it is already running. Only two modes are supported, cover (the default) and contain, so all other modes are mapped to one of the two. Due to a bug in Hyprpaper, the latest release (v0.6.0) is not compatible because it does not support wildcard display selection. Until a new release is published, only builds directly from Git will work correctly.
1 parent d6b7784 commit 47c1ea1

File tree

3 files changed

+116
-0
lines changed

3 files changed

+116
-0
lines changed

backend.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package wallutils
66
// WMs contains all available backends for changing the wallpaper
77
// Some backends may require cgo (sway + x11)
88
var WMs = []WM{
9+
&Hyprpaper{},
910
&Sway{},
1011
&Deepin{},
1112
&Xfce4{},

backend_nocgo.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package wallutils
66
// WMs contains all available backends for changing the wallpaper
77
// Only backends that do not require cgo should be included here.
88
var WMs = []WM{
9+
&Hyprpaper{},
910
//&Sway{},
1011
&Deepin{},
1112
&Xfce4{},

hyprpaper.go

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package wallutils
2+
3+
import (
4+
"fmt"
5+
"net"
6+
"path"
7+
8+
"github.com/xyproto/env/v2"
9+
)
10+
11+
// Hyprpaper compatible windowmanager
12+
type Hyprpaper struct {
13+
mode string
14+
verbose bool
15+
sock string
16+
}
17+
18+
// Name returns the name of this window manager or desktop environment
19+
func (sb *Hyprpaper) Name() string {
20+
return "Hyprpaper"
21+
}
22+
23+
// ExecutablesExists checks if executables associated with this backend exists in the PATH
24+
func (sb *Hyprpaper) ExecutablesExists() bool {
25+
return which("hyprpaper") != ""
26+
}
27+
28+
// Running examines environment variables to try to figure out if this backend is currently running
29+
func (sb *Hyprpaper) Running() bool {
30+
inst := env.Str("HYPRLAND_INSTANCE_SIGNATURE")
31+
sb.sock = path.Join("/tmp/hypr", inst, ".hyprpaper.sock")
32+
return exists(sb.sock)
33+
}
34+
35+
// SetMode will set the current way to display the wallpaper (stretched, tiled etc)
36+
func (sb *Hyprpaper) SetMode(mode string) {
37+
sb.mode = mode
38+
}
39+
40+
// SetVerbose can be used for setting the verbose field to true or false.
41+
// This will cause this backend to output information about what is is doing on stdout.
42+
func (sb *Hyprpaper) SetVerbose(verbose bool) {
43+
sb.verbose = verbose
44+
}
45+
46+
// SetWallpaper sets the desktop wallpaper, given an image filename.
47+
// The image must exist and be readable.
48+
func (sb *Hyprpaper) SetWallpaper(imageFilename string) error {
49+
if !exists(imageFilename) {
50+
return fmt.Errorf("no such file: %s", imageFilename)
51+
}
52+
53+
// Connect to the Hyprpaper socket
54+
sock, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: sb.sock, Net: "unix"})
55+
56+
if err != nil {
57+
return err
58+
}
59+
60+
defer sock.Close()
61+
62+
// Preload the image
63+
if err = runHyprCmd(sock, "preload "+imageFilename); err != nil {
64+
return err
65+
}
66+
67+
// Set the wallpaper mode
68+
mode := defaultMode
69+
if sb.mode != "" {
70+
mode = sb.mode
71+
}
72+
73+
switch mode {
74+
case "center", "tile", "fill", "stretch", "scale", "scaled", "zoom", "zoomed", "stretched":
75+
mode = ""
76+
case "fit":
77+
mode = "contain:"
78+
default:
79+
// Invalid and unrecognized desktop wallpaper mode
80+
return fmt.Errorf("invalid desktop wallpaper mode for swaybg: %s", mode)
81+
}
82+
83+
// Set the wallpaper
84+
if err = runHyprCmd(sock, "wallpaper ,"+mode+imageFilename); err != nil {
85+
return err
86+
}
87+
88+
// Unload unused images
89+
return runHyprCmd(sock, "unload unused")
90+
}
91+
92+
func runHyprCmd(sock *net.UnixConn, cmd string) error {
93+
_, err := sock.Write([]byte(cmd))
94+
95+
if err != nil {
96+
return err
97+
}
98+
99+
buf := [32]byte{}
100+
101+
n, err := sock.Read(buf[:])
102+
103+
if err != nil {
104+
return err
105+
}
106+
107+
res := string(buf[:n])
108+
109+
if res != "ok" {
110+
return fmt.Errorf("cmd %q failed: %s", cmd, res)
111+
}
112+
113+
return nil
114+
}

0 commit comments

Comments
 (0)