1 //! Xlib calls related to a mouse.
2 use super::{XlibError, MOUSEMASK};
3 use crate::display_servers::xlib_display_server::xwrap::BUTTONMASK;
4 use crate::XWrap;
5 use std::os::raw::{c_int, c_ulong};
6 use x11_dl::xlib;
7 
8 impl XWrap {
9     /// Grabs the mouse clicks of a window.
grab_mouse_clicks(&self, handle: xlib::Window, is_focused: bool)10     pub fn grab_mouse_clicks(&self, handle: xlib::Window, is_focused: bool) {
11         self.ungrab_buttons(handle);
12         if !is_focused {
13             self.grab_buttons(handle, xlib::Button1, xlib::AnyModifier, xlib::GrabModeSync);
14             self.grab_buttons(handle, xlib::Button3, xlib::AnyModifier, xlib::GrabModeSync);
15         }
16         self.grab_buttons(
17             handle,
18             xlib::Button1,
19             self.mouse_key_mask,
20             xlib::GrabModeAsync,
21         );
22         self.grab_buttons(
23             handle,
24             xlib::Button1,
25             self.mouse_key_mask | xlib::ShiftMask,
26             xlib::GrabModeAsync,
27         );
28         self.grab_buttons(
29             handle,
30             xlib::Button3,
31             self.mouse_key_mask,
32             xlib::GrabModeAsync,
33         );
34         self.grab_buttons(
35             handle,
36             xlib::Button3,
37             self.mouse_key_mask | xlib::ShiftMask,
38             xlib::GrabModeAsync,
39         );
40     }
41 
42     /// Grabs the button with the modifier for a window.
43     // `XGrabButton`: https://tronche.com/gui/x/xlib/input/XGrabButton.html
grab_buttons( &self, window: xlib::Window, button: u32, modifiers: u32, pointer_mode: i32, )44     pub fn grab_buttons(
45         &self,
46         window: xlib::Window,
47         button: u32,
48         modifiers: u32,
49         pointer_mode: i32,
50     ) {
51         // Grab the buttons with and without numlock (Mod2).
52         let mods: Vec<u32> = vec![
53             modifiers,
54             modifiers | xlib::Mod2Mask,
55             modifiers | xlib::LockMask,
56         ];
57         for m in mods {
58             unsafe {
59                 (self.xlib.XGrabButton)(
60                     self.display,
61                     button,
62                     m,
63                     window,
64                     0,
65                     BUTTONMASK as u32,
66                     pointer_mode,
67                     xlib::GrabModeAsync,
68                     self.root,
69                     0,
70                 );
71             }
72         }
73     }
74 
75     /// Cleans all currently grabbed buttons of a window.
76     // `XUngrabButton`: https://tronche.com/gui/x/xlib/input/XUngrabButton.html
ungrab_buttons(&self, handle: xlib::Window)77     pub fn ungrab_buttons(&self, handle: xlib::Window) {
78         unsafe {
79             (self.xlib.XUngrabButton)(
80                 self.display,
81                 xlib::AnyButton as u32,
82                 xlib::AnyModifier,
83                 handle,
84             );
85         }
86     }
87 
88     /// Grabs the cursor and sets its visual.
89     // `XGrabPointer`: https://tronche.com/gui/x/xlib/input/XGrabPointer.html
grab_pointer(&self, cursor: c_ulong)90     pub fn grab_pointer(&self, cursor: c_ulong) {
91         unsafe {
92             //grab the mouse
93             (self.xlib.XGrabPointer)(
94                 self.display,
95                 self.root,
96                 0,
97                 MOUSEMASK as u32,
98                 xlib::GrabModeAsync,
99                 xlib::GrabModeAsync,
100                 0,
101                 cursor,
102                 xlib::CurrentTime,
103             );
104         }
105     }
106 
107     /// Ungrab the cursor.
108     // `XUngrabPointer`: https://tronche.com/gui/x/xlib/input/XUngrabPointer.html
ungrab_pointer(&self)109     pub fn ungrab_pointer(&self) {
110         unsafe {
111             //release the mouse grab
112             (self.xlib.XUngrabPointer)(self.display, xlib::CurrentTime);
113         }
114     }
115 
116     /// Move the cursor to a window.
117     /// # Errors
118     ///
119     /// Will error if unable to obtain window attributes. See `get_window_attrs`.
move_cursor_to_window(&self, window: xlib::Window) -> Result<(), XlibError>120     pub fn move_cursor_to_window(&self, window: xlib::Window) -> Result<(), XlibError> {
121         let attrs = self.get_window_attrs(window)?;
122         let point = (attrs.x + (attrs.width / 2), attrs.y + (attrs.height / 2));
123         self.move_cursor_to_point(point)
124     }
125 
126     /// Move the cursor to a point.
127     /// # Errors
128     ///
129     /// Error indicates `XlibError`.
130     // `XWarpPointer`: https://tronche.com/gui/x/xlib/input/XWarpPointer.html
131     // TODO: Verify that Error is unreachable or specify conditions that may result
132     // in an error.
move_cursor_to_point(&self, point: (i32, i32)) -> Result<(), XlibError>133     pub fn move_cursor_to_point(&self, point: (i32, i32)) -> Result<(), XlibError> {
134         if point.0 >= 0 && point.1 >= 0 {
135             let none: c_int = 0;
136             unsafe {
137                 (self.xlib.XWarpPointer)(
138                     self.display,
139                     none as c_ulong,
140                     self.root,
141                     none,
142                     none,
143                     none as u32,
144                     none as u32,
145                     point.0,
146                     point.1,
147                 );
148             }
149         }
150         Ok(())
151     }
152 
153     /// Replay a click on a window.
154     // `XAllowEvents`: https://linux.die.net/man/3/xallowevents
155     //  `XSync`: https://tronche.com/gui/x/xlib/event-handling/XSync.html
replay_click(&self)156     pub fn replay_click(&self) {
157         unsafe {
158             (self.xlib.XAllowEvents)(self.display, xlib::ReplayPointer, xlib::CurrentTime);
159             (self.xlib.XSync)(self.display, xlib::False);
160         }
161     }
162 }
163