winit/platform_impl/linux/x11/util/
hint.rs

1use crate::platform::x11::WindowType;
2use std::sync::Arc;
3
4use super::*;
5
6#[derive(Debug)]
7#[allow(dead_code)]
8pub enum StateOperation {
9    Remove = 0, // _NET_WM_STATE_REMOVE
10    Add = 1,    // _NET_WM_STATE_ADD
11    Toggle = 2, // _NET_WM_STATE_TOGGLE
12}
13
14impl From<bool> for StateOperation {
15    fn from(op: bool) -> Self {
16        if op {
17            StateOperation::Add
18        } else {
19            StateOperation::Remove
20        }
21    }
22}
23
24impl WindowType {
25    pub(crate) fn as_atom(&self, xconn: &Arc<XConnection>) -> xproto::Atom {
26        use self::WindowType::*;
27        let atom_name = match *self {
28            Desktop => _NET_WM_WINDOW_TYPE_DESKTOP,
29            Dock => _NET_WM_WINDOW_TYPE_DOCK,
30            Toolbar => _NET_WM_WINDOW_TYPE_TOOLBAR,
31            Menu => _NET_WM_WINDOW_TYPE_MENU,
32            Utility => _NET_WM_WINDOW_TYPE_UTILITY,
33            Splash => _NET_WM_WINDOW_TYPE_SPLASH,
34            Dialog => _NET_WM_WINDOW_TYPE_DIALOG,
35            DropdownMenu => _NET_WM_WINDOW_TYPE_DROPDOWN_MENU,
36            PopupMenu => _NET_WM_WINDOW_TYPE_POPUP_MENU,
37            Tooltip => _NET_WM_WINDOW_TYPE_TOOLTIP,
38            Notification => _NET_WM_WINDOW_TYPE_NOTIFICATION,
39            Combo => _NET_WM_WINDOW_TYPE_COMBO,
40            Dnd => _NET_WM_WINDOW_TYPE_DND,
41            Normal => _NET_WM_WINDOW_TYPE_NORMAL,
42        };
43
44        let atoms = xconn.atoms();
45        atoms[atom_name]
46    }
47}
48
49pub struct MotifHints {
50    hints: MwmHints,
51}
52
53struct MwmHints {
54    flags: u32,
55    functions: u32,
56    decorations: u32,
57    input_mode: u32,
58    status: u32,
59}
60
61#[allow(dead_code)]
62mod mwm {
63    // Motif WM hints are obsolete, but still widely supported.
64    // https://stackoverflow.com/a/1909708
65    pub const MWM_HINTS_FUNCTIONS: u32 = 1 << 0;
66    pub const MWM_HINTS_DECORATIONS: u32 = 1 << 1;
67
68    pub const MWM_FUNC_ALL: u32 = 1 << 0;
69    pub const MWM_FUNC_RESIZE: u32 = 1 << 1;
70    pub const MWM_FUNC_MOVE: u32 = 1 << 2;
71    pub const MWM_FUNC_MINIMIZE: u32 = 1 << 3;
72    pub const MWM_FUNC_MAXIMIZE: u32 = 1 << 4;
73    pub const MWM_FUNC_CLOSE: u32 = 1 << 5;
74}
75
76impl MotifHints {
77    pub fn new() -> MotifHints {
78        MotifHints {
79            hints: MwmHints { flags: 0, functions: 0, decorations: 0, input_mode: 0, status: 0 },
80        }
81    }
82
83    pub fn set_decorations(&mut self, decorations: bool) {
84        self.hints.flags |= mwm::MWM_HINTS_DECORATIONS;
85        self.hints.decorations = decorations as u32;
86    }
87
88    pub fn set_maximizable(&mut self, maximizable: bool) {
89        if maximizable {
90            self.add_func(mwm::MWM_FUNC_MAXIMIZE);
91        } else {
92            self.remove_func(mwm::MWM_FUNC_MAXIMIZE);
93        }
94    }
95
96    fn add_func(&mut self, func: u32) {
97        if self.hints.flags & mwm::MWM_HINTS_FUNCTIONS != 0 {
98            if self.hints.functions & mwm::MWM_FUNC_ALL != 0 {
99                self.hints.functions &= !func;
100            } else {
101                self.hints.functions |= func;
102            }
103        }
104    }
105
106    fn remove_func(&mut self, func: u32) {
107        if self.hints.flags & mwm::MWM_HINTS_FUNCTIONS == 0 {
108            self.hints.flags |= mwm::MWM_HINTS_FUNCTIONS;
109            self.hints.functions = mwm::MWM_FUNC_ALL;
110        }
111
112        if self.hints.functions & mwm::MWM_FUNC_ALL != 0 {
113            self.hints.functions |= func;
114        } else {
115            self.hints.functions &= !func;
116        }
117    }
118}
119
120impl Default for MotifHints {
121    fn default() -> Self {
122        Self::new()
123    }
124}
125
126impl XConnection {
127    pub fn get_motif_hints(&self, window: xproto::Window) -> MotifHints {
128        let atoms = self.atoms();
129        let motif_hints = atoms[_MOTIF_WM_HINTS];
130
131        let mut hints = MotifHints::new();
132
133        if let Ok(props) = self.get_property::<u32>(window, motif_hints, motif_hints) {
134            hints.hints.flags = props.first().cloned().unwrap_or(0);
135            hints.hints.functions = props.get(1).cloned().unwrap_or(0);
136            hints.hints.decorations = props.get(2).cloned().unwrap_or(0);
137            hints.hints.input_mode = props.get(3).cloned().unwrap_or(0);
138            hints.hints.status = props.get(4).cloned().unwrap_or(0);
139        }
140
141        hints
142    }
143
144    #[allow(clippy::unnecessary_cast)]
145    pub fn set_motif_hints(
146        &self,
147        window: xproto::Window,
148        hints: &MotifHints,
149    ) -> Result<VoidCookie<'_>, X11Error> {
150        let atoms = self.atoms();
151        let motif_hints = atoms[_MOTIF_WM_HINTS];
152
153        let hints_data: [u32; 5] = [
154            hints.hints.flags as u32,
155            hints.hints.functions as u32,
156            hints.hints.decorations as u32,
157            hints.hints.input_mode as u32,
158            hints.hints.status as u32,
159        ];
160
161        self.change_property(
162            window,
163            motif_hints,
164            motif_hints,
165            xproto::PropMode::REPLACE,
166            &hints_data,
167        )
168    }
169}