window.rs 10 KB

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