xlib_display_server/xwrap/
setters.rs

1//! `XWrap` setters.
2use super::WindowHandle;
3use crate::{XWrap, XlibWindowHandle};
4use leftwm_core::models::TagId;
5use std::ffi::CString;
6use std::os::raw::{c_long, c_ulong};
7use x11_dl::xlib;
8
9impl XWrap {
10    // Public functions.
11
12    /// Appends a window property.
13    // `XChangeProperty`: https://tronche.com/gui/x/xlib/window-information/XChangeProperty.html
14    pub fn append_property_long(
15        &self,
16        window: xlib::Window,
17        property: xlib::Atom,
18        r#type: xlib::Atom,
19        data: &[c_long],
20    ) {
21        unsafe {
22            (self.xlib.XChangeProperty)(
23                self.display,
24                window,
25                property,
26                r#type,
27                32,
28                xlib::PropModeAppend,
29                data.as_ptr().cast::<u8>(),
30                data.len() as i32,
31            );
32        }
33    }
34
35    /// Replaces a window property.
36    // `XChangeProperty`: https://tronche.com/gui/x/xlib/window-information/XChangeProperty.html
37    pub fn replace_property_long(
38        &self,
39        window: xlib::Window,
40        property: xlib::Atom,
41        r#type: xlib::Atom,
42        data: &[c_long],
43    ) {
44        unsafe {
45            (self.xlib.XChangeProperty)(
46                self.display,
47                window,
48                property,
49                r#type,
50                32,
51                xlib::PropModeReplace,
52                data.as_ptr().cast::<u8>(),
53                data.len() as i32,
54            );
55        }
56    }
57
58    /// Sets the client list to the currently managed windows.
59    // `XDeleteProperty`: https://tronche.com/gui/x/xlib/window-information/XDeleteProperty.html
60    pub fn set_client_list(&self) {
61        unsafe {
62            (self.xlib.XDeleteProperty)(self.display, self.root, self.atoms.NetClientList);
63        }
64        for w in &self.managed_windows {
65            let list = vec![*w as c_long];
66            self.append_property_long(self.root, self.atoms.NetClientList, xlib::XA_WINDOW, &list);
67        }
68    }
69
70    /// Sets the current desktop.
71    pub fn set_current_desktop(&self, current_tag: Option<TagId>) {
72        let indexes: Vec<u32> = match current_tag {
73            Some(tag) => vec![tag as u32 - 1],
74            None => vec![0],
75        };
76        self.set_desktop_prop(&indexes, self.atoms.NetCurrentDesktop);
77    }
78
79    // /// Sets the current viewport.
80    // fn set_current_viewport(&self, tags: Vec<&String>) {
81    //     let mut indexes: Vec<u32> = vec![];
82    //     for tag in tags {
83    //         for (i, mytag) in self.tags.iter().enumerate() {
84    //             if tag.contains(mytag) {
85    //                 indexes.push(i as u32);
86    //             }
87    //         }
88    //     }
89    //     if indexes.is_empty() {
90    //         indexes.push(0);
91    //     }
92    //     self.set_desktop_prop(&indexes, self.atoms.NetDesktopViewport);
93    // }
94
95    /// Sets a desktop property.
96    // We allow the lossless cast here so that 32 bit systems may work with
97    // leftwm. See https://github.com/leftwm/leftwm/discussions/1201 for
98    // more details.
99    #[allow(clippy::cast_lossless)]
100    pub fn set_desktop_prop(&self, data: &[u32], atom: c_ulong) {
101        let x_data: Vec<c_long> = data.iter().map(|x| *x as c_long).collect();
102        self.replace_property_long(self.root, atom, xlib::XA_CARDINAL, &x_data);
103    }
104
105    /// Sets a desktop property with type `c_ulong`.
106    pub fn set_desktop_prop_c_ulong(&self, value: c_ulong, atom: c_ulong, r#type: c_ulong) {
107        let data = vec![value as c_long];
108        self.replace_property_long(self.root, atom, r#type, &data);
109    }
110
111    /// Sets a desktop property with type string.
112    // `XChangeProperty`: https://tronche.com/gui/x/xlib/window-information/XChangeProperty.html
113    pub fn set_desktop_prop_string(&self, value: &str, atom: c_ulong, encoding: xlib::Atom) {
114        if let Ok(cstring) = CString::new(value) {
115            unsafe {
116                (self.xlib.XChangeProperty)(
117                    self.display,
118                    self.root,
119                    atom,
120                    encoding,
121                    8,
122                    xlib::PropModeReplace,
123                    cstring.as_ptr().cast::<u8>(),
124                    value.len() as i32,
125                );
126                std::mem::forget(cstring);
127            }
128        }
129    }
130
131    /// Sets a windows state.
132    pub fn set_state(
133        &self,
134        handle: WindowHandle<XlibWindowHandle>,
135        toggle_to: bool,
136        atom: xlib::Atom,
137    ) {
138        let WindowHandle(XlibWindowHandle(h)) = handle;
139        let mut states = self.get_window_states_atoms(h);
140        if toggle_to {
141            if states.contains(&atom) {
142                return;
143            }
144            states.push(atom);
145        } else {
146            let Some(index) = states.iter().position(|s| s == &atom) else {
147                return;
148            };
149            states.remove(index);
150        }
151        self.set_window_states_atoms(h, &states);
152    }
153
154    /// Sets a windows border color.
155    // `XSetWindowBorder`: https://tronche.com/gui/x/xlib/window/XSetWindowBorder.html
156    pub fn set_window_border_color(&self, window: xlib::Window, mut color: c_ulong) {
157        unsafe {
158            // Force border opacity to 0xff. (color is <aarrggbb> in hex format)
159            color |= 0xff00_0000;
160            (self.xlib.XSetWindowBorder)(self.display, window, color);
161        }
162    }
163
164    pub fn set_background_color(&self, mut color: c_ulong) {
165        unsafe {
166            // Force border opacity to 0xff. (color is <aarrggbb> in hex format)
167            color |= 0xff00_0000;
168            (self.xlib.XSetWindowBackground)(self.display, self.root, color);
169            (self.xlib.XClearWindow)(self.display, self.root);
170            (self.xlib.XFlush)(self.display);
171            (self.xlib.XSync)(self.display, 0);
172        }
173    }
174
175    /// Sets a windows configuration.
176    pub fn set_window_config(
177        &self,
178        window: xlib::Window,
179        mut window_changes: xlib::XWindowChanges,
180        unlock: u32,
181    ) {
182        unsafe { (self.xlib.XConfigureWindow)(self.display, window, unlock, &mut window_changes) };
183        self.sync();
184    }
185
186    /// Sets what desktop a window is on.
187    pub fn set_window_desktop(&self, window: xlib::Window, current_tag: &TagId) {
188        let mut indexes: Vec<c_long> = vec![*current_tag as c_long - 1];
189        if indexes.is_empty() {
190            indexes.push(0);
191        }
192        self.replace_property_long(window, self.atoms.NetWMDesktop, xlib::XA_CARDINAL, &indexes);
193    }
194
195    /// Sets the atom states of a window.
196    pub fn set_window_states_atoms(&self, window: xlib::Window, states: &[xlib::Atom]) {
197        let data: Vec<c_long> = states.iter().map(|x| *x as c_long).collect();
198        self.replace_property_long(window, self.atoms.NetWMState, xlib::XA_ATOM, &data);
199    }
200
201    pub fn set_window_urgency(&self, window: xlib::Window, is_urgent: bool) {
202        if let Some(mut wmh) = self.get_wmhints(window) {
203            if ((wmh.flags & xlib::XUrgencyHint) != 0) == is_urgent {
204                return;
205            }
206            wmh.flags = if is_urgent {
207                wmh.flags | xlib::XUrgencyHint
208            } else {
209                wmh.flags & !xlib::XUrgencyHint
210            };
211            self.set_wmhints(window, &mut wmh);
212        }
213    }
214
215    /// Sets the `XWMHints` of a window.
216    pub fn set_wmhints(&self, window: xlib::Window, wmh: &mut xlib::XWMHints) {
217        unsafe { (self.xlib.XSetWMHints)(self.display, window, wmh) };
218    }
219
220    /// Sets the `WM_STATE` of a window.
221    pub fn set_wm_states(&self, window: xlib::Window, states: &[c_long]) {
222        self.replace_property_long(window, self.atoms.WMState, self.atoms.WMState, states);
223    }
224}