use std::{env, process};
pub fn set_keep_above(enable: bool) -> bool {
set_keep_above_impl(enable).is_ok()
}
fn set_keep_above_impl(enable: bool) -> Result<(), Box<dyn std::error::Error>> {
#[cfg(not(target_os = "linux"))]
{
let _ = enable;
Err("unsupported platform".into())
}
#[cfg(target_os = "linux")]
{
use x11rb::connection::Connection;
use x11rb::protocol::xproto::{AtomEnum, ClientMessageEvent, ConnectionExt, EventMask};
let (conn, screen) = x11rb::connect(None).map_err(|e| e.to_string())?;
let root = conn.setup().roots[screen].root;
let pid = process::id();
let net_wm_state = conn.intern_atom(false, b"_NET_WM_STATE")?.reply()?.atom;
let state_above = conn
.intern_atom(false, b"_NET_WM_STATE_ABOVE")?
.reply()?
.atom;
let net_wm_pid = conn.intern_atom(false, b"_NET_WM_PID")?.reply()?.atom;
let net_client_list = conn.intern_atom(false, b"_NET_CLIENT_LIST")?.reply()?.atom;
let wm_class = conn.intern_atom(false, b"WM_CLASS")?.reply()?.atom;
let prgname = env::args()
.next()
.as_deref()
.and_then(|argv0| std::path::Path::new(argv0).file_name())
.map(|name| name.to_string_lossy().into_owned());
let clients = conn
.get_property(false, root, net_client_list, AtomEnum::WINDOW, 0, 1024)?
.reply()?
.value32()
.ok_or("unreadable _NET_CLIENT_LIST")?
.collect::<Vec<_>>();
let mut target = None;
for child in clients {
let pid_matches = conn
.get_property(false, child, net_wm_pid, AtomEnum::CARDINAL, 0, 1)?
.reply()
.ok()
.and_then(|reply| reply.value32().and_then(|mut v| v.next()))
.is_some_and(|owner| owner == pid);
if pid_matches {
target = Some(child);
break;
}
let class_matches = prgname
.as_ref()
.and_then(|name| {
conn.get_property(false, child, wm_class, AtomEnum::STRING, 0, 128)
.ok()?
.reply()
.ok()
.map(|reply| {
reply
.value
.split(|&b| b == 0)
.any(|part| part == name.as_bytes())
})
})
.unwrap_or(false);
if class_matches {
target = Some(child);
break;
}
}
let Some(window) = target else {
return Err("own top-level window not found".into());
};
let mode: u32 = if enable { 1 } else { 0 };
let event = ClientMessageEvent::new(32, window, net_wm_state, [mode, state_above, 0, 1, 0]);
conn.send_event(
false,
root,
EventMask::SUBSTRUCTURE_REDIRECT | EventMask::SUBSTRUCTURE_NOTIFY,
event,
)
.map_err(|e| e.to_string())?;
conn.flush().map_err(|e| e.to_string())?;
Ok(())
}
}