window.rs 9.0 KB

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