window.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. use x11::{xlib,xinput2};
  2. use std::ffi::CString;
  3. use std::{mem,ptr};
  4. use std::os::raw::{c_int,c_uchar};
  5. use crate::widgets::Size;
  6. pub struct Display {
  7. pub display: *mut xlib::_XDisplay,
  8. pub screen: i32,
  9. }
  10. impl Display {
  11. pub fn create() -> Result<Display, failure::Error> {
  12. let display = unsafe { xlib::XOpenDisplay(ptr::null()) };
  13. if display.is_null() {
  14. bail!("Unable to open X11 display");
  15. }
  16. let screen = unsafe { xlib::XDefaultScreen(display) };
  17. Ok(Display { display, screen })
  18. }
  19. pub fn get_width(&mut self) -> i32 {
  20. unsafe {
  21. let s = xlib::XScreenOfDisplay(self.display, self.screen);
  22. xlib::XWidthOfScreen(s)
  23. }
  24. }
  25. pub fn get_widths(&mut self) -> Result<Vec<(i32,i32)>, failure::Error> {
  26. if unsafe { x11::xinerama::XineramaIsActive(self.display) != 0 } {
  27. let mut screens = 0;
  28. let screen_info = unsafe { x11::xinerama::XineramaQueryScreens(self.display, &mut screens) };
  29. let mut widths = Vec::new();
  30. for i in 0..screens {
  31. unsafe {
  32. let si = screen_info.offset(i as isize).as_ref().ok_or(format_err!("bad pointer"))?;
  33. widths.push((si.x_org as i32, si.width as i32));
  34. }
  35. }
  36. Ok(widths)
  37. } else {
  38. Ok(vec![(0, self.get_width())])
  39. }
  40. }
  41. }
  42. impl Drop for Display {
  43. fn drop(&mut self) {
  44. unsafe {
  45. xlib::XCloseDisplay(self.display);
  46. }
  47. }
  48. }
  49. /// All the state needed to keep around to run this sort of
  50. /// application!
  51. pub struct Window<'t> {
  52. pub display: &'t Display,
  53. pub screen: i32,
  54. pub window: u64,
  55. // these two are interned strings kept around because we want to
  56. // check against them a _lot_, to find out if an event is a quit
  57. // event
  58. pub wm_protocols: u64,
  59. pub wm_delete_window: u64,
  60. // The width and height of the window
  61. pub width: i32,
  62. pub height: i32,
  63. }
  64. impl<'t> Window<'t> {
  65. /// Create a new Window from a given Display and with the desire
  66. /// width and height
  67. pub fn create(
  68. display: &'t Display,
  69. Size { wd: width, ht: height, xo, yo }: Size,
  70. ) -> Result<Window<'t>, failure::Error> {
  71. unsafe {
  72. let screen = display.screen;
  73. let window = xlib::XCreateSimpleWindow(
  74. display.display,
  75. xlib::XRootWindow(display.display, screen),
  76. xo as i32,
  77. yo as i32,
  78. width as u32,
  79. height as u32,
  80. 1,
  81. xlib::XBlackPixel(display.display, screen),
  82. xlib::XWhitePixel(display.display, screen),
  83. );
  84. let wm_protocols = {
  85. let cstr = CString::new("WM_PROTOCOLS")?;
  86. xlib::XInternAtom(display.display, cstr.as_ptr(), 0)
  87. };
  88. let wm_delete_window = {
  89. let cstr = CString::new("WM_DELETE_WINDOW")?;
  90. xlib::XInternAtom(display.display, cstr.as_ptr(), 0)
  91. };
  92. Ok(Window {
  93. display,
  94. screen,
  95. window,
  96. wm_protocols,
  97. wm_delete_window,
  98. width,
  99. height,
  100. })
  101. }
  102. }
  103. /// for this application, we might eventually care about the
  104. /// mouse, so make sure we notify x11 that we care about those
  105. pub fn set_input_masks(&mut self) -> Result<(), failure::Error> {
  106. let mut opcode = 0;
  107. let mut event = 0;
  108. let mut error = 0;
  109. let xinput_str = CString::new("XInputExtension")?;
  110. unsafe {
  111. xlib::XQueryExtension(
  112. self.display.display,
  113. xinput_str.as_ptr(),
  114. &mut opcode,
  115. &mut event,
  116. &mut error,
  117. );
  118. }
  119. let mut mask: [c_uchar;1] = [0];
  120. let mut input_event_mask = xinput2::XIEventMask {
  121. deviceid: xinput2::XIAllMasterDevices,
  122. mask_len: mask.len() as i32,
  123. mask: mask.as_mut_ptr(),
  124. };
  125. let events = &[
  126. xinput2::XI_ButtonPress,
  127. xinput2::XI_ButtonRelease,
  128. ];
  129. for &event in events {
  130. xinput2::XISetMask(&mut mask, event);
  131. }
  132. match unsafe {
  133. xinput2::XISelectEvents(
  134. self.display.display,
  135. self.window,
  136. &mut input_event_mask,
  137. 1,
  138. )
  139. } {
  140. status if status as u8 == xlib::Success => (),
  141. err => bail!("Failed to select events {:?}", err)
  142. }
  143. Ok(())
  144. }
  145. pub fn set_protocols(&mut self) -> Result<(), failure::Error> {
  146. let mut protocols = [self.intern("WM_DELETE_WINDOW")?];
  147. unsafe {
  148. xlib::XSetWMProtocols(
  149. self.display.display,
  150. self.window,
  151. protocols.as_mut_ptr(),
  152. protocols.len() as c_int,
  153. );
  154. }
  155. Ok(())
  156. }
  157. /// Set the name of the window to the desired string
  158. pub fn set_title(&mut self, name: &str) -> Result<(), failure::Error> {
  159. unsafe {
  160. xlib::XStoreName(
  161. self.display.display,
  162. self.window,
  163. CString::new(name)?.as_ptr(),
  164. );
  165. }
  166. Ok(())
  167. }
  168. /// Map the window to the screen
  169. pub fn map(&mut self) {
  170. unsafe {
  171. xlib::XMapWindow(self.display.display, self.window);
  172. }
  173. }
  174. /// Intern a string in the x server
  175. pub fn intern(&mut self, s: &str) -> Result<u64, failure::Error> {
  176. unsafe {
  177. let cstr = CString::new(s)?;
  178. Ok(xlib::XInternAtom(self.display.display, cstr.as_ptr(), 0))
  179. }
  180. }
  181. /// Modify the supplied property to the noted value.
  182. pub fn change_property<T: XProperty>(
  183. &mut self,
  184. prop: &str,
  185. val: &[T]
  186. ) -> Result<(), failure::Error>
  187. {
  188. let prop = self.intern(prop)?;
  189. unsafe {
  190. let len = val.len();
  191. T::with_ptr(val, self, |w, typ, ptr| {
  192. xlib::XChangeProperty(
  193. w.display.display,
  194. w.window,
  195. prop,
  196. typ,
  197. 32,
  198. xlib::PropModeReplace,
  199. ptr,
  200. len as c_int,
  201. );
  202. })?;
  203. }
  204. Ok(())
  205. }
  206. /// Get the Cairo drawing surface corresponding to the whole
  207. /// window
  208. pub fn get_cairo_surface(&mut self) -> cairo::Surface {
  209. unsafe {
  210. let s = cairo_sys::cairo_xlib_surface_create(
  211. self.display.display,
  212. self.window,
  213. xlib::XDefaultVisual(self.display.display, self.screen),
  214. self.width,
  215. self.height,
  216. );
  217. cairo::Surface::from_raw_none(s)
  218. }
  219. }
  220. /// handle a single event, wrapping it as an 'Event'. This is
  221. /// pretty useless right now, but the plan is to make it easier to
  222. /// handle things like keyboard input and mouse input later. This
  223. /// will also only return values for events we care about
  224. pub fn handle(&mut self) -> Option<Event> {
  225. let mut e = unsafe { mem::uninitialized() };
  226. unsafe { xlib::XNextEvent(self.display.display, &mut e) };
  227. match e.get_type() {
  228. // Is it a quit event? We gotta do some tedious string
  229. // comparison to find out
  230. xlib::ClientMessage => {
  231. let xclient: xlib::XClientMessageEvent = From::from(e);
  232. if xclient.message_type == self.wm_protocols && xclient.format == 32 {
  233. let protocol = xclient.data.get_long(0) as xlib::Atom;
  234. if protocol == self.wm_delete_window {
  235. return Some(Event::QuitEvent);
  236. }
  237. }
  238. }
  239. // Is it a show event?
  240. xlib::Expose => return Some(Event::ShowEvent),
  241. // otherwise, it might be a mouse press event
  242. xlib::GenericEvent => {
  243. let mut cookie: xlib::XGenericEventCookie = From::from(e);
  244. unsafe { xlib::XGetEventData(self.display.display, &mut cookie) };
  245. match cookie.evtype {
  246. xinput2::XI_ButtonPress => {
  247. let data: &xinput2::XIDeviceEvent =
  248. unsafe { mem::transmute(cookie.data) };
  249. return Some(Event::MouseEvent { x: data.event_x, y: data.event_y });
  250. }
  251. _ => (),
  252. }
  253. }
  254. _ => (),
  255. }
  256. None
  257. }
  258. /// True if there are any pending events.
  259. pub fn has_events(&mut self) -> bool {
  260. unsafe {
  261. xlib::XPending(self.display.display) != 0
  262. }
  263. }
  264. /// Did you know that X11 uses a file descriptor underneath the
  265. /// surface to wait on events? This lets us use select on it!
  266. pub fn get_fd(&mut self) -> i32 {
  267. unsafe {
  268. xlib::XConnectionNumber(self.display.display)
  269. }
  270. }
  271. pub fn size(&self) -> Size {
  272. Size { wd: self.width, ht: self.height, xo: 0, yo: 0 }
  273. }
  274. }
  275. /// A trait for abstracting over different values which are allowed
  276. /// for xlib properties
  277. pub trait XProperty : Sized {
  278. fn with_ptr(
  279. xs: &[Self],
  280. w: &mut Window,
  281. f: impl FnOnce(&mut Window, u64, *const u8),
  282. ) -> Result<(), failure::Error> ;
  283. }
  284. impl XProperty for i64 {
  285. fn with_ptr(
  286. xs: &[Self],
  287. w: &mut Window,
  288. f: impl FnOnce(&mut Window, u64, *const u8),
  289. ) -> Result<(), failure::Error> {
  290. f(w, xlib::XA_CARDINAL, unsafe { mem::transmute(xs.as_ptr()) });
  291. Ok(())
  292. }
  293. }
  294. impl XProperty for &str {
  295. fn with_ptr(
  296. xs: &[Self],
  297. w: &mut Window,
  298. f: impl FnOnce(&mut Window, u64, *const u8),
  299. ) -> Result<(), failure::Error> {
  300. let xs: Result<Vec<u64>, failure::Error> =
  301. xs.iter().map(|s| w.intern(s)).collect();
  302. f(w, xlib::XA_ATOM, unsafe { mem::transmute(xs?.as_ptr()) });
  303. Ok(())
  304. }
  305. }
  306. /// An ADT of only the events we care about, wrapped in a high-level
  307. /// way
  308. #[derive(Debug)]
  309. pub enum Event {
  310. MouseEvent { x:f64, y: f64 },
  311. ShowEvent,
  312. QuitEvent,
  313. }