1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use hyprwire_rs::client::HyprWireClient;
use hyprwire_rs::wire;
use std::collections::HashMap;
use std::env;
use std::thread;
use std::time::Duration;
const SUPPORTED_VERSION: u32 = 1;
pub struct Hyprpaper;
impl Hyprpaper {
/// Generate and push appropriate socket commands to hyprpaper given new input wallpapers
pub fn push(wallpapers: &HashMap<String, String>) -> Result<(), String> {
// find socket base with fallback
let socket_base: String;
if let Ok(xdg_dir) = env::var("XDG_RUNTIME_DIR") {
socket_base = xdg_dir;
} else if let Ok(uid) = env::var("UID") {
socket_base = format!("/run/user/{}", uid);
} else {
return Err("hyprpaper: no valid socket path found".to_string());
}
// set target socket with fallback
let target_socket: String;
if let Ok(instance_id) = env::var("HYPRLAND_INSTANCE_SIGNATURE") {
target_socket = format!("{}/hypr/{}/.hyprpaper.sock", socket_base, instance_id)
} else {
target_socket = format!("{}/hypr/.hyprpaper.sock", socket_base)
}
// block till we can connect or met retry limit
for _ in 0..40 {
match HyprWireClient::connect(&target_socket) {
Ok(mut client) => {
// perform the handshake
let protocols = client.perform_handshake(SUPPORTED_VERSION)?;
// bind to first available protocol
let object_id: u32;
if let Some(protocol) = protocols.first() {
object_id = client.bind_protocol(&protocol.spec)?;
} else {
return Err("no protocol to bind to".to_string());
}
// apply for every wallpaper
for paper in wallpapers {
// request the new object
client.send_message(
wire::Code::HW_GENERIC_PROTOCOL_MESSAGE,
&[
wire::Value::Object(object_id),
wire::Value::Uint(0),
wire::Value::Seq(client.get_sequence()),
],
)?;
// process new object handle
let response = client.read_message()?;
if response.code != wire::Code::HW_NEW_OBJECT {
return Err(
"expected new object response after object request".to_string()
);
}
let Some(wire::Value::Uint(hp_object_id)) = response.args.get(0) else {
return Err(
"expected new object for hyprpaper wallpaper object".to_string()
);
};
// set wallpaper path
client.send_message(
wire::Code::HW_GENERIC_PROTOCOL_MESSAGE,
&[
wire::Value::Object(*hp_object_id),
wire::Value::Uint(0),
wire::Value::Varchar(paper.1.to_string()),
wire::Value::Seq(client.get_sequence()),
],
)?;
// set monitor
client.send_message(
wire::Code::HW_GENERIC_PROTOCOL_MESSAGE,
&[
wire::Value::Object(*hp_object_id),
wire::Value::Uint(2),
wire::Value::Varchar(paper.0.to_string()),
wire::Value::Seq(client.get_sequence()),
],
)?;
// set fit mode
client.send_message(
wire::Code::HW_GENERIC_PROTOCOL_MESSAGE,
&[
wire::Value::Object(*hp_object_id),
wire::Value::Uint(1),
wire::Value::Uint(1),
wire::Value::Seq(client.get_sequence()),
],
)?;
// apply
client.send_message(
wire::Code::HW_GENERIC_PROTOCOL_MESSAGE,
&[
wire::Value::Object(*hp_object_id),
wire::Value::Uint(3),
wire::Value::Seq(client.get_sequence()),
],
)?;
_ = client.read_message()?;
}
// try to disconnect properly, but dont panic if we cant
client.disconnect().unwrap_or(());
return Ok(());
}
Err(_) => {
thread::sleep(Duration::from_millis(250));
}
}
}
Err("hyprpaper: connection timeout reached".to_string())
}
}